hyper-html-api 0.4.0 → 0.5.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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Self-describing data layer for HTML files — a bidirectional engine that reads structured data out of an HTML page and writes structured data back into it, driven by a single declarative rules tag.
4
4
 
5
- Status: **early development** (Phase 0 — repo bootstrap). API shape and behavior are being ported from `hyperclay/server-lib/data-extractor.js`. See `plans/hyperclay/hyper-html-api/` in the workspace for the full specification.
5
+ Runs in production behind [hyperclay](https://hyperclay.com), Hyperclay Local, and [`@panphora/hyper-cms`](https://github.com/panphora/hypercms), and is vendored into [hyperclayjs](https://github.com/panphora/hyperclayjs) and [clayjs](https://clayjs.com). The same rules run in the browser and in Node under cheerio, through a pluggable adapter.
6
6
 
7
7
  ## Install
8
8
 
@@ -48,6 +48,66 @@ extracts data and `set(data)` writes it back. Token resolution is
48
48
  document-scoped, so a tag mounted in `<head>` is found even when `bind` is given
49
49
  a body or form element; `get()`/`set()` stay scoped to that element.
50
50
 
51
+ ## Upgrade
52
+
53
+ A page that was copied from a template can pull in the template's newer
54
+ version while keeping its own data. Two meta tags opt a page in:
55
+
56
+ ```html
57
+ <meta name="hyper-source" content="https://devlog.panphora.hyperclay.com">
58
+ <meta name="hyper-version" content="1.0.0">
59
+ ```
60
+
61
+ `hyper-source` points at the canonical version (and doubles as identity);
62
+ `hyper-version` is a dotted version number. Forks inherit both because copying
63
+ the HTML copies the tags. Without them the upgrade subsystem is inert.
64
+
65
+ ```js
66
+ HyperHtmlApi.upgrade.checkForUpdate({ force? })
67
+ // → { available, currentVersion, sourceVersion, sourceUrl } | null
68
+ // Fetches the source anonymously, reads its hyper-version, caches the result
69
+ // in localStorage for 24h. null = inert (missing tags, self-source, unreachable).
70
+
71
+ HyperHtmlApi.upgrade.extractAll(root?)
72
+ // → { dataByName, version } — keyed extraction of every rules tag on the page.
73
+
74
+ HyperHtmlApi.upgrade.run({ sourceUrl?, dataByName?, fromVersion? })
75
+ // → { html, fromVersion, toVersion, summary }
76
+ // The whole flow: extract keyed data from the live page, fetch the source's
77
+ // pristine HTML (DOMParser — its scripts never execute), evaluate its optional
78
+ // transform tag, join data into the parsed copy by exact rules-tag name, and
79
+ // serialize. Does NOT save; the caller decides how to persist `html`.
80
+ ```
81
+
82
+ The join is name-match per rules tag: fields present in both carry over, fields
83
+ only in the old data are discarded (and counted in `summary`), fields only in
84
+ the new template keep its defaults, and list counts follow the old data. For
85
+ richer migrations (renames, splits, computed fields) the source declares a
86
+ transform as a non-executing script tag in its own HTML:
87
+
88
+ ```html
89
+ <script type="text/hyper-upgrade">
90
+ export default function upgrade(dataByName, { fromVersion, toVersion }) {
91
+ return {
92
+ api: { heading: dataByName.api.title }, // rename a field
93
+ settings: dataByName.profile, // re-key a rules tag
94
+ }
95
+ }
96
+ </script>
97
+ ```
98
+
99
+ Browsers ignore the unknown script type, so the tag never runs on the source
100
+ page itself. The upgrading fork reads it out of the fetched copy and evaluates
101
+ it as a real ES module (Blob URL import), so it may be `async`; it must be
102
+ self-contained (relative imports won't resolve; absolute CDN imports work). At
103
+ most one per document. If it throws, the upgrade aborts and nothing is saved.
104
+
105
+ Security: the transform runs in the fork's context, but only after an explicit
106
+ upgrade action, and upgrading means adopting the source's HTML and scripts
107
+ wholesale anyway — evaluating its transform first adds no new trust. Sources
108
+ must be served with CORS open for anonymous reads (Hyperclay serves all site
109
+ HTML with `Access-Control-Allow-Origin: *`).
110
+
51
111
  ## Node API
52
112
 
53
113
  ```js
@@ -1 +1 @@
1
- var hyperHtmlApiData=(()=>{var k=Object.defineProperty;var ce=Object.getOwnPropertyDescriptor;var fe=Object.getOwnPropertyNames;var ue=Object.prototype.hasOwnProperty;var Y=(e,t)=>{for(var n in t)k(e,n,{get:t[n],enumerable:!0})},ae=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of fe(t))!ue.call(e,r)&&r!==n&&k(e,r,{get:()=>t[r],enumerable:!(o=ce(t,r))||o.enumerable});return e};var he=e=>ae(k({},"__esModule",{value:!0}),e);var Me={};Y(Me,{applyData:()=>z,default:()=>we,engine:()=>P,extractData:()=>X});var C=["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"],B=new Set(C),Q=new Set(["textContent","innerText","innerHTML","value","checked","selected","disabled","readOnly","type","id","className","title"]),Z=new Set(["tagName","nodeName","nodeType","nodeValue","childElementCount","classList","baseURI","documentURI","contentType","offsetWidth","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","currentSrc","duration","paused","dataset"]);var j={};Y(j,{EmptyListInsert:()=>I,MAX_RULE_DEPTH:()=>A,MaxRuleDepthExceeded:()=>E,RuleTargetReadOnly:()=>w,RulesParseError:()=>S,ShapeMismatch:()=>b,UnknownRulesVersion:()=>N,UpgradeAlreadyRegistered:()=>U});var S=class extends Error{constructor(t,n){super(t),this.name="RulesParseError",this.cause=n}},N=class extends Error{constructor(t){super(`unknown rules version: ${t}. Library supports "1".`),this.name="UnknownRulesVersion",this.version=t}},A=20,E=class extends Error{constructor(t){super(`rule depth exceeded ${A} at path: ${t.join(".")}`),this.name="MaxRuleDepthExceeded",this.path=t}},b=class extends Error{constructor(t){super(`shape mismatch: ${t.length} field(s) failed validation`),this.name="ShapeMismatch",this.mismatches=t}},I=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}},w=class extends Error{constructor(t){super(`cannot write to read-only DOM property "${t}"`),this.name="RuleTargetReadOnly",this.target=t}},U=class extends Error{constructor(){super("upgrade transform already registered; only one registration is allowed per page."),this.name="UpgradeAlreadyRegistered"}};function g(e,t,n,o={}){return q(e,t,n,{depth:0,path:[]},o)}function q(e,t,n,o,r){if(o.depth>A)throw new E(o.path);if(typeof n=="string")return de(e,t,n,r);if(Array.isArray(n)){let[i,c]=n;return e.find(t,i,r).map((l,a)=>q(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]=q(e,t,s,{depth:o.depth+1,path:[...o.path,c]},r);return i}return null}function de(e,t,n,o){if(n.endsWith("[]")){let i=n.slice(0,-2);return e.find(t,i,o).map(c=>e.text(c))}if(n.startsWith("@"))return ee(e,t,n.slice(1));if(n.includes("@")){let i=n.lastIndexOf("@"),c=n.slice(0,i),s=n.slice(i+1),l=c?e.find(t,c,o):[t];return l.length===0?null:ee(e,l[0],s)}if(n===".")return e.text(t);let r=e.find(t,n,o);return r.length===0?null:e.text(r[0])}function ee(e,t,n){if(B.has(n)){let r=e.prop(t,n);return r==null?null:String(r)}let o=e.attr(t,n);return o||null}var pe=.5;function v(e,t,n,o,r,i,c,s={}){let l=e.find(t,n,s);if(r.length===0){l.forEach(h=>e.remove(h));return}let a=r.length>l.length,u=l[0]||null;if(a&&!u&&(u=Re(e,t,n,s),!u))throw new I(i.path);let d=l.map(h=>me(e,h,o,s)),f=null;if(u){f=e.clone(u),s.templateAttr&&e.removeAttr(f,s.templateAttr);let h=e.stripIds(f);h>0&&console.warn(`[hyper-html-api] stripped ${h} id attribute(s) from cloned template at "${i.path.join(".")||"(root)"}"`)}let H=ye(r,d,o),R=l[0]||u,L=e.parent(R),se=l.length>0?Ee(e,L,R):0,K=new Set,W=r.map((h,m)=>{let p=H[m];if(p>=0)return K.add(p),l[p];let O=e.clone(f);return e.stripIds(O),O});l.forEach((h,m)=>{K.has(m)||e.remove(h)}),W.forEach((h,m)=>{let p=se+m;e.children(L).findIndex(le=>e.sameNode(le,h))!==p&&e.insertAt(L,h,p)}),W.forEach((h,m)=>{if(o===null){let p=r[m],O=p==null?"":String(p);e.text(h)!==O&&e.text(h,O)}else{let p=c(e,h,o,r[m],{depth:i.depth+1,path:[...i.path,m]},s);p&&p!==h&&(W[m]=p)}})}function me(e,t,n,o){return n===null?e.text(t):g(e,t,n,o)}function ye(e,t,n){let o=new Array(e.length).fill(-1),r=new Set;return e.forEach((i,c)=>{let s=-1,l=-1;t.forEach((a,u)=>{if(r.has(u))return;let d=ge(i,a,n),f=d===l&&s>=0?Math.abs(u-c)<Math.abs(s-c):!1;(d>l||f)&&(l=d,s=u)}),l>=pe&&(o[c]=s,r.add(s))}),o}function ge(e,t,n){if(n===null)return e===t?1:0;let o=Object.keys(n||{});if(o.length===0)return 0;let r=0;for(let i of o)JSON.stringify(e?.[i])===JSON.stringify(t?.[i])&&r++;return r/o.length}function Ee(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 Re(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}var te=new Set(["checked","selected","disabled","readOnly","paused"]);function T(e,t,n,o,r={}){let i=[];if(J(n,o,[],i),i.length)throw new b(i);$(e,t,n,o,{depth:0,path:[]},r)}function $(e,t,n,o,r,i={}){if(r.depth>A)throw new E(r.path);if(o===void 0)return t;if(typeof n=="string")return Oe(e,t,n,o,r,i);if(Array.isArray(n)){let[c,s]=n;return v(e,t,c,s,o,r,$,i),t}if(typeof n=="object"&&n!==null){for(let[c,s]of Object.entries(n)){let l=$(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 Oe(e,t,n,o,r,i){if(n.endsWith("[]")){let s=n.slice(0,-2);return v(e,t,s,null,o,r,$,i),t}if(n.startsWith("@"))return ne(e,t,n.slice(1),o);if(n.includes("@")){let s=n.lastIndexOf("@"),l=n.slice(0,s),a=n.slice(s+1),u=l?e.find(t,l,i):[t];return u.length===0||ne(e,u[0],a,o),t}if(n===".")return e.text(t,o==null?"":String(o)),t;let c=e.find(t,n,i);return c.length===0||e.text(c[0],o==null?"":String(o)),t}function ne(e,t,n,o){if(Z.has(n))throw new w(n);if(n==="outerHTML"){let r=o==null?"":String(o);return e.replaceWith(t,r)}return Q.has(n)?(e.prop(t,n,Se(n,o)),t):(e.attr(t,n,o==null?"":String(o)),t)}function Se(e,t){return t==null?te.has(e)?!1:"":te.has(e)?!!t:t}function J(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:_([...n,i]),expected:"scalar",got:M(r)})}):o.push({path:_(n),expected:"array",got:M(t)});return}t!==null&&typeof t=="object"&&o.push({path:_(n),expected:"scalar",got:M(t)});return}if(Array.isArray(e)){if(!Array.isArray(t)){o.push({path:_(n),expected:"array",got:M(t)});return}let r=e[1];t.forEach((i,c)=>J(r,i,[...n,c],o));return}if(typeof e=="object"&&e!==null){if(t===null||Array.isArray(t)||typeof t!="object"){o.push({path:_(n),expected:"object",got:M(t)});return}for(let[r,i]of Object.entries(e))J(i,t[r],[...n,r],o)}}}function M(e){return e===null?"null":Array.isArray(e)?"array":typeof e}function _(e){return e.join(".")}function V(e){try{return JSON.parse(e)}catch(t){throw new S(`Invalid strict JSON: ${t.message}`,t)}}function D(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 d=!1,f=c+1;for(;f<r.length&&/\s/.test(r[f]);)f++;if(f<r.length&&/[a-zA-Z_]/.test(r[f])&&(d=!0),!d){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 d=s,f=c+1;for(;f<r.length&&r[f]!==d;)r[f]==="\\"&&f++,f++;i.push({type:t.STRING,value:r.substring(c+1,f),quoted:!0,sourceQuote:d}),c=f+1;continue}let l=c,a;for(;l<r.length&&!/[{},]/.test(r[l]);)if(r[l]===":"){let d=[":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"],f=!1;for(let H of d){let R=H.substring(1);if(r.substring(l+1,l+1+R.length)===R){f=!0,l+=R.length;break}}if(!f)break}else if(r[l]==="["){for(l++;l<r.length&&r[l]!=="]";){if(r[l]==='"'||r[l]==="'"){let d=r[l];for(l++;l<r.length&&r[l]!==d;)r[l]==="\\"&&l++,l++}l++}l<r.length&&r[l]==="]"&&l++}else l++;a=r.substring(c,l);let u=t.IDENTIFIER;/^-?\d+(\.\d+)?$/.test(a)?u=t.NUMBER:a==="true"||a==="false"||a==="null"?u=t.BOOLEAN:/^[.#@\[]|[.#@\[]| /.test(a)&&(u=t.SELECTOR),i.push({type:u,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,u)=>u.length%2===0?u+'\\"':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 S("Invalid extraction rules syntax: "+r.message,r)}}var Ae="1",re=/^[a-zA-Z0-9_-]+$/;function x(e,t,n){let o;if(n===void 0)o="script[data-rules-name]";else{if(typeof n!="string"||!re.test(n))throw new Error(`hyper-html-api: invalid rules token ${JSON.stringify(n)} (must match ${re})`);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!==Ae)throw new N(c);return{rules:D(e.text(i)),tagNode:i}}function F(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 x(e,o,n)}return null}function oe(e,t,n,o){let r=F(e,t,n);if(!r){let s=typeof n=="string"?`data-rules-name~="${n}"`:"the provided rules object";throw new Error(`hyper-html-api: could not resolve rules for ${s}`)}let{rules:i,tagNode:c}=r;return{rules:i,tagNode:c,get:()=>g(e,t,i,o),set:s=>T(e,t,i,s,o)}}function xe(e){return e&&e.nodeType===1&&e.tagName==="SCRIPT"&&e.hasAttribute&&e.hasAttribute("data-rules-name")}function Ne(e){return e?(e.nodeType===9||e.nodeType===11,e):null}var be={find(e,t,n={}){let o=Ne(e);if(!o||!o.querySelectorAll)return[];let r=Array.from(o.querySelectorAll(t));n.includeRulesTag||(r=r.filter(s=>!xe(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}},y=be;var P={extract:(e,t,n)=>g(y,e,t,n),apply:(e,t,n,o)=>T(y,e,t,n,o),findRulesIn:(e,t)=>x(y,e,t),findRules:(e,t)=>F(y,e,t),bind:(e,t,n)=>oe(y,e,t,n),parseStrict:V,parseRelaxed:D,errors:j,DOM_PROPERTIES:C},G=e=>!!e&&typeof e.nodeType=="number";function ie(e){let t=e&&e.ownerDocument?e.ownerDocument:e,n=y.find(t,"script[data-rules-name]",{includeRulesTag:!0});if(n.length===0)throw new Error('hyper-html-api: no rules tag found. Add <script type="application/json" data-rules-name="\u2026" data-rules-version="1"> or pass rules.');if(n.length>1)throw new Error('hyper-html-api: multiple rules tags found; pass a name, e.g. extractData("api").');return x(y,t).rules}function X(e,t){let n=G(e)?e:document,o=G(e)?t:e;return o===void 0?g(y,n,ie(n)):P.bind(n,o).get()}function z(e,t,n){if(!G(e))throw new Error("hyper-html-api: applyData(root, data, source?) needs a DOM root as the first argument.");return n===void 0?T(y,e,ie(e),t):P.bind(e,n).set(t),e}var Ie={engine:P,extractData:X,applyData:z},we=Ie;return he(Me);})();
1
+ var hyperHtmlApiData=(()=>{var k=Object.defineProperty;var lt=Object.getOwnPropertyDescriptor;var ct=Object.getOwnPropertyNames;var ft=Object.prototype.hasOwnProperty;var K=(t,e)=>{for(var n in e)k(t,n,{get:e[n],enumerable:!0})},ut=(t,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of ct(e))!ft.call(t,r)&&r!==n&&k(t,r,{get:()=>e[r],enumerable:!(o=lt(e,r))||o.enumerable});return t};var at=t=>ut(k({},"__esModule",{value:!0}),t);var wt={};K(wt,{applyData:()=>X,default:()=>It,engine:()=>P,extractData:()=>G});var C=["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"],B=new Set(C),Y=new Set(["textContent","innerText","innerHTML","value","checked","selected","disabled","readOnly","type","id","className","title"]),Q=new Set(["tagName","nodeName","nodeType","nodeValue","childElementCount","classList","baseURI","documentURI","contentType","offsetWidth","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","currentSrc","duration","paused","dataset"]);var j={};K(j,{EmptyListInsert:()=>I,MAX_RULE_DEPTH:()=>A,MaxRuleDepthExceeded:()=>E,RuleTargetReadOnly:()=>w,RulesParseError:()=>S,ShapeMismatch:()=>b,UnknownRulesVersion:()=>N});var S=class extends Error{constructor(e,n){super(e),this.name="RulesParseError",this.cause=n}},N=class extends Error{constructor(e){super(`unknown rules version: ${e}. Library supports "1".`),this.name="UnknownRulesVersion",this.version=e}},A=20,E=class extends Error{constructor(e){super(`rule depth exceeded ${A} at path: ${e.join(".")}`),this.name="MaxRuleDepthExceeded",this.path=e}},b=class extends Error{constructor(e){super(`shape mismatch: ${e.length} field(s) failed validation`),this.name="ShapeMismatch",this.mismatches=e}},I=class extends Error{constructor(e){super(`cannot add items to empty list at "${e.join(".")}" \u2014 no sibling to clone as template. Seed the list with a hidden item first.`),this.name="EmptyListInsert",this.path=e}},w=class extends Error{constructor(e){super(`cannot write to read-only DOM property "${e}"`),this.name="RuleTargetReadOnly",this.target=e}};function g(t,e,n,o={}){return U(t,e,n,{depth:0,path:[]},o)}function U(t,e,n,o,r){if(o.depth>A)throw new E(o.path);if(typeof n=="string")return ht(t,e,n,r);if(Array.isArray(n)){let[i,c]=n;return t.find(e,i,r).map((l,a)=>U(t,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]=U(t,e,s,{depth:o.depth+1,path:[...o.path,c]},r);return i}return null}function ht(t,e,n,o){if(n.endsWith("[]")){let i=n.slice(0,-2);return t.find(e,i,o).map(c=>t.text(c))}if(n.startsWith("@"))return Z(t,e,n.slice(1));if(n.includes("@")){let i=n.lastIndexOf("@"),c=n.slice(0,i),s=n.slice(i+1),l=c?t.find(e,c,o):[e];return l.length===0?null:Z(t,l[0],s)}if(n===".")return t.text(e);let r=t.find(e,n,o);return r.length===0?null:t.text(r[0])}function Z(t,e,n){if(B.has(n)){let r=t.prop(e,n);return r==null?null:String(r)}let o=t.attr(e,n);return o||null}var dt=.5;function q(t,e,n,o,r,i,c,s={}){let l=t.find(e,n,s);if(r.length===0){l.forEach(h=>t.remove(h));return}let a=r.length>l.length,u=l[0]||null;if(a&&!u&&(u=Et(t,e,n,s),!u))throw new I(i.path);let d=l.map(h=>pt(t,h,o,s)),f=null;if(u){f=t.clone(u),s.templateAttr&&t.removeAttr(f,s.templateAttr);let h=t.stripIds(f);h>0&&console.warn(`[hyper-html-api] stripped ${h} id attribute(s) from cloned template at "${i.path.join(".")||"(root)"}"`)}let H=mt(r,d,o),R=l[0]||u,L=t.parent(R),it=l.length>0?gt(t,L,R):0,z=new Set,W=r.map((h,m)=>{let p=H[m];if(p>=0)return z.add(p),l[p];let O=t.clone(f);return t.stripIds(O),O});l.forEach((h,m)=>{z.has(m)||t.remove(h)}),W.forEach((h,m)=>{let p=it+m;t.children(L).findIndex(st=>t.sameNode(st,h))!==p&&t.insertAt(L,h,p)}),W.forEach((h,m)=>{if(o===null){let p=r[m],O=p==null?"":String(p);t.text(h)!==O&&t.text(h,O)}else{let p=c(t,h,o,r[m],{depth:i.depth+1,path:[...i.path,m]},s);p&&p!==h&&(W[m]=p)}})}function pt(t,e,n,o){return n===null?t.text(e):g(t,e,n,o)}function mt(t,e,n){let o=new Array(t.length).fill(-1),r=new Set;return t.forEach((i,c)=>{let s=-1,l=-1;e.forEach((a,u)=>{if(r.has(u))return;let d=yt(i,a,n),f=d===l&&s>=0?Math.abs(u-c)<Math.abs(s-c):!1;(d>l||f)&&(l=d,s=u)}),l>=dt&&(o[c]=s,r.add(s))}),o}function yt(t,e,n){if(n===null)return t===e?1:0;let o=Object.keys(n||{});if(o.length===0)return 0;let r=0;for(let i of o)JSON.stringify(t?.[i])===JSON.stringify(e?.[i])&&r++;return r/o.length}function gt(t,e,n){let o=t.children(e);for(let r=0;r<o.length;r++)if(t.sameNode(o[r],n))return r;return-1}function Et(t,e,n,o){if(!o.templateAttr)return null;let r=e;for(;r;){let i=t.find(r,n,{includeRulesTag:!1,templateAttr:null});for(let c of i)if(t.attr(c,o.templateAttr)!=null)return c;r=t.parent(r)}return null}var tt=new Set(["checked","selected","disabled","readOnly","paused"]);function T(t,e,n,o,r={}){let i=[];if(v(n,o,[],i),i.length)throw new b(i);$(t,e,n,o,{depth:0,path:[]},r)}function $(t,e,n,o,r,i={}){if(r.depth>A)throw new E(r.path);if(o===void 0)return e;if(typeof n=="string")return Rt(t,e,n,o,r,i);if(Array.isArray(n)){let[c,s]=n;return q(t,e,c,s,o,r,$,i),e}if(typeof n=="object"&&n!==null){for(let[c,s]of Object.entries(n)){let l=$(t,e,s,o==null?o:o[c],{depth:r.depth+1,path:[...r.path,c]},i);l&&l!==e&&(e=l)}return e}return e}function Rt(t,e,n,o,r,i){if(n.endsWith("[]")){let s=n.slice(0,-2);return q(t,e,s,null,o,r,$,i),e}if(n.startsWith("@"))return et(t,e,n.slice(1),o);if(n.includes("@")){let s=n.lastIndexOf("@"),l=n.slice(0,s),a=n.slice(s+1),u=l?t.find(e,l,i):[e];return u.length===0||et(t,u[0],a,o),e}if(n===".")return t.text(e,o==null?"":String(o)),e;let c=t.find(e,n,i);return c.length===0||t.text(c[0],o==null?"":String(o)),e}function et(t,e,n,o){if(Q.has(n))throw new w(n);if(n==="outerHTML"){let r=o==null?"":String(o);return t.replaceWith(e,r)}return Y.has(n)?(t.prop(e,n,Ot(n,o)),e):(t.attr(e,n,o==null?"":String(o)),e)}function Ot(t,e){return e==null?tt.has(t)?!1:"":tt.has(t)?!!e:e}function v(t,e,n,o){if(e!==void 0){if(typeof t=="string"){if(t.endsWith("[]")){Array.isArray(e)?e.forEach((r,i)=>{typeof r=="object"&&r!==null&&o.push({path:_([...n,i]),expected:"scalar",got:M(r)})}):o.push({path:_(n),expected:"array",got:M(e)});return}e!==null&&typeof e=="object"&&o.push({path:_(n),expected:"scalar",got:M(e)});return}if(Array.isArray(t)){if(!Array.isArray(e)){o.push({path:_(n),expected:"array",got:M(e)});return}let r=t[1];e.forEach((i,c)=>v(r,i,[...n,c],o));return}if(typeof t=="object"&&t!==null){if(e===null||Array.isArray(e)||typeof e!="object"){o.push({path:_(n),expected:"object",got:M(e)});return}for(let[r,i]of Object.entries(t))v(i,e[r],[...n,r],o)}}}function M(t){return t===null?"null":Array.isArray(t)?"array":typeof t}function _(t){return t.join(".")}function J(t){try{return JSON.parse(t)}catch(e){throw new S(`Invalid strict JSON: ${e.message}`,e)}}function D(t){try{return JSON.parse(t)}catch{}let e={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 d=!1,f=c+1;for(;f<r.length&&/\s/.test(r[f]);)f++;if(f<r.length&&/[a-zA-Z_]/.test(r[f])&&(d=!0),!d){i.push({type:s,value:s}),c++;continue}}if(s==="]"){i.push({type:s,value:s}),c++;continue}if(s===":"){i.push({type:e.COLON,value:s}),c++;continue}if(s===","){i.push({type:e.COMMA,value:s}),c++;continue}if(s==='"'||s==="'"){let d=s,f=c+1;for(;f<r.length&&r[f]!==d;)r[f]==="\\"&&f++,f++;i.push({type:e.STRING,value:r.substring(c+1,f),quoted:!0,sourceQuote:d}),c=f+1;continue}let l=c,a;for(;l<r.length&&!/[{},]/.test(r[l]);)if(r[l]===":"){let d=[":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"],f=!1;for(let H of d){let R=H.substring(1);if(r.substring(l+1,l+1+R.length)===R){f=!0,l+=R.length;break}}if(!f)break}else if(r[l]==="["){for(l++;l<r.length&&r[l]!=="]";){if(r[l]==='"'||r[l]==="'"){let d=r[l];for(l++;l<r.length&&r[l]!==d;)r[l]==="\\"&&l++,l++}l++}l<r.length&&r[l]==="]"&&l++}else l++;a=r.substring(c,l);let u=e.IDENTIFIER;/^-?\d+(\.\d+)?$/.test(a)?u=e.NUMBER:a==="true"||a==="false"||a==="null"?u=e.BOOLEAN:/^[.#@\[]|[.#@\[]| /.test(a)&&(u=e.SELECTOR),i.push({type:u,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===e.COLON){i+=s.value;continue}if(s.type===e.COMMA){let l=r[c+1];if(l&&(l.type==="}"||l.type==="]"))continue;i+=s.value;continue}if(s.type===e.STRING&&s.quoted){let l=s.value;s.sourceQuote==="'"&&(l=l.replace(/\\'/g,"'"),l=l.replace(/(\\*)"/g,(a,u)=>u.length%2===0?u+'\\"':a)),i+=`"${l}"`;continue}if(s.type===e.NUMBER||s.type===e.BOOLEAN){i+=s.value;continue}if(s.type===e.SELECTOR||s.type===e.IDENTIFIER){i+=`"${s.value}"`;continue}i+=`"${s.value}"`}return i}try{let r=n(t),i=o(r);return JSON.parse(i)}catch(r){throw new S("Invalid extraction rules syntax: "+r.message,r)}}var St="1",nt=/^[a-zA-Z0-9_-]+$/;function x(t,e,n){let o;if(n===void 0)o="script[data-rules-name]";else{if(typeof n!="string"||!nt.test(n))throw new Error(`hyper-html-api: invalid rules token ${JSON.stringify(n)} (must match ${nt})`);o=`script[data-rules-name~="${n}"]`}let r=t.find(e,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=t.attr(i,"data-rules-version");if(c!==St)throw new N(c);return{rules:D(t.text(i)),tagNode:i}}function V(t,e,n){if(n&&typeof n=="object")return{rules:n,tagNode:null};if(typeof n=="string"){let o=e&&e.ownerDocument?e.ownerDocument:e;return x(t,o,n)}return null}function rt(t,e,n,o){let r=V(t,e,n);if(!r){let s=typeof n=="string"?`data-rules-name~="${n}"`:"the provided rules object";throw new Error(`hyper-html-api: could not resolve rules for ${s}`)}let{rules:i,tagNode:c}=r;return{rules:i,tagNode:c,get:()=>g(t,e,i,o),set:s=>T(t,e,i,s,o)}}function Tt(t){return t&&t.nodeType===1&&t.tagName==="SCRIPT"&&t.hasAttribute&&t.hasAttribute("data-rules-name")}function xt(t){return t?(t.nodeType===9||t.nodeType===11,t):null}var Nt={find(t,e,n={}){let o=xt(t);if(!o||!o.querySelectorAll)return[];let r=Array.from(o.querySelectorAll(e));n.includeRulesTag||(r=r.filter(s=>!Tt(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(t){return t?t.parentElement:null},children(t){return t?Array.from(t.children):[]},text(t,e){if(e===void 0)return(t.textContent||"").trim();t.textContent=e},attr(t,e,n){if(n===void 0)return t.hasAttribute&&t.hasAttribute(e)?t.getAttribute(e):null;t.setAttribute(e,n)},removeAttr(t,e){t&&t.removeAttribute&&t.removeAttribute(e)},prop(t,e,n){if(n===void 0){let o=t?t[e]:void 0;return o!==void 0?o:null}t[e]=n},clone(t){return t.cloneNode(!0)},insertAt(t,e,n){let o=t.children[n]||null;t.insertBefore(e,o)},remove(t){t&&t.parentNode&&t.parentNode.removeChild(t)},replaceWith(t,e){if(!t||!t.parentNode)throw new Error("dom.replaceWith: node has no parent");let o=t.ownerDocument.createElement("template");o.innerHTML=e;let r=o.content.firstElementChild;if(!r)throw new Error("dom.replaceWith: html did not parse to an element");return t.parentNode.replaceChild(r,t),r},stripIds(t){let e=0;return t.id&&(t.removeAttribute("id"),e++),(t.querySelectorAll?t.querySelectorAll("[id]"):[]).forEach(o=>{o.removeAttribute("id"),e++}),e},sameNode(t,e){return t===e}},y=Nt;var P={extract:(t,e,n)=>g(y,t,e,n),apply:(t,e,n,o)=>T(y,t,e,n,o),findRulesIn:(t,e)=>x(y,t,e),findRules:(t,e)=>V(y,t,e),bind:(t,e,n)=>rt(y,t,e,n),parseStrict:J,parseRelaxed:D,errors:j,DOM_PROPERTIES:C},F=t=>!!t&&typeof t.nodeType=="number";function ot(t){let e=t&&t.ownerDocument?t.ownerDocument:t,n=y.find(e,"script[data-rules-name]",{includeRulesTag:!0});if(n.length===0)throw new Error('hyper-html-api: no rules tag found. Add <script type="application/json" data-rules-name="\u2026" data-rules-version="1"> or pass rules.');if(n.length>1)throw new Error('hyper-html-api: multiple rules tags found; pass a name, e.g. extractData("api").');return x(y,e).rules}function G(t,e){let n=F(t)?t:document,o=F(t)?e:t;return o===void 0?g(y,n,ot(n)):P.bind(n,o).get()}function X(t,e,n){if(!F(t))throw new Error("hyper-html-api: applyData(root, data, source?) needs a DOM root as the first argument.");return n===void 0?T(y,t,ot(t),e):P.bind(t,n).set(e),t}var bt={engine:P,extractData:G,applyData:X},It=bt;return at(wt);})();
@@ -1,3 +1,3 @@
1
- var HyperHtmlApi=(()=>{var Se=Object.defineProperty;var bt=Object.getOwnPropertyDescriptor;var At=Object.getOwnPropertyNames;var Mt=Object.prototype.hasOwnProperty;var xe=(e,t)=>{for(var n in t)Se(e,n,{get:t[n],enumerable:!0})},Et=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of At(t))!Mt.call(e,o)&&o!==n&&Se(e,o,{get:()=>t[o],enumerable:!(r=bt(t,o))||r.enumerable});return e};var St=e=>Et(Se({},"__esModule",{value:!0}),e);var Sn={};xe(Sn,{applyData:()=>ze,cms:()=>gt,default:()=>En,engine:()=>ae,extractData:()=>Ke,upgrade:()=>yt});var le={};xe(le,{fromString:()=>ue,getRuleAtPath:()=>ve,getValueAtPath:()=>Q,parseConfigKey:()=>vt,setAtPath:()=>F,toConfigKey:()=>xt,toString:()=>_});function _(e){return e.map(String).join(".")}function xt(e){return e.map(t=>typeof t=="number"?"*":String(t)).join(".")}function vt(e){return e===""?[]:e.split(".")}function ue(e){return e===""?[]:e.split(".").map(t=>/^\d+$/.test(t)?Number(t):t)}function ve(e,t){let n=e;for(let r of t){if(n==null||typeof n=="string")return;if(Array.isArray(n)){if(typeof r!="number"&&r!=="*")return;n=n[1];continue}if(typeof n=="object"){if(typeof r=="number"||!(r in n))return;n=n[r];continue}return}return n}function Q(e,t){let n=e;for(let r of t){if(n==null)return;n=n[r]}return n}function F(e,t,n){if(t.length===0)return n;let[r,...o]=t;if(typeof r=="number"){let i=Array.isArray(e)?[...e]:[];return i[r]=F(i[r],o,n),i}return{...e&&typeof e=="object"?e:{},[r]:F((e||{})[r],o,n)}}function z(e){if(typeof e=="string")return e.endsWith("[]")?[]:"";if(Array.isArray(e))return[];if(typeof e=="object"&&e!==null){let t={};for(let[n,r]of Object.entries(e))t[n]=z(r);return t}return""}var fe=new WeakMap;var wt=new Set(["checked","selected","disabled","readOnly","paused"]);function we({rules:e,data:t,appRoot:n,cmsRoot:r}){let o=document.createDocumentFragment(),i={rules:e,appRoot:n,cmsRoot:r};return o.appendChild(Re({rule:e,value:t,path:[],ctx:i})),o}function Te(e,{rules:t,getData:n,onChange:r}){e.setAttribute("data-hha-form-root",""),Xe.set(e,{rules:t,getData:n,onChange:r}),Tt()}var Xe=new WeakMap,Ge=!1;function Tt(){Ge||(document.addEventListener("input",Qe,!0),document.addEventListener("change",Qe,!0),document.addEventListener("click",Rt,!0),Ge=!0)}function Ze(e){if(!(e instanceof Element))return null;let t=e.closest("[data-hha-form-root]");return t&&Xe.get(t)||null}function Rt(e){if(!(e.target instanceof Element))return;let t=e.target.closest("[data-hha-action]");if(!t||e.defaultPrevented)return;let n=Ze(t);if(!n)return;let{rules:r,getData:o,onChange:i}=n,u=t.getAttribute("data-hha-action"),s=ue(t.getAttribute("data-hha-path")||"");if(u==="scalar-array-add"){let a=Q(o(),s)||[];i(F(o(),s,[...a,""]),{structural:!0});return}if(u==="object-array-add"){let a=ve(r,s);if(!Array.isArray(a))return;let M=Q(o(),s)||[];i(F(o(),s,[...M,z(a[1])]),{structural:!0});return}if(u==="array-remove"){if(s.length===0)return;let a=s.slice(0,-1),M=s[s.length-1],w=Q(o(),a)||[];if(typeof M!="number")return;let b=w.filter((h,R)=>R!==M);i(F(o(),a,b),{structural:!0})}}function Qe(e){let t=e.target;if(!t?.matches?.("input, textarea, select"))return;let n=Ze(t);if(!n)return;let{getData:r,onChange:o}=n,i=t.closest("[data-hha-path]");if(!i)return;let u=ue(i.getAttribute("data-hha-path")||""),s=t.type==="checkbox"?t.checked:t.value;o(F(r(),u,s),{structural:!1})}function Re({rule:e,value:t,path:n,ctx:r}){if(typeof e=="string")return e.endsWith("[]")?It({rule:e,value:t,path:n,ctx:r}):Ot({rule:e,value:t,path:n,ctx:r});if(Array.isArray(e))return kt({rule:e,value:t,path:n,ctx:r});if(typeof e=="object"&&e!==null)return Nt({rule:e,value:t,path:n,ctx:r});let o=document.createElement("span");return o.textContent="(unsupported rule)",o}function Nt({rule:e,value:t,path:n,ctx:r}){let o=document.createElement("div");if(o.className="form-section",o.setAttribute("data-hha-path",_(n)),n.length>0){let i=document.createElement("div");i.className="form-section-label",i.textContent=de(n[n.length-1]),o.appendChild(i)}for(let[i,u]of Object.entries(e)){let s=[...n,i],a=t?.[i];o.appendChild(Re({rule:u,value:a,path:s,ctx:r}))}return o}function Ot({rule:e,value:t,path:n,ctx:r}){let o=document.createElement("div");o.className="field-row",o.setAttribute("data-hha-path",_(n));let i=document.createElement("div");i.className="field-body";let u=document.createElement("label");u.className="field-label",u.textContent=de(n[n.length-1]||".")+Dt(e);let s=Ct(e,r.appRoot),a=Lt(s,{value:t,rule:e,path:n,appRoot:r.appRoot}),M=a.el;return M.classList.add(s.type==="textarea"?"field-textarea":"field-input"),i.appendChild(u),i.appendChild(M),o.appendChild(i),fe.set(o,a),o}function It({rule:e,value:t,path:n,ctx:r}){let o=document.createElement("div");o.className="form-section",o.setAttribute("data-hha-path",_(n));let i=document.createElement("div");i.className="form-section-label",i.textContent=de(n[n.length-1]),o.appendChild(i);let u=Array.isArray(t)?t:[],s=document.createElement("div");o.appendChild(s),u.forEach((M,w)=>{let b=[...n,w],h=document.createElement("div");h.className="scalar-array-row",h.setAttribute("data-hha-path",_(b));let R=document.createElement("input");R.type="text",R.className="field-input",R.value=M==null?"":String(M);let N=document.createElement("button");N.type="button",N.className="array-remove",N.textContent="\xD7",N.title="remove",N.setAttribute("data-hha-action","array-remove"),N.setAttribute("data-hha-path",_(b)),h.appendChild(R),h.appendChild(N),s.appendChild(h)});let a=document.createElement("button");return a.type="button",a.className="array-add",a.textContent="+ add",a.setAttribute("data-hha-action","scalar-array-add"),a.setAttribute("data-hha-path",_(n)),o.appendChild(a),o}function kt({rule:e,value:t,path:n,ctx:r}){let[,o]=e,i=Array.isArray(t)?t:[],u=document.createElement("div");u.className="form-section",u.setAttribute("data-hha-path",_(n));let s=document.createElement("div");s.className="form-section-label",s.textContent=de(n[n.length-1]),u.appendChild(s),i.forEach((M,w)=>{let b=[...n,w],h=document.createElement("div");h.className="array-card",h.setAttribute("data-hha-path",_(b));let R=document.createElement("button");R.type="button",R.className="array-remove",R.textContent="\xD7",R.title="remove item",R.setAttribute("data-hha-action","array-remove"),R.setAttribute("data-hha-path",_(b)),h.appendChild(R);let N=Re({rule:o,value:M,path:b,ctx:r});N.querySelector(".form-section-label")?.remove(),h.appendChild(N),u.appendChild(h)});let a=document.createElement("button");return a.type="button",a.className="array-add",a.textContent="+ add",a.setAttribute("data-hha-action","object-array-add"),a.setAttribute("data-hha-path",_(n)),u.appendChild(a),u}function Lt(e,t){let n=Pt(e);if(e.type==="select"&&e.options)for(let r of e.options){let o=document.createElement("option");o.value=r.value,o.textContent=r.text,String(t.value)===r.value&&(o.selected=!0),n.appendChild(o)}else e.type==="checkbox"?n.checked=t.value===!0||t.value==="true"||t.value==="checked":(e.type,n.value=t.value==null?"":String(t.value));return{el:n,destroy(){},focus(){n.focus()},validate(){}}}function Ct(e,t){let n=null;if(e.startsWith("@")?n=e.slice(1):e.includes("@")&&(n=e.split("@")[1]||null),n&&wt.has(n))return{type:"checkbox"};if(n==="innerHTML")return{type:"textarea"};let r=Ht(e,t);if(!r)return{type:"text"};let o=(r.tagName||"").toLowerCase();if(o==="textarea")return{type:"textarea"};if(o==="select")return{type:"select",options:Array.from(r.querySelectorAll("option")).map(s=>({value:s.getAttribute("value")||s.textContent,text:s.textContent.trim()||s.getAttribute("value")||""}))};if(o==="input"){let u=(r.getAttribute("type")||"text").toLowerCase();if(u==="checkbox"||u==="radio")return{type:"checkbox"};if(u==="number")return{type:"number"}}let i=(r.textContent||"").trim();return i.length>60||i.includes(`
2
- `)?{type:"textarea"}:{type:"text"}}function Ht(e,t){if(!t||e==="."||e===""||e.startsWith("@"))return null;let n=e.includes("@")?e.split("@")[0]:e;if(!n)return null;try{return t.querySelector(n)}catch{return null}}function Pt(e){if(e.type==="textarea")return document.createElement("textarea");if(e.type==="select")return document.createElement("select");let t=document.createElement("input");return t.type=e.type==="checkbox"?"checkbox":e.type==="number"?"number":"text",t}function de(e){return typeof e=="number"?`#${e+1}`:String(e).replace(/([a-z])([A-Z])/g,"$1 $2").replace(/[_-]+/g," ").replace(/^\w/,t=>t.toUpperCase())}function Dt(e){return` \xB7 ${e}`}var et={includeClasses:!0,includeAttributes:["href","src","name","type","role","aria-label","alt","title"],excludeAttributePrefixes:["data-morph-","data-hyper-","data-im-"],textHintLength:64,excludeIds:!0,maxPathDepth:4,landmarks:["HEADER","NAV","MAIN","ASIDE","FOOTER","SECTION","ARTICLE"],weights:{signature:100,pathSegment:10,textMatch:20,textMismatch:25,uniqueCandidate:50,positionPenalty:1,slotMatch:30},minConfidence:101};function _t(e){let t=5381;for(let n=0;n<e.length;n++)t=(t<<5)+t^e.charCodeAt(n);return Math.abs(t).toString(36)}function jt(e){if(e.classList&&e.classList.length>0)return Array.from(e.classList).sort().join(" ");let t=e.getAttribute?.("class");return t?t.split(/\s+/).filter(Boolean).sort().join(" "):""}function $t(e,t){let n=[];for(let r of e.attributes||[]){let o=r.name;o==="id"||o==="class"||t.excludeAttributePrefixes.some(i=>o.startsWith(i))||t.includeAttributes.includes(o)&&n.push(`${o}=${r.value}`)}return n.sort().join("|")}function Bt(e,t){return(e.textContent||"").replace(/\s+/g," ").trim().slice(0,t.textHintLength)}function Ft(e,t){let n=[e.tagName];return t.includeClasses&&n.push(jt(e)),n.push($t(e,t)),_t(n.join("|"))}function Ut(e){let t=e.tagName,n=1,r=e.previousElementSibling;for(;r;)r.tagName===t&&n++,r=r.previousElementSibling;return n}function Wt(e,t){return e.id||e.getAttribute?.("role")?!0:t.landmarks.includes(e.tagName)}function qt(e){if(e.id)return`#${e.id}`;let t=e.getAttribute?.("role");return t?`@${t}`:e.tagName}function Vt(e,t){let n=[],r=e;for(;r&&r.tagName&&n.length<t.maxPathDepth;){let o=`${r.tagName}:${Ut(r)}`;if(n.unshift(o),r!==e&&Wt(r,t)){n.unshift(qt(r));break}r=r.parentElement}return n}function Kt(e,t){let n=0,r=e.length-1,o=t.length-1;for(;r>=0&&o>=0&&e[r]===t[o];)n++,r--,o--;return n}function $(e,t,n){if(n.has(e))return n.get(e);let r={signature:Ft(e,t),path:Vt(e,t),textHint:Bt(e,t)};return n.set(e,r),r}function ot(e,t,n,r){if(r.has(e))return r.get(e);let o=new Map,i=e.querySelectorAll("*"),u=0;for(let s of i){let a=$(s,t,n);a.domIndex=u++,o.has(a.signature)||o.set(a.signature,[]),o.get(a.signature).push(s)}return r.set(e,o),o}function zt(e,t,n){n.delete(e),t.delete(e);let r=e.querySelectorAll("*");for(let o of r)t.delete(o)}function Ne(e,t,n,r,o){let i=$(e,n,r),u=$(t,n,r),s=n.weights,a={},M=0;if(i.signature!==u.signature)return{score:0,breakdown:{rejected:"signature mismatch"}};M+=s.signature,a.signature=s.signature;let b=Kt(i.path,u.path)*s.pathSegment;M+=b,a.path=b;let h=!0;if(i.textHint&&u.textHint?i.textHint===u.textHint?(M+=s.textMatch,a.text=s.textMatch):(M-=s.textMismatch,a.text=-s.textMismatch,h=!1):i.textHint!==u.textHint&&(M-=s.textMismatch,a.text=-s.textMismatch,h=!1),o.candidateCount===1&&h&&(M+=s.uniqueCandidate,a.unique=s.uniqueCandidate),typeof i.domIndex=="number"&&typeof u.domIndex=="number"){let R=Math.abs(i.domIndex-u.domIndex),N=Math.min(R*s.positionPenalty,20);M-=N,a.drift=-N}return{score:M,breakdown:a}}function tt(e,t,n,r,o){if(n.excludeIds&&e.id)return null;let i=ot(t,n,r,o),u=$(e,n,r);if(typeof u.domIndex!="number"){let h=0,R=e.previousElementSibling;for(;R;)h++,R=R.previousElementSibling;u.domIndex=h}let s=i.get(u.signature)||[],a=n.excludeIds?s.filter(h=>!h.id):s;if(a.length===0)return null;let M=null,w=0,b=null;for(let h of a){let{score:R,breakdown:N}=Ne(e,h,n,r,{candidateCount:a.length});R>w&&(w=R,M=h,b=N)}return w<n.minConfidence?null:{element:M,confidence:w,breakdown:b}}function Jt(e,t,n,r){let o=[],i=n.weights.signature+n.weights.slotMatch,u={slot:i};function s(b){if(b.children)return b.children;let h=b.childNodes;if(!h)return[];let R=[];for(let N=0;N<h.length;N++)h[N].nodeType===1&&R.push(h[N]);return R}function a(b,h){let R=s(b),N=s(h);if(R.length===N.length)for(let k=0;k<R.length;k++){let m=R[k],O=N[k];if(n.excludeIds&&(m.id||O.id)||m.tagName!==O.tagName)continue;let x=$(m,n,r).signature,S=$(O,n,r).signature;x!==S&&o.push({newEl:m,oldEl:O,score:i,breakdown:u}),a(m,O)}}function M(b,h){for(;;){if(b.tagName===h.tagName)return[b,h];let R=s(b);if(!b.tagName&&R.length===1){b=R[0];continue}let N=s(h);if(N.length===1&&N[0].tagName===b.tagName){h=N[0];continue}return null}}let w=M(e,t);return w&&a(w[0],w[1]),o}function nt(e,t,n,r,o){let i=t.querySelectorAll("*"),u=ot(e,n,r,o),s=0;for(let b of i){let h=$(b,n,r);h.domIndex=s++}let a=[];for(let b of i){if(n.excludeIds&&b.id)continue;let h=$(b,n,r),R=u.get(h.signature)||[],N=n.excludeIds?R.filter(k=>!k.id):R;for(let k of N){let{score:m,breakdown:O}=Ne(b,k,n,r,{candidateCount:N.length});m>=n.minConfidence&&a.push({newEl:b,oldEl:k,score:m,breakdown:O})}}if(n.weights.slotMatch>0){let b=Jt(t,e,n,r);for(let h of b)a.push(h)}a.sort((b,h)=>h.score-b.score);let M=new Map,w=new Set;for(let{newEl:b,oldEl:h}of a)M.has(b)||w.has(h)||(M.set(b,h),w.add(h));return M}function rt(e,t,n,r){let o=$(e,n,r),i=$(t,n,r),{score:u,breakdown:s}=Ne(e,t,n,r,{candidateCount:1});return{matches:u>=n.minConfidence,score:u,breakdown:s,newMeta:{signature:o.signature,path:o.path,textHint:o.textHint},oldMeta:{signature:i.signature,path:i.path,textHint:i.textHint}}}function it(e={}){let t={...et,...e,weights:{...et.weights,...e.weights}},n=new WeakMap,r=new WeakMap;return{findMatch:(o,i)=>tt(o,i,t,n,r),computeMatches:(o,i)=>nt(o,i,t,n,r),explain:(o,i)=>rt(o,i,t,n),invalidate:o=>zt(o,n,r),session:()=>{let o=new WeakMap,i=new WeakMap;return{findMatch:(u,s)=>tt(u,s,t,o,i),computeMatches:(u,s)=>nt(u,s,t,o,i),explain:(u,s)=>rt(u,s,t,o)}},getConfig:()=>({...t})}}var Yt=it(),Oe=function(){"use strict";let e=()=>{};function t(m){if(!(m instanceof Element))return!1;if(m.hasAttribute("save-ignore"))return!0;if(m.tagName==="LINK"||m.tagName==="SCRIPT"){let O=m.getAttribute("src")||m.getAttribute("href")||"";if(O.startsWith("chrome-extension://")||O.startsWith("moz-extension://")||O.startsWith("safari-web-extension://"))return!0}return!1}function n(m,O){if(O!=="smart")return m.outerHTML;let x=m.getAttribute("src"),S=m.getAttribute("type")||"text/javascript";if(x)try{let v=new URL(x,window.location.href);return`ext:${S}:${v.origin}${v.pathname}${v.search}`}catch{return`ext:${S}:${x}`}else{let v=m.textContent.trim(),E=5381;for(let d=0;d<v.length;d++)E=(E<<5)+E^v.charCodeAt(d);return`inline:${S}:${Math.abs(E).toString(36)}`}}let r={morphStyle:"outerHTML",callbacks:{beforeNodeAdded:e,afterNodeAdded:e,beforeNodeMorphed:e,afterNodeMorphed:e,beforeNodeRemoved:e,afterNodeRemoved:e,beforeAttributeUpdated:e},head:{style:"merge",shouldPreserve:m=>m.getAttribute("im-preserve")==="true",shouldReAppend:m=>m.getAttribute("im-re-append")==="true",shouldRemove:e,afterHeadMorphed:e},scripts:{handle:!1,matchMode:"outerHTML",shouldPreserve:m=>m.getAttribute("im-preserve")==="true",shouldReAppend:m=>m.getAttribute("im-re-append")==="true",shouldRemove:e,afterScriptsHandled:e},restoreFocus:!0},o={computeMatches(m,O){let{computeMatches:x}=Yt.session();return x(m,O)}};function i(m,O,x={}){m=N(m);let S=k(O),v=R(m,S,x),E=v.scripts.matchMode,d=new Set(Array.from(m.querySelectorAll("script")).map(l=>n(l,E))),y=s(v,()=>w(v,m,S,l=>l.morphStyle==="innerHTML"?(a(l,m,S),Array.from(m.childNodes)):u(l,m,S)));v.pantry.remove();let c=h(m,d,v);return c.length>0?y instanceof Promise?y.then(l=>Promise.all(c).then(()=>l)):Promise.all(c).then(()=>y):y}function u(m,O,x){let S=k(O);return a(m,S,x,O,O.nextSibling),Array.from(S.childNodes)}function s(m,O){if(!m.config.restoreFocus)return O();let x=document.activeElement;if(!(x instanceof HTMLInputElement||x instanceof HTMLTextAreaElement))return O();let{id:S,selectionStart:v,selectionEnd:E}=x,d=O();return S&&S!==document.activeElement?.getAttribute("id")&&(x=m.target.querySelector(`[id="${S}"]`),x?.focus()),x&&!x.selectionEnd&&E!=null&&x.setSelectionRange(v,E),d}let a=function(){function m(c,l,p,f=null,g=null){l instanceof HTMLTemplateElement&&p instanceof HTMLTemplateElement&&(l=l.content,p=p.content),f||=l.firstChild;for(let A of p.childNodes){if(t(A))continue;if(f&&f!=g){let I=x(c,A,f,g);if(I){I!==f&&v(c,f,I),M(I,A,c),f=I.nextSibling;continue}}if(A instanceof Element){let I=A.getAttribute("id");if(c.persistentIds.has(I)){let L=E(l,I,f,c);M(L,A,c),f=L.nextSibling;continue}if(!c.idMap.has(A)){let L=c.hyperMatches.get(A);if(L&&!c.idMap.has(L)){y(l,L,f),M(L,A,c),f=L.nextSibling;continue}}}let T=O(l,A,f,c);T&&(f=T.nextSibling)}for(;f&&f!=g;){let A=f;f=f.nextSibling,t(A)||S(c,A)}}function O(c,l,p,f){if(f.callbacks.beforeNodeAdded(l)===!1)return null;if(f.idMap.has(l)){let g=document.createElement(l.tagName);return c.insertBefore(g,p),M(g,l,f),f.callbacks.afterNodeAdded(g),g}else{let g=document.importNode(l,!0);return c.insertBefore(g,p),f.callbacks.afterNodeAdded(g),g}}let x=function(){function c(f,g,A,T){let I=g instanceof Element&&!f.idMap.has(g)?f.hyperMatches.get(g):null,L=null,j=g.nextSibling,G=0,C=A;for(;C&&C!=T;){if(p(C,g)){if(l(f,C,g)||C===I&&!f.idMap.has(C))return C;if(L===null){let V=C instanceof Element&&f.hyperMatchedOldElements.has(C);!f.idMap.has(C)&&!V&&(L=C)}}if(L===null&&j&&p(C,j)&&(G++,j=j.nextSibling,G>=2&&(L=void 0)),f.activeElementAndParents.includes(C))break;C=C.nextSibling}return L||null}function l(f,g,A){let T=f.idMap.get(g),I=f.idMap.get(A);if(!I||!T)return!1;for(let L of T)if(I.has(L))return!0;return!1}function p(f,g){let A=f,T=g;return A.nodeType===T.nodeType&&A.tagName===T.tagName&&(!A.getAttribute?.("id")||A.getAttribute?.("id")===T.getAttribute?.("id"))}return c}();function S(c,l){let p=l instanceof Element&&c.hyperMatchedOldElements.has(l)&&!c.idMap.has(l);if(c.idMap.has(l)||p)y(c.pantry,l,null);else{if(c.callbacks.beforeNodeRemoved(l)===!1)return;l.parentNode?.removeChild(l),c.callbacks.afterNodeRemoved(l)}}function v(c,l,p){let f=l;for(;f&&f!==p;){let g=f;f=f.nextSibling,t(g)||S(c,g)}return f}function E(c,l,p,f){let g=f.target.getAttribute?.("id")===l&&f.target||f.target.querySelector(`[id="${l}"]`)||f.pantry.querySelector(`[id="${l}"]`);return d(g,f),y(c,g,p),g}function d(c,l){let p=c.getAttribute("id");for(;c=c.parentNode;){let f=l.idMap.get(c);f&&(f.delete(p),f.size||l.idMap.delete(c))}}function y(c,l,p){if(c.moveBefore)try{c.moveBefore(l,p)}catch{c.insertBefore(l,p)}else c.insertBefore(l,p)}return m}(),M=function(){function m(d,y,c){return c.ignoreActive&&d===document.activeElement?null:(c.callbacks.beforeNodeMorphed(d,y)===!1||(d instanceof HTMLHeadElement&&c.head.ignore||(d instanceof HTMLHeadElement&&c.head.style!=="morph"?b(d,y,c):(O(d,y,c),E(d,c)||a(c,d,y))),c.callbacks.afterNodeMorphed(d,y)),d)}function O(d,y,c){let l=y.nodeType;if(l===1){let p=d,f=y,g=p.attributes,A=f.attributes;for(let T of A)v(T.name,p,"update",c)||p.getAttribute(T.name)!==T.value&&p.setAttribute(T.name,T.value);for(let T=g.length-1;0<=T;T--){let I=g[T];if(I&&!f.hasAttribute(I.name)){if(v(I.name,p,"remove",c))continue;p.removeAttribute(I.name)}}E(p,c)||x(p,f,c)}(l===8||l===3)&&d.nodeValue!==y.nodeValue&&(d.nodeValue=y.nodeValue)}function x(d,y,c){if(d instanceof HTMLInputElement&&y instanceof HTMLInputElement&&y.type!=="file"){let l=y.value,p=d.value;S(d,y,"checked",c),S(d,y,"disabled",c),c.formStateSync==="property"?p!==l&&(v("value",d,"update",c)||(d.value=l)):y.hasAttribute("value")?p!==l&&(v("value",d,"update",c)||(d.setAttribute("value",l),d.value=l)):v("value",d,"remove",c)||(d.value="",d.removeAttribute("value"))}else if(d instanceof HTMLOptionElement&&y instanceof HTMLOptionElement)S(d,y,"selected",c);else if(d instanceof HTMLTextAreaElement&&y instanceof HTMLTextAreaElement){let l=y.value,p=d.value;if(v("value",d,"update",c))return;l!==p&&(d.value=l),d.firstChild&&d.firstChild.nodeValue!==l&&(d.firstChild.nodeValue=l)}}function S(d,y,c,l){let p=y[c],f=d[c];if(p!==f){let g=v(c,d,"update",l);if(g||(d[c]=y[c]),l.formStateSync==="property")return;p?g||d.setAttribute(c,""):v(c,d,"remove",l)||d.removeAttribute(c)}}function v(d,y,c,l){return d==="value"&&l.ignoreActiveValue&&y===document.activeElement?!0:l.callbacks.beforeAttributeUpdated(d,y,c)===!1}function E(d,y){return!!y.ignoreActiveValue&&d===document.activeElement&&d!==document.body}return m}();function w(m,O,x,S){if(m.head.block){let v=O.querySelector("head"),E=x.querySelector("head");if(v&&E){let d=b(v,E,m);return Promise.all(d).then(()=>{let y=Object.assign(m,{head:{block:!1,ignore:!0}});return S(y)})}}return S(m)}function b(m,O,x){let S=[],v=[],E=[],d=[],y=x.scripts.matchMode,c=f=>{if(f.tagName==="SCRIPT")return n(f,y);if(f.tagName==="LINK"&&y==="smart"){let g=f.getAttribute("href");if(g)try{let A=new URL(g,window.location.href);return`link:${f.getAttribute("rel")||""}:${A.origin}${A.pathname}${A.search}`}catch{}}return f.outerHTML},l=new Map;for(let f of O.children)t(f)||l.set(c(f),f);for(let f of m.children){let g=c(f),A=l.has(g),T=x.head.shouldReAppend(f),I=x.head.shouldPreserve(f);A||I?T?v.push(f):(l.delete(g),E.push(f)):x.head.style==="append"?T&&(v.push(f),d.push(f)):x.head.shouldRemove(f)!==!1&&!t(f)&&v.push(f)}d.push(...l.values());let p=[];for(let f of d){let g=document.createRange().createContextualFragment(f.outerHTML).firstChild;if(x.callbacks.beforeNodeAdded(g)!==!1){if("href"in g&&g.href||"src"in g&&g.src){let A,T=new Promise(function(I){A=I});g.addEventListener("load",function(){A()}),p.push(T)}m.appendChild(g),x.callbacks.afterNodeAdded(g),S.push(g)}}for(let f of v)x.callbacks.beforeNodeRemoved(f)!==!1&&(m.removeChild(f),x.callbacks.afterNodeRemoved(f));return x.head.afterHeadMorphed(m,{added:S,kept:E,removed:v}),p}function h(m,O,x){if(!x.scripts.handle)return[];let S=[],v=[],E=[],d=[],y=x.scripts.matchMode,c=Array.from(m.querySelectorAll("script"));for(let p of c){let f=n(p,y),g=O.has(f),A=x.scripts.shouldPreserve(p),T=x.scripts.shouldReAppend(p);g||A?T?(v.push(p),d.push(p)):E.push(p):d.push(p)}for(let p of O){let f=c.some(g=>g.outerHTML===p)}let l=[];for(let p of d){if(x.callbacks.beforeNodeAdded(p)===!1)continue;let f=document.createRange().createContextualFragment(p.outerHTML).firstChild;if(f.src){let g,A=new Promise(function(T){g=T});f.addEventListener("load",function(){g()}),f.addEventListener("error",function(){g()}),l.push(A)}p.replaceWith(f),x.callbacks.afterNodeAdded(f),S.push(f)}return x.scripts.afterScriptsHandled(m,{added:S,kept:E,removed:v}),l}let R=function(){function m(c,l,p){let{persistentIds:f,idMap:g}=d(c,l),A=o.computeMatches(c,l);if(typeof p.key=="function"){let j=new Map,G=new Set,C=H=>{let P=p.key(H);P!=null&&(j.has(P)?G.add(P):j.set(P,H))};c instanceof Element&&C(c);for(let H of c.querySelectorAll("*"))C(H);for(let H of G)j.delete(H);let V=new Map;for(let[H,P]of A)V.set(P,H);let Ae=l.__hyperMorphRoot||l,ce=new Map,Je=new Set,Ye=H=>{let P=p.key(H);P!=null&&(ce.has(P)?Je.add(P):ce.set(P,H))};Ae instanceof Element&&Ye(Ae);for(let H of Ae.querySelectorAll("*"))Ye(H);for(let H of Je)ce.delete(H);for(let[H,P]of ce){let K=j.get(H);if(!K||K.tagName!==P.tagName)continue;let Me=V.get(K);Me&&Me!==P&&A.delete(Me);let Ee=A.get(P);Ee&&Ee!==K&&V.delete(Ee),A.set(P,K),V.set(K,P)}}let T=new Set;for(let j of A.values())T.add(j);let I=O(p),L=I.morphStyle||"outerHTML";if(!["innerHTML","outerHTML"].includes(L))throw`Do not understand how to morph style ${L}`;return{target:c,newContent:l,config:I,morphStyle:L,ignoreActive:I.ignoreActive,ignoreActiveValue:I.ignoreActiveValue,restoreFocus:I.restoreFocus,formStateSync:I.formStateSync||"attribute",idMap:g,persistentIds:f,hyperMatches:A,hyperMatchedOldElements:T,pantry:x(),activeElementAndParents:S(c),callbacks:I.callbacks,head:I.head,scripts:I.scripts}}function O(c){let l=Object.assign({},r);return Object.assign(l,c),l.callbacks=Object.assign({},r.callbacks,c.callbacks),l.head=Object.assign({},r.head,c.head),l.scripts=Object.assign({},r.scripts,c.scripts),l}function x(){let c=document.createElement("div");return c.hidden=!0,document.body.insertAdjacentElement("afterend",c),c}function S(c){let l=[],p=document.activeElement;if(p?.tagName!=="BODY"&&c.contains(p))for(;p&&(l.push(p),p!==c);)p=p.parentElement;return l}function v(c){let l=Array.from(c.querySelectorAll("[id]"));return c.getAttribute?.("id")&&l.push(c),l}function E(c,l,p,f){for(let g of f){let A=g.getAttribute("id");if(l.has(A)){let T=g;for(;T;){let I=c.get(T);if(I==null&&(I=new Set,c.set(T,I)),I.add(A),T===p)break;T=T.parentElement}}}}function d(c,l){let p=v(c),f=v(l),g=y(p,f),A=new Map;E(A,g,c,p);let T=l.__hyperMorphRoot||l;return E(A,g,T,f),{persistentIds:g,idMap:A}}function y(c,l){let p=new Set,f=new Map;for(let{id:A,tagName:T}of c)f.has(A)?p.add(A):f.set(A,T);let g=new Set;for(let{id:A,tagName:T}of l)g.has(A)?p.add(A):f.get(A)===T&&g.add(A);for(let A of p)g.delete(A);return g}return m}(),{normalizeElement:N,normalizeParent:k}=function(){let m=new WeakSet;function O(E){return E instanceof Document?E.documentElement:E}function x(E){if(E==null)return document.createElement("div");if(typeof E=="string")return x(v(E));if(m.has(E))return E;if(E instanceof Node){if(E.parentNode)return new S(E);{let d=document.createElement("div");return d.append(E),d}}else{let d=document.createElement("div");for(let y of[...E])d.append(y);return d}}class S{constructor(d){this.originalNode=d,this.realParentNode=d.parentNode,this.previousSibling=d.previousSibling,this.nextSibling=d.nextSibling}get childNodes(){let d=[],y=this.previousSibling?this.previousSibling.nextSibling:this.realParentNode.firstChild;for(;y&&y!=this.nextSibling;)d.push(y),y=y.nextSibling;return d}querySelectorAll(d){return this.childNodes.reduce((y,c)=>{if(c instanceof Element){c.matches(d)&&y.push(c);let l=c.querySelectorAll(d);for(let p=0;p<l.length;p++)y.push(l[p])}return y},[])}insertBefore(d,y){return this.realParentNode.insertBefore(d,y)}moveBefore(d,y){return this.realParentNode.moveBefore(d,y)}get __hyperMorphRoot(){return this.originalNode}}function v(E){let d=new DOMParser,y=E.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");if(y.match(/<\/html>/)||y.match(/<\/head>/)||y.match(/<\/body>/)){let c=d.parseFromString(E,"text/html");if(y.match(/<\/html>/))return m.add(c),c;{let l=c.firstChild;return l&&m.add(l),l}}else{let l=d.parseFromString("<body><template>"+E+"</template></body>","text/html").body.querySelector("template").content;return m.add(l),l}}return{normalizeElement:O,normalizeParent:x}}();return{morph:i,defaults:r}}();var Ln=Oe.morph,Cn=Oe.defaults,st=Oe;function Ie(e,t,{onWidgetRemoved:n}={}){st.morph(e,t,{morphStyle:"innerHTML",ignoreActiveValue:!0,restoreFocus:!0,formStateSync:"property",callbacks:{beforeNodeRemoved(r){let o=fe.get(r);o?.destroy&&o.destroy(),n?.(r)}}})}var pe={};xe(pe,{EmptyListInsert:()=>ee,MAX_RULE_DEPTH:()=>Y,MaxRuleDepthExceeded:()=>q,RuleTargetReadOnly:()=>te,RulesParseError:()=>J,ShapeMismatch:()=>Z,UnknownRulesVersion:()=>X,UpgradeAlreadyRegistered:()=>ne});var J=class extends Error{constructor(t,n){super(t),this.name="RulesParseError",this.cause=n}},X=class extends Error{constructor(t){super(`unknown rules version: ${t}. Library supports "1".`),this.name="UnknownRulesVersion",this.version=t}},Y=20,q=class extends Error{constructor(t){super(`rule depth exceeded ${Y} at path: ${t.join(".")}`),this.name="MaxRuleDepthExceeded",this.path=t}},Z=class extends Error{constructor(t){super(`shape mismatch: ${t.length} field(s) failed validation`),this.name="ShapeMismatch",this.mismatches=t}},ee=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}},te=class extends Error{constructor(t){super(`cannot write to read-only DOM property "${t}"`),this.name="RuleTargetReadOnly",this.target=t}},ne=class extends Error{constructor(){super("upgrade transform already registered; only one registration is allowed per page."),this.name="UpgradeAlreadyRegistered"}};var ke=null;function Le(e){if(typeof e!="function")throw new TypeError("registerUpgrade expects a function (v1Data) => v2Data");if(ke)throw new ne;ke=e}function he(){return ke}function re(e,t){let n={carriedOver:0,discarded:0,listItems:0},r=Ce(t,e,n);return He(t,e,n),{data:r,summary:n}}function Ce(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?void 0:(n.carriedOver++,t);if(Array.isArray(e)){let[,r]=e;return Array.isArray(t)?(n.listItems+=t.length,t.map(o=>Ce(r,o,n))):void 0}if(typeof e=="object"&&e!==null){let r={};for(let[o,i]of Object.entries(e)){let u=Ce(i,t?.[o],n);u!==void 0&&(r[o]=u)}return r}}function He(e,t,n){if(t!=null){if(typeof e=="object"&&e!==null&&!Array.isArray(e)){if(typeof t!="object"||Array.isArray(t))return;let r=new Set(Object.keys(e));for(let o of Object.keys(t))r.has(o)?He(e[o],t[o],n):n.discarded+=me(t[o]);return}if(Array.isArray(e)&&Array.isArray(t)){let r=e[1];t.forEach(o=>He(r,o,n));return}typeof e=="string"&&!e.endsWith("[]")&&typeof t=="object"&&t!==null&&(n.discarded+=me(t))}}function me(e){return e==null?0:Array.isArray(e)?e.reduce((t,n)=>t+me(n),0):typeof e=="object"?Object.values(e).reduce((t,n)=>t+me(n),0):1}async function Pe({sourceUrl:e,v1Data:t,v1Version:n=null,parent:r=typeof window<"u"?window:null,timeoutMs:o=15e3,hidden:i=!0}={}){if(!r)throw new Error("upgrade.run requires a window context");if(!e)throw new Error("upgrade.run requires sourceUrl");let u=Qt(e,r.location.origin),s=new URL(u,r.location.href).origin,a=r.document.createElement("iframe");i&&(a.style.cssText="position:absolute;left:-9999px;top:-9999px;width:1px;height:1px;border:0;"),a.setAttribute("aria-hidden","true"),a.src=u,r.document.body.appendChild(a);let M=()=>{};try{return await new Promise((w,b)=>{let h=setTimeout(()=>{b(new Error(`upgrade.run: helper iframe timed out after ${o}ms`))},o),R=N=>{if(N.source!==a.contentWindow||N.origin!==s)return;let k=N.data;if(!(!k||typeof k!="object")){if(k.type==="hha:upgrade-ready"){a.contentWindow.postMessage({type:"hha:upgrade-data",v1Data:t,v1Version:n},s);return}if(k.type==="hha:upgrade-result"){clearTimeout(h),w({html:k.html,summary:k.summary});return}if(k.type==="hha:upgrade-error"){clearTimeout(h);let m=new Error(k.message||"helper error");m.name=k.name||"UpgradeHelperError",b(m);return}}};r.addEventListener("message",R),M=()=>{r.removeEventListener("message",R),clearTimeout(h),a.parentNode&&a.parentNode.removeChild(a)}})}finally{M()}}function Qt(e,t){let n=new URL(e,typeof location<"u"?location.href:void 0);return n.searchParams.set("_hyperHtmlApi","upgrade-helper"),n.searchParams.set("parentOrigin",t),n.toString()}function De(e){try{return JSON.parse(e)}catch(t){throw new J(`Invalid strict JSON: ${t.message}`,t)}}function oe(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(o){let i=[],u=0;for(;u<o.length;){let s=o[u];if(/\s/.test(s)){u++;continue}if("{}".includes(s)){i.push({type:s,value:s}),u++;continue}if(s==="["){let b=!1,h=u+1;for(;h<o.length&&/\s/.test(o[h]);)h++;if(h<o.length&&/[a-zA-Z_]/.test(o[h])&&(b=!0),!b){i.push({type:s,value:s}),u++;continue}}if(s==="]"){i.push({type:s,value:s}),u++;continue}if(s===":"){i.push({type:t.COLON,value:s}),u++;continue}if(s===","){i.push({type:t.COMMA,value:s}),u++;continue}if(s==='"'||s==="'"){let b=s,h=u+1;for(;h<o.length&&o[h]!==b;)o[h]==="\\"&&h++,h++;i.push({type:t.STRING,value:o.substring(u+1,h),quoted:!0,sourceQuote:b}),u=h+1;continue}let a=u,M;for(;a<o.length&&!/[{},]/.test(o[a]);)if(o[a]===":"){let b=[":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"],h=!1;for(let R of b){let N=R.substring(1);if(o.substring(a+1,a+1+N.length)===N){h=!0,a+=N.length;break}}if(!h)break}else if(o[a]==="["){for(a++;a<o.length&&o[a]!=="]";){if(o[a]==='"'||o[a]==="'"){let b=o[a];for(a++;a<o.length&&o[a]!==b;)o[a]==="\\"&&a++,a++}a++}a<o.length&&o[a]==="]"&&a++}else a++;M=o.substring(u,a);let w=t.IDENTIFIER;/^-?\d+(\.\d+)?$/.test(M)?w=t.NUMBER:M==="true"||M==="false"||M==="null"?w=t.BOOLEAN:/^[.#@\[]|[.#@\[]| /.test(M)&&(w=t.SELECTOR),i.push({type:w,value:M,quoted:!1}),u=a}return i}function r(o){let i="";for(let u=0;u<o.length;u++){let s=o[u];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 a=o[u+1];if(a&&(a.type==="}"||a.type==="]"))continue;i+=s.value;continue}if(s.type===t.STRING&&s.quoted){let a=s.value;s.sourceQuote==="'"&&(a=a.replace(/\\'/g,"'"),a=a.replace(/(\\*)"/g,(M,w)=>w.length%2===0?w+'\\"':M)),i+=`"${a}"`;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 o=n(e),i=r(o);return JSON.parse(i)}catch(o){throw new J("Invalid extraction rules syntax: "+o.message,o)}}var Xt="1",at=/^[a-zA-Z0-9_-]+$/;function U(e,t,n){let r;if(n===void 0)r="script[data-rules-name]";else{if(typeof n!="string"||!at.test(n))throw new Error(`hyper-html-api: invalid rules token ${JSON.stringify(n)} (must match ${at})`);r=`script[data-rules-name~="${n}"]`}let o=e.find(t,r,{includeRulesTag:!0});if(o.length===0)return null;n!==void 0&&o.length>1&&console.warn(`hyper-html-api: ${o.length} rules tags match data-rules-name~="${n}"; using the first.`);let i=o[0],u=e.attr(i,"data-rules-version");if(u!==Xt)throw new X(u);return{rules:oe(e.text(i)),tagNode:i}}var ge=["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"],_e=new Set(ge),ct=new Set(["textContent","innerText","innerHTML","value","checked","selected","disabled","readOnly","type","id","className","title"]),ut=new Set(["tagName","nodeName","nodeType","nodeValue","childElementCount","classList","baseURI","documentURI","contentType","offsetWidth","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","currentSrc","duration","paused","dataset"]);function B(e,t,n,r={}){return je(e,t,n,{depth:0,path:[]},r)}function je(e,t,n,r,o){if(r.depth>Y)throw new q(r.path);if(typeof n=="string")return Zt(e,t,n,o);if(Array.isArray(n)){let[i,u]=n;return e.find(t,i,o).map((a,M)=>je(e,a,u,{depth:r.depth+1,path:[...r.path,M]},o))}if(typeof n=="object"&&n!==null){let i={};for(let[u,s]of Object.entries(n))i[u]=je(e,t,s,{depth:r.depth+1,path:[...r.path,u]},o);return i}return null}function Zt(e,t,n,r){if(n.endsWith("[]")){let i=n.slice(0,-2);return e.find(t,i,r).map(u=>e.text(u))}if(n.startsWith("@"))return lt(e,t,n.slice(1));if(n.includes("@")){let i=n.lastIndexOf("@"),u=n.slice(0,i),s=n.slice(i+1),a=u?e.find(t,u,r):[t];return a.length===0?null:lt(e,a[0],s)}if(n===".")return e.text(t);let o=e.find(t,n,r);return o.length===0?null:e.text(o[0])}function lt(e,t,n){if(_e.has(n)){let o=e.prop(t,n);return o==null?null:String(o)}let r=e.attr(t,n);return r||null}var en=.5;function $e(e,t,n,r,o,i,u,s={}){let a=e.find(t,n,s);if(o.length===0){a.forEach(S=>e.remove(S));return}let M=o.length>a.length,w=a[0]||null;if(M&&!w&&(w=sn(e,t,n,s),!w))throw new ee(i.path);let b=a.map(S=>tn(e,S,r,s)),h=null;if(w){h=e.clone(w),s.templateAttr&&e.removeAttr(h,s.templateAttr);let S=e.stripIds(h);S>0&&console.warn(`[hyper-html-api] stripped ${S} id attribute(s) from cloned template at "${i.path.join(".")||"(root)"}"`)}let R=nn(o,b,r),N=a[0]||w,k=e.parent(N),m=a.length>0?on(e,k,N):0,O=new Set,x=o.map((S,v)=>{let E=R[v];if(E>=0)return O.add(E),a[E];let d=e.clone(h);return e.stripIds(d),d});a.forEach((S,v)=>{O.has(v)||e.remove(S)}),x.forEach((S,v)=>{let E=m+v;e.children(k).findIndex(c=>e.sameNode(c,S))!==E&&e.insertAt(k,S,E)}),x.forEach((S,v)=>{if(r===null){let E=o[v],d=E==null?"":String(E);e.text(S)!==d&&e.text(S,d)}else{let E=u(e,S,r,o[v],{depth:i.depth+1,path:[...i.path,v]},s);E&&E!==S&&(x[v]=E)}})}function tn(e,t,n,r){return n===null?e.text(t):B(e,t,n,r)}function nn(e,t,n){let r=new Array(e.length).fill(-1),o=new Set;return e.forEach((i,u)=>{let s=-1,a=-1;t.forEach((M,w)=>{if(o.has(w))return;let b=rn(i,M,n),h=b===a&&s>=0?Math.abs(w-u)<Math.abs(s-u):!1;(b>a||h)&&(a=b,s=w)}),a>=en&&(r[u]=s,o.add(s))}),r}function rn(e,t,n){if(n===null)return e===t?1:0;let r=Object.keys(n||{});if(r.length===0)return 0;let o=0;for(let i of r)JSON.stringify(e?.[i])===JSON.stringify(t?.[i])&&o++;return o/r.length}function on(e,t,n){let r=e.children(t);for(let o=0;o<r.length;o++)if(e.sameNode(r[o],n))return o;return-1}function sn(e,t,n,r){if(!r.templateAttr)return null;let o=t;for(;o;){let i=e.find(o,n,{includeRulesTag:!1,templateAttr:null});for(let u of i)if(e.attr(u,r.templateAttr)!=null)return u;o=e.parent(o)}return null}var ft=new Set(["checked","selected","disabled","readOnly","paused"]);function W(e,t,n,r,o={}){let i=[];if(Be(n,r,[],i),i.length)throw new Z(i);ye(e,t,n,r,{depth:0,path:[]},o)}function ye(e,t,n,r,o,i={}){if(o.depth>Y)throw new q(o.path);if(r===void 0)return t;if(typeof n=="string")return an(e,t,n,r,o,i);if(Array.isArray(n)){let[u,s]=n;return $e(e,t,u,s,r,o,ye,i),t}if(typeof n=="object"&&n!==null){for(let[u,s]of Object.entries(n)){let a=ye(e,t,s,r==null?r:r[u],{depth:o.depth+1,path:[...o.path,u]},i);a&&a!==t&&(t=a)}return t}return t}function an(e,t,n,r,o,i){if(n.endsWith("[]")){let s=n.slice(0,-2);return $e(e,t,s,null,r,o,ye,i),t}if(n.startsWith("@"))return dt(e,t,n.slice(1),r);if(n.includes("@")){let s=n.lastIndexOf("@"),a=n.slice(0,s),M=n.slice(s+1),w=a?e.find(t,a,i):[t];return w.length===0||dt(e,w[0],M,r),t}if(n===".")return e.text(t,r==null?"":String(r)),t;let u=e.find(t,n,i);return u.length===0||e.text(u[0],r==null?"":String(r)),t}function dt(e,t,n,r){if(ut.has(n))throw new te(n);if(n==="outerHTML"){let o=r==null?"":String(r);return e.replaceWith(t,o)}return ct.has(n)?(e.prop(t,n,cn(n,r)),t):(e.attr(t,n,r==null?"":String(r)),t)}function cn(e,t){return t==null?ft.has(e)?!1:"":ft.has(e)?!!t:t}function Be(e,t,n,r){if(t!==void 0){if(typeof e=="string"){if(e.endsWith("[]")){Array.isArray(t)?t.forEach((o,i)=>{typeof o=="object"&&o!==null&&r.push({path:se([...n,i]),expected:"scalar",got:ie(o)})}):r.push({path:se(n),expected:"array",got:ie(t)});return}t!==null&&typeof t=="object"&&r.push({path:se(n),expected:"scalar",got:ie(t)});return}if(Array.isArray(e)){if(!Array.isArray(t)){r.push({path:se(n),expected:"array",got:ie(t)});return}let o=e[1];t.forEach((i,u)=>Be(o,i,[...n,u],r));return}if(typeof e=="object"&&e!==null){if(t===null||Array.isArray(t)||typeof t!="object"){r.push({path:se(n),expected:"object",got:ie(t)});return}for(let[o,i]of Object.entries(e))Be(i,t[o],[...n,o],r)}}}function ie(e){return e===null?"null":Array.isArray(e)?"array":typeof e}function se(e){return e.join(".")}function un(e){return e&&e.nodeType===1&&e.tagName==="SCRIPT"&&e.hasAttribute&&e.hasAttribute("data-rules-name")}function ln(e){return e?(e.nodeType===9||e.nodeType===11,e):null}var fn={find(e,t,n={}){let r=ln(e);if(!r||!r.querySelectorAll)return[];let o=Array.from(r.querySelectorAll(t));n.includeRulesTag||(o=o.filter(s=>!un(s)));let i=[];n.skip&&i.push(n.skip);let u=n.templateAttr===null?null:n.templateAttr||"cms-template";if(u&&i.push("["+u+"]"),i.length){let s=i.join(", ");o=o.filter(a=>!a.closest||!a.closest(s))}return o},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 r=e?e[t]:void 0;return r!==void 0?r:null}e[t]=n},clone(e){return e.cloneNode(!0)},insertAt(e,t,n){let r=e.children[n]||null;e.insertBefore(t,r)},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 r=e.ownerDocument.createElement("template");r.innerHTML=t;let o=r.content.firstElementChild;if(!o)throw new Error("dom.replaceWith: html did not parse to an element");return e.parentNode.replaceChild(o,e),o},stripIds(e){let t=0;return e.id&&(e.removeAttribute("id"),t++),(e.querySelectorAll?e.querySelectorAll("[id]"):[]).forEach(r=>{r.removeAttribute("id"),t++}),t},sameNode(e,t){return e===t}},D=fn;var dn="_hyperHtmlApi",pn="upgrade-helper",hn="parentOrigin";function be(e=typeof location<"u"?location:null){if(!e)return!1;try{return new URLSearchParams(e.search).get(dn)===pn}catch{return!1}}function pt(e=typeof location<"u"?location:null){return e?new URLSearchParams(e.search).get(hn):null}function We({win:e,doc:t,parentOrigin:n}={}){if(e=e||(typeof window<"u"?window:null),t=t||(typeof document<"u"?document:null),!e||!t||(n=n||pt(e.location),!n))return;let r=()=>mn({win:e,doc:t,parentOrigin:n});t.readyState==="loading"?t.addEventListener("DOMContentLoaded",r,{once:!0}):r()}function mn({win:e,doc:t,parentOrigin:n}){let r;try{r=U(D,t.body)}catch(a){return Fe(e,n,a)}if(!r)return Fe(e,n,new Error("helper-mode: no rules tag in v2 document"));let o=r.rules,i=yn(t,"hyper-version"),u=!!he(),s=a=>{if(a.source!==e.parent||a.origin!==n)return;let M=a.data;if(!(!M||M.type!=="hha:upgrade-data")){e.removeEventListener("message",s);try{let w=gn({doc:t,rules:o,v1Data:M.v1Data});e.parent.postMessage({type:"hha:upgrade-result",html:w.html,summary:w.summary},n)}catch(w){Fe(e,n,w)}}};e.addEventListener("message",s),e.parent.postMessage({type:"hha:upgrade-ready",rules:o,version:i,hasTransform:u},n)}function gn({doc:e,rules:t,v1Data:n}){let r=he(),o=n,i=!1;r&&(o=r(n),i=!0);let{data:u,summary:s}=re(o,t);W(D,e.body,t,u);let a=B(D,e.body,t);return{html:`<!DOCTYPE html>
3
- `+e.documentElement.outerHTML,summary:{...s,transformApplied:i,appliedFieldCount:Ue(a)}}}function Fe(e,t,n){e.parent.postMessage({type:"hha:upgrade-error",name:n?.name||"Error",message:n?.message||String(n)},t)}function yn(e,t){let n=e.querySelector(`meta[name="${t}"]`);return n?n.getAttribute("content"):null}function Ue(e){return e==null?0:Array.isArray(e)?e.reduce((t,n)=>t+Ue(n),0):typeof e=="object"?Object.values(e).reduce((t,n)=>t+Ue(n),0):1}function qe(e,t,n){if(n&&typeof n=="object")return{rules:n,tagNode:null};if(typeof n=="string"){let r=t&&t.ownerDocument?t.ownerDocument:t;return U(e,r,n)}return null}function ht(e,t,n,r){let o=qe(e,t,n);if(!o){let s=typeof n=="string"?`data-rules-name~="${n}"`:"the provided rules object";throw new Error(`hyper-html-api: could not resolve rules for ${s}`)}let{rules:i,tagNode:u}=o;return{rules:i,tagNode:u,get:()=>B(e,t,i,r),set:s=>W(e,t,i,s,r)}}var ae={extract:(e,t,n)=>B(D,e,t,n),apply:(e,t,n,r)=>W(D,e,t,n,r),findRulesIn:(e,t)=>U(D,e,t),findRules:(e,t)=>qe(D,e,t),bind:(e,t,n)=>ht(D,e,t,n),parseStrict:De,parseRelaxed:oe,errors:pe,DOM_PROPERTIES:ge},Ve=e=>!!e&&typeof e.nodeType=="number";function mt(e){let t=e&&e.ownerDocument?e.ownerDocument:e,n=D.find(t,"script[data-rules-name]",{includeRulesTag:!0});if(n.length===0)throw new Error('hyper-html-api: no rules tag found. Add <script type="application/json" data-rules-name="\u2026" data-rules-version="1"> or pass rules.');if(n.length>1)throw new Error('hyper-html-api: multiple rules tags found; pass a name, e.g. extractData("api").');return U(D,t).rules}function Ke(e,t){let n=Ve(e)?e:document,r=Ve(e)?t:e;return r===void 0?B(D,n,mt(n)):ae.bind(n,r).get()}function ze(e,t,n){if(!Ve(e))throw new Error("hyper-html-api: applyData(root, data, source?) needs a DOM root as the first argument.");return n===void 0?W(D,e,mt(e),t):ae.bind(e,n).set(t),e}var gt={buildForm:we,bindFormEvents:Te,scaffold:z,morphForm:Ie,path:le},yt={registerUpgrade:Le,run:Pe,shapeMatch:re,isHelperMode:be};typeof window<"u"&&be(window.location)&&We({win:window,doc:document});var Mn={engine:ae,cms:gt,upgrade:yt,extractData:Ke,applyData:ze},En=Mn;return St(Sn);})();
1
+ var HyperHtmlApi=(()=>{var Te=Object.defineProperty;var Tt=Object.getOwnPropertyDescriptor;var Rt=Object.getOwnPropertyNames;var Ot=Object.prototype.hasOwnProperty;var Re=(e,t)=>{for(var n in t)Te(e,n,{get:t[n],enumerable:!0})},Nt=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Rt(t))!Ot.call(e,r)&&r!==n&&Te(e,r,{get:()=>t[r],enumerable:!(o=Tt(t,r))||o.enumerable});return e};var It=e=>Nt(Te({},"__esModule",{value:!0}),e);var On={};Re(On,{applyData:()=>Qe,cms:()=>vt,default:()=>Rn,engine:()=>pe,extractData:()=>Ze,upgrade:()=>wt});var ge={};Re(ge,{fromString:()=>me,getRuleAtPath:()=>Oe,getValueAtPath:()=>re,parseConfigKey:()=>Ct,setAtPath:()=>B,toConfigKey:()=>kt,toString:()=>_});function _(e){return e.map(String).join(".")}function kt(e){return e.map(t=>typeof t=="number"?"*":String(t)).join(".")}function Ct(e){return e===""?[]:e.split(".")}function me(e){return e===""?[]:e.split(".").map(t=>/^\d+$/.test(t)?Number(t):t)}function Oe(e,t){let n=e;for(let o of t){if(n==null||typeof n=="string")return;if(Array.isArray(n)){if(typeof o!="number"&&o!=="*")return;n=n[1];continue}if(typeof n=="object"){if(typeof o=="number"||!(o in n))return;n=n[o];continue}return}return n}function re(e,t){let n=e;for(let o of t){if(n==null)return;n=n[o]}return n}function B(e,t,n){if(t.length===0)return n;let[o,...r]=t;if(typeof o=="number"){let s=Array.isArray(e)?[...e]:[];return s[o]=B(s[o],r,n),s}return{...e&&typeof e=="object"?e:{},[o]:B((e||{})[o],r,n)}}function X(e){if(typeof e=="string")return e.endsWith("[]")?[]:"";if(Array.isArray(e))return[];if(typeof e=="object"&&e!==null){let t={};for(let[n,o]of Object.entries(e))t[n]=X(o);return t}return""}var ye=new WeakMap;var Lt=new Set(["checked","selected","disabled","readOnly","paused"]);function Ne({rules:e,data:t,appRoot:n,cmsRoot:o}){let r=document.createDocumentFragment(),s={rules:e,appRoot:n,cmsRoot:o};return r.appendChild(ke({rule:e,value:t,path:[],ctx:s})),r}function Ie(e,{rules:t,getData:n,onChange:o}){e.setAttribute("data-hha-form-root",""),ot.set(e,{rules:t,getData:n,onChange:o}),Ht()}var ot=new WeakMap,nt=!1;function Ht(){nt||(document.addEventListener("input",rt,!0),document.addEventListener("change",rt,!0),document.addEventListener("click",Pt,!0),nt=!0)}function st(e){if(!(e instanceof Element))return null;let t=e.closest("[data-hha-form-root]");return t&&ot.get(t)||null}function Pt(e){if(!(e.target instanceof Element))return;let t=e.target.closest("[data-hha-action]");if(!t||e.defaultPrevented)return;let n=st(t);if(!n)return;let{rules:o,getData:r,onChange:s}=n,a=t.getAttribute("data-hha-action"),i=me(t.getAttribute("data-hha-path")||"");if(a==="scalar-array-add"){let c=re(r(),i)||[];s(B(r(),i,[...c,""]),{structural:!0});return}if(a==="object-array-add"){let c=Oe(o,i);if(!Array.isArray(c))return;let A=re(r(),i)||[];s(B(r(),i,[...A,X(c[1])]),{structural:!0});return}if(a==="array-remove"){if(i.length===0)return;let c=i.slice(0,-1),A=i[i.length-1],x=re(r(),c)||[];if(typeof A!="number")return;let y=x.filter((p,R)=>R!==A);s(B(r(),c,y),{structural:!0})}}function rt(e){let t=e.target;if(!t?.matches?.("input, textarea, select"))return;let n=st(t);if(!n)return;let{getData:o,onChange:r}=n,s=t.closest("[data-hha-path]");if(!s)return;let a=me(s.getAttribute("data-hha-path")||""),i=t.type==="checkbox"?t.checked:t.value;r(B(o(),a,i),{structural:!1})}function ke({rule:e,value:t,path:n,ctx:o}){if(typeof e=="string")return e.endsWith("[]")?$t({rule:e,value:t,path:n,ctx:o}):_t({rule:e,value:t,path:n,ctx:o});if(Array.isArray(e))return jt({rule:e,value:t,path:n,ctx:o});if(typeof e=="object"&&e!==null)return Dt({rule:e,value:t,path:n,ctx:o});let r=document.createElement("span");return r.textContent="(unsupported rule)",r}function Dt({rule:e,value:t,path:n,ctx:o}){let r=document.createElement("div");if(r.className="form-section",r.setAttribute("data-hha-path",_(n)),n.length>0){let s=document.createElement("div");s.className="form-section-label",s.textContent=be(n[n.length-1]),r.appendChild(s)}for(let[s,a]of Object.entries(e)){let i=[...n,s],c=t?.[s];r.appendChild(ke({rule:a,value:c,path:i,ctx:o}))}return r}function _t({rule:e,value:t,path:n,ctx:o}){let r=document.createElement("div");r.className="field-row",r.setAttribute("data-hha-path",_(n));let s=document.createElement("div");s.className="field-body";let a=document.createElement("label");a.className="field-label",a.textContent=be(n[n.length-1]||".")+Vt(e);let i=Ft(e,o.appRoot),c=Ut(i,{value:t,rule:e,path:n,appRoot:o.appRoot}),A=c.el;return A.classList.add(i.type==="textarea"?"field-textarea":"field-input"),s.appendChild(a),s.appendChild(A),r.appendChild(s),ye.set(r,c),r}function $t({rule:e,value:t,path:n,ctx:o}){let r=document.createElement("div");r.className="form-section",r.setAttribute("data-hha-path",_(n));let s=document.createElement("div");s.className="form-section-label",s.textContent=be(n[n.length-1]),r.appendChild(s);let a=Array.isArray(t)?t:[],i=document.createElement("div");r.appendChild(i),a.forEach((A,x)=>{let y=[...n,x],p=document.createElement("div");p.className="scalar-array-row",p.setAttribute("data-hha-path",_(y));let R=document.createElement("input");R.type="text",R.className="field-input",R.value=A==null?"":String(A);let N=document.createElement("button");N.type="button",N.className="array-remove",N.textContent="\xD7",N.title="remove",N.setAttribute("data-hha-action","array-remove"),N.setAttribute("data-hha-path",_(y)),p.appendChild(R),p.appendChild(N),i.appendChild(p)});let c=document.createElement("button");return c.type="button",c.className="array-add",c.textContent="+ add",c.setAttribute("data-hha-action","scalar-array-add"),c.setAttribute("data-hha-path",_(n)),r.appendChild(c),r}function jt({rule:e,value:t,path:n,ctx:o}){let[,r]=e,s=Array.isArray(t)?t:[],a=document.createElement("div");a.className="form-section",a.setAttribute("data-hha-path",_(n));let i=document.createElement("div");i.className="form-section-label",i.textContent=be(n[n.length-1]),a.appendChild(i),s.forEach((A,x)=>{let y=[...n,x],p=document.createElement("div");p.className="array-card",p.setAttribute("data-hha-path",_(y));let R=document.createElement("button");R.type="button",R.className="array-remove",R.textContent="\xD7",R.title="remove item",R.setAttribute("data-hha-action","array-remove"),R.setAttribute("data-hha-path",_(y)),p.appendChild(R);let N=ke({rule:r,value:A,path:y,ctx:o});N.querySelector(".form-section-label")?.remove(),p.appendChild(N),a.appendChild(p)});let c=document.createElement("button");return c.type="button",c.className="array-add",c.textContent="+ add",c.setAttribute("data-hha-action","object-array-add"),c.setAttribute("data-hha-path",_(n)),a.appendChild(c),a}function Ut(e,t){let n=Wt(e);if(e.type==="select"&&e.options)for(let o of e.options){let r=document.createElement("option");r.value=o.value,r.textContent=o.text,String(t.value)===o.value&&(r.selected=!0),n.appendChild(r)}else e.type==="checkbox"?n.checked=t.value===!0||t.value==="true"||t.value==="checked":(e.type,n.value=t.value==null?"":String(t.value));return{el:n,destroy(){},focus(){n.focus()},validate(){}}}function Ft(e,t){let n=null;if(e.startsWith("@")?n=e.slice(1):e.includes("@")&&(n=e.split("@")[1]||null),n&&Lt.has(n))return{type:"checkbox"};if(n==="innerHTML")return{type:"textarea"};let o=Bt(e,t);if(!o)return{type:"text"};let r=(o.tagName||"").toLowerCase();if(r==="textarea")return{type:"textarea"};if(r==="select")return{type:"select",options:Array.from(o.querySelectorAll("option")).map(i=>({value:i.getAttribute("value")||i.textContent,text:i.textContent.trim()||i.getAttribute("value")||""}))};if(r==="input"){let a=(o.getAttribute("type")||"text").toLowerCase();if(a==="checkbox"||a==="radio")return{type:"checkbox"};if(a==="number")return{type:"number"}}let s=(o.textContent||"").trim();return s.length>60||s.includes(`
2
+ `)?{type:"textarea"}:{type:"text"}}function Bt(e,t){if(!t||e==="."||e===""||e.startsWith("@"))return null;let n=e.includes("@")?e.split("@")[0]:e;if(!n)return null;try{return t.querySelector(n)}catch{return null}}function Wt(e){if(e.type==="textarea")return document.createElement("textarea");if(e.type==="select")return document.createElement("select");let t=document.createElement("input");return t.type=e.type==="checkbox"?"checkbox":e.type==="number"?"number":"text",t}function be(e){return typeof e=="number"?`#${e+1}`:String(e).replace(/([a-z])([A-Z])/g,"$1 $2").replace(/[_-]+/g," ").replace(/^\w/,t=>t.toUpperCase())}function Vt(e){return` \xB7 ${e}`}var it={includeClasses:!0,includeAttributes:["href","src","name","type","role","aria-label","alt","title"],excludeAttributePrefixes:["data-morph-","data-hyper-","data-im-"],textHintLength:64,excludeIds:!0,maxPathDepth:4,landmarks:["HEADER","NAV","MAIN","ASIDE","FOOTER","SECTION","ARTICLE"],weights:{signature:100,pathSegment:10,textMatch:20,textMismatch:25,uniqueCandidate:50,positionPenalty:1,slotMatch:30},minConfidence:101};function qt(e){let t=5381;for(let n=0;n<e.length;n++)t=(t<<5)+t^e.charCodeAt(n);return Math.abs(t).toString(36)}function Kt(e){if(e.classList&&e.classList.length>0)return Array.from(e.classList).sort().join(" ");let t=e.getAttribute?.("class");return t?t.split(/\s+/).filter(Boolean).sort().join(" "):""}function zt(e,t){let n=[];for(let o of e.attributes||[]){let r=o.name;r==="id"||r==="class"||t.excludeAttributePrefixes.some(s=>r.startsWith(s))||t.includeAttributes.includes(r)&&n.push(`${r}=${o.value}`)}return n.sort().join("|")}function Jt(e,t){return(e.textContent||"").replace(/\s+/g," ").trim().slice(0,t.textHintLength)}function Yt(e,t){let n=[e.tagName];return t.includeClasses&&n.push(Kt(e)),n.push(zt(e,t)),qt(n.join("|"))}function Gt(e){let t=e.tagName,n=1,o=e.previousElementSibling;for(;o;)o.tagName===t&&n++,o=o.previousElementSibling;return n}function Xt(e,t){return e.id||e.getAttribute?.("role")?!0:t.landmarks.includes(e.tagName)}function Zt(e){if(e.id)return`#${e.id}`;let t=e.getAttribute?.("role");return t?`@${t}`:e.tagName}function Qt(e,t){let n=[],o=e;for(;o&&o.tagName&&n.length<t.maxPathDepth;){let r=`${o.tagName}:${Gt(o)}`;if(n.unshift(r),o!==e&&Xt(o,t)){n.unshift(Zt(o));break}o=o.parentElement}return n}function en(e,t){let n=0,o=e.length-1,r=t.length-1;for(;o>=0&&r>=0&&e[o]===t[r];)n++,o--,r--;return n}function j(e,t,n){if(n.has(e))return n.get(e);let o={signature:Yt(e,t),path:Qt(e,t),textHint:Jt(e,t)};return n.set(e,o),o}function ut(e,t,n,o){if(o.has(e))return o.get(e);let r=new Map,s=e.querySelectorAll("*"),a=0;for(let i of s){let c=j(i,t,n);c.domIndex=a++,r.has(c.signature)||r.set(c.signature,[]),r.get(c.signature).push(i)}return o.set(e,r),r}function tn(e,t,n){n.delete(e),t.delete(e);let o=e.querySelectorAll("*");for(let r of o)t.delete(r)}function Ce(e,t,n,o,r){let s=j(e,n,o),a=j(t,n,o),i=n.weights,c={},A=0;if(s.signature!==a.signature)return{score:0,breakdown:{rejected:"signature mismatch"}};A+=i.signature,c.signature=i.signature;let y=en(s.path,a.path)*i.pathSegment;A+=y,c.path=y;let p=!0;if(s.textHint&&a.textHint?s.textHint===a.textHint?(A+=i.textMatch,c.text=i.textMatch):(A-=i.textMismatch,c.text=-i.textMismatch,p=!1):s.textHint!==a.textHint&&(A-=i.textMismatch,c.text=-i.textMismatch,p=!1),r.candidateCount===1&&p&&(A+=i.uniqueCandidate,c.unique=i.uniqueCandidate),typeof s.domIndex=="number"&&typeof a.domIndex=="number"){let R=Math.abs(s.domIndex-a.domIndex),N=Math.min(R*i.positionPenalty,20);A-=N,c.drift=-N}return{score:A,breakdown:c}}function at(e,t,n,o,r){if(n.excludeIds&&e.id)return null;let s=ut(t,n,o,r),a=j(e,n,o);if(typeof a.domIndex!="number"){let p=0,R=e.previousElementSibling;for(;R;)p++,R=R.previousElementSibling;a.domIndex=p}let i=s.get(a.signature)||[],c=n.excludeIds?i.filter(p=>!p.id):i;if(c.length===0)return null;let A=null,x=0,y=null;for(let p of c){let{score:R,breakdown:N}=Ce(e,p,n,o,{candidateCount:c.length});R>x&&(x=R,A=p,y=N)}return x<n.minConfidence?null:{element:A,confidence:x,breakdown:y}}function nn(e,t,n,o){let r=[],s=n.weights.signature+n.weights.slotMatch,a={slot:s};function i(y){if(y.children)return y.children;let p=y.childNodes;if(!p)return[];let R=[];for(let N=0;N<p.length;N++)p[N].nodeType===1&&R.push(p[N]);return R}function c(y,p){let R=i(y),N=i(p);if(R.length===N.length)for(let C=0;C<R.length;C++){let g=R[C],T=N[C];if(n.excludeIds&&(g.id||T.id)||g.tagName!==T.tagName)continue;let E=j(g,n,o).signature,v=j(T,n,o).signature;E!==v&&r.push({newEl:g,oldEl:T,score:s,breakdown:a}),c(g,T)}}function A(y,p){for(;;){if(y.tagName===p.tagName)return[y,p];let R=i(y);if(!y.tagName&&R.length===1){y=R[0];continue}let N=i(p);if(N.length===1&&N[0].tagName===y.tagName){p=N[0];continue}return null}}let x=A(e,t);return x&&c(x[0],x[1]),r}function ct(e,t,n,o,r){let s=t.querySelectorAll("*"),a=ut(e,n,o,r),i=0;for(let y of s){let p=j(y,n,o);p.domIndex=i++}let c=[];for(let y of s){if(n.excludeIds&&y.id)continue;let p=j(y,n,o),R=a.get(p.signature)||[],N=n.excludeIds?R.filter(C=>!C.id):R;for(let C of N){let{score:g,breakdown:T}=Ce(y,C,n,o,{candidateCount:N.length});g>=n.minConfidence&&c.push({newEl:y,oldEl:C,score:g,breakdown:T})}}if(n.weights.slotMatch>0){let y=nn(t,e,n,o);for(let p of y)c.push(p)}c.sort((y,p)=>p.score-y.score);let A=new Map,x=new Set;for(let{newEl:y,oldEl:p}of c)A.has(y)||x.has(p)||(A.set(y,p),x.add(p));return A}function lt(e,t,n,o){let r=j(e,n,o),s=j(t,n,o),{score:a,breakdown:i}=Ce(e,t,n,o,{candidateCount:1});return{matches:a>=n.minConfidence,score:a,breakdown:i,newMeta:{signature:r.signature,path:r.path,textHint:r.textHint},oldMeta:{signature:s.signature,path:s.path,textHint:s.textHint}}}function ft(e={}){let t={...it,...e,weights:{...it.weights,...e.weights}},n=new WeakMap,o=new WeakMap;return{findMatch:(r,s)=>at(r,s,t,n,o),computeMatches:(r,s)=>ct(r,s,t,n,o),explain:(r,s)=>lt(r,s,t,n),invalidate:r=>tn(r,n,o),session:()=>{let r=new WeakMap,s=new WeakMap;return{findMatch:(a,i)=>at(a,i,t,r,s),computeMatches:(a,i)=>ct(a,i,t,r,s),explain:(a,i)=>lt(a,i,t,r)}},getConfig:()=>({...t})}}var rn=ft(),Le=function(){"use strict";let e=()=>{};function t(g){if(!(g instanceof Element))return!1;if(g.hasAttribute("save-ignore"))return!0;if(g.tagName==="LINK"||g.tagName==="SCRIPT"){let T=g.getAttribute("src")||g.getAttribute("href")||"";if(T.startsWith("chrome-extension://")||T.startsWith("moz-extension://")||T.startsWith("safari-web-extension://"))return!0}return!1}function n(g,T){if(T!=="smart")return g.outerHTML;let E=g.getAttribute("src"),v=g.getAttribute("type")||"text/javascript";if(E)try{let w=new URL(E,window.location.href);return`ext:${v}:${w.origin}${w.pathname}${w.search}`}catch{return`ext:${v}:${E}`}else{let w=g.textContent.trim(),M=5381;for(let d=0;d<w.length;d++)M=(M<<5)+M^w.charCodeAt(d);return`inline:${v}:${Math.abs(M).toString(36)}`}}let o={morphStyle:"outerHTML",callbacks:{beforeNodeAdded:e,afterNodeAdded:e,beforeNodeMorphed:e,afterNodeMorphed:e,beforeNodeRemoved:e,afterNodeRemoved:e,beforeAttributeUpdated:e},head:{style:"merge",shouldPreserve:g=>g.getAttribute("im-preserve")==="true",shouldReAppend:g=>g.getAttribute("im-re-append")==="true",shouldRemove:e,afterHeadMorphed:e},scripts:{handle:!1,matchMode:"outerHTML",shouldPreserve:g=>g.getAttribute("im-preserve")==="true",shouldReAppend:g=>g.getAttribute("im-re-append")==="true",shouldRemove:e,afterScriptsHandled:e},restoreFocus:!0},r={computeMatches(g,T){let{computeMatches:E}=rn.session();return E(g,T)}};function s(g,T,E={}){g=N(g);let v=C(T),w=R(g,v,E),M=w.scripts.matchMode,d=new Set(Array.from(g.querySelectorAll("script")).map(u=>n(u,M))),b=i(w,()=>x(w,g,v,u=>u.morphStyle==="innerHTML"?(c(u,g,v),Array.from(g.childNodes)):a(u,g,v)));w.pantry.remove();let l=p(g,d,w);return l.length>0?b instanceof Promise?b.then(u=>Promise.all(l).then(()=>u)):Promise.all(l).then(()=>b):b}function a(g,T,E){let v=C(T);return c(g,v,E,T,T.nextSibling),Array.from(v.childNodes)}function i(g,T){if(!g.config.restoreFocus)return T();let E=document.activeElement;if(!(E instanceof HTMLInputElement||E instanceof HTMLTextAreaElement))return T();let{id:v,selectionStart:w,selectionEnd:M}=E,d=T();return v&&v!==document.activeElement?.getAttribute("id")&&(E=g.target.querySelector(`[id="${v}"]`),E?.focus()),E&&!E.selectionEnd&&M!=null&&E.setSelectionRange(w,M),d}let c=function(){function g(l,u,h,f=null,m=null){u instanceof HTMLTemplateElement&&h instanceof HTMLTemplateElement&&(u=u.content,h=h.content),f||=u.firstChild;for(let S of h.childNodes){if(t(S))continue;if(f&&f!=m){let I=E(l,S,f,m);if(I){I!==f&&w(l,f,I),A(I,S,l),f=I.nextSibling;continue}}if(S instanceof Element){let I=S.getAttribute("id");if(l.persistentIds.has(I)){let k=M(u,I,f,l);A(k,S,l),f=k.nextSibling;continue}if(!l.idMap.has(S)){let k=l.hyperMatches.get(S);if(k&&!l.idMap.has(k)){b(u,k,f),A(k,S,l),f=k.nextSibling;continue}}}let O=T(u,S,f,l);O&&(f=O.nextSibling)}for(;f&&f!=m;){let S=f;f=f.nextSibling,t(S)||v(l,S)}}function T(l,u,h,f){if(f.callbacks.beforeNodeAdded(u)===!1)return null;if(f.idMap.has(u)){let m=document.createElement(u.tagName);return l.insertBefore(m,h),A(m,u,f),f.callbacks.afterNodeAdded(m),m}else{let m=document.importNode(u,!0);return l.insertBefore(m,h),f.callbacks.afterNodeAdded(m),m}}let E=function(){function l(f,m,S,O){let I=m instanceof Element&&!f.idMap.has(m)?f.hyperMatches.get(m):null,k=null,$=m.nextSibling,ne=0,L=S;for(;L&&L!=O;){if(h(L,m)){if(u(f,L,m)||L===I&&!f.idMap.has(L))return L;if(k===null){let Y=L instanceof Element&&f.hyperMatchedOldElements.has(L);!f.idMap.has(L)&&!Y&&(k=L)}}if(k===null&&$&&h(L,$)&&(ne++,$=$.nextSibling,ne>=2&&(k=void 0)),f.activeElementAndParents.includes(L))break;L=L.nextSibling}return k||null}function u(f,m,S){let O=f.idMap.get(m),I=f.idMap.get(S);if(!I||!O)return!1;for(let k of O)if(I.has(k))return!0;return!1}function h(f,m){let S=f,O=m;return S.nodeType===O.nodeType&&S.tagName===O.tagName&&(!S.getAttribute?.("id")||S.getAttribute?.("id")===O.getAttribute?.("id"))}return l}();function v(l,u){let h=u instanceof Element&&l.hyperMatchedOldElements.has(u)&&!l.idMap.has(u);if(l.idMap.has(u)||h)b(l.pantry,u,null);else{if(l.callbacks.beforeNodeRemoved(u)===!1)return;u.parentNode?.removeChild(u),l.callbacks.afterNodeRemoved(u)}}function w(l,u,h){let f=u;for(;f&&f!==h;){let m=f;f=f.nextSibling,t(m)||v(l,m)}return f}function M(l,u,h,f){let m=f.target.getAttribute?.("id")===u&&f.target||f.target.querySelector(`[id="${u}"]`)||f.pantry.querySelector(`[id="${u}"]`);return d(m,f),b(l,m,h),m}function d(l,u){let h=l.getAttribute("id");for(;l=l.parentNode;){let f=u.idMap.get(l);f&&(f.delete(h),f.size||u.idMap.delete(l))}}function b(l,u,h){if(l.moveBefore)try{l.moveBefore(u,h)}catch{l.insertBefore(u,h)}else l.insertBefore(u,h)}return g}(),A=function(){function g(d,b,l){return l.ignoreActive&&d===document.activeElement?null:(l.callbacks.beforeNodeMorphed(d,b)===!1||(d instanceof HTMLHeadElement&&l.head.ignore||(d instanceof HTMLHeadElement&&l.head.style!=="morph"?y(d,b,l):(T(d,b,l),M(d,l)||c(l,d,b))),l.callbacks.afterNodeMorphed(d,b)),d)}function T(d,b,l){let u=b.nodeType;if(u===1){let h=d,f=b,m=h.attributes,S=f.attributes;for(let O of S)w(O.name,h,"update",l)||h.getAttribute(O.name)!==O.value&&h.setAttribute(O.name,O.value);for(let O=m.length-1;0<=O;O--){let I=m[O];if(I&&!f.hasAttribute(I.name)){if(w(I.name,h,"remove",l))continue;h.removeAttribute(I.name)}}M(h,l)||E(h,f,l)}(u===8||u===3)&&d.nodeValue!==b.nodeValue&&(d.nodeValue=b.nodeValue)}function E(d,b,l){if(d instanceof HTMLInputElement&&b instanceof HTMLInputElement&&b.type!=="file"){let u=b.value,h=d.value;v(d,b,"checked",l),v(d,b,"disabled",l),l.formStateSync==="property"?h!==u&&(w("value",d,"update",l)||(d.value=u)):b.hasAttribute("value")?h!==u&&(w("value",d,"update",l)||(d.setAttribute("value",u),d.value=u)):w("value",d,"remove",l)||(d.value="",d.removeAttribute("value"))}else if(d instanceof HTMLOptionElement&&b instanceof HTMLOptionElement)v(d,b,"selected",l);else if(d instanceof HTMLTextAreaElement&&b instanceof HTMLTextAreaElement){let u=b.value,h=d.value;if(w("value",d,"update",l))return;u!==h&&(d.value=u),d.firstChild&&d.firstChild.nodeValue!==u&&(d.firstChild.nodeValue=u)}}function v(d,b,l,u){let h=b[l],f=d[l];if(h!==f){let m=w(l,d,"update",u);if(m||(d[l]=b[l]),u.formStateSync==="property")return;h?m||d.setAttribute(l,""):w(l,d,"remove",u)||d.removeAttribute(l)}}function w(d,b,l,u){return d==="value"&&u.ignoreActiveValue&&b===document.activeElement?!0:u.callbacks.beforeAttributeUpdated(d,b,l)===!1}function M(d,b){return!!b.ignoreActiveValue&&d===document.activeElement&&d!==document.body}return g}();function x(g,T,E,v){if(g.head.block){let w=T.querySelector("head"),M=E.querySelector("head");if(w&&M){let d=y(w,M,g);return Promise.all(d).then(()=>{let b=Object.assign(g,{head:{block:!1,ignore:!0}});return v(b)})}}return v(g)}function y(g,T,E){let v=[],w=[],M=[],d=[],b=E.scripts.matchMode,l=f=>{if(f.tagName==="SCRIPT")return n(f,b);if(f.tagName==="LINK"&&b==="smart"){let m=f.getAttribute("href");if(m)try{let S=new URL(m,window.location.href);return`link:${f.getAttribute("rel")||""}:${S.origin}${S.pathname}${S.search}`}catch{}}return f.outerHTML},u=new Map;for(let f of T.children)t(f)||u.set(l(f),f);for(let f of g.children){let m=l(f),S=u.has(m),O=E.head.shouldReAppend(f),I=E.head.shouldPreserve(f);S||I?O?w.push(f):(u.delete(m),M.push(f)):E.head.style==="append"?O&&(w.push(f),d.push(f)):E.head.shouldRemove(f)!==!1&&!t(f)&&w.push(f)}d.push(...u.values());let h=[];for(let f of d){let m=document.createRange().createContextualFragment(f.outerHTML).firstChild;if(E.callbacks.beforeNodeAdded(m)!==!1){if("href"in m&&m.href||"src"in m&&m.src){let S,O=new Promise(function(I){S=I});m.addEventListener("load",function(){S()}),h.push(O)}g.appendChild(m),E.callbacks.afterNodeAdded(m),v.push(m)}}for(let f of w)E.callbacks.beforeNodeRemoved(f)!==!1&&(g.removeChild(f),E.callbacks.afterNodeRemoved(f));return E.head.afterHeadMorphed(g,{added:v,kept:M,removed:w}),h}function p(g,T,E){if(!E.scripts.handle)return[];let v=[],w=[],M=[],d=[],b=E.scripts.matchMode,l=Array.from(g.querySelectorAll("script"));for(let h of l){let f=n(h,b),m=T.has(f),S=E.scripts.shouldPreserve(h),O=E.scripts.shouldReAppend(h);m||S?O?(w.push(h),d.push(h)):M.push(h):d.push(h)}for(let h of T){let f=l.some(m=>m.outerHTML===h)}let u=[];for(let h of d){if(E.callbacks.beforeNodeAdded(h)===!1)continue;let f=document.createRange().createContextualFragment(h.outerHTML).firstChild;if(f.src){let m,S=new Promise(function(O){m=O});f.addEventListener("load",function(){m()}),f.addEventListener("error",function(){m()}),u.push(S)}h.replaceWith(f),E.callbacks.afterNodeAdded(f),v.push(f)}return E.scripts.afterScriptsHandled(g,{added:v,kept:M,removed:w}),u}let R=function(){function g(l,u,h){let{persistentIds:f,idMap:m}=d(l,u),S=r.computeMatches(l,u);if(typeof h.key=="function"){let $=new Map,ne=new Set,L=H=>{let P=h.key(H);P!=null&&($.has(P)?ne.add(P):$.set(P,H))};l instanceof Element&&L(l);for(let H of l.querySelectorAll("*"))L(H);for(let H of ne)$.delete(H);let Y=new Map;for(let[H,P]of S)Y.set(P,H);let xe=u.__hyperMorphRoot||u,he=new Map,et=new Set,tt=H=>{let P=h.key(H);P!=null&&(he.has(P)?et.add(P):he.set(P,H))};xe instanceof Element&&tt(xe);for(let H of xe.querySelectorAll("*"))tt(H);for(let H of et)he.delete(H);for(let[H,P]of he){let G=$.get(H);if(!G||G.tagName!==P.tagName)continue;let ve=Y.get(G);ve&&ve!==P&&S.delete(ve);let we=S.get(P);we&&we!==G&&Y.delete(we),S.set(P,G),Y.set(G,P)}}let O=new Set;for(let $ of S.values())O.add($);let I=T(h),k=I.morphStyle||"outerHTML";if(!["innerHTML","outerHTML"].includes(k))throw`Do not understand how to morph style ${k}`;return{target:l,newContent:u,config:I,morphStyle:k,ignoreActive:I.ignoreActive,ignoreActiveValue:I.ignoreActiveValue,restoreFocus:I.restoreFocus,formStateSync:I.formStateSync||"attribute",idMap:m,persistentIds:f,hyperMatches:S,hyperMatchedOldElements:O,pantry:E(),activeElementAndParents:v(l),callbacks:I.callbacks,head:I.head,scripts:I.scripts}}function T(l){let u=Object.assign({},o);return Object.assign(u,l),u.callbacks=Object.assign({},o.callbacks,l.callbacks),u.head=Object.assign({},o.head,l.head),u.scripts=Object.assign({},o.scripts,l.scripts),u}function E(){let l=document.createElement("div");return l.hidden=!0,document.body.insertAdjacentElement("afterend",l),l}function v(l){let u=[],h=document.activeElement;if(h?.tagName!=="BODY"&&l.contains(h))for(;h&&(u.push(h),h!==l);)h=h.parentElement;return u}function w(l){let u=Array.from(l.querySelectorAll("[id]"));return l.getAttribute?.("id")&&u.push(l),u}function M(l,u,h,f){for(let m of f){let S=m.getAttribute("id");if(u.has(S)){let O=m;for(;O;){let I=l.get(O);if(I==null&&(I=new Set,l.set(O,I)),I.add(S),O===h)break;O=O.parentElement}}}}function d(l,u){let h=w(l),f=w(u),m=b(h,f),S=new Map;M(S,m,l,h);let O=u.__hyperMorphRoot||u;return M(S,m,O,f),{persistentIds:m,idMap:S}}function b(l,u){let h=new Set,f=new Map;for(let{id:S,tagName:O}of l)f.has(S)?h.add(S):f.set(S,O);let m=new Set;for(let{id:S,tagName:O}of u)m.has(S)?h.add(S):f.get(S)===O&&m.add(S);for(let S of h)m.delete(S);return m}return g}(),{normalizeElement:N,normalizeParent:C}=function(){let g=new WeakSet;function T(M){return M instanceof Document?M.documentElement:M}function E(M){if(M==null)return document.createElement("div");if(typeof M=="string")return E(w(M));if(g.has(M))return M;if(M instanceof Node){if(M.parentNode)return new v(M);{let d=document.createElement("div");return d.append(M),d}}else{let d=document.createElement("div");for(let b of[...M])d.append(b);return d}}class v{constructor(d){this.originalNode=d,this.realParentNode=d.parentNode,this.previousSibling=d.previousSibling,this.nextSibling=d.nextSibling}get childNodes(){let d=[],b=this.previousSibling?this.previousSibling.nextSibling:this.realParentNode.firstChild;for(;b&&b!=this.nextSibling;)d.push(b),b=b.nextSibling;return d}querySelectorAll(d){return this.childNodes.reduce((b,l)=>{if(l instanceof Element){l.matches(d)&&b.push(l);let u=l.querySelectorAll(d);for(let h=0;h<u.length;h++)b.push(u[h])}return b},[])}insertBefore(d,b){return this.realParentNode.insertBefore(d,b)}moveBefore(d,b){return this.realParentNode.moveBefore(d,b)}get __hyperMorphRoot(){return this.originalNode}}function w(M){let d=new DOMParser,b=M.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");if(b.match(/<\/html>/)||b.match(/<\/head>/)||b.match(/<\/body>/)){let l=d.parseFromString(M,"text/html");if(b.match(/<\/html>/))return g.add(l),l;{let u=l.firstChild;return u&&g.add(u),u}}else{let u=d.parseFromString("<body><template>"+M+"</template></body>","text/html").body.querySelector("template").content;return g.add(u),u}}return{normalizeElement:T,normalizeParent:E}}();return{morph:s,defaults:o}}();var $n=Le.morph,jn=Le.defaults,dt=Le;function He(e,t,{onWidgetRemoved:n}={}){dt.morph(e,t,{morphStyle:"innerHTML",ignoreActiveValue:!0,restoreFocus:!0,formStateSync:"property",callbacks:{beforeNodeRemoved(o){let r=ye.get(o);r?.destroy&&r.destroy(),n?.(o)}}})}var sn="hha:upgrade-check:";function U(e,t){let n=e.querySelector(`meta[name="${t}"]`),o=n?n.getAttribute("content"):null;return o&&o.trim()?o.trim():null}function Pe(e){if(typeof e!="string")return null;let t=e.trim().replace(/^v/,"");return/^\d+(\.\d+)*$/.test(t)?t.split(".").map(Number):null}function pt(e,t){let n=Pe(e),o=Pe(t);if(!n||!o)return!1;let r=Math.max(n.length,o.length);for(let s=0;s<r;s++){let a=n[s]||0,i=o[s]||0;if(a!==i)return a>i}return!1}function an(e){try{let t=globalThis.localStorage.getItem(e);return t?JSON.parse(t):null}catch{return null}}function cn(e,t){try{globalThis.localStorage.setItem(e,JSON.stringify(t))}catch{}}async function De({force:e=!1,doc:t,loc:n,fetchFn:o,now:r,ttlMs:s=864e5}={}){if(t=t||(typeof document<"u"?document:null),n=n||(typeof location<"u"?location:null),o=o||(p=>fetch(p)),r=r??Date.now(),!t)return null;let a=U(t,"hyper-source");if(!a)return null;let i=U(t,"hyper-version"),c;try{c=new URL(a,n?n.href:void 0)}catch{return null}if(n&&c.origin===n.origin&&c.pathname===n.pathname)return null;let A=`${sn}${c.href}:${i||"none"}`,x,y=e?null:an(A);if(y&&typeof y.checkedAt=="number"&&r-y.checkedAt<s)x=y.sourceVersion;else{try{let p=await o(c.href);if(!p.ok)throw new Error(`HTTP ${p.status}`);let R=await p.text(),N=new DOMParser().parseFromString(R,"text/html");x=U(N,"hyper-version")}catch{x=null}cn(A,{checkedAt:r,sourceVersion:x})}return x?{available:pt(x,i||"0.0.0"),currentVersion:i,sourceVersion:x,sourceUrl:c.href}:null}var Ae=["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"],_e=new Set(Ae),ht=new Set(["textContent","innerText","innerHTML","value","checked","selected","disabled","readOnly","type","id","className","title"]),mt=new Set(["tagName","nodeName","nodeType","nodeValue","childElementCount","classList","baseURI","documentURI","contentType","offsetWidth","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","currentSrc","duration","paused","dataset"]);var Se={};Re(Se,{EmptyListInsert:()=>se,MAX_RULE_DEPTH:()=>Q,MaxRuleDepthExceeded:()=>K,RuleTargetReadOnly:()=>ie,RulesParseError:()=>Z,ShapeMismatch:()=>oe,UnknownRulesVersion:()=>q});var Z=class extends Error{constructor(t,n){super(t),this.name="RulesParseError",this.cause=n}},q=class extends Error{constructor(t){super(`unknown rules version: ${t}. Library supports "1".`),this.name="UnknownRulesVersion",this.version=t}},Q=20,K=class extends Error{constructor(t){super(`rule depth exceeded ${Q} at path: ${t.join(".")}`),this.name="MaxRuleDepthExceeded",this.path=t}},oe=class extends Error{constructor(t){super(`shape mismatch: ${t.length} field(s) failed validation`),this.name="ShapeMismatch",this.mismatches=t}},se=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}},ie=class extends Error{constructor(t){super(`cannot write to read-only DOM property "${t}"`),this.name="RuleTargetReadOnly",this.target=t}};function F(e,t,n,o={}){return $e(e,t,n,{depth:0,path:[]},o)}function $e(e,t,n,o,r){if(o.depth>Q)throw new K(o.path);if(typeof n=="string")return ln(e,t,n,r);if(Array.isArray(n)){let[s,a]=n;return e.find(t,s,r).map((c,A)=>$e(e,c,a,{depth:o.depth+1,path:[...o.path,A]},r))}if(typeof n=="object"&&n!==null){let s={};for(let[a,i]of Object.entries(n))s[a]=$e(e,t,i,{depth:o.depth+1,path:[...o.path,a]},r);return s}return null}function ln(e,t,n,o){if(n.endsWith("[]")){let s=n.slice(0,-2);return e.find(t,s,o).map(a=>e.text(a))}if(n.startsWith("@"))return gt(e,t,n.slice(1));if(n.includes("@")){let s=n.lastIndexOf("@"),a=n.slice(0,s),i=n.slice(s+1),c=a?e.find(t,a,o):[t];return c.length===0?null:gt(e,c[0],i)}if(n===".")return e.text(t);let r=e.find(t,n,o);return r.length===0?null:e.text(r[0])}function gt(e,t,n){if(_e.has(n)){let r=e.prop(t,n);return r==null?null:String(r)}let o=e.attr(t,n);return o||null}function un(e){return e&&e.nodeType===1&&e.tagName==="SCRIPT"&&e.hasAttribute&&e.hasAttribute("data-rules-name")}function fn(e){return e?(e.nodeType===9||e.nodeType===11,e):null}var dn={find(e,t,n={}){let o=fn(e);if(!o||!o.querySelectorAll)return[];let r=Array.from(o.querySelectorAll(t));n.includeRulesTag||(r=r.filter(i=>!un(i)));let s=[];n.skip&&s.push(n.skip);let a=n.templateAttr===null?null:n.templateAttr||"cms-template";if(a&&s.push("["+a+"]"),s.length){let i=s.join(", ");r=r.filter(c=>!c.closest||!c.closest(i))}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}},D=dn;function je(e){try{return JSON.parse(e)}catch(t){throw new Z(`Invalid strict JSON: ${t.message}`,t)}}function z(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 s=[],a=0;for(;a<r.length;){let i=r[a];if(/\s/.test(i)){a++;continue}if("{}".includes(i)){s.push({type:i,value:i}),a++;continue}if(i==="["){let y=!1,p=a+1;for(;p<r.length&&/\s/.test(r[p]);)p++;if(p<r.length&&/[a-zA-Z_]/.test(r[p])&&(y=!0),!y){s.push({type:i,value:i}),a++;continue}}if(i==="]"){s.push({type:i,value:i}),a++;continue}if(i===":"){s.push({type:t.COLON,value:i}),a++;continue}if(i===","){s.push({type:t.COMMA,value:i}),a++;continue}if(i==='"'||i==="'"){let y=i,p=a+1;for(;p<r.length&&r[p]!==y;)r[p]==="\\"&&p++,p++;s.push({type:t.STRING,value:r.substring(a+1,p),quoted:!0,sourceQuote:y}),a=p+1;continue}let c=a,A;for(;c<r.length&&!/[{},]/.test(r[c]);)if(r[c]===":"){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"],p=!1;for(let R of y){let N=R.substring(1);if(r.substring(c+1,c+1+N.length)===N){p=!0,c+=N.length;break}}if(!p)break}else if(r[c]==="["){for(c++;c<r.length&&r[c]!=="]";){if(r[c]==='"'||r[c]==="'"){let y=r[c];for(c++;c<r.length&&r[c]!==y;)r[c]==="\\"&&c++,c++}c++}c<r.length&&r[c]==="]"&&c++}else c++;A=r.substring(a,c);let x=t.IDENTIFIER;/^-?\d+(\.\d+)?$/.test(A)?x=t.NUMBER:A==="true"||A==="false"||A==="null"?x=t.BOOLEAN:/^[.#@\[]|[.#@\[]| /.test(A)&&(x=t.SELECTOR),s.push({type:x,value:A,quoted:!1}),a=c}return s}function o(r){let s="";for(let a=0;a<r.length;a++){let i=r[a];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=r[a+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,(A,x)=>x.length%2===0?x+'\\"':A)),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 r=n(e),s=o(r);return JSON.parse(s)}catch(r){throw new Z("Invalid extraction rules syntax: "+r.message,r)}}var Ue="1",yt=/^[a-zA-Z0-9_-]+$/;function ee(e,t,n){let o;if(n===void 0)o="script[data-rules-name]";else{if(typeof n!="string"||!yt.test(n))throw new Error(`hyper-html-api: invalid rules token ${JSON.stringify(n)} (must match ${yt})`);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 s=r[0],a=e.attr(s,"data-rules-version");if(a!==Ue)throw new q(a);return{rules:z(e.text(s)),tagNode:s}}var pn="script[data-rules-name]";function bt(e){return typeof e=="string"?e.trim().replace(/\s+/g," "):""}function ae(e,t){let n=e.find(t,pn,{includeRulesTag:!0}),o=new Set,r=[];for(let s of n){let a=bt(e.attr(s,"data-rules-name"));if(!a)continue;if(o.has(a)){console.warn(`hyper-html-api: duplicate rules tag name "${a}"; using the first.`);continue}let i=e.attr(s,"data-rules-version");if(i!==Ue)throw new q(i);o.add(a),r.push({name:a,rules:z(e.text(s))})}return r}function Me(e,t){let n={};for(let{name:o,rules:r}of ae(e,t))n[o]=F(e,t,r);return n}function Fe(e){let t=e||document,n=t.nodeType===9?t:t.ownerDocument||t;return{dataByName:Me(D,t),version:U(n,"hyper-version")}}var te=class extends Error{constructor(t,n){super(`could not fetch upgrade source: ${t}`),this.name="UpgradeSourceUnreachable",this.sourceUrl=t,this.cause=n}},ce=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}},W=class extends Error{constructor(t,n){super(t),this.name="UpgradeTransformInvalid",this.cause=n}},le=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 At="text/hyper-upgrade";function Be(e,t){let n=e.find(t,`script[type="${At}"]`);if(n.length===0)return null;if(n.length>1)throw new le(n.length);return e.text(n[0])||null}var hn=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 hn(n)}catch(r){throw new W(`transform failed to load: ${r&&r.message?r.message:r}`,r)}finally{URL.revokeObjectURL(n)}if(typeof o.default!="function")throw new W("transform must `export default` a function");return o.default}var mn=.5;function Ve(e,t,n,o,r,s,a,i={}){let c=e.find(t,n,i);if(r.length===0){c.forEach(v=>e.remove(v));return}let A=r.length>c.length,x=c[0]||null;if(A&&!x&&(x=Sn(e,t,n,i),!x))throw new se(s.path);let y=c.map(v=>gn(e,v,o,i)),p=null;if(x){p=e.clone(x),i.templateAttr&&e.removeAttr(p,i.templateAttr);let v=e.stripIds(p);v>0&&console.warn(`[hyper-html-api] stripped ${v} id attribute(s) from cloned template at "${s.path.join(".")||"(root)"}"`)}let R=yn(r,y,o),N=c[0]||x,C=e.parent(N),g=c.length>0?An(e,C,N):0,T=new Set,E=r.map((v,w)=>{let M=R[w];if(M>=0)return T.add(M),c[M];let d=e.clone(p);return e.stripIds(d),d});c.forEach((v,w)=>{T.has(w)||e.remove(v)}),E.forEach((v,w)=>{let M=g+w;e.children(C).findIndex(l=>e.sameNode(l,v))!==M&&e.insertAt(C,v,M)}),E.forEach((v,w)=>{if(o===null){let M=r[w],d=M==null?"":String(M);e.text(v)!==d&&e.text(v,d)}else{let M=a(e,v,o,r[w],{depth:s.depth+1,path:[...s.path,w]},i);M&&M!==v&&(E[w]=M)}})}function gn(e,t,n,o){return n===null?e.text(t):F(e,t,n,o)}function yn(e,t,n){let o=new Array(e.length).fill(-1),r=new Set;return e.forEach((s,a)=>{let i=-1,c=-1;t.forEach((A,x)=>{if(r.has(x))return;let y=bn(s,A,n),p=y===c&&i>=0?Math.abs(x-a)<Math.abs(i-a):!1;(y>c||p)&&(c=y,i=x)}),c>=mn&&(o[a]=i,r.add(i))}),o}function bn(e,t,n){if(n===null)return e===t?1:0;let o=Object.keys(n||{});if(o.length===0)return 0;let r=0;for(let s of o)JSON.stringify(e?.[s])===JSON.stringify(t?.[s])&&r++;return r/o.length}function An(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 Sn(e,t,n,o){if(!o.templateAttr)return null;let r=t;for(;r;){let s=e.find(r,n,{includeRulesTag:!1,templateAttr:null});for(let a of s)if(e.attr(a,o.templateAttr)!=null)return a;r=e.parent(r)}return null}var St=new Set(["checked","selected","disabled","readOnly","paused"]);function V(e,t,n,o,r={}){let s=[];if(qe(n,o,[],s),s.length)throw new oe(s);Ee(e,t,n,o,{depth:0,path:[]},r)}function Ee(e,t,n,o,r,s={}){if(r.depth>Q)throw new K(r.path);if(o===void 0)return t;if(typeof n=="string")return Mn(e,t,n,o,r,s);if(Array.isArray(n)){let[a,i]=n;return Ve(e,t,a,i,o,r,Ee,s),t}if(typeof n=="object"&&n!==null){for(let[a,i]of Object.entries(n)){let c=Ee(e,t,i,o==null?o:o[a],{depth:r.depth+1,path:[...r.path,a]},s);c&&c!==t&&(t=c)}return t}return t}function Mn(e,t,n,o,r,s){if(n.endsWith("[]")){let i=n.slice(0,-2);return Ve(e,t,i,null,o,r,Ee,s),t}if(n.startsWith("@"))return Mt(e,t,n.slice(1),o);if(n.includes("@")){let i=n.lastIndexOf("@"),c=n.slice(0,i),A=n.slice(i+1),x=c?e.find(t,c,s):[t];return x.length===0||Mt(e,x[0],A,o),t}if(n===".")return e.text(t,o==null?"":String(o)),t;let a=e.find(t,n,s);return a.length===0||e.text(a[0],o==null?"":String(o)),t}function Mt(e,t,n,o){if(mt.has(n))throw new ie(n);if(n==="outerHTML"){let r=o==null?"":String(o);return e.replaceWith(t,r)}return ht.has(n)?(e.prop(t,n,En(n,o)),t):(e.attr(t,n,o==null?"":String(o)),t)}function En(e,t){return t==null?St.has(e)?!1:"":St.has(e)?!!t:t}function qe(e,t,n,o){if(t!==void 0){if(typeof e=="string"){if(e.endsWith("[]")){Array.isArray(t)?t.forEach((r,s)=>{typeof r=="object"&&r!==null&&o.push({path:fe([...n,s]),expected:"scalar",got:ue(r)})}):o.push({path:fe(n),expected:"array",got:ue(t)});return}t!==null&&typeof t=="object"&&o.push({path:fe(n),expected:"scalar",got:ue(t)});return}if(Array.isArray(e)){if(!Array.isArray(t)){o.push({path:fe(n),expected:"array",got:ue(t)});return}let r=e[1];t.forEach((s,a)=>qe(r,s,[...n,a],o));return}if(typeof e=="object"&&e!==null){if(t===null||Array.isArray(t)||typeof t!="object"){o.push({path:fe(n),expected:"object",got:ue(t)});return}for(let[r,s]of Object.entries(e))qe(s,t[r],[...n,r],o)}}}function ue(e){return e===null?"null":Array.isArray(e)?"array":typeof e}function fe(e){return e.join(".")}function de(e,t){let n={carriedOver:0,discarded:0,listItems:0},o=Ke(t,e,n);return ze(t,e,n),{data:o,summary:n}}function Ke(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=>Ke(o,r,n))):void 0}if(typeof e=="object"&&e!==null){let o={};for(let[r,s]of Object.entries(e)){let a=Ke(s,t?.[r],n);a!==void 0&&(o[r]=a)}return o}}function ze(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)?ze(e[r],t[r],n):n.discarded+=J(t[r]);return}if(Array.isArray(e)&&Array.isArray(t)){let o=e[1];t.forEach(r=>ze(o,r,n));return}typeof e=="string"&&!e.endsWith("[]")&&typeof t=="object"&&t!==null&&(n.discarded+=J(t))}}function J(e){return e==null?0:Array.isArray(e)?e.reduce((t,n)=>t+J(n),0):typeof e=="object"?Object.values(e).reduce((t,n)=>t+J(n),0):1}function Je(e,t,n){let o=ae(e,t),r={carriedOver:0,discarded:0,listItems:0},s={},a=new Set;for(let{name:i,rules:c}of o){if(a.add(i),!Object.prototype.hasOwnProperty.call(n,i)){s[i]={carriedOver:0,discarded:0,listItems:0};continue}let{data:A,summary:x}=de(n[i],c);V(e,t,c,A),s[i]=x,r.carriedOver+=x.carriedOver,r.discarded+=x.discarded,r.listItems+=x.listItems}for(let i of Object.keys(n))a.has(i)||(r.discarded+=J(n[i]));return{totals:r,byName:s,rulesTagCount:o.length}}async function Ye({sourceUrl:e,dataByName:t,fromVersion:n,doc:o,loc:r,fetchFn:s}={}){if(o=o||(typeof document<"u"?document:null),r=r||(typeof location<"u"?location:null),s=s||(T=>fetch(T)),!o)throw new Error("upgrade.run requires a document context");if(e=e||U(o,"hyper-source"),!e)throw new Error("upgrade.run: no sourceUrl given and no hyper-source meta tag found");let a=new URL(e,r?r.href:void 0);n=n!==void 0?n:U(o,"hyper-version"),t=t||Me(D,o);let i;try{i=await s(a.href)}catch(T){throw new te(a.href,T)}if(!i.ok)throw new te(a.href,new Error(`HTTP ${i.status}`));let c=await i.text(),A=new DOMParser().parseFromString(c,"text/html"),x=U(A,"hyper-version"),y=t,p=!1,R=Be(D,A);if(R){let E=await(await We(R))(y,{fromVersion:n,toVersion:x});if(!E||typeof E!="object"||Array.isArray(E))throw new W("transform must return a plain object map of { rulesName: data }");y=E,p=!0}let{totals:N,byName:C,rulesTagCount:g}=Je(D,A,y);if(g===0&&Object.keys(y).length>0)throw new ce(a.href);return{html:xn(A),fromVersion:n,toVersion:x,summary:{transformApplied:p,totals:N,byName:C}}}function xn(e){return`<!DOCTYPE ${e.doctype&&e.doctype.name?e.doctype.name:"html"}>
3
+ `+e.documentElement.outerHTML}function Ge(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 ee(e,o,n)}return null}function Et(e,t,n,o){let r=Ge(e,t,n);if(!r){let i=typeof n=="string"?`data-rules-name~="${n}"`:"the provided rules object";throw new Error(`hyper-html-api: could not resolve rules for ${i}`)}let{rules:s,tagNode:a}=r;return{rules:s,tagNode:a,get:()=>F(e,t,s,o),set:i=>V(e,t,s,i,o)}}var pe={extract:(e,t,n)=>F(D,e,t,n),apply:(e,t,n,o)=>V(D,e,t,n,o),findRulesIn:(e,t)=>ee(D,e,t),findRules:(e,t)=>Ge(D,e,t),bind:(e,t,n)=>Et(D,e,t,n),parseStrict:je,parseRelaxed:z,errors:Se,DOM_PROPERTIES:Ae},Xe=e=>!!e&&typeof e.nodeType=="number";function xt(e){let t=e&&e.ownerDocument?e.ownerDocument:e,n=D.find(t,"script[data-rules-name]",{includeRulesTag:!0});if(n.length===0)throw new Error('hyper-html-api: no rules tag found. Add <script type="application/json" data-rules-name="\u2026" data-rules-version="1"> or pass rules.');if(n.length>1)throw new Error('hyper-html-api: multiple rules tags found; pass a name, e.g. extractData("api").');return ee(D,t).rules}function Ze(e,t){let n=Xe(e)?e:document,o=Xe(e)?t:e;return o===void 0?F(D,n,xt(n)):pe.bind(n,o).get()}function Qe(e,t,n){if(!Xe(e))throw new Error("hyper-html-api: applyData(root, data, source?) needs a DOM root as the first argument.");return n===void 0?V(D,e,xt(e),t):pe.bind(e,n).set(t),e}var vt={buildForm:Ne,bindFormEvents:Ie,scaffold:X,morphForm:He,path:ge},wt={checkForUpdate:De,run:Ye,extractAll:Fe,shapeMatch:de};var Tn={engine:pe,cms:vt,upgrade:wt,extractData:Ze,applyData:Qe},Rn=Tn;return It(On);})();
@@ -0,0 +1,2 @@
1
+ var hyperHtmlApiUpgrade=(()=>{var Y=Object.defineProperty;var Te=Object.getOwnPropertyDescriptor;var we=Object.getOwnPropertyNames;var Se=Object.prototype.hasOwnProperty;var ie=(e,t)=>{for(var r in t)Y(e,r,{get:t[r],enumerable:!0})},be=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of we(t))!Se.call(e,n)&&n!==r&&Y(e,n,{get:()=>t[n],enumerable:!(o=Te(t,n))||o.enumerable});return e};var Ie=e=>be(Y({},"__esModule",{value:!0}),e);var Qe={};ie(Qe,{default:()=>Xe,engine:()=>re,upgrade:()=>Oe});var W=["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"],z=new Set(W),ce=new Set(["textContent","innerText","innerHTML","value","checked","selected","disabled","readOnly","type","id","className","title"]),le=new Set(["tagName","nodeName","nodeType","nodeValue","childElementCount","classList","baseURI","documentURI","contentType","offsetWidth","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","currentSrc","duration","paused","dataset"]);var B={};ie(B,{EmptyListInsert:()=>j,MAX_RULE_DEPTH:()=>P,MaxRuleDepthExceeded:()=>w,RuleTargetReadOnly:()=>C,RulesParseError:()=>_,ShapeMismatch:()=>L,UnknownRulesVersion:()=>T});var _=class extends Error{constructor(t,r){super(t),this.name="RulesParseError",this.cause=r}},T=class extends Error{constructor(t){super(`unknown rules version: ${t}. Library supports "1".`),this.name="UnknownRulesVersion",this.version=t}},P=20,w=class extends Error{constructor(t){super(`rule depth exceeded ${P} 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 E(e,t,r,o={}){return G(e,t,r,{depth:0,path:[]},o)}function G(e,t,r,o,n){if(o.depth>P)throw new w(o.path);if(typeof r=="string")return Ne(e,t,r,n);if(Array.isArray(r)){let[i,c]=r;return e.find(t,i,n).map((l,u)=>G(e,l,c,{depth:o.depth+1,path:[...o.path,u]},n))}if(typeof r=="object"&&r!==null){let i={};for(let[c,s]of Object.entries(r))i[c]=G(e,t,s,{depth:o.depth+1,path:[...o.path,c]},n);return i}return null}function Ne(e,t,r,o){if(r.endsWith("[]")){let i=r.slice(0,-2);return e.find(t,i,o).map(c=>e.text(c))}if(r.startsWith("@"))return fe(e,t,r.slice(1));if(r.includes("@")){let i=r.lastIndexOf("@"),c=r.slice(0,i),s=r.slice(i+1),l=c?e.find(t,c,o):[t];return l.length===0?null:fe(e,l[0],s)}if(r===".")return e.text(t);let n=e.find(t,r,o);return n.length===0?null:e.text(n[0])}function fe(e,t,r){if(z.has(r)){let n=e.prop(t,r);return n==null?null:String(n)}let o=e.attr(t,r);return o||null}var Me=.5;function X(e,t,r,o,n,i,c,s={}){let l=e.find(t,r,s);if(n.length===0){l.forEach(p=>e.remove(p));return}let u=n.length>l.length,f=l[0]||null;if(u&&!f&&(f=je(e,t,r,s),!f))throw new j(i.path);let d=l.map(p=>_e(e,p,o,s)),a=null;if(f){a=e.clone(f),s.templateAttr&&e.removeAttr(a,s.templateAttr);let p=e.stripIds(a);p>0&&console.warn(`[hyper-html-api] stripped ${p} id attribute(s) from cloned template at "${i.path.join(".")||"(root)"}"`)}let R=Pe(n,d,o),y=l[0]||f,N=e.parent(y),K=l.length>0?Le(e,N,y):0,A=new Set,O=n.map((p,g)=>{let h=R[g];if(h>=0)return A.add(h),l[h];let M=e.clone(a);return e.stripIds(M),M});l.forEach((p,g)=>{A.has(g)||e.remove(p)}),O.forEach((p,g)=>{let h=K+g;e.children(N).findIndex(Ae=>e.sameNode(Ae,p))!==h&&e.insertAt(N,p,h)}),O.forEach((p,g)=>{if(o===null){let h=n[g],M=h==null?"":String(h);e.text(p)!==M&&e.text(p,M)}else{let h=c(e,p,o,n[g],{depth:i.depth+1,path:[...i.path,g]},s);h&&h!==p&&(O[g]=h)}})}function _e(e,t,r,o){return r===null?e.text(t):E(e,t,r,o)}function Pe(e,t,r){let o=new Array(e.length).fill(-1),n=new Set;return e.forEach((i,c)=>{let s=-1,l=-1;t.forEach((u,f)=>{if(n.has(f))return;let d=De(i,u,r),a=d===l&&s>=0?Math.abs(f-c)<Math.abs(s-c):!1;(d>l||a)&&(l=d,s=f)}),l>=Me&&(o[c]=s,n.add(s))}),o}function De(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 i of o)JSON.stringify(e?.[i])===JSON.stringify(t?.[i])&&n++;return n/o.length}function Le(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 je(e,t,r,o){if(!o.templateAttr)return null;let n=t;for(;n;){let i=e.find(n,r,{includeRulesTag:!1,templateAttr:null});for(let c of i)if(e.attr(c,o.templateAttr)!=null)return c;n=e.parent(n)}return null}var ae=new Set(["checked","selected","disabled","readOnly","paused"]);function S(e,t,r,o,n={}){let i=[];if(Q(r,o,[],i),i.length)throw new L(i);q(e,t,r,o,{depth:0,path:[]},n)}function q(e,t,r,o,n,i={}){if(n.depth>P)throw new w(n.path);if(o===void 0)return t;if(typeof r=="string")return Ce(e,t,r,o,n,i);if(Array.isArray(r)){let[c,s]=r;return X(e,t,c,s,o,n,q,i),t}if(typeof r=="object"&&r!==null){for(let[c,s]of Object.entries(r)){let l=q(e,t,s,o==null?o:o[c],{depth:n.depth+1,path:[...n.path,c]},i);l&&l!==t&&(t=l)}return t}return t}function Ce(e,t,r,o,n,i){if(r.endsWith("[]")){let s=r.slice(0,-2);return X(e,t,s,null,o,n,q,i),t}if(r.startsWith("@"))return ue(e,t,r.slice(1),o);if(r.includes("@")){let s=r.lastIndexOf("@"),l=r.slice(0,s),u=r.slice(s+1),f=l?e.find(t,l,i):[t];return f.length===0||ue(e,f[0],u,o),t}if(r===".")return e.text(t,o==null?"":String(o)),t;let c=e.find(t,r,i);return c.length===0||e.text(c[0],o==null?"":String(o)),t}function ue(e,t,r,o){if(le.has(r))throw new C(r);if(r==="outerHTML"){let n=o==null?"":String(o);return e.replaceWith(t,n)}return ce.has(r)?(e.prop(t,r,ke(r,o)),t):(e.attr(t,r,o==null?"":String(o)),t)}function ke(e,t){return t==null?ae.has(e)?!1:"":ae.has(e)?!!t:t}function Q(e,t,r,o){if(t!==void 0){if(typeof e=="string"){if(e.endsWith("[]")){Array.isArray(t)?t.forEach((n,i)=>{typeof n=="object"&&n!==null&&o.push({path:$([...r,i]),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((i,c)=>Q(n,i,[...r,c],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,i]of Object.entries(e))Q(i,t[n],[...r,n],o)}}}function k(e){return e===null?"null":Array.isArray(e)?"array":typeof e}function $(e){return e.join(".")}function Z(e){try{return JSON.parse(e)}catch(t){throw new _(`Invalid strict JSON: ${t.message}`,t)}}function b(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 i=[],c=0;for(;c<n.length;){let s=n[c];if(/\s/.test(s)){c++;continue}if("{}".includes(s)){i.push({type:s,value:s}),c++;continue}if(s==="["){let d=!1,a=c+1;for(;a<n.length&&/\s/.test(n[a]);)a++;if(a<n.length&&/[a-zA-Z_]/.test(n[a])&&(d=!0),!d){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 d=s,a=c+1;for(;a<n.length&&n[a]!==d;)n[a]==="\\"&&a++,a++;i.push({type:t.STRING,value:n.substring(c+1,a),quoted:!0,sourceQuote:d}),c=a+1;continue}let l=c,u;for(;l<n.length&&!/[{},]/.test(n[l]);)if(n[l]===":"){let d=[":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 R of d){let y=R.substring(1);if(n.substring(l+1,l+1+y.length)===y){a=!0,l+=y.length;break}}if(!a)break}else if(n[l]==="["){for(l++;l<n.length&&n[l]!=="]";){if(n[l]==='"'||n[l]==="'"){let d=n[l];for(l++;l<n.length&&n[l]!==d;)n[l]==="\\"&&l++,l++}l++}l<n.length&&n[l]==="]"&&l++}else l++;u=n.substring(c,l);let f=t.IDENTIFIER;/^-?\d+(\.\d+)?$/.test(u)?f=t.NUMBER:u==="true"||u==="false"||u==="null"?f=t.BOOLEAN:/^[.#@\[]|[.#@\[]| /.test(u)&&(f=t.SELECTOR),i.push({type:f,value:u,quoted:!1}),c=l}return i}function o(n){let i="";for(let c=0;c<n.length;c++){let s=n[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=n[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,(u,f)=>f.length%2===0?f+'\\"':u)),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 n=r(e),i=o(n);return JSON.parse(i)}catch(n){throw new _("Invalid extraction rules syntax: "+n.message,n)}}var ee="1",de=/^[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"||!de.test(r))throw new Error(`hyper-html-api: invalid rules token ${JSON.stringify(r)} (must match ${de})`);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 i=n[0],c=e.attr(i,"data-rules-version");if(c!==ee)throw new T(c);return{rules:b(e.text(i)),tagNode:i}}function te(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 pe(e,t,r,o){let n=te(e,t,r);if(!n){let s=typeof r=="string"?`data-rules-name~="${r}"`:"the provided rules object";throw new Error(`hyper-html-api: could not resolve rules for ${s}`)}let{rules:i,tagNode:c}=n;return{rules:i,tagNode:c,get:()=>E(e,t,i,o),set:s=>S(e,t,i,s,o)}}function Ue(e){return e&&e.nodeType===1&&e.tagName==="SCRIPT"&&e.hasAttribute&&e.hasAttribute("data-rules-name")}function He(e){return e?(e.nodeType===9||e.nodeType===11,e):null}var We={find(e,t,r={}){let o=He(e);if(!o||!o.querySelectorAll)return[];let n=Array.from(o.querySelectorAll(t));r.includeRulesTag||(n=n.filter(s=>!Ue(s)));let i=[];r.skip&&i.push(r.skip);let c=r.templateAttr===null?null:r.templateAttr||"cms-template";if(c&&i.push("["+c+"]"),i.length){let s=i.join(", ");n=n.filter(l=>!l.closest||!l.closest(s))}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}},m=We;var re={extract:(e,t,r)=>E(m,e,t,r),apply:(e,t,r,o)=>S(m,e,t,r,o),findRulesIn:(e,t)=>U(m,e,t),findRules:(e,t)=>te(m,e,t),bind:(e,t,r)=>pe(m,e,t,r),parseStrict:Z,parseRelaxed:b,errors:B,DOM_PROPERTIES:W};var Be="hha:upgrade-check:";function x(e,t){let r=e.querySelector(`meta[name="${t}"]`),o=r?r.getAttribute("content"):null;return o&&o.trim()?o.trim():null}function he(e){if(typeof e!="string")return null;let t=e.trim().replace(/^v/,"");return/^\d+(\.\d+)*$/.test(t)?t.split(".").map(Number):null}function qe(e,t){let r=he(e),o=he(t);if(!r||!o)return!1;let n=Math.max(r.length,o.length);for(let i=0;i<n;i++){let c=r[i]||0,s=o[i]||0;if(c!==s)return c>s}return!1}function Fe(e){try{let t=globalThis.localStorage.getItem(e);return t?JSON.parse(t):null}catch{return null}}function Je(e,t){try{globalThis.localStorage.setItem(e,JSON.stringify(t))}catch{}}async function me({force:e=!1,doc:t,loc:r,fetchFn:o,now:n,ttlMs:i=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 c=x(t,"hyper-source");if(!c)return null;let s=x(t,"hyper-version"),l;try{l=new URL(c,r?r.href:void 0)}catch{return null}if(r&&l.origin===r.origin&&l.pathname===r.pathname)return null;let u=`${Be}${l.href}:${s||"none"}`,f,d=e?null:Fe(u);if(d&&typeof d.checkedAt=="number"&&n-d.checkedAt<i)f=d.sourceVersion;else{try{let a=await o(l.href);if(!a.ok)throw new Error(`HTTP ${a.status}`);let R=await a.text(),y=new DOMParser().parseFromString(R,"text/html");f=x(y,"hyper-version")}catch{f=null}Je(u,{checkedAt:n,sourceVersion:f})}return f?{available:qe(f,s||"0.0.0"),currentVersion:s,sourceVersion:f,sourceUrl:l.href}:null}var Ve="script[data-rules-name]";function ve(e){return typeof e=="string"?e.trim().replace(/\s+/g," "):""}function F(e,t){let r=e.find(t,Ve,{includeRulesTag:!0}),o=new Set,n=[];for(let i of r){let c=ve(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!==ee)throw new T(s);o.add(c),n.push({name:c,rules:b(e.text(i))})}return n}function ne(e,t){let r={};for(let{name:o,rules:n}of F(e,t))r[o]=E(e,t,n);return r}function ye(e){let t=e||document,r=t.nodeType===9?t:t.ownerDocument||t;return{dataByName:ne(m,t),version:x(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}},J=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}},I=class extends Error{constructor(t,r){super(t),this.name="UpgradeTransformInvalid",this.cause=r}},V=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 Ke="text/hyper-upgrade";function ge(e,t){let r=e.find(t,`script[type="${Ke}"]`);if(r.length===0)return null;if(r.length>1)throw new V(r.length);return e.text(r[0])||null}var Ye=new Function("url","return import(url)");async function Ee(e){let t=new Blob([e],{type:"text/javascript"}),r=URL.createObjectURL(t),o;try{o=await Ye(r)}catch(n){throw new I(`transform failed to load: ${n&&n.message?n.message:n}`,n)}finally{URL.revokeObjectURL(r)}if(typeof o.default!="function")throw new I("transform must `export default` a function");return o.default}function v(e,t){let r={carriedOver:0,discarded:0,listItems:0},o=oe(t,e,r);return se(t,e,r),{data:o,summary:r}}function oe(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=>oe(o,n,r))):void 0}if(typeof e=="object"&&e!==null){let o={};for(let[n,i]of Object.entries(e)){let c=oe(i,t?.[n],r);c!==void 0&&(o[n]=c)}return o}}function se(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)?se(e[n],t[n],r):r.discarded+=D(t[n]);return}if(Array.isArray(e)&&Array.isArray(t)){let o=e[1];t.forEach(n=>se(o,n,r));return}typeof e=="string"&&!e.endsWith("[]")&&typeof t=="object"&&t!==null&&(r.discarded+=D(t))}}function D(e){return e==null?0:Array.isArray(e)?e.reduce((t,r)=>t+D(r),0):typeof e=="object"?Object.values(e).reduce((t,r)=>t+D(r),0):1}function xe(e,t,r){let o=F(e,t),n={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(r,s)){i[s]={carriedOver:0,discarded:0,listItems:0};continue}let{data:u,summary:f}=v(r[s],l);S(e,t,l,u),i[s]=f,n.carriedOver+=f.carriedOver,n.discarded+=f.discarded,n.listItems+=f.listItems}for(let s of Object.keys(r))c.has(s)||(n.discarded+=D(r[s]));return{totals:n,byName:i,rulesTagCount:o.length}}async function Re({sourceUrl:e,dataByName:t,fromVersion:r,doc:o,loc:n,fetchFn:i}={}){if(o=o||(typeof document<"u"?document:null),n=n||(typeof location<"u"?location:null),i=i||(A=>fetch(A)),!o)throw new Error("upgrade.run requires a document context");if(e=e||x(o,"hyper-source"),!e)throw new Error("upgrade.run: no sourceUrl given and no hyper-source meta tag found");let c=new URL(e,n?n.href:void 0);r=r!==void 0?r:x(o,"hyper-version"),t=t||ne(m,o);let s;try{s=await i(c.href)}catch(A){throw new H(c.href,A)}if(!s.ok)throw new H(c.href,new Error(`HTTP ${s.status}`));let l=await s.text(),u=new DOMParser().parseFromString(l,"text/html"),f=x(u,"hyper-version"),d=t,a=!1,R=ge(m,u);if(R){let O=await(await Ee(R))(d,{fromVersion:r,toVersion:f});if(!O||typeof O!="object"||Array.isArray(O))throw new I("transform must return a plain object map of { rulesName: data }");d=O,a=!0}let{totals:y,byName:N,rulesTagCount:K}=xe(m,u,d);if(K===0&&Object.keys(d).length>0)throw new J(c.href);return{html:ze(u),fromVersion:r,toVersion:f,summary:{transformApplied:a,totals:y,byName:N}}}function ze(e){return`<!DOCTYPE ${e.doctype&&e.doctype.name?e.doctype.name:"html"}>
2
+ `+e.documentElement.outerHTML}var Oe={checkForUpdate:me,run:Re,extractAll:ye,shapeMatch:v};var Ge={engine:re,upgrade:Oe},Xe=Ge;return Ie(Qe);})();
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "apply",
10
10
  "CMS"
11
11
  ],
12
- "version": "0.4.0",
12
+ "version": "0.5.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"
@@ -30,12 +30,15 @@
30
30
  "./cms": "./src/cms/index.js",
31
31
  "./cheerio": "./src/adapters/cheerio.js",
32
32
  "./dom": "./src/adapters/dom.js",
33
- "./data": "./src/data.js"
33
+ "./data": "./src/data.js",
34
+ "./upgrade": "./src/upgrade.js"
34
35
  },
35
36
  "scripts": {
36
37
  "build": "npx esbuild src/hyper-html-api.js --bundle --minify --format=iife --global-name=HyperHtmlApi --outfile=dist/hyper-html-api.min.js",
37
38
  "build:engine": "npx esbuild src/data.js --bundle --minify --format=iife --global-name=hyperHtmlApiData --outfile=dist/hyper-html-api.engine.min.js",
38
- "copy-to-hyperclayjs": "npm run build:engine && node scripts/copy-to-hyperclayjs.js",
39
+ "build:upgrade": "npx esbuild src/upgrade.js --bundle --minify --format=iife --global-name=hyperHtmlApiUpgrade --outfile=dist/hyper-html-api.upgrade.min.js",
40
+ "copy-to-hyperclayjs": "npm run build:engine && npm run build:upgrade && node scripts/copy-to-hyperclayjs.js",
41
+ "copy-to-clayjs": "npm run build:engine && node scripts/copy-to-clayjs.js",
39
42
  "prepublishOnly": "npm run build",
40
43
  "demo": "http-server . -p 5693 -c-1 -o /demo/",
41
44
  "test": "web-test-runner",
@@ -49,10 +49,3 @@ export class RuleTargetReadOnly extends Error {
49
49
  this.target = name
50
50
  }
51
51
  }
52
-
53
- export class UpgradeAlreadyRegistered extends Error {
54
- constructor() {
55
- super('upgrade transform already registered; only one registration is allowed per page.')
56
- this.name = 'UpgradeAlreadyRegistered'
57
- }
58
- }
@@ -1,7 +1,7 @@
1
1
  import { parseRelaxed } from './rules.js'
2
2
  import { UnknownRulesVersion } from './errors.js'
3
3
 
4
- const SUPPORTED_VERSION = '1'
4
+ export const SUPPORTED_VERSION = '1'
5
5
  const TOKEN_RE = /^[a-zA-Z0-9_-]+$/
6
6
 
7
7
  // findRulesIn(adapter, root) → first script[data-rules-name] (tooling/no-token)
@@ -11,19 +11,10 @@ const cms = {
11
11
  }
12
12
 
13
13
  const upgrade = {
14
- registerUpgrade: upgradeMod.registerUpgrade,
14
+ checkForUpdate: upgradeMod.checkForUpdate,
15
15
  run: upgradeMod.run,
16
+ extractAll: upgradeMod.extractAll,
16
17
  shapeMatch: upgradeMod.shapeMatch,
17
- isHelperMode: upgradeMod.isHelperMode,
18
- }
19
-
20
- // Helper-mode auto-boot: when the library loads inside an iframe whose URL
21
- // carries `?_hyperHtmlApi=upgrade-helper`, we wire up the postMessage handshake
22
- // immediately so authors don't have to add any boot code themselves. Their
23
- // `registerUpgrade(...)` calls (which run inline as v2's scripts execute) are
24
- // captured by the registry before the handshake message fires.
25
- if (typeof window !== 'undefined' && upgradeMod.isHelperMode(window.location)) {
26
- upgradeMod.bootHelper({ win: window, doc: document })
27
18
  }
28
19
 
29
20
  // Named exports ensure the IIFE namespace exposes engine/cms/upgrade and the
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Load-time update check. Reads the page's hyper-source / hyper-version meta
3
+ * tags, fetches the source anonymously, and compares versions. Results are
4
+ * cached in localStorage for 24 hours, keyed by source + current version so
5
+ * a fresh check happens immediately after an upgrade.
6
+ *
7
+ * Returns null whenever the subsystem should stay inert: missing meta tags,
8
+ * the page IS the canonical source, an unreachable/private source, or
9
+ * unparseable versions. Callers (the popover UI) never need to distinguish
10
+ * these cases.
11
+ */
12
+
13
+ const CHECK_TTL_MS = 24 * 60 * 60 * 1000
14
+ const CHECK_KEY_PREFIX = 'hha:upgrade-check:'
15
+
16
+ export function readMeta(doc, name) {
17
+ const el = doc.querySelector(`meta[name="${name}"]`)
18
+ const content = el ? el.getAttribute('content') : null
19
+ return content && content.trim() ? content.trim() : null
20
+ }
21
+
22
+ export function parseVersion(v) {
23
+ if (typeof v !== 'string') return null
24
+ const cleaned = v.trim().replace(/^v/, '')
25
+ if (!/^\d+(\.\d+)*$/.test(cleaned)) return null
26
+ return cleaned.split('.').map(Number)
27
+ }
28
+
29
+ export function isNewerVersion(candidate, current) {
30
+ const a = parseVersion(candidate)
31
+ const b = parseVersion(current)
32
+ if (!a || !b) return false
33
+ const len = Math.max(a.length, b.length)
34
+ for (let i = 0; i < len; i++) {
35
+ const x = a[i] || 0
36
+ const y = b[i] || 0
37
+ if (x !== y) return x > y
38
+ }
39
+ return false
40
+ }
41
+
42
+ function storageGet(key) {
43
+ try {
44
+ const raw = globalThis.localStorage.getItem(key)
45
+ return raw ? JSON.parse(raw) : null
46
+ } catch {
47
+ return null
48
+ }
49
+ }
50
+
51
+ function storageSet(key, value) {
52
+ try {
53
+ globalThis.localStorage.setItem(key, JSON.stringify(value))
54
+ } catch {
55
+ /* storage unavailable (private mode): every check is uncached */
56
+ }
57
+ }
58
+
59
+ export async function checkForUpdate({
60
+ force = false,
61
+ doc,
62
+ loc,
63
+ fetchFn,
64
+ now,
65
+ ttlMs = CHECK_TTL_MS,
66
+ } = {}) {
67
+ doc = doc || (typeof document !== 'undefined' ? document : null)
68
+ loc = loc || (typeof location !== 'undefined' ? location : null)
69
+ fetchFn = fetchFn || ((url) => fetch(url))
70
+ now = now ?? Date.now()
71
+ if (!doc) return null
72
+
73
+ const sourceUrl = readMeta(doc, 'hyper-source')
74
+ if (!sourceUrl) return null
75
+ const currentVersion = readMeta(doc, 'hyper-version')
76
+
77
+ let source
78
+ try {
79
+ source = new URL(sourceUrl, loc ? loc.href : undefined)
80
+ } catch {
81
+ return null
82
+ }
83
+ // Self-source guard: the canonical page carries a self-pointing
84
+ // hyper-source; it must never offer to upgrade from itself.
85
+ if (loc && source.origin === loc.origin && source.pathname === loc.pathname) {
86
+ return null
87
+ }
88
+
89
+ const cacheKey = `${CHECK_KEY_PREFIX}${source.href}:${currentVersion || 'none'}`
90
+ let sourceVersion
91
+ const cached = force ? null : storageGet(cacheKey)
92
+ if (cached && typeof cached.checkedAt === 'number' && now - cached.checkedAt < ttlMs) {
93
+ sourceVersion = cached.sourceVersion
94
+ } else {
95
+ try {
96
+ const res = await fetchFn(source.href)
97
+ if (!res.ok) throw new Error(`HTTP ${res.status}`)
98
+ const text = await res.text()
99
+ const sourceDoc = new DOMParser().parseFromString(text, 'text/html')
100
+ sourceVersion = readMeta(sourceDoc, 'hyper-version')
101
+ } catch {
102
+ sourceVersion = null
103
+ }
104
+ storageSet(cacheKey, { checkedAt: now, sourceVersion })
105
+ }
106
+
107
+ if (!sourceVersion) return null
108
+ return {
109
+ // A fork without a hyper-version predates versioning: any source version
110
+ // counts as newer.
111
+ available: isNewerVersion(sourceVersion, currentVersion || '0.0.0'),
112
+ currentVersion,
113
+ sourceVersion,
114
+ sourceUrl: source.href,
115
+ }
116
+ }
@@ -0,0 +1,36 @@
1
+ export class UpgradeSourceUnreachable extends Error {
2
+ constructor(url, cause) {
3
+ super(`could not fetch upgrade source: ${url}`)
4
+ this.name = 'UpgradeSourceUnreachable'
5
+ this.sourceUrl = url
6
+ this.cause = cause
7
+ }
8
+ }
9
+
10
+ export class UpgradeSourceHasNoRules extends Error {
11
+ constructor(url) {
12
+ super(
13
+ `upgrade source has no rules tags; refusing to drop all existing data: ${url}`,
14
+ )
15
+ this.name = 'UpgradeSourceHasNoRules'
16
+ this.sourceUrl = url
17
+ }
18
+ }
19
+
20
+ export class UpgradeTransformInvalid extends Error {
21
+ constructor(message, cause) {
22
+ super(message)
23
+ this.name = 'UpgradeTransformInvalid'
24
+ this.cause = cause
25
+ }
26
+ }
27
+
28
+ export class UpgradeMultipleTransforms extends Error {
29
+ constructor(count) {
30
+ super(
31
+ `found ${count} script[type="text/hyper-upgrade"] tags; only one is allowed per document.`,
32
+ )
33
+ this.name = 'UpgradeMultipleTransforms'
34
+ this.count = count
35
+ }
36
+ }
@@ -0,0 +1,26 @@
1
+ import { extract } from '../engine/extract.js'
2
+ import domAdapter from '../adapters/dom.js'
3
+ import { collectRulesTags } from './rules-tags.js'
4
+ import { readMeta } from './check.js'
5
+
6
+ /**
7
+ * Keyed extraction: one entry per rules tag under `root`, keyed by the
8
+ * normalized data-rules-name value. This is the v1 side of an upgrade:
9
+ * pack the page's data into labeled boxes.
10
+ */
11
+ export function extractAllFrom(adapter, root) {
12
+ const dataByName = {}
13
+ for (const { name, rules } of collectRulesTags(adapter, root)) {
14
+ dataByName[name] = extract(adapter, root, rules)
15
+ }
16
+ return dataByName
17
+ }
18
+
19
+ export function extractAll(root) {
20
+ const r = root || document
21
+ const doc = r.nodeType === 9 ? r : r.ownerDocument || r
22
+ return {
23
+ dataByName: extractAllFrom(domAdapter, r),
24
+ version: readMeta(doc, 'hyper-version'),
25
+ }
26
+ }
@@ -1,4 +1,13 @@
1
- export { registerUpgrade, getRegisteredTransform, _resetRegistryForTests } from './registry.js'
2
- export { shapeMatch } from './shape-match.js'
3
- export { run } from './runner.js'
4
- export { isHelperMode, getParentOrigin, bootHelper } from './helper.js'
1
+ export { checkForUpdate, readMeta, parseVersion, isNewerVersion } from './check.js'
2
+ export { extractAll, extractAllFrom } from './extract-all.js'
3
+ export { findTransformTag, evaluateTransform, TRANSFORM_TYPE } from './transform.js'
4
+ export { migrateInto } from './migrate.js'
5
+ export { run } from './run.js'
6
+ export { shapeMatch, countScalarLeaves } from './shape-match.js'
7
+ export { collectRulesTags, normalizeName } from './rules-tags.js'
8
+ export {
9
+ UpgradeSourceUnreachable,
10
+ UpgradeSourceHasNoRules,
11
+ UpgradeTransformInvalid,
12
+ UpgradeMultipleTransforms,
13
+ } from './errors.js'
@@ -0,0 +1,36 @@
1
+ import { apply } from '../engine/apply.js'
2
+ import { collectRulesTags } from './rules-tags.js'
3
+ import { shapeMatch, countScalarLeaves } from './shape-match.js'
4
+
5
+ /**
6
+ * Pour keyed v1 data into the v2 document. Exact-name join: each v2 rules
7
+ * tag pulls the entry with the same normalized name; tags with no matching
8
+ * entry keep their template defaults; v1 entries with no matching tag are
9
+ * counted as discarded. Renames are the transform's job, not the join's.
10
+ */
11
+ export function migrateInto(adapter, root, dataByName) {
12
+ const tags = collectRulesTags(adapter, root)
13
+ const totals = { carriedOver: 0, discarded: 0, listItems: 0 }
14
+ const byName = {}
15
+ const v2Names = new Set()
16
+
17
+ for (const { name, rules } of tags) {
18
+ v2Names.add(name)
19
+ if (!Object.prototype.hasOwnProperty.call(dataByName, name)) {
20
+ byName[name] = { carriedOver: 0, discarded: 0, listItems: 0 }
21
+ continue
22
+ }
23
+ const { data, summary } = shapeMatch(dataByName[name], rules)
24
+ apply(adapter, root, rules, data)
25
+ byName[name] = summary
26
+ totals.carriedOver += summary.carriedOver
27
+ totals.discarded += summary.discarded
28
+ totals.listItems += summary.listItems
29
+ }
30
+
31
+ for (const key of Object.keys(dataByName)) {
32
+ if (!v2Names.has(key)) totals.discarded += countScalarLeaves(dataByName[key])
33
+ }
34
+
35
+ return { totals, byName, rulesTagCount: tags.length }
36
+ }
@@ -0,0 +1,37 @@
1
+ import { parseRelaxed } from '../engine/rules.js'
2
+ import { SUPPORTED_VERSION } from '../engine/rules-tag.js'
3
+ import { UnknownRulesVersion } from '../engine/errors.js'
4
+
5
+ const RULES_SELECTOR = 'script[data-rules-name]'
6
+
7
+ export function normalizeName(raw) {
8
+ return typeof raw === 'string' ? raw.trim().replace(/\s+/g, ' ') : ''
9
+ }
10
+
11
+ /**
12
+ * Collect every rules tag under `root` as [{ name, rules }], keyed by the
13
+ * whitespace-normalized data-rules-name attribute value. Duplicate names:
14
+ * first tag wins with a warning (mirrors findRulesIn). Unsupported
15
+ * data-rules-version throws so engine-format skew fails loudly instead of
16
+ * corrupting a migration.
17
+ */
18
+ export function collectRulesTags(adapter, root) {
19
+ const tags = adapter.find(root, RULES_SELECTOR, { includeRulesTag: true })
20
+ const seen = new Set()
21
+ const out = []
22
+ for (const tag of tags) {
23
+ const name = normalizeName(adapter.attr(tag, 'data-rules-name'))
24
+ if (!name) continue
25
+ if (seen.has(name)) {
26
+ console.warn(
27
+ `hyper-html-api: duplicate rules tag name "${name}"; using the first.`,
28
+ )
29
+ continue
30
+ }
31
+ const version = adapter.attr(tag, 'data-rules-version')
32
+ if (version !== SUPPORTED_VERSION) throw new UnknownRulesVersion(version)
33
+ seen.add(name)
34
+ out.push({ name, rules: parseRelaxed(adapter.text(tag)) })
35
+ }
36
+ return out
37
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Parent-side upgrade runner (the whole flow, no iframe):
3
+ *
4
+ * 1. Pack: extract keyed data from the live page.
5
+ * 2. Download: fetch the source's pristine HTML, parse with DOMParser
6
+ * (scripts never execute, so no runtime DOM noise can leak into what
7
+ * gets saved).
8
+ * 3. Recipe: find the source's text/hyper-upgrade tag, evaluate it, and
9
+ * reshape the data ({ [name]: data } in, same shape out).
10
+ * 4. Unpack: exact-name join + apply into the parsed copy.
11
+ * 5. Serialize and return. The caller decides how to save — hyperclayjs
12
+ * uses saveHtml(); standalone users do their own thing.
13
+ */
14
+
15
+ import domAdapter from '../adapters/dom.js'
16
+ import { readMeta } from './check.js'
17
+ import { extractAllFrom } from './extract-all.js'
18
+ import { findTransformTag, evaluateTransform } from './transform.js'
19
+ import { migrateInto } from './migrate.js'
20
+ import { UpgradeSourceUnreachable, UpgradeSourceHasNoRules, UpgradeTransformInvalid } from './errors.js'
21
+
22
+ export async function run({ sourceUrl, dataByName, fromVersion, doc, loc, fetchFn } = {}) {
23
+ doc = doc || (typeof document !== 'undefined' ? document : null)
24
+ loc = loc || (typeof location !== 'undefined' ? location : null)
25
+ fetchFn = fetchFn || ((url) => fetch(url))
26
+ if (!doc) throw new Error('upgrade.run requires a document context')
27
+
28
+ sourceUrl = sourceUrl || readMeta(doc, 'hyper-source')
29
+ if (!sourceUrl) {
30
+ throw new Error('upgrade.run: no sourceUrl given and no hyper-source meta tag found')
31
+ }
32
+ const source = new URL(sourceUrl, loc ? loc.href : undefined)
33
+ fromVersion = fromVersion !== undefined ? fromVersion : readMeta(doc, 'hyper-version')
34
+ dataByName = dataByName || extractAllFrom(domAdapter, doc)
35
+
36
+ let res
37
+ try {
38
+ res = await fetchFn(source.href)
39
+ } catch (err) {
40
+ throw new UpgradeSourceUnreachable(source.href, err)
41
+ }
42
+ if (!res.ok) {
43
+ throw new UpgradeSourceUnreachable(source.href, new Error(`HTTP ${res.status}`))
44
+ }
45
+ const text = await res.text()
46
+ const sourceDoc = new DOMParser().parseFromString(text, 'text/html')
47
+ const toVersion = readMeta(sourceDoc, 'hyper-version')
48
+
49
+ let map = dataByName
50
+ let transformApplied = false
51
+ const code = findTransformTag(domAdapter, sourceDoc)
52
+ if (code) {
53
+ const transform = await evaluateTransform(code)
54
+ const out = await transform(map, { fromVersion, toVersion })
55
+ if (!out || typeof out !== 'object' || Array.isArray(out)) {
56
+ throw new UpgradeTransformInvalid('transform must return a plain object map of { rulesName: data }')
57
+ }
58
+ map = out
59
+ transformApplied = true
60
+ }
61
+
62
+ const { totals, byName, rulesTagCount } = migrateInto(domAdapter, sourceDoc, map)
63
+ if (rulesTagCount === 0 && Object.keys(map).length > 0) {
64
+ throw new UpgradeSourceHasNoRules(source.href)
65
+ }
66
+
67
+ return {
68
+ html: serializeDocument(sourceDoc),
69
+ fromVersion,
70
+ toVersion,
71
+ summary: { transformApplied, totals, byName },
72
+ }
73
+ }
74
+
75
+ function serializeDocument(doc) {
76
+ const name = doc.doctype && doc.doctype.name ? doc.doctype.name : 'html'
77
+ return `<!DOCTYPE ${name}>\n` + doc.documentElement.outerHTML
78
+ }
@@ -28,6 +28,9 @@ function walk(rule, v1, summary) {
28
28
  return v1
29
29
  }
30
30
  if (v1 === undefined || v1 === null) return undefined
31
+ // A scalar slot can't hold an object/array from v1; leave the template
32
+ // default (collectDiscards counts the dropped leaves).
33
+ if (typeof v1 === 'object') return undefined
31
34
  summary.carriedOver++
32
35
  return v1
33
36
  }
@@ -77,7 +80,7 @@ function collectDiscards(rule, v1, summary) {
77
80
  }
78
81
  }
79
82
 
80
- function countScalarLeaves(v) {
83
+ export function countScalarLeaves(v) {
81
84
  if (v === null || v === undefined) return 0
82
85
  if (Array.isArray(v)) return v.reduce((n, x) => n + countScalarLeaves(x), 0)
83
86
  if (typeof v === 'object') {
@@ -0,0 +1,51 @@
1
+ import { UpgradeMultipleTransforms, UpgradeTransformInvalid } from './errors.js'
2
+
3
+ export const TRANSFORM_TYPE = 'text/hyper-upgrade'
4
+
5
+ /**
6
+ * The migration recipe is a non-executing script tag in the source HTML:
7
+ *
8
+ * <script type="text/hyper-upgrade">
9
+ * export default (dataByName, { fromVersion, toVersion }) => dataByName
10
+ * </script>
11
+ *
12
+ * Browsers ignore unknown script types, so it never runs on the source page
13
+ * itself; the upgrading fork reads it out of the fetched pristine copy and
14
+ * evaluates it on demand. Returns the tag's code, or null when absent.
15
+ */
16
+ export function findTransformTag(adapter, root) {
17
+ const tags = adapter.find(root, `script[type="${TRANSFORM_TYPE}"]`)
18
+ if (tags.length === 0) return null
19
+ if (tags.length > 1) throw new UpgradeMultipleTransforms(tags.length)
20
+ const code = adapter.text(tags[0])
21
+ return code || null
22
+ }
23
+
24
+ // Bundlers rewrite a bare dynamic import() when emitting non-ESM formats; the
25
+ // Function indirection keeps it a native browser import() at runtime.
26
+ const dynamicImport = new Function('url', 'return import(url)')
27
+
28
+ /**
29
+ * Evaluate transform code as a real ES module (Blob URL import). The module
30
+ * must `export default` a function; it may be async. Relative imports won't
31
+ * resolve from a Blob URL; absolute (CDN) imports work.
32
+ */
33
+ export async function evaluateTransform(code) {
34
+ const blob = new Blob([code], { type: 'text/javascript' })
35
+ const url = URL.createObjectURL(blob)
36
+ let mod
37
+ try {
38
+ mod = await dynamicImport(url)
39
+ } catch (err) {
40
+ throw new UpgradeTransformInvalid(
41
+ `transform failed to load: ${err && err.message ? err.message : err}`,
42
+ err,
43
+ )
44
+ } finally {
45
+ URL.revokeObjectURL(url)
46
+ }
47
+ if (typeof mod.default !== 'function') {
48
+ throw new UpgradeTransformInvalid('transform must `export default` a function')
49
+ }
50
+ return mod.default
51
+ }
package/src/upgrade.js ADDED
@@ -0,0 +1,14 @@
1
+ // Lean upgrade entry: the DOM-bound engine + the template-upgrade flow,
2
+ // WITHOUT cms. This is what `hyper-html-api/upgrade` exports and what
3
+ // hyperclayjs vendors for its `upgrade` module.
4
+ import { engine } from './dom-api.js'
5
+ import { checkForUpdate } from './upgrade/check.js'
6
+ import { run } from './upgrade/run.js'
7
+ import { extractAll } from './upgrade/extract-all.js'
8
+ import { shapeMatch } from './upgrade/shape-match.js'
9
+
10
+ export const upgrade = { checkForUpdate, run, extractAll, shapeMatch }
11
+ export { engine }
12
+
13
+ const HyperHtmlApiUpgrade = { engine, upgrade }
14
+ export default HyperHtmlApiUpgrade
@@ -1,143 +0,0 @@
1
- /**
2
- * Helper-mode boot path. When the library loads in an iframe whose URL
3
- * includes `?_hyperHtmlApi=upgrade-helper&parentOrigin=...`, it skips its
4
- * normal idle state and instead participates in the postMessage protocol
5
- * defined in upgrade-plan.md:
6
- *
7
- * 1. Once the iframe document is ready, post `hha:upgrade-ready` to
8
- * `parentOrigin` with the v2 rules + version + whether a transform
9
- * was registered.
10
- * 2. Wait for the parent's `hha:upgrade-data` message carrying v1Data.
11
- * 3. Run the registered transform (if any), shape-match against v2's
12
- * rules, then `engine.apply` to the iframe DOM.
13
- * 4. Serialize `documentElement.outerHTML` and post `hha:upgrade-result`
14
- * back to the parent.
15
- *
16
- * Errors at any step bubble out as `hha:upgrade-error`.
17
- */
18
-
19
- import { findRulesIn } from '../engine/rules-tag.js'
20
- import { extract } from '../engine/extract.js'
21
- import { apply } from '../engine/apply.js'
22
- import domAdapter from '../adapters/dom.js'
23
- import { getRegisteredTransform } from './registry.js'
24
- import { shapeMatch } from './shape-match.js'
25
-
26
- const HELPER_QUERY = '_hyperHtmlApi'
27
- const HELPER_VALUE = 'upgrade-helper'
28
- const PARENT_ORIGIN_QUERY = 'parentOrigin'
29
-
30
- export function isHelperMode(loc = typeof location !== 'undefined' ? location : null) {
31
- if (!loc) return false
32
- try {
33
- const params = new URLSearchParams(loc.search)
34
- return params.get(HELPER_QUERY) === HELPER_VALUE
35
- } catch {
36
- return false
37
- }
38
- }
39
-
40
- export function getParentOrigin(loc = typeof location !== 'undefined' ? location : null) {
41
- if (!loc) return null
42
- const params = new URLSearchParams(loc.search)
43
- return params.get(PARENT_ORIGIN_QUERY)
44
- }
45
-
46
- export function bootHelper({ win, doc, parentOrigin } = {}) {
47
- win = win || (typeof window !== 'undefined' ? window : null)
48
- doc = doc || (typeof document !== 'undefined' ? document : null)
49
- if (!win || !doc) return
50
- parentOrigin = parentOrigin || getParentOrigin(win.location)
51
- if (!parentOrigin) return
52
-
53
- const start = () => runHandshake({ win, doc, parentOrigin })
54
-
55
- if (doc.readyState === 'loading') {
56
- doc.addEventListener('DOMContentLoaded', start, { once: true })
57
- } else {
58
- start()
59
- }
60
- }
61
-
62
- function runHandshake({ win, doc, parentOrigin }) {
63
- let found
64
- try {
65
- found = findRulesIn(domAdapter, doc.body)
66
- } catch (e) {
67
- return postError(win, parentOrigin, e)
68
- }
69
- if (!found) {
70
- return postError(
71
- win,
72
- parentOrigin,
73
- new Error('helper-mode: no rules tag in v2 document'),
74
- )
75
- }
76
- const rules = found.rules
77
- const version = readMeta(doc, 'hyper-version')
78
- const hasTransform = !!getRegisteredTransform()
79
-
80
- const onMessage = (e) => {
81
- if (e.source !== win.parent) return
82
- if (e.origin !== parentOrigin) return
83
- const msg = e.data
84
- if (!msg || msg.type !== 'hha:upgrade-data') return
85
- win.removeEventListener('message', onMessage)
86
- try {
87
- const result = runUpgrade({ doc, rules, v1Data: msg.v1Data })
88
- win.parent.postMessage(
89
- { type: 'hha:upgrade-result', html: result.html, summary: result.summary },
90
- parentOrigin,
91
- )
92
- } catch (err) {
93
- postError(win, parentOrigin, err)
94
- }
95
- }
96
- win.addEventListener('message', onMessage)
97
-
98
- win.parent.postMessage(
99
- { type: 'hha:upgrade-ready', rules, version, hasTransform },
100
- parentOrigin,
101
- )
102
- }
103
-
104
- function runUpgrade({ doc, rules, v1Data }) {
105
- const transform = getRegisteredTransform()
106
- let transformed = v1Data
107
- let didTransform = false
108
- if (transform) {
109
- transformed = transform(v1Data)
110
- didTransform = true
111
- }
112
- const { data, summary } = shapeMatch(transformed, rules)
113
- apply(domAdapter, doc.body, rules, data)
114
- // Re-extract to confirm the apply landed; surface as part of summary.
115
- const applied = extract(domAdapter, doc.body, rules)
116
- const html =
117
- '<!DOCTYPE html>\n' + doc.documentElement.outerHTML
118
- return {
119
- html,
120
- summary: { ...summary, transformApplied: didTransform, appliedFieldCount: countLeaves(applied) },
121
- }
122
- }
123
-
124
- function postError(win, parentOrigin, err) {
125
- win.parent.postMessage(
126
- { type: 'hha:upgrade-error', name: err?.name || 'Error', message: err?.message || String(err) },
127
- parentOrigin,
128
- )
129
- }
130
-
131
- function readMeta(doc, name) {
132
- const el = doc.querySelector(`meta[name="${name}"]`)
133
- return el ? el.getAttribute('content') : null
134
- }
135
-
136
- function countLeaves(v) {
137
- if (v == null) return 0
138
- if (Array.isArray(v)) return v.reduce((n, x) => n + countLeaves(x), 0)
139
- if (typeof v === 'object') {
140
- return Object.values(v).reduce((n, x) => n + countLeaves(x), 0)
141
- }
142
- return 1
143
- }
@@ -1,19 +0,0 @@
1
- import { UpgradeAlreadyRegistered } from '../engine/errors.js'
2
-
3
- let registered = null
4
-
5
- export function registerUpgrade(fn) {
6
- if (typeof fn !== 'function') {
7
- throw new TypeError('registerUpgrade expects a function (v1Data) => v2Data')
8
- }
9
- if (registered) throw new UpgradeAlreadyRegistered()
10
- registered = fn
11
- }
12
-
13
- export function getRegisteredTransform() {
14
- return registered
15
- }
16
-
17
- export function _resetRegistryForTests() {
18
- registered = null
19
- }
@@ -1,92 +0,0 @@
1
- /**
2
- * Iframe-based upgrade runner.
3
- *
4
- * Loads the v2 source URL in a hidden iframe with the `_hyperHtmlApi=upgrade-helper`
5
- * query param. The helper inside the iframe handles transform + apply +
6
- * serialize; the parent only orchestrates the postMessage handshake and
7
- * returns the resulting HTML + summary to the caller.
8
- *
9
- * const { html, summary } = await run({ sourceUrl, v1Data })
10
- *
11
- * The caller decides what to do with `html` (e.g. POST to `/save`, render
12
- * in a preview pane, etc.). The runner deliberately doesn't touch the
13
- * network beyond the iframe load.
14
- */
15
-
16
- const DEFAULT_TIMEOUT_MS = 15000
17
-
18
- export async function run({
19
- sourceUrl,
20
- v1Data,
21
- v1Version = null,
22
- parent = typeof window !== 'undefined' ? window : null,
23
- timeoutMs = DEFAULT_TIMEOUT_MS,
24
- hidden = true,
25
- } = {}) {
26
- if (!parent) throw new Error('upgrade.run requires a window context')
27
- if (!sourceUrl) throw new Error('upgrade.run requires sourceUrl')
28
-
29
- const helperUrl = buildHelperUrl(sourceUrl, parent.location.origin)
30
- const expectedOrigin = new URL(helperUrl, parent.location.href).origin
31
-
32
- const iframe = parent.document.createElement('iframe')
33
- if (hidden) {
34
- iframe.style.cssText =
35
- 'position:absolute;left:-9999px;top:-9999px;width:1px;height:1px;border:0;'
36
- }
37
- iframe.setAttribute('aria-hidden', 'true')
38
- iframe.src = helperUrl
39
- parent.document.body.appendChild(iframe)
40
-
41
- let cleanup = () => {}
42
- try {
43
- return await new Promise((resolve, reject) => {
44
- const timer = setTimeout(() => {
45
- reject(new Error(`upgrade.run: helper iframe timed out after ${timeoutMs}ms`))
46
- }, timeoutMs)
47
-
48
- const onMessage = (e) => {
49
- if (e.source !== iframe.contentWindow) return
50
- if (e.origin !== expectedOrigin) return
51
- const msg = e.data
52
- if (!msg || typeof msg !== 'object') return
53
-
54
- if (msg.type === 'hha:upgrade-ready') {
55
- iframe.contentWindow.postMessage(
56
- { type: 'hha:upgrade-data', v1Data, v1Version },
57
- expectedOrigin,
58
- )
59
- return
60
- }
61
- if (msg.type === 'hha:upgrade-result') {
62
- clearTimeout(timer)
63
- resolve({ html: msg.html, summary: msg.summary })
64
- return
65
- }
66
- if (msg.type === 'hha:upgrade-error') {
67
- clearTimeout(timer)
68
- const err = new Error(msg.message || 'helper error')
69
- err.name = msg.name || 'UpgradeHelperError'
70
- reject(err)
71
- return
72
- }
73
- }
74
-
75
- parent.addEventListener('message', onMessage)
76
- cleanup = () => {
77
- parent.removeEventListener('message', onMessage)
78
- clearTimeout(timer)
79
- if (iframe.parentNode) iframe.parentNode.removeChild(iframe)
80
- }
81
- })
82
- } finally {
83
- cleanup()
84
- }
85
- }
86
-
87
- function buildHelperUrl(sourceUrl, parentOrigin) {
88
- const url = new URL(sourceUrl, typeof location !== 'undefined' ? location.href : undefined)
89
- url.searchParams.set('_hyperHtmlApi', 'upgrade-helper')
90
- url.searchParams.set('parentOrigin', parentOrigin)
91
- return url.toString()
92
- }