@wcstack/state 3.5.0 → 3.5.2
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.ja.md +3 -3
- package/README.md +3 -3
- package/dist/auto.min.js +1 -1
- package/dist/auto.min.js.map +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/split/chunks/binder.js +1 -1
- package/dist/split/chunks/binder.js.map +1 -1
- package/dist/split/chunks/checkDependency.js +1 -1
- package/dist/split/chunks/featureBridge.js +1 -1
- package/dist/split/chunks/getAllPropertyDescriptors.js +1 -1
- package/dist/split/chunks/lifecycleHooks.js +1 -1
- package/dist/split/chunks/registerComponents.js +1 -1
- package/dist/split/chunks/setAll.js +1 -1
- package/dist/split/chunks/version.js +1 -1
- package/dist/split/features/devtools.js +1 -1
- package/dist/split/features/recursion.js +1 -1
- package/dist/split/features/scopes.js +1 -1
- package/dist/split/features/scopes.js.map +1 -1
- package/dist/split/features/ssr.js +1 -1
- package/dist/split/features/ssr.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{c as t,a as e,S as n}from"../chunks/filterRegistry.js";import{P as s,Q as o,R as r,S as a,U as i,V as c,W as l,X as d,Y as u,y as f,Z as p,_ as m,F as h,$ as g,a0 as y,a1 as b,a2 as N,M as S,x as w,a3 as x,a4 as A,K as v,a5 as T,a6 as k,a7 as C,D,a8 as O,a9 as _,aa as j,ab as $,ac as P,ad as E,ae as M,af as B,ag as q,ah as R,ai as F,aj as I,ak as H,j as z,al as W,v as J,am as V,an as L,ao as G,ap as K,aq as Q,ar as U,as as X,at as Y,g as Z}from"../chunks/binder.js";import{H as tt,a as et}from"../chunks/registerComponents.js";import{V as nt}from"../chunks/version.js";import{W as st,g as ot}from"../chunks/pathDiagnostics.js";import"../chunks/errorGuidance.js";import"../chunks/lifecycleHooks.js";import"../chunks/declarationAliases.js";import"../chunks/setAll.js";import"../chunks/checkDependency.js";import"../chunks/getAllPropertyDescriptors.js";import"../chunks/declarationHooks.js";import"../chunks/diagnosticsHooks.js";const rt=/^@@wcs-(?:for|if|elseif|else):[^-]/,at=/^@@wcs-(for|if|elseif|else)-start:(.+)$/,it=/^@@wcs-(for|if|elseif|else)-end:(.+)$/,ct=/^@@wcs-text-start:(.+)$/;function lt(t){return t.replace(/</g,"\\u003c").replace(/>/g,"\\u003e").replace(/&/g,"\\u0026").replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")}function dt(t,e){const n=document.createTreeWalker(t,NodeFilter.SHOW_COMMENT),s=[];for(;n.nextNode();){const t=n.currentNode;e(t.data)&&s.push(t)}return s}const ut=t=>rt.test(t),ft=t=>at.test(t),pt=t=>at.test(t)||it.test(t);function mt(t){if("else"===t.bindingType)return"else:";let e=`${t.bindingType}: ${t.statePathName}`;for(const n of t.outFilters){const t=n.literals??n.args;e+=`|${n.filterName}`,n.args.length>0&&(e+=`(${n.args.map((e,n)=>"string"==typeof t[n]?`'${e.split("'").join("'\"'\"'")}'`:e).join(",")})`)}return e}function ht(t){const e=t.fragment.cloneNode(!0);for(const n of t.nodeInfos){const s=i(c(t.fragment,n.nodePath));if(null===s)continue;const o=c(e,n.nodePath);o.parentNode.replaceChild(document.createComment(s),o)}return e}class gt extends tt{_stateData=null;_templates=null;_hydrateProps=null;get version(){return this.getAttribute("version")||""}get stateData(){return null===this._stateData&&(this._stateData=this._loadStateData()),this._stateData}get templates(){return null===this._templates&&(this._templates=this._loadTemplates()),this._templates}get hydrateProps(){return null===this._hydrateProps&&(this._hydrateProps=this._loadHydrateProps()),this._hydrateProps}getTemplate(t){return this.templates.get(t)??null}verifyVersion(){const t=this.version;if(!t)return!0;const e=t.split("."),n=nt.split(".");return e[0]===n[0]&&e[1]===n[1]}setStateData(t){this._stateData=t}setHydrateProps(t){this._hydrateProps=t}_loadStateData(){const t=this.querySelector('script[type="application/json"]:not([data-wcs-ssr-props])');if(!t)return{};try{return JSON.parse(t.textContent||"{}")}catch{return{}}}_loadTemplates(){const t=new Map,e=this.querySelectorAll("template[id]");for(const n of e){const e=n.getAttribute("id");e&&t.set(e,n)}return t}_loadHydrateProps(){const t=this.querySelector("script[data-wcs-ssr-props]");if(!t)return{};try{return JSON.parse(t.textContent||"{}")}catch{return{}}}static find(e){const n=t.tagNames.ssr,s=e instanceof Element?e:e instanceof Document?e.documentElement:null;if(!s)return null;return s.querySelector(n)}static extractStateData(t){const e=t.__state;if(!e||"object"!=typeof e)return{};const n={};for(const t of Object.keys(e)){if(t.startsWith("$"))continue;const s=Object.getOwnPropertyDescriptor(e,t);if(void 0!==s&&"function"==typeof s.get)continue;const o=e[t];"function"!=typeof o&&(n[t]=o)}return n}static buildContent(n,i,c){const l=c??n.ownerDocument;e.seen&&function(t){const e=new Map;for(const n of dt(t,ft)){if(null===n.parentNode)continue;const[,t,s]=at.exec(n.data),o=s.split(":")[0],r=n.previousSibling?.data,a=`@@wcs-${t}-end:${s}`;if(r!==`@@wcs-${t}:${o}`&&e.get(r)!==o)for(let t=n;null!==t;){const e=t.nextSibling;t.remove(),t=t.data===a?null:e}else"for"===t&&e.set(a,o)}}(l);const d=document.createElement("script");d.setAttribute("type","application/json"),d.textContent=lt(JSON.stringify(i)),n.appendChild(d);for(const[e,s]of function(t){const e=new Map,n=[t];for(;n.length>0;)for(const t of dt(n.shift(),ut)){const s=t.data,o=s.slice(s.indexOf(":")+1);if(e.has(o))continue;const r=a(o);null!==r&&(e.set(o,r),n.push(r.fragment))}return e}(l)){const o=document.createElement("template");o.setAttribute("id",e),o.setAttribute(t.bindAttributeName,mt(s.parseBindTextResult)),o.content.appendChild(ht(s)),n.appendChild(o)}const u=n.ownerDocument,f=s();if(f.length>0){const t={};for(let e=0;e<f.length;e++){const n=f[e];if(!n.isConnected||n.ownerDocument!==u)continue;const s=o(n);if(0===s.length)continue;const r=`wcs-ssr-${e}`;n.setAttribute("data-wcs-ssr-id",r);const a={};for(const t of s)a[t.propName]=t.value;t[r]=a}if(Object.keys(t).length>0){const e=document.createElement("script");e.setAttribute("type","application/json"),e.setAttribute("data-wcs-ssr-props",""),e.textContent=lt(JSON.stringify(t)),n.appendChild(e)}}r()}static removeBlockBoundaryComments(t){for(const e of dt(t,pt))e.remove()}static removeStructuralComments(t){for(const e of dt(t,ut))e.remove()}static restoreTextBindings(t){for(const e of dt(t,t=>ct.test(t))){const t=ct.exec(e.data)[1],n=document.createComment(`@@: ${t}`);e.parentNode.insertBefore(n,e);let s=e.nextSibling;e.remove();const o=`@@wcs-text-end:${t}`;for(;s;){const t=s.nextSibling;if(s.nodeType===Node.COMMENT_NODE&&s.data===o){s.parentNode.removeChild(s);break}s.parentNode.removeChild(s),s=t}}}static cleanupDom(e){const n=document.body,s=e.querySelectorAll(t.tagNames.ssr),o=new Map;for(const t of s){const e=t.querySelectorAll("template[id]");for(const t of e){const e=t.getAttribute("id");e&&o.set(e,t)}}for(const t of dt(n,ft)){const e=at.exec(t.data),n=`@@wcs-${e[1]}-end:${e[2]}`;let s=t.nextSibling;for(;s;){const t=s.nextSibling;if(s.nodeType===Node.COMMENT_NODE&&s.data===n){s.remove();break}s.remove(),s=t}t.remove()}gt.restoreTextBindings(n);const r=e=>{for(const n of dt(e,ut)){const e=o.get(n.data.split(":")[1]);if(e){const s=document.createElement("template"),o=e.getAttribute(t.bindAttributeName);o&&s.setAttribute(t.bindAttributeName,o);const a=document.importNode(e.content,!0);if(a.childNodes.length>0)s.content.appendChild(a);else for(const t of Array.from(e.childNodes))s.content.appendChild(document.importNode(t,!0));r(s.content),n.parentNode.replaceChild(s,n)}}};r(n);const a=e.querySelectorAll("[data-wcs-ssr-id]");for(const t of a)t.removeAttribute("data-wcs-ssr-id");for(const t of s)t.remove()}}const yt={protocol:"wcs-ssr-snapshot",version:1,build:function(e){const n=t.tagNames.state,s=t.tagNames.ssr,o=e.querySelectorAll(`${n}[enable-ssr]:not([mount]):not([bind-component])`);for(const t of o){const e=t.previousElementSibling;if(null!==e&&e.tagName.toLowerCase()===s)continue;const n=document.createElement(s);n.setAttribute("version",nt),gt.buildContent(n,gt.extractStateData(t),t.getRootNode()),t.parentNode?.insertBefore(n,t)}r()},reset:function(){l(),r(),e.seen=!1}};const bt=new Set(["for","if","elseif","else"]);function Nt(t){const[,e,n]=at.exec(t),[s,...o]=n.split(":");return"for"===e?{type:e,uuid:s,path:o[0],index:parseInt(o[1],10),nodes:[]}:{type:e,uuid:s,path:o.join(":"),index:null,nodes:[]}}function St(e){const n=[];for(const s of e)if(s.nodeType===Node.ELEMENT_NODE){const e=s;e.hasAttribute(t.bindAttributeName)&&n.push(e),Array.from(e.children).some(e=>e.localName===t.tagNames.state&&V(e))||n.push(...L(e))}else null!==G(s)&&n.push(s);return n}function wt(t){const[e,n,s]=K(t),o=new Q;return{bindingInfos:o.initialize(n,{registerAddress:!1,applyOnReconnect:!1}),subscriberNodes:e,bindingSession:o,deferredSpreads:s}}const xt=/^\s*@@\s*(?:wcs-text)?\s*:/;function At(t,e){for(const n of e)"event"===n.bindingType||bt.has(n.bindingType)||(n.node.nodeType!==Node.COMMENT_NODE||"text"===n.bindingType&&xt.test(n.node.data))&&t.push(n)}function vt(t,e){const n=[];for(let s=0;s<t.nodes.length;s++){const o=e.get(t.nodes[s]);o?s+=o.nodes.length+1:n.push(t.nodes[s])}return n}function Tt(t,e,n,s,o,r){e.length>0&&(t.spreads=e);for(const t of e)X(t.node);p(e,n,s,o,r)}function kt(t,e){const n=a(e),s=h(t.getRootNode());let o=null;if(n&&s){const{statePathName:t,outFilters:e}=n.parseBindTextResult;s.createState("readonly",n=>{const s=g(n[t],U(e,"output"));Array.isArray(s)&&(o=s)})}return o}function Ct(e,n){return`@@${{for:t.commentForPrefix,if:t.commentIfPrefix,elseif:t.commentElseIfPrefix,else:t.commentElsePrefix}[e]}:${n}`}function Dt(t,e,n){const s=Ct(e,n);return dt(t,t=>t===s)[0]??null}function Ot(e,n){const s=e,o=n.templates,r=new Map;for(const[t,e]of o)for(const n of dt(e.content,ut))r.set(n.data.slice(n.data.indexOf(":")+1),t);const a=new Set(A(e));if(a.size>0)for(const t of dt(s,ut)){const e=t.data.slice(t.data.indexOf(":")+1);let n=t.parentNode;for(;null!==n&&!a.has(n);)n=n.parentNode;null===n||r.has(e)||r.set(e,n)}const i=new Map,c=[];for(const[e,n]of o){const s=n.getAttribute(t.bindAttributeName)||"";let o=v(s)[0];const a=o.bindingType,l=r.get(e),d=i.get(l);"else"===a&&d&&(o={...d,outFilters:[...d.outFilters,T()],bindingType:"else"}),"if"===a||"elseif"===a?i.set(l,o):"else"===a&&i.set(l,null),c.push([e,n,o])}for(const[t,e,n]of c.reverse()){const o=document.importNode(e.content,!0),r="for"===n.bindingType?n.statePathName:void 0;k(o),"string"==typeof r&&C(o,r),D(s,o,r);const a={fragment:o,parseBindTextResult:n,nodeInfos:O(o)};_(t,s,a)}}const _t={hydrate:async function(e){await d(e);const n=e.querySelectorAll(t.tagNames.ssr);for(const t of n){const n=t;if(!n.verifyVersion())return console.warn(`[@wcstack/state] SSR version mismatch: server="${n.version}", client="${nt}". Falling back to full render.`),gt.cleanupDom(e),!1}const s=function(t){const e=[];for(const n of dt(t,pt)){if(!ft(n.data)){e.pop();continue}const t=Nt(n.data),s=e.at(-1);if("for"===t.type&&s&&s.uuid!==t.uuid)return[t,s];e.push(t)}return null}(document.body);if(null!==s){const[t,n]=s;return console.warn(`[@wcstack/state] SSR: "for: ${t.path}" in "${n.type}: ${n.path}" (known limitation). Falling back to full render.`),gt.cleanupDom(e),!1}for(const t of n)Ot(e,t);gt.restoreTextBindings(document.body);const o=function(t){const e=[];for(const n of dt(t,ft)){const t=Nt(n.data);t.start=n;const s=n.data.replace("-start:","-end:");let o=n.nextSibling;for(;o&&(o.nodeType!==Node.COMMENT_NODE||o.data!==s);)t.nodes.push(o),o=o.nextSibling;e.push(t)}return e}(document.body),r=new Map,a=function(t,e,n=new Map){const s=new Map,o=[],r=new Map(e.map(t=>[t.start,t])),a=new Set;for(let t=e.length-1;t>=0;t--){const n=St(e[t].nodes).filter(t=>!a.has(t));for(const t of n)a.add(t);e[t].subscribers=n}for(const a of e){const e=vt(a,r);if(0===e.length)continue;const i=e.some(t=>ut(t.data));if(i){const t=document.createComment(`wcs-row-end:${a.uuid}`);a.nodes[a.nodes.length-1].after(t),e.push(t)}const{bindingInfos:c,subscriberNodes:l,bindingSession:d,deferredSpreads:u}=wt(a.subscribers);for(const t of c)if(t.node!==t.replaceNode){const n=e.indexOf(t.node);n>=0&&(e[n]=t.replaceNode)}const f=j(e,i);$(f,d),P(f,c),E(f,l);const p=c.filter(t=>M(t,B));if(q(f,p),"for"===a.type&&null!==a.index){const e=Dt(t,"for",a.uuid);if(e){let t=n.get(a.uuid);if(!t){const o=kt(e,a.uuid)??a.path;t=s.get(o),t||s.set(o,t=[]),n.set(a.uuid,t)}const r=t[a.index]??=R(null,a.index);F(e,r,f),I(e,f.lastNode),H(e,f);const i=ot(a.path+"."+st),l=z(i,r);W(f,l),d.initialize(c,{registerAddress:!0,registerPathInfo:!1,applyOnReconnect:!1}),At(o,c),Tt(f,u,l,d,c,p)}}else{const e=a.start.previousSibling,n=e?.data===Ct(a.type,a.uuid)?e:Dt(t,a.type,a.uuid);if(n){H(n,f);const t=J(n);W(f,t),d.initialize(c,{registerAddress:!0,registerPathInfo:!1,applyOnReconnect:!1}),At(o,c),Tt(f,u,t,d,c,p)}}}return o}(document.body,o,r);gt.removeBlockBoundaryComments(document.body);const i=[];for(const t of n)t.parentNode&&(i.push({el:t,parent:t.parentNode,next:t.nextSibling}),t.remove());const[,c,l]=u(document.body),A=[],v=[],T=f(document.body),k=T.initialize(c);p(l,null,T);for(const t of k)if("event"!==t.bindingType)if(bt.has(t.bindingType))v.push(t);else{if(t.statePathName.includes(st))continue;A.push(t)}for(const t of v)if("for"===t.bindingType){const e=m(t),n=t.replaceNode.getRootNode(),s=h(n);s&&s.createState("readonly",n=>{const s=g(n[t.statePathName],t.outFilters);if(Array.isArray(s)){const n=r.get(t.uuid);n&&y(s,n),b(e,s),N(t.node,s),S(e,s)}})}w([...A,...a]);for(const{el:t,parent:e,next:n}of i)e.insertBefore(t,n);const C=new Map;for(const t of e.querySelectorAll("[data-wcs-ssr-id]"))C.set(t.getAttribute("data-wcs-ssr-id"),t);for(const n of e.querySelectorAll(t.tagNames.ssr))for(const[t,e]of Object.entries(n.hydrateProps)){const n=C.get(t);if(n)for(const[t,s]of Object.entries(e))x?.isDeclared(n,t)||(n[t]=s)}for(const t of e.querySelectorAll("[data-wcs-ssr-id]"))t.removeAttribute("data-wcs-ssr-id");return!0},loadState(t){const e=t.parentNode;if(!e)return null;const n=gt.find(e);if(!n)return null;const s=n.stateData;return Object.keys(s).length>0?s:null},async emitSnapshot(e){await Z(e.rootNode);const n=gt.extractStateData(e),s=document.createElement(t.tagNames.ssr);s.setAttribute("version",nt),gt.buildContent(s,n,e.rootNode),e.parentNode?.insertBefore(s,e)}};let jt=!1;function $t(){jt||(jt=!0,Y(_t),et(e=>{e.get(t.tagNames.ssr)||e.define(t.tagNames.ssr,gt)}),function(){const t=globalThis;void 0===t[n]&&(t[n]=yt)}())}const Pt={name:"ssr",install(){$t()}};export{Pt as default,Pt as ssr};
|
|
1
|
+
import{c as t,a as e,S as n}from"../chunks/filterRegistry.js";import{Q as s,R as o,S as r,U as a,V as i,W as c,X as l,Y as d,Z as u,y as f,_ as p,$ as m,G as h,a0 as g,a1 as y,a2 as b,a3 as N,N as S,x as w,a4 as x,a5 as A,L as v,a6 as T,a7 as k,a8 as C,D,a9 as O,aa as _,ab as j,ac as $,ad as P,ae as E,af as M,ag as B,ah as q,ai as R,aj as F,ak as I,al as H,j as z,am as W,v as J,an as V,ao as L,ap as G,aq as Q,ar as U,as as X,at as Y,au as Z,g as K}from"../chunks/binder.js";import{H as tt,a as et}from"../chunks/registerComponents.js";import{V as nt}from"../chunks/version.js";import{W as st,g as ot}from"../chunks/pathDiagnostics.js";import"../chunks/errorGuidance.js";import"../chunks/lifecycleHooks.js";import"../chunks/declarationAliases.js";import"../chunks/setAll.js";import"../chunks/checkDependency.js";import"../chunks/getAllPropertyDescriptors.js";import"../chunks/declarationHooks.js";import"../chunks/diagnosticsHooks.js";const rt=/^@@wcs-(?:for|if|elseif|else):[^-]/,at=/^@@wcs-(for|if|elseif|else)-start:(.+)$/,it=/^@@wcs-(for|if|elseif|else)-end:(.+)$/,ct=/^@@wcs-text-start:(.+)$/;function lt(t){return t.replace(/</g,"\\u003c").replace(/>/g,"\\u003e").replace(/&/g,"\\u0026").replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029")}function dt(t,e){const n=document.createTreeWalker(t,NodeFilter.SHOW_COMMENT),s=[];for(;n.nextNode();){const t=n.currentNode;e(t.data)&&s.push(t)}return s}const ut=t=>rt.test(t),ft=t=>at.test(t),pt=t=>at.test(t)||it.test(t);function mt(t){if("else"===t.bindingType)return"else:";let e=`${t.bindingType}: ${t.statePathName}`;for(const n of t.outFilters){const t=n.literals??n.args;e+=`|${n.filterName}`,n.args.length>0&&(e+=`(${n.args.map((e,n)=>"string"==typeof t[n]?`'${e.split("'").join("'\"'\"'")}'`:e).join(",")})`)}return e}function ht(t){const e=t.fragment.cloneNode(!0);for(const n of t.nodeInfos){const s=i(c(t.fragment,n.nodePath));if(null===s)continue;const o=c(e,n.nodePath);o.parentNode.replaceChild(document.createComment(s),o)}return e}class gt extends tt{_stateData=null;_templates=null;_hydrateProps=null;get version(){return this.getAttribute("version")||""}get stateData(){return null===this._stateData&&(this._stateData=this._loadStateData()),this._stateData}get templates(){return null===this._templates&&(this._templates=this._loadTemplates()),this._templates}get hydrateProps(){return null===this._hydrateProps&&(this._hydrateProps=this._loadHydrateProps()),this._hydrateProps}getTemplate(t){return this.templates.get(t)??null}verifyVersion(){const t=this.version;if(!t)return!0;const e=t.split("."),n=nt.split(".");return e[0]===n[0]&&e[1]===n[1]}setStateData(t){this._stateData=t}setHydrateProps(t){this._hydrateProps=t}_loadStateData(){const t=this.querySelector('script[type="application/json"]:not([data-wcs-ssr-props])');if(!t)return{};try{return JSON.parse(t.textContent||"{}")}catch{return{}}}_loadTemplates(){const t=new Map,e=this.querySelectorAll("template[id]");for(const n of e){const e=n.getAttribute("id");e&&t.set(e,n)}return t}_loadHydrateProps(){const t=this.querySelector("script[data-wcs-ssr-props]");if(!t)return{};try{return JSON.parse(t.textContent||"{}")}catch{return{}}}static find(e){const n=t.tagNames.ssr,s=e instanceof Element?e:e instanceof Document?e.documentElement:null;if(!s)return null;return s.querySelector(n)}static extractStateData(t){const e=t.__state;if(!e||"object"!=typeof e)return{};const n={};for(const t of Object.keys(e)){if(t.startsWith("$"))continue;const s=Object.getOwnPropertyDescriptor(e,t);if(void 0!==s&&"function"==typeof s.get)continue;const o=e[t];"function"!=typeof o&&(n[t]=o)}return n}static buildContent(n,i,c){const l=c??n.ownerDocument;e.seen&&function(t){const e=new Map;for(const n of dt(t,ft)){if(null===n.parentNode)continue;const[,t,s]=at.exec(n.data),o=s.split(":")[0],r=n.previousSibling?.data,a=`@@wcs-${t}-end:${s}`;if(r!==`@@wcs-${t}:${o}`&&e.get(r)!==o)for(let t=n;null!==t;){const e=t.nextSibling;t.remove(),t=t.data===a?null:e}else"for"===t&&e.set(a,o)}}(l);const d=document.createElement("script");d.setAttribute("type","application/json"),d.textContent=lt(JSON.stringify(i)),n.appendChild(d);for(const[e,s]of function(t){const e=new Map,n=[t];for(;n.length>0;)for(const t of dt(n.shift(),ut)){const s=t.data,o=s.slice(s.indexOf(":")+1);if(e.has(o))continue;const r=a(o);null!==r&&(e.set(o,r),n.push(r.fragment))}return e}(l)){const o=document.createElement("template");o.setAttribute("id",e),o.setAttribute(t.bindAttributeName,mt(s.parseBindTextResult)),o.content.appendChild(ht(s)),n.appendChild(o)}const u=n.ownerDocument,f=s();if(f.length>0){const t={};for(let e=0;e<f.length;e++){const n=f[e];if(!n.isConnected||n.ownerDocument!==u)continue;const s=o(n);if(0===s.length)continue;const r=`wcs-ssr-${e}`;n.setAttribute("data-wcs-ssr-id",r);const a={};for(const t of s)a[t.propName]=t.value;t[r]=a}if(Object.keys(t).length>0){const e=document.createElement("script");e.setAttribute("type","application/json"),e.setAttribute("data-wcs-ssr-props",""),e.textContent=lt(JSON.stringify(t)),n.appendChild(e)}}r()}static removeBlockBoundaryComments(t){for(const e of dt(t,pt))e.remove()}static removeStructuralComments(t){for(const e of dt(t,ut))e.remove()}static restoreTextBindings(t){for(const e of dt(t,t=>ct.test(t))){const t=ct.exec(e.data)[1],n=document.createComment(`@@: ${t}`);e.parentNode.insertBefore(n,e);let s=e.nextSibling;e.remove();const o=`@@wcs-text-end:${t}`;for(;s;){const t=s.nextSibling;if(s.nodeType===Node.COMMENT_NODE&&s.data===o){s.parentNode.removeChild(s);break}s.parentNode.removeChild(s),s=t}}}static cleanupDom(e){const n=document.body,s=e.querySelectorAll(t.tagNames.ssr),o=new Map;for(const t of s){const e=t.querySelectorAll("template[id]");for(const t of e){const e=t.getAttribute("id");e&&o.set(e,t)}}for(const t of dt(n,ft)){const e=at.exec(t.data),n=`@@wcs-${e[1]}-end:${e[2]}`;let s=t.nextSibling;for(;s;){const t=s.nextSibling;if(s.nodeType===Node.COMMENT_NODE&&s.data===n){s.remove();break}s.remove(),s=t}t.remove()}gt.restoreTextBindings(n);const r=e=>{for(const n of dt(e,ut)){const e=o.get(n.data.split(":")[1]);if(e){const s=document.createElement("template"),o=e.getAttribute(t.bindAttributeName);o&&s.setAttribute(t.bindAttributeName,o);const a=document.importNode(e.content,!0);if(a.childNodes.length>0)s.content.appendChild(a);else for(const t of Array.from(e.childNodes))s.content.appendChild(document.importNode(t,!0));r(s.content),n.parentNode.replaceChild(s,n)}}};r(n);const a=e.querySelectorAll("[data-wcs-ssr-id]");for(const t of a)t.removeAttribute("data-wcs-ssr-id");for(const t of s)t.remove()}}const yt={protocol:"wcs-ssr-snapshot",version:1,build:function(e){const n=t.tagNames.state,s=t.tagNames.ssr,o=e.querySelectorAll(`${n}[enable-ssr]:not([mount]):not([bind-component])`);for(const t of o){const e=t.previousElementSibling;if(null!==e&&e.tagName.toLowerCase()===s)continue;const n=document.createElement(s);n.setAttribute("version",nt),gt.buildContent(n,gt.extractStateData(t),t.getRootNode()),t.parentNode?.insertBefore(n,t)}r()},reset:function(){l(),r(),e.seen=!1}};const bt=new Set(["for","if","elseif","else"]);function Nt(t){const[,e,n]=at.exec(t),[s,...o]=n.split(":");return"for"===e?{type:e,uuid:s,path:o[0],index:parseInt(o[1],10),nodes:[]}:{type:e,uuid:s,path:o.join(":"),index:null,nodes:[]}}function St(e){const n=[];for(const s of e)if(s.nodeType===Node.ELEMENT_NODE){const e=s;e.hasAttribute(t.bindAttributeName)&&n.push(e),Array.from(e.children).some(e=>e.localName===t.tagNames.state&&V(e))||n.push(...L(e))}else null!==G(s)&&n.push(s);return n}function wt(t){const[e,n,s]=Q(t),o=new U;return{bindingInfos:o.initialize(n,{registerAddress:!1,applyOnReconnect:!1}),subscriberNodes:e,bindingSession:o,deferredSpreads:s}}const xt=/^\s*@@\s*(?:wcs-text)?\s*:/;function At(t,e){for(const n of e)"event"===n.bindingType||bt.has(n.bindingType)||(n.node.nodeType!==Node.COMMENT_NODE||"text"===n.bindingType&&xt.test(n.node.data))&&t.push(n)}function vt(t,e){const n=[];for(let s=0;s<t.nodes.length;s++){const o=e.get(t.nodes[s]);o?s+=o.nodes.length+1:n.push(t.nodes[s])}return n}function Tt(t,e,n,s,o,r){e.length>0&&(t.spreads=e);for(const t of e)Y(t.node);p(e,n,s,o,r)}function kt(t,e){const n=a(e),s=h(t.getRootNode());let o=null;if(n&&s){const{statePathName:t,outFilters:e}=n.parseBindTextResult;s.createState("readonly",n=>{const s=g(n[t],X(e,"output"));Array.isArray(s)&&(o=s)})}return o}function Ct(e,n){return`@@${{for:t.commentForPrefix,if:t.commentIfPrefix,elseif:t.commentElseIfPrefix,else:t.commentElsePrefix}[e]}:${n}`}function Dt(t,e,n){const s=Ct(e,n);return dt(t,t=>t===s)[0]??null}function Ot(e,n){const s=e,o=n.templates,r=new Map;for(const[t,e]of o)for(const n of dt(e.content,ut))r.set(n.data.slice(n.data.indexOf(":")+1),t);const a=new Set(A(e));if(a.size>0)for(const t of dt(s,ut)){const e=t.data.slice(t.data.indexOf(":")+1);let n=t.parentNode;for(;null!==n&&!a.has(n);)n=n.parentNode;null===n||r.has(e)||r.set(e,n)}const i=new Map,c=[];for(const[e,n]of o){const s=n.getAttribute(t.bindAttributeName)||"";let o=v(s)[0];const a=o.bindingType,l=r.get(e),d=i.get(l);"else"===a&&d&&(o={...d,outFilters:[...d.outFilters,T()],bindingType:"else"}),"if"===a||"elseif"===a?i.set(l,o):"else"===a&&i.set(l,null),c.push([e,n,o])}for(const[t,e,n]of c.reverse()){const o=document.importNode(e.content,!0),r="for"===n.bindingType?n.statePathName:void 0;k(o),"string"==typeof r&&C(o,r),D(s,o,r);const a={fragment:o,parseBindTextResult:n,nodeInfos:O(o)};_(t,s,a)}}const _t={hydrate:async function(e){await d(e);const n=e.querySelectorAll(t.tagNames.ssr);for(const t of n){const n=t;if(!n.verifyVersion())return console.warn(`[@wcstack/state] SSR version mismatch: server="${n.version}", client="${nt}". Falling back to full render.`),gt.cleanupDom(e),!1}const s=function(t){const e=[];for(const n of dt(t,pt)){if(!ft(n.data)){e.pop();continue}const t=Nt(n.data),s=e.at(-1);if("for"===t.type&&s&&s.uuid!==t.uuid)return[t,s];e.push(t)}return null}(document.body);if(null!==s){const[t,n]=s;return console.warn(`[@wcstack/state] SSR: "for: ${t.path}" in "${n.type}: ${n.path}" (known limitation). Falling back to full render.`),gt.cleanupDom(e),!1}for(const t of n)Ot(e,t);gt.restoreTextBindings(document.body);const o=function(t){const e=[];for(const n of dt(t,ft)){const t=Nt(n.data);t.start=n;const s=n.data.replace("-start:","-end:");let o=n.nextSibling;for(;o&&(o.nodeType!==Node.COMMENT_NODE||o.data!==s);)t.nodes.push(o),o=o.nextSibling;e.push(t)}return e}(document.body),r=new Map,a=function(t,e,n=new Map){const s=new Map,o=[],r=new Map(e.map(t=>[t.start,t])),a=new Set;for(let t=e.length-1;t>=0;t--){const n=St(e[t].nodes).filter(t=>!a.has(t));for(const t of n)a.add(t);e[t].subscribers=n}for(const a of e){const e=vt(a,r);if(0===e.length)continue;const i=e.some(t=>ut(t.data));if(i){const t=document.createComment(`wcs-row-end:${a.uuid}`);a.nodes[a.nodes.length-1].after(t),e.push(t)}const{bindingInfos:c,subscriberNodes:l,bindingSession:d,deferredSpreads:u}=wt(a.subscribers);for(const t of c)if(t.node!==t.replaceNode){const n=e.indexOf(t.node);n>=0&&(e[n]=t.replaceNode)}const f=j(e,i);$(f,d),P(f,c),E(f,l);const p=c.filter(t=>M(t,B));if(q(f,p),"for"===a.type&&null!==a.index){const e=Dt(t,"for",a.uuid);if(e){let t=n.get(a.uuid);if(!t){const o=kt(e,a.uuid)??a.path;t=s.get(o),t||s.set(o,t=[]),n.set(a.uuid,t)}const r=t[a.index]??=R(null,a.index);F(e,r,f),I(e,f.lastNode),H(e,f);const i=ot(a.path+"."+st),l=z(i,r);W(f,l),d.initialize(c,{registerAddress:!0,registerPathInfo:!1,applyOnReconnect:!1}),At(o,c),Tt(f,u,l,d,c,p)}}else{const e=a.start.previousSibling,n=e?.data===Ct(a.type,a.uuid)?e:Dt(t,a.type,a.uuid);if(n){H(n,f);const t=J(n);W(f,t),d.initialize(c,{registerAddress:!0,registerPathInfo:!1,applyOnReconnect:!1}),At(o,c),Tt(f,u,t,d,c,p)}}}return o}(document.body,o,r);gt.removeBlockBoundaryComments(document.body);const i=[];for(const t of n)t.parentNode&&(i.push({el:t,parent:t.parentNode,next:t.nextSibling}),t.remove());const[,c,l]=u(document.body),A=[],v=[],T=f(document.body),k=T.initialize(c);p(l,null,T);for(const t of k)if("event"!==t.bindingType)if(bt.has(t.bindingType))v.push(t);else{if(t.statePathName.includes(st))continue;A.push(t)}for(const t of v)if("for"===t.bindingType){const e=m(t),n=t.replaceNode.getRootNode(),s=h(n);s&&s.createState("readonly",n=>{const s=g(n[t.statePathName],t.outFilters);if(Array.isArray(s)){const n=r.get(t.uuid);n&&y(s,n),b(e,s),N(t.node,s),S(e,s)}})}w([...A,...a]);for(const{el:t,parent:e,next:n}of i)e.insertBefore(t,n);const C=new Map;for(const t of e.querySelectorAll("[data-wcs-ssr-id]"))C.set(t.getAttribute("data-wcs-ssr-id"),t);for(const n of e.querySelectorAll(t.tagNames.ssr))for(const[t,e]of Object.entries(n.hydrateProps)){const n=C.get(t);if(n)for(const[t,s]of Object.entries(e))x?.isDeclared(n,t)||(n[t]=s)}for(const t of e.querySelectorAll("[data-wcs-ssr-id]"))t.removeAttribute("data-wcs-ssr-id");return!0},loadState(t){const e=t.parentNode;if(!e)return null;const n=gt.find(e);if(!n)return null;const s=n.stateData;return Object.keys(s).length>0?s:null},async emitSnapshot(e){await K(e.rootNode);const n=gt.extractStateData(e),s=document.createElement(t.tagNames.ssr);s.setAttribute("version",nt),gt.buildContent(s,n,e.rootNode),e.parentNode?.insertBefore(s,e)}};let jt=!1;function $t(){jt||(jt=!0,Z(_t),et(e=>{e.get(t.tagNames.ssr)||e.define(t.tagNames.ssr,gt)}),function(){const t=globalThis;void 0===t[n]&&(t[n]=yt)}())}const Pt={name:"ssr",install(){$t()}};export{Pt as default,Pt as ssr};
|
|
2
2
|
//# sourceMappingURL=ssr.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr.js","sources":["../../../../../src/ssr/Ssr.ts","../../../../../src/ssr/buildSsrDocument.ts","../../../../../src/ssr/hydrateBindings.ts","../../../../../src/ssr/install.ts","../../../../../src/features/ssr.ts"],"sourcesContent":["import { config, ssrBlockRemoval } from \"../config\";\nimport { IState } from \"../types\";\nimport { VERSION } from \"../version\";\nimport { getFragmentInfoByUUID } from \"../structural/fragmentInfoByUUID\";\nimport { getNormalizedTextCommentData } from \"../structural/getFragmentNodeInfos\";\nimport { resolveNodePath } from \"../structural/resolveNodePath\";\nimport { IFragmentInfo } from \"../structural/types\";\nimport { ParseBindTextResult } from \"../bindTextParser/types\";\nimport { getAllSsrPropertyNodes, getSsrProperties, clearSsrPropertyStore } from \"../apply/ssrPropertyStore\";\nimport { HTMLElementBase } from \"../platform/HTMLElementBase\";\n\nexport interface ISsrElement {\n readonly version: string;\n readonly stateData: IState;\n readonly templates: Map<string, HTMLTemplateElement>;\n readonly hydrateProps: Record<string, Record<string, unknown>>;\n getTemplate(uuid: string): HTMLTemplateElement | null;\n verifyVersion(): boolean;\n}\n\n// SSR コメントパターン\nconst SSR_PLACEHOLDER_COMMENT = /^@@wcs-(?:for|if|elseif|else):[^-]/;\nconst SSR_BLOCK_START = /^@@wcs-(for|if|elseif|else)-start:(.+)$/;\nconst SSR_BLOCK_END = /^@@wcs-(for|if|elseif|else)-end:(.+)$/;\nconst SSR_TEXT_START = /^@@wcs-text-start:(.+)$/;\n\nexport {\n SSR_PLACEHOLDER_COMMENT,\n SSR_BLOCK_START,\n SSR_BLOCK_END,\n SSR_TEXT_START,\n};\n\n/**\n * script 要素へ埋め込む JSON を HTML パーサから保護する。\n * HTML 直列化時、script の中身は生のまま出力されるため、state 値に\n * \"</script>\" や \"<!--\" を含む文字列があると script を脱出できてしまう。\n * \"<\" \">\" \"&\" と U+2028/U+2029 を JSON の \\uXXXX エスケープへ置換する\n * (JSON.parse では元の文字列と等価に復元される)。\n */\nfunction escapeJsonForScript(json: string): string {\n return json\n .replace(/</g, '\\\\u003c')\n .replace(/>/g, '\\\\u003e')\n .replace(/&/g, '\\\\u0026')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029');\n}\n\n/**\n * **このドキュメントから到達できる**構造テンプレートの uuid だけを、文書順・幅優先で集める。\n *\n * `fragmentInfoByUUID` はモジュール寿命の台帳で削除の口が無く、`getAllFragmentUUIDs()` を\n * そのまま直列化すると、同じプロセスで描いた**別のドキュメント**のテンプレートまで\n * `<wcs-ssr>` に載る(実測: 同じページを繰り返すと 2 → 12 テンプレートに増え、ページ A の\n * `for: secretItems` がページ B の HTML に混入した)。uuid は単調増加で再利用されないので、\n * 「この文書のプレースホルダから辿れるか」は正確な所属判定になる。\n *\n * 入れ子のテンプレートは親の fragment の中にプレースホルダコメントとして居る(`if` が偽で\n * 一度も描かれていない枝の中身も含む)ので、辿りは fragment へ再帰する。\n */\nfunction collectReachableFragments(scanRoot: Node): Map<string, IFragmentInfo> {\n const found = new Map<string, IFragmentInfo>();\n const pending: Node[] = [scanRoot];\n while (pending.length > 0) {\n for (const placeholder of collectComments(pending.shift() as Node, isPlaceholder)) {\n const data = placeholder.data;\n const uuid = data.slice(data.indexOf(':') + 1);\n // 入れ子のプレースホルダは行ごとに現れるので重複する。台帳に無い uuid(別の\n // レンダリングの痕跡・後始末の順序違い)はそのまま落とす\n if (found.has(uuid)) continue;\n const info = getFragmentInfoByUUID(uuid);\n if (info === null) continue;\n found.set(uuid, info);\n pending.push(info.fragment);\n }\n }\n return found;\n}\n\n/**\n * `root` 以下のコメントのうち `match` が真を返すものを文書順で集める。\n *\n * この 1 本に寄せているのは、走査の**途中で DOM を壊す**呼び手が多いからでもある\n * (境界コメントの除去・テキスト束縛の復元・プレースホルダの差し替え)。先に集めてから\n * 触るという規則をここに固定しておくと、各所で TreeWalker を書き写さずに済む。\n */\nexport function collectComments(root: Node, match: (data: string) => boolean): Comment[] {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT);\n const found: Comment[] = [];\n while (walker.nextNode()) {\n const comment = walker.currentNode as Comment;\n if (match(comment.data)) {\n found.push(comment);\n }\n }\n return found;\n}\n\nexport const isPlaceholder = (data: string): boolean => SSR_PLACEHOLDER_COMMENT.test(data);\nexport const isBlockStart = (data: string): boolean => SSR_BLOCK_START.test(data);\nexport const isBlockBoundary = (data: string): boolean => SSR_BLOCK_START.test(data) || SSR_BLOCK_END.test(data);\n\n/**\n * サーバー出力から、取り残されたブロック境界コメントの組を間に残ったものごと除く(#356)。\n *\n * 境界は枝・行の Content の外に置かれる(apply/applyChangeToIf・applyChangeToFor)ので、サーバー描画中に\n * 祖先の `if:` が隠れる・行が消えると、Content のノード(入れ子の置き場を含む)だけが外れ、入れ子の境界の\n * 組が文書に残る。残った組は、ハイドレーションで「別のブロックの中の `for`」(全描画に倒れる)や、\n * 描いていない枝として読まれていた。隠してから戻した `if:` も、前の組を後ろに残す。\n *\n * 生きている組の開始コメントは自分の置き場の直後に居る(`for:` の行は、同じ `for:` の生きている前の行の\n * 終了コメントの直後)。そうでない組は取り残されたもので、間に残っているのも取り残された組だけ\n * (外した Content のノードは外れている)。組は文書順に読むので、前の行が生きているかは読み終えている。\n * 生きている組の中は辿らない(辿る費用は取り残された組の分だけ)。\n */\nexport function removeStaleBlockBoundaries(root: Node): void {\n // 生きている `for:` の行の終了コメントの data → その `for:` の uuid(行ごとに添字が違うので data で引ける)\n const rowEnds = new Map<string | undefined, string>();\n for (const start of collectComments(root, isBlockStart)) {\n // 外側の取り残された組と一緒に外れた\n if (start.parentNode === null) continue;\n const [, type, info] = SSR_BLOCK_START.exec(start.data) as RegExpExecArray;\n const uuid = info.split(\":\")[0];\n const prev = (start.previousSibling as Comment | null)?.data;\n const end = `@@wcs-${type}-end:${info}`;\n if (prev === `@@wcs-${type}:${uuid}` || rowEnds.get(prev) === uuid) {\n if (type === \"for\") rowEnds.set(end, uuid);\n continue;\n }\n for (let node: ChildNode | null = start; node !== null;) {\n const next: ChildNode | null = node.nextSibling;\n node.remove();\n node = (node as Comment).data === end ? null : next;\n }\n }\n}\n\n/**\n * `<wcs-ssr>` のテンプレートの束縛の文。**出力フィルタも書き戻す** — `${bindingType}: ${statePathName}` と\n * 組み直していたので、`if: x|not` が `if: x` としてハイドレーションされて条件が反転し、`else:`(クライアントが\n * 直前の `if:` の否定として組む)もフィルタの無い条件の否定になっていた。文字列の引数は `'…'` で囲み(`'` は\n * `\"'\"` を挟んで繋ぐ — 引数の文法に逃がしは無く、引用符の区間は連ねられる)、型付きの値(数値・真偽・null)は\n * 原文のまま書くので、読み直すと同じ引数と値(要件 B9)になる。`else:` の条件はクライアントが組み直す。\n */\nexport function structuralBindText(result: ParseBindTextResult): string {\n if (result.bindingType === \"else\") return \"else:\";\n let text = `${result.bindingType}: ${result.statePathName}`;\n for (const filter of result.outFilters) {\n const literals = filter.literals ?? filter.args;\n text += `|${filter.filterName}`;\n if (filter.args.length > 0) {\n text += `(${filter.args.map((arg, i) => typeof literals[i] === \"string\" ? `'${arg.split(\"'\").join(`'\"'\"'`)}'` : arg).join(\",\")})`;\n }\n }\n return text;\n}\n\n/**\n * 直列化用のクローン。`getFragmentNodeInfos` がテンプレート登録時に空 Text へ潰した\n * テキスト束縛のコメントを、**クローンの上でだけ**原文へ戻す。\n *\n * 戻さないと `for` / `if` テンプレートの中の `{{ }}` がマークアップから消え、\n * ハイドレーションが束縛を復元できず、その行のテキストが**恒久的に空**になる。\n * 元の fragment は生きているページの正本なので絶対に壊さない。\n */\nfunction cloneFragmentForSnapshot(fragmentInfo: IFragmentInfo): DocumentFragment {\n const clone = fragmentInfo.fragment.cloneNode(true) as DocumentFragment;\n for (const nodeInfo of fragmentInfo.nodeInfos) {\n const commentData = getNormalizedTextCommentData(\n resolveNodePath(fragmentInfo.fragment, nodeInfo.nodePath));\n if (commentData === null) continue;\n // nodePath はこの fragment から採ったもので、クローンは同形。ここまで来た枝は\n // 必ず解決でき、正規化された Text は必ず親を持つ(fragment 直下でも親は fragment)。\n // 同じ位置への置換なので、以降の nodePath は変わらない(正規化と対称)\n const target = resolveNodePath(clone, nodeInfo.nodePath) as Node;\n (target.parentNode as Node).replaceChild(document.createComment(commentData), target);\n }\n return clone;\n}\n\nexport class Ssr extends HTMLElementBase implements ISsrElement {\n private _stateData: IState | null = null;\n private _templates: Map<string, HTMLTemplateElement> | null = null;\n private _hydrateProps: Record<string, Record<string, unknown>> | null = null;\n\n get version(): string {\n return this.getAttribute('version') || '';\n }\n\n get stateData(): IState {\n if (this._stateData === null) {\n this._stateData = this._loadStateData();\n }\n return this._stateData;\n }\n\n get templates(): Map<string, HTMLTemplateElement> {\n if (this._templates === null) {\n this._templates = this._loadTemplates();\n }\n return this._templates;\n }\n\n get hydrateProps(): Record<string, Record<string, unknown>> {\n if (this._hydrateProps === null) {\n this._hydrateProps = this._loadHydrateProps();\n }\n return this._hydrateProps;\n }\n\n getTemplate(uuid: string): HTMLTemplateElement | null {\n return this.templates.get(uuid) ?? null;\n }\n\n /**\n * サーバーの SSR バージョンとクライアントの state バージョンを検証する。\n * メジャー・マイナーバージョンが一致すればtrue。\n * version 属性がない場合は検証スキップ(true)。\n */\n verifyVersion(): boolean {\n const serverVersion = this.version;\n if (!serverVersion) return true;\n const serverParts = serverVersion.split('.');\n const clientParts = VERSION.split('.');\n // メジャー・マイナーが一致すれば互換\n return serverParts[0] === clientParts[0] && serverParts[1] === clientParts[1];\n }\n\n setStateData(data: IState): void {\n this._stateData = data;\n }\n\n setHydrateProps(props: Record<string, Record<string, unknown>>): void {\n this._hydrateProps = props;\n }\n\n private _loadStateData(): IState {\n const script = this.querySelector(\n `script[type=\"application/json\"]:not([data-wcs-ssr-props])`\n );\n if (!script) return {};\n try {\n return JSON.parse(script.textContent || '{}');\n } catch {\n return {};\n }\n }\n\n private _loadTemplates(): Map<string, HTMLTemplateElement> {\n const map = new Map<string, HTMLTemplateElement>();\n const templates = this.querySelectorAll<HTMLTemplateElement>('template[id]');\n for (const tpl of templates) {\n const id = tpl.getAttribute('id');\n if (id) {\n map.set(id, tpl);\n }\n }\n return map;\n }\n\n private _loadHydrateProps(): Record<string, Record<string, unknown>> {\n const script = this.querySelector('script[data-wcs-ssr-props]');\n if (!script) return {};\n try {\n return JSON.parse(script.textContent || '{}');\n } catch {\n return {};\n }\n }\n\n static find(root: Node): ISsrElement | null {\n const tagName = config.tagNames.ssr;\n const parentEl = root instanceof Element\n ? root\n : root instanceof Document\n ? root.documentElement\n : null;\n if (!parentEl) return null;\n const el = parentEl.querySelector(tagName);\n return el as ISsrElement | null;\n }\n\n /**\n * stateData と構造テンプレート・プロパティから <wcs-ssr> の中身を構築する。\n * server パッケージの renderToString から呼ばれる。\n */\n /**\n * wcs-state 要素から $ プレフィックスや関数を除いたデータを抽出する。\n */\n static extractStateData(stateEl: Element): Record<string, any> {\n const raw = (stateEl as any).__state;\n if (!raw || typeof raw !== 'object') return {};\n const data: Record<string, any> = {};\n for (const key of Object.keys(raw)) {\n if (key.startsWith('$')) continue;\n // **アクセサは評価しない。** スナップショットが運ぶのはデータで、派生値は\n // クライアントが同じ宣言から作り直す。ここは Object.entries で舐めていたので、\n // own かつ enumerable な getter を**生の state オブジェクト**を this にして\n // 評価していた — proxy の上でしか意味を持たない本体(`this[\"items.*.n\"]` や\n // `this.$getAll(...)`)が、パス getter なら NaN → JSON の null で静かに壊れ、\n // `$getAll` を呼ぶ getter なら TypeError でページ全体の SSR を落としていた\n // (docs/state-recursive-path-impl-plan.md §7)。\n const descriptor = Object.getOwnPropertyDescriptor(raw, key);\n if (descriptor !== undefined && typeof descriptor.get === 'function') continue;\n const value = (raw as Record<string, unknown>)[key];\n if (typeof value !== 'function') {\n data[key] = value;\n }\n }\n return data;\n }\n\n /**\n * @param scanRoot このスナップショットが属するツリー(既定は `ssrEl` の document)。\n * テンプレートと props はここから到達できるものだけを載せる — モジュール寿命の台帳に\n * 残った**別のレンダリング**の分を混ぜないため(リクエスト間のデータ漏れ)。\n */\n static buildContent(ssrEl: Element, stateData: Record<string, any>, scanRoot?: Node): void {\n const root: Node = scanRoot ?? (ssrEl.ownerDocument as Document);\n // スナップショットと同じ時点で、出力の本文から取り残された境界を除く(inline 生成・最終パスの両方が通る)。\n // 取り残しは描いた枝・行を外したときにしか生じないので、外していなければ探さない\n if (ssrBlockRemoval.seen) removeStaleBlockBoundaries(root);\n // 初期データ JSON\n const jsonScript = document.createElement('script');\n jsonScript.setAttribute('type', 'application/json');\n jsonScript.textContent = escapeJsonForScript(JSON.stringify(stateData));\n ssrEl.appendChild(jsonScript);\n\n // この文書のプレースホルダから辿れるテンプレートだけを復元して格納\n for (const [uuid, fragmentInfo] of collectReachableFragments(root)) {\n const tpl = document.createElement('template');\n tpl.setAttribute('id', uuid);\n\n tpl.setAttribute(config.bindAttributeName, structuralBindText(fragmentInfo.parseBindTextResult));\n\n tpl.content.appendChild(cloneFragmentForSnapshot(fragmentInfo));\n\n ssrEl.appendChild(tpl);\n }\n\n // 属性で代替不可なプロパティをハイドレーション用に格納。\n // **この文書に今も繋がっているノードだけ**を載せる — props の台帳(apply/ssrPropertyStore)は\n // `buildContent` の末尾でしか空にならないので、`enable-ssr` の無いページを 1 枚描くと\n // 次のレンダリングの props JSON に前のページの値が載っていた(実測)\n const ownerDocument = ssrEl.ownerDocument;\n const ssrNodes = getAllSsrPropertyNodes();\n if (ssrNodes.length > 0) {\n const propsData: Record<string, Record<string, unknown>> = {};\n for (let i = 0; i < ssrNodes.length; i++) {\n const node = ssrNodes[i];\n if (!node.isConnected || node.ownerDocument !== ownerDocument) continue;\n const entries = getSsrProperties(node);\n if (entries.length === 0) continue;\n const id = `wcs-ssr-${i}`;\n (node as Element).setAttribute('data-wcs-ssr-id', id);\n const props: Record<string, unknown> = {};\n for (const entry of entries) {\n props[entry.propName] = entry.value;\n }\n propsData[id] = props;\n }\n if (Object.keys(propsData).length > 0) {\n const propsScript = document.createElement('script');\n propsScript.setAttribute('type', 'application/json');\n propsScript.setAttribute('data-wcs-ssr-props', '');\n propsScript.textContent = escapeJsonForScript(JSON.stringify(propsData));\n ssrEl.appendChild(propsScript);\n }\n }\n\n clearSsrPropertyStore();\n }\n\n /**\n * SSR ブロック境界コメント (@@wcs-*-start/end) を除去する\n */\n static removeBlockBoundaryComments(root: Node): void {\n for (const comment of collectComments(root, isBlockBoundary)) {\n comment.remove();\n }\n }\n\n /**\n * SSR の構造プレースホルダーコメント (@@wcs-for:uuid 等) を除去する\n */\n static removeStructuralComments(root: Node): void {\n for (const comment of collectComments(root, isPlaceholder)) {\n comment.remove();\n }\n }\n\n /**\n * SSR テキストバインディングコメントを復元する。\n * <!--@@wcs-text-start:path-->text<!--@@wcs-text-end:path-->\n * → <!--@@: path--> (バインディングシステムが認識する形式)\n */\n static restoreTextBindings(root: Node): void {\n for (const comment of collectComments(root, (d) => SSR_TEXT_START.test(d))) {\n const path = (SSR_TEXT_START.exec(comment.data) as RegExpExecArray)[1];\n const bindComment = document.createComment(`@@: ${path}`);\n comment.parentNode!.insertBefore(bindComment, comment);\n\n let sibling: Node | null = comment.nextSibling;\n comment.remove();\n\n const endPattern = `@@wcs-text-end:${path}`;\n while (sibling) {\n const next: Node | null = sibling.nextSibling;\n if (sibling.nodeType === Node.COMMENT_NODE && (sibling as Comment).data === endPattern) {\n sibling.parentNode!.removeChild(sibling);\n break;\n }\n sibling.parentNode!.removeChild(sibling);\n sibling = next;\n }\n }\n }\n\n /**\n * SSR DOM をクリーンアップし、buildBindings が動作できる状態に戻す。\n * バージョン不一致時のフォールバック用。\n *\n * 1. SSR ブロック境界コメント間のレンダリング済みノードを除去\n * 2. SSR テキストバインディングを @@: 形式に復元\n * 3. プレースホルダーコメントを <wcs-ssr> 内のテンプレートで差し替え\n * 4. data-wcs-ssr-id 属性を除去\n * 5. <wcs-ssr> を除去\n */\n static cleanupDom(root: Document): void {\n const body = document.body;\n\n // <wcs-ssr> からテンプレート UUID マップを構築(カスタム要素未定義でも動作するよう DOM 直接走査)\n const ssrElements = root.querySelectorAll(config.tagNames.ssr);\n const templateByUuid = new Map<string, HTMLTemplateElement>();\n for (const ssrNode of ssrElements) {\n const templates = ssrNode.querySelectorAll<HTMLTemplateElement>('template[id]');\n for (const tpl of templates) {\n const id = tpl.getAttribute('id');\n if (id) {\n templateByUuid.set(id, tpl);\n }\n }\n }\n\n // SSR ブロック境界コメント間のレンダリング済みノードと境界コメントを除去\n for (const startComment of collectComments(body, isBlockStart)) {\n const match = SSR_BLOCK_START.exec(startComment.data)!;\n const type = match[1];\n const info = match[2];\n const endPattern = `@@wcs-${type}-end:${info}`;\n let sibling = startComment.nextSibling;\n while (sibling) {\n const next = sibling.nextSibling;\n if (sibling.nodeType === Node.COMMENT_NODE && (sibling as Comment).data === endPattern) {\n sibling.remove();\n break;\n }\n sibling.remove();\n sibling = next;\n }\n startComment.remove();\n }\n\n // SSR テキストバインディングを @@: 形式に復元\n Ssr.restoreTextBindings(body);\n\n // プレースホルダーコメント (@@wcs-for:uuid 等) をテンプレートに差し替える。\n // **差し替えたテンプレートの中身にも掛ける**(#258): スナップショットのテンプレートは平らで\n // (入れ子のテンプレートは親の中身にプレースホルダとして居る — collectReachableFragments)、\n // 中身のプレースホルダが指すのはサーバーの uuid。クライアントの台帳には無いので、残すと\n // `text: <uuid>` と解釈され(binding-path-missing)、入れ子の内側が一度も描かれなかった\n // (実 Chromium で実測。同じモジュールでサーバー描画する vitest では台帳が残っていて見えない)\n const restorePlaceholders = (scope: Node): void => {\n for (const comment of collectComments(scope, isPlaceholder)) {\n const tpl = templateByUuid.get(comment.data.split(':')[1]);\n if (tpl) {\n const restored = document.createElement('template') as HTMLTemplateElement;\n const bindAttr = tpl.getAttribute(config.bindAttributeName);\n if (bindAttr) restored.setAttribute(config.bindAttributeName, bindAttr);\n const imported = document.importNode(tpl.content, true);\n if (imported.childNodes.length > 0) {\n restored.content.appendChild(imported);\n } else {\n for (const child of Array.from(tpl.childNodes)) {\n restored.content.appendChild(document.importNode(child, true));\n }\n }\n restorePlaceholders(restored.content);\n comment.parentNode!.replaceChild(restored, comment);\n }\n }\n };\n restorePlaceholders(body);\n\n // data-wcs-ssr-id 属性を除去\n const ssrIdElements = root.querySelectorAll('[data-wcs-ssr-id]');\n for (const el of ssrIdElements) {\n el.removeAttribute('data-wcs-ssr-id');\n }\n\n // <wcs-ssr> を除去\n for (const el of ssrElements) {\n el.remove();\n }\n }\n}\n","import { config, ssrBlockRemoval } from \"../config\";\nimport { Ssr } from \"./Ssr\";\nimport { VERSION } from \"../version\";\nimport { IWcsSsrSnapshotBuilder, SSR_SNAPSHOT_BUILDER_KEY } from \"../protocol/ssrSnapshot\";\nimport { clearSsrPropertyStore } from \"../apply/ssrPropertyStore\";\nimport { clearFragmentInfos } from \"../structural/fragmentInfoByUUID\";\n\n/**\n * ssr-snapshot プロトコルの提供側(docs/ssr-router-design.md §5)。\n *\n * `<wcs-ssr>` スナップショットを document 全体に対する最終パスとして生成する。\n * connectedCallback 内の inline 生成は「その時点の DOM」しか見えず、router が\n * 後から挿入するルート内容の構造テンプレートを取り逃がすレースがあった\n * (state のロード方式と文書順に依存)。renderToString が全要素の完了と\n * バインディング構築の後にこれを呼ぶことで、スナップショットは常に確定後の\n * DOM を見る。\n *\n * 複数 `enable-ssr` state の意味論は inline 生成と同一に保つ(文書順に生成・\n * fragment レジストリはモジュール共有・props store は生成ごとにクリア)。\n * その整理は本プロトコルの範囲外の既存挙動として引き継ぐ。\n */\nexport function buildSsrDocument(root: Document): void {\n const stateTag = config.tagNames.state;\n const ssrTag = config.tagNames.ssr;\n // スナップショットはルートツリーに 1 本(D14): ボリューム(mount=)と bind-component は\n // 独立ツリー(__state)を持たないため、含めると空の <wcs-ssr> を生成してしまう。\n // Ssr.find は文書先頭一致なので、ルートより前の空スナップショットをルートが掴み、\n // ハイドレーション全体が無言で CSR 退化する\n const stateElements = root.querySelectorAll(`${stateTag}[enable-ssr]:not([mount]):not([bind-component])`);\n for (const stateEl of stateElements) {\n // 既に直前へ生成済み(旧 server との組み合わせで inline 生成された等)なら\n // 何もしない — build() は冪等でなければならない(プロトコル契約)\n const prev = stateEl.previousElementSibling;\n if (prev !== null && prev.tagName.toLowerCase() === ssrTag) {\n continue;\n }\n const ssrEl = document.createElement(ssrTag);\n ssrEl.setAttribute(\"version\", VERSION);\n Ssr.buildContent(ssrEl, Ssr.extractStateData(stateEl), stateEl.getRootNode());\n stateEl.parentNode?.insertBefore(ssrEl, stateEl);\n }\n // props の台帳は `buildContent` の末尾でも空にするが、**`enable-ssr` が 1 件も無いページ**は\n // そこを通らない。通らないと強参照の `Set<Node>` が次のレンダリングまで残り、前のページの\n // 値が次のリクエストの props JSON に載る(実測: `{\"wcs-ssr-0\":{\"valueAsNumber\":\"PRIVATE-C\"}}`)。\n // ここはサーバーの最終パスなので、この文書の props をこの後で読む者は居ない。\n // 構造テンプレートの台帳(fragmentInfoByUUID)はここでは消さない — この後に走る\n // 進行中のバインディング構築がまだ読む。プロセスの後始末は `resetSsrRenderState()`\n clearSsrPropertyStore();\n}\n\n/**\n * サーバーのレンダリング 1 回分のモジュール大域を捨てる。**サーバー専用**。\n *\n * `@wcstack/server` の `renderToString` は 1 プロセスで何枚も描くが、state 側の台帳\n * (構造テンプレート・SSR props)はモジュール寿命で削除の口が無い。出力への混入は\n * 到達可能性フィルタ(`Ssr.buildContent`)で閉じてあるので、これは**メモリ**の口である。\n *\n * 呼ぶ位置: `renderToString`(正確には `renderInWindow`)の `finally` の最後 — その\n * レンダリングの DOM をもう誰も触らないことが確定してから。ブラウザでは呼ばない。\n */\nexport function resetSsrRenderState(): void {\n clearFragmentInfos();\n clearSsrPropertyStore();\n ssrBlockRemoval.seen = false;\n}\n\nconst builder: IWcsSsrSnapshotBuilder = {\n protocol: \"wcs-ssr-snapshot\",\n version: 1,\n build: buildSsrDocument,\n // レンダラ(@wcstack/server)が後始末の最後に呼ぶ。パッケージの import ではなく\n // プロトコル越しに渡すのは `build` と同じ理由 — グローバル symbol は「実際に動いた\n // state のコピー」を指すので、捨てるべき台帳を持っている当人に必ず届く。\n // 分割エントリを直接 import すると core がもう 1 つ読み込まれ、**別の**台帳を\n // 空にして終わる\n reset: resetSsrRenderState,\n};\n\n/**\n * グローバル symbol へ自分を載せる。`bootstrapState` から呼ぶ。\n * binder(registerBinder)と同じ規範 — 既に別のコピーが載っているなら譲る\n * (そのコピーのレジストリが、そのページの正本だからである)。\n */\nexport function registerSsrSnapshotBuilder(): void {\n const globals = globalThis as Record<symbol, unknown>;\n if (globals[SSR_SNAPSHOT_BUILDER_KEY] === undefined) {\n globals[SSR_SNAPSHOT_BUILDER_KEY] = builder;\n }\n}\n\n/** テスト用: 登録を外す */\nexport function _unregisterSsrSnapshotBuilder(): void {\n const globals = globalThis as Record<symbol, unknown>;\n if (globals[SSR_SNAPSHOT_BUILDER_KEY] === builder) {\n delete globals[SSR_SNAPSHOT_BUILDER_KEY];\n }\n}\n","import { getAbsoluteStateAddressByBinding } from \"../binding/getAbsoluteStateAddressByBinding\";\nimport { setLastListValueByAbsoluteStateAddress } from \"../list/lastListValueByAbsoluteStateAddress\";\nimport { setStateListBaseline } from \"../list/stateListBaseline\";\nimport { parseBindTextsForElement } from \"../bindTextParser/parseBindTextsForElement\";\nimport { ParseBindTextResult } from \"../bindTextParser/types\";\nimport { BindingSession, getOrCreateBindingSession } from \"../bindings/BindingSession\";\nimport { collectNodesAndBindingInfos, collectNodesAndBindingInfosOf, IDeferredSpreadEntry, markNodeRegistered } from \"../bindings/collectNodesAndBindingInfos\";\nimport { getSubscriberNodes } from \"../bindings/getSubscriberNodes\";\nimport { findNestedLightDomComponents, isLightDomMappedStateElement } from \"../bindings/lightDomComponentScope\";\nimport { parseCommentNode } from \"../bindings/parseCommentNode\";\nimport { componentApplyHooks } from \"../core/componentApplyHooks\";\nimport { scheduleDeferredSpreads } from \"../bindings/initializeBindings\";\nimport { setBindingsByContent } from \"../bindings/bindingsByContent\";\nimport { setBindingSessionByContent } from \"../bindings/bindingSessionByContent\";\nimport { setIndexBindingsByContent } from \"../bindings/indexBindingsByContent\";\nimport { setNodesByContent } from \"../bindings/nodesByContent\";\nimport { bindLoopContextToContent } from \"../bindings/bindLoopContextToContent\";\nimport { config } from \"../config\";\nimport { WILDCARD } from \"../define\";\nimport { Ssr, SSR_BLOCK_START, collectComments, isBlockBoundary, isBlockStart, isPlaceholder } from \"./Ssr\";\nimport { getStateElement } from \"../stateElementByName\";\nimport { applyChangeFromBindings } from \"../apply/applyChangeFromBindings\";\nimport { hydrateSetContent, hydrateSetLastNode, hydrateSetRenderedList } from \"../apply/applyChangeToFor\";\nimport { waitForStateInitialize } from \"../waitForStateInitialize\";\nimport { setFragmentInfoByUUID, getFragmentInfoByUUID } from \"../structural/fragmentInfoByUUID\";\nimport { getFilteredValue } from \"../apply/getFilteredValue\";\nimport { planFilters } from \"../bindings/planFilters\";\nimport { setContentByNode } from \"../structural/contentsByNode\";\nimport { ALL_INDEX_BITS, createContentFromNodes, isIndexBinding } from \"../structural/createContent\";\nimport { IContent } from \"../structural/types\";\nimport { collectStructuralFragments } from \"../structural/collectStructuralFragments\";\nimport { createNotFilter } from \"../structural/createNotFilter\";\nimport { getFragmentNodeInfos } from \"../structural/getFragmentNodeInfos\";\nimport { optimizeFragment } from \"../structural/optimizeFragment\";\nimport { expandShorthandPaths } from \"../structural/expandShorthandPaths\";\nimport { createListIndex } from \"../list/createListIndex\";\nimport { IListIndex, ILoopContext } from \"../list/types\";\nimport { getLoopContextByNode } from \"../list/loopContextByNode\";\nimport { setListIndexesByList } from \"../list/listIndexesByList\";\nimport { getPathInfo } from \"../address/PathInfo\";\nimport { createStateAddress } from \"../address/StateAddress\";\nimport { IBindingInfo } from \"../types\";\nimport { VERSION } from \"../version\";\n\n// ハイドレーション時にスキップするバインディングタイプ\nconst STRUCTURAL_TYPES = new Set(['for', 'if', 'elseif', 'else']);\n\n\ninterface ISsrBlock {\n type: string; // for, if, elseif, else\n uuid: string;\n path: string;\n index: number | null; // for のみ\n nodes: Node[]; // start〜end 間のノード\n start?: Comment; // 開始コメント(collectSsrBlocks が付ける)\n subscribers?: Node[]; // このブロックが自分で持つ購読ノード(hydrateBlocks が付ける)\n}\n\n/**\n * ブロック開始コメントの中身(`@@wcs-for-start:uuid:path:index` / `@@wcs-if-start:uuid:path`)を読む。\n * `nodes` は空で返す(collectSsrBlocks が埋める)。\n */\nfunction parseBlockStart(data: string): ISsrBlock {\n const [, type, info] = SSR_BLOCK_START.exec(data) as RegExpExecArray;\n const [uuid, ...rest] = info.split(':');\n return type === 'for'\n ? { type, uuid, path: rest[0], index: parseInt(rest[1], 10), nodes: [] }\n // if / elseif / else のパスは `:` を含み得るので残りを繋ぐ\n : { type, uuid, path: rest.join(':'), index: null, nodes: [] };\n}\n\n/**\n * SSR ブロック境界コメントを走査して、start〜end 間のノードを収集する\n */\nfunction collectSsrBlocks(root: Node): ISsrBlock[] {\n const blocks: ISsrBlock[] = [];\n // 先に集めてから触る(この後で兄弟を引き剥がすため)\n for (const comment of collectComments(root, isBlockStart)) {\n const block = parseBlockStart(comment.data);\n block.start = comment;\n // start と end の間のノードを収集\n const endPattern = comment.data.replace('-start:', '-end:');\n let sibling = comment.nextSibling;\n while (sibling) {\n if (sibling.nodeType === Node.COMMENT_NODE && (sibling as Comment).data === endPattern) {\n break;\n }\n block.nodes.push(sibling);\n sibling = sibling.nextSibling;\n }\n blocks.push(block);\n }\n\n return blocks;\n}\n\n/**\n * 別のブロックの中にある `for` のブロック(入れ子の for・`if` / `else` の中の for)を探す。\n * 見つかれば `[内側の for, それを囲むブロック]`、無ければ null。\n *\n * このハイドレーションはブロックを文書順に**平らに**集め、行ごとの文脈を 1 段しか持てない。\n * 別のブロックの中の `for` を進めると、外側のブロックが内側の行のノードとバインディングを吸収し、\n * 内側の行の listIndex は親を持たない(#258)。実際のサーバー出力では、入れ子の for は\n * `ListIndex not found` でハイドレーション全体を止め(ready が reject され、ページのどの\n * バインディングも以後の書き込みに追従しない)、if の中の for は行が書き込みに追従せず、\n * 行を足すと SSR の行を残したまま重複した。\n *\n * 境界コメントは文書順に開き・閉じるので、開いているブロックを積んで数える。\n */\nfunction findNestedForBlock(root: Node): [ISsrBlock, ISsrBlock] | null {\n const open: ISsrBlock[] = [];\n for (const comment of collectComments(root, isBlockBoundary)) {\n if (!isBlockStart(comment.data)) {\n open.pop();\n continue;\n }\n const block = parseBlockStart(comment.data);\n // 同じ for(同じテンプレート = uuid)の行が入れ子の順に並ぶのは、サーバーが空でないリストへ\n // 行をまとめて足したときの境界コメントの順序で、入れ子の for ではない(#258)。今のサーバーはこの順に\n // 並べない(#334)が、同じ minor の修正前のサーバーの出力はバージョン検証を通るので残す\n const outer = open.at(-1);\n if (block.type === 'for' && outer && outer.uuid !== block.uuid) {\n return [block, outer];\n }\n open.push(block);\n }\n return null;\n}\n\n/**\n * ノード列の購読ノード(`getSubscriberNodes` をノード列へ広げたもの)。列の要素**自身**も拾い、\n * Light DOM の mapped コンポーネントの内側は除く(子スコープが自分で集める — getSubscriberNodes の注記)。\n * `getSubscriberNodes` は走査の根をコンポーネントとして数えないので、根がそれならここで降りない。\n */\nfunction getBlockSubscriberNodes(nodes: Node[]): Node[] {\n const found: Node[] = [];\n for (const node of nodes) {\n if (node.nodeType === Node.ELEMENT_NODE) {\n const element = node as Element;\n if (element.hasAttribute(config.bindAttributeName)) {\n found.push(element);\n }\n if (!Array.from(element.children).some(\n (child) => child.localName === config.tagNames.state && isLightDomMappedStateElement(child))) {\n found.push(...getSubscriberNodes(element));\n }\n } else if (parseCommentNode(node) !== null) {\n found.push(node);\n }\n }\n return found;\n}\n\n/**\n * live DOM の購読ノード(ブロックが自分で持つもの — hydrateBlocks)からバインディングを収集する。\n *\n * ノードは**動かさない**(#258)。以前は一時的な div へ移して `collectNodesAndBindingInfos` に掛け、\n * 元の位置に戻していた。移すとブロックの中のカスタム要素が切断・再接続され、`bind-component` の子は\n * スコープのバインディングを破棄したまま登録し直さず、親への書き込みに追従しなかった\n * (I/O ノードも切断の後始末と接続の開始をやり直していた)。\n */\nfunction collectBindingsFromLiveNodes(\n nodes: Node[],\n): { bindingInfos: IBindingInfo[], subscriberNodes: Node[], bindingSession: BindingSession, deferredSpreads: IDeferredSpreadEntry[] } {\n // 3 要素目(未定義カスタム要素への `...: path`)は呼び出し側が\n // ループ文脈を確定させてから予約する(`scheduleDeferredSpreads`)\n const [subscriberNodes, allBindings, deferredSpreads] = collectNodesAndBindingInfosOf(nodes);\n const bindingSession = new BindingSession();\n const bindingInfos = bindingSession.initialize(allBindings, {\n registerAddress: false,\n applyOnReconnect: false,\n });\n\n return {\n bindingInfos,\n subscriberNodes,\n bindingSession,\n deferredSpreads,\n };\n}\n\n/**\n * ブロックの中で初回値を適用するバインディングを集める(#258 X6 — hydrateBindings の注記)。\n *\n * 除くもの:\n * - 構造バインディング(SSR が描画済み)とイベント。\n * - コメントに乗ったバインディング。ブロックを集める時点のコメントのバインディングは構造の置き場\n * (`<!--@@wcs-for:uuid-->`)だけで、テキストの `@@:` はこの後で `Ssr.restoreTextBindings` が戻す。\n * テンプレートを復帰できなかった入れ子の置き場は text として解釈される(`text: uuid`)ので、\n * 構造の種別だけでは除けない。\n * コメントのバインディングは、適用しても失敗の報告をハイドレーションのたびに増やすだけになる。\n *\n * 添字のバインディング(`$1` / `$2` …)は除かない(#350)。state に依存しないので依存辺のためには\n * 要らないが、`{{ $1 }}` のサーバーのテキストは `Ssr.restoreTextBindings` が捨てているので、適用しないと\n * 行の添字が変わるまで空のままだった。以前除いていたのは、入れ子の for の内側の `$2` が外側のループ文脈\n * しか持たず読めなかったからで、別のブロックの中の `for` は今はハイドレーションしない(findNestedForBlock)。\n *\n * 以前はループの深さより多いワイルドカードを持つバインディング(外側のブロックに吸収された入れ子の\n * 内側の行)も除いていた。別のブロックの中の `for` は今はハイドレーションせずに全描画へ倒すので\n * (findNestedForBlock)、ここへは来ない。\n */\n/**\n * コメントに乗った**本物のテキスト束縛**の形(`<!--@@: path-->` / `<!--@@wcs-text:path-->`)。\n *\n * コメントの束縛を一律に除いていたのは、テンプレートを復帰できなかった入れ子の構造プレースホルダが\n * `text: uuid` として解釈され、適用すると `binding-path-missing` を量産するからである。それは\n * `@@wcs-for:` のような**構造のキーワード付き**コメントなので、キーワードの有無で precise に分けられる。\n * 分けないと、`{{ }}` から復元したテキスト束縛まで初回適用から落ち、`restoreTextBindings` が\n * 捨てたサーバー側のテキストが戻らない。\n */\nconst TEXT_BINDING_COMMENT = /^\\s*@@\\s*(?:wcs-text)?\\s*:/;\n\nfunction collectBlockBindings(out: IBindingInfo[], bindings: readonly IBindingInfo[]): void {\n for (const binding of bindings) {\n if (binding.bindingType === \"event\" || STRUCTURAL_TYPES.has(binding.bindingType)) {\n continue;\n }\n if (binding.node.nodeType === Node.COMMENT_NODE\n && !(binding.bindingType === \"text\" && TEXT_BINDING_COMMENT.test((binding.node as Comment).data))) {\n continue;\n }\n out.push(binding);\n }\n}\n\n/**\n * ブロックが**自分で**持つトップレベルのノード(#347 / #349)。CSR の Content が持つのはテンプレートの\n * トップレベルのノードだけで、入れ子の `if:`(行の直下・要素で包まない枝の中)の枝は置き場の後ろに\n * 自分の Content として描かれる。ブロックの `nodes` は入れ子のブロックの境界と中身も含むので、それを飛ばす。\n * 含めていたので、外した境界コメントが行の終わりになって末尾に足した行が文書に入らず、行を動かすと\n * 外した境界が文書に戻った。\n */\nfunction collectOwnNodes(block: ISsrBlock, blockByStart: Map<Node | undefined, ISsrBlock>): Node[] {\n const own: Node[] = [];\n for (let i = 0; i < block.nodes.length; i++) {\n const nested = blockByStart.get(block.nodes[i]);\n if (nested) {\n // 開始コメント・中身・終了コメント\n i += nested.nodes.length + 1;\n } else {\n own.push(block.nodes[i]);\n }\n }\n return own;\n}\n\n/**\n * ブロックの中の未定義カスタム要素への `...: path`(#330)を、CSR の行(createContent → activateContent)と\n * 同じくブロックの Content の待ちとして予約する(#358)。\n *\n * - 展開した束縛はブロックの束縛の列(と添字の列)に足す。足さないと行をプールから使い回しても当て直されず、\n * 消した行の値を出し続けた。\n * - `content.spreads` に持たせる。定義前に使い回した行・開き直した枝は活性化が予約し直す。\n * - ノードを登録済みにする。しないとこの後の body 全体の走査が同じノードをもう一度拾い、ループ文脈なしの\n * 2 つ目の展開を予約した。後から発火した方が行のノードの文脈を空にし、要素の出力の書き戻し\n * (`items.*.status`)が `ListIndex not found` で失敗した。\n */\nfunction scheduleBlockSpreads(\n content: IContent,\n deferredSpreads: IDeferredSpreadEntry[],\n loopContext: ILoopContext | null,\n session: BindingSession,\n bindings: IBindingInfo[],\n indexBindings: IBindingInfo[],\n): void {\n if (deferredSpreads.length > 0) content.spreads = deferredSpreads;\n for (const entry of deferredSpreads) markNodeRegistered(entry.node);\n scheduleDeferredSpreads(deferredSpreads, loopContext, session, bindings, indexBindings);\n}\n\n/**\n * SSR ブロックの DOM ノードを Content 化し、バインディングを登録する。\n * 戻り値はブロックの中で初回値を適用するバインディング(`collectBlockBindings`)。\n * `rowsByUuid` には for の行(listIndex)を `for`(uuid)ごとに行の添字順で集める。同じ配列を描く `for` は\n * 同じ組を持つ。リストの値へ紐づけるのは for のバインディングを起こした後(hydrateBindings — for のフィルタを\n * 通した値が行の並び)。\n */\nfunction hydrateBlocks(root: Node, blocks: ISsrBlock[], rowsByUuid: Map<string, IListIndex[]> = new Map()): IBindingInfo[] {\n // 描いたリスト(for のフィルタを通した値。配列でなければパス)→ 行の組\n const rowsByList = new Map<unknown, IListIndex[]>();\n const blockBindings: IBindingInfo[] = [];\n const blockByStart = new Map(blocks.map((block) => [block.start, block]));\n\n // 購読ノードは**内側のブロックから**割り当てる(#349)。ブロックの `nodes` は入れ子のブロックのノードも\n // 含むので、文書順(外側が先)に集めると外側が内側の置き場の束縛まで登録し、内側の Content は束縛を\n // 持たなかった — 外すときに入れ子の枝を連鎖して外さず(Content.unmount は自分の構造の束縛を辿る)、\n // 前の枝が残って 2 つの枝が同時に出た。内側のブロックは必ず外側より文書で後ろに居る\n const claimed = new Set<Node>();\n for (let i = blocks.length - 1; i >= 0; i--) {\n const subscribers = getBlockSubscriberNodes(blocks[i].nodes).filter((node) => !claimed.has(node));\n for (const node of subscribers) claimed.add(node);\n blocks[i].subscribers = subscribers;\n }\n\n for (const block of blocks) {\n const nodes = collectOwnNodes(block, blockByStart);\n // 中身が入れ子の境界だけのブロック(サーバー描画の最後に隠れた枝の残り — #356)は描かれていない\n if (nodes.length === 0) continue;\n // トップレベルに構造の置き場を持つブロックは CSR と同じく範囲モードにし、終端マーカー(ブロックの最後の\n // ノード=入れ子の枝の後ろ)で範囲を閉じる(createContent の resolveRanged)。入れ子の枝は置き場の後ろ=\n // 自分のノードの外に描かれるので、閉じないと差分が次の行を枝の手前へ入れ、行を動かすと枝を置き去りにする\n // (#347)。Text の data は置き場の形にならない\n const ranged = nodes.some((node) => isPlaceholder((node as Comment).data));\n if (ranged) {\n const marker = document.createComment(`wcs-row-end:${block.uuid}`);\n (block.nodes[block.nodes.length - 1] as ChildNode).after(marker);\n nodes.push(marker);\n }\n\n // Content のバインディングを収集\n const { bindingInfos, subscriberNodes, bindingSession, deferredSpreads } = collectBindingsFromLiveNodes(block.subscribers!);\n // トップレベルの `{{ }}` のコメントは初期化で Text に差し替わった。Content は差し替えた後のノードを\n // 持つ(CSR の行と同じ)— コメントを持っていたので、行を外す・動かすと値の Text が取り残された(#347)\n for (const binding of bindingInfos) {\n if (binding.node !== binding.replaceNode) {\n const index = nodes.indexOf(binding.node);\n if (index >= 0) nodes[index] = binding.replaceNode;\n }\n }\n const content = createContentFromNodes(nodes, ranged);\n setBindingSessionByContent(content, bindingSession);\n setBindingsByContent(content, bindingInfos);\n setNodesByContent(content, subscriberNodes);\n\n // 行の位置が変わったときに当て直す列(createContent と同じ振り分け — 添字の束縛と、中に添字の束縛を\n // 持つ入れ子の構造ディレクティブ。後から描いた枝の添字へ辿る入口・#360、#390)。段では絞らない — 入れ子の\n // for を持つブロックは全描画に倒す(findNestedForBlock)ので、ブロックの中の入れ子は if の枝だけ\n const indexBindings = bindingInfos.filter((binding) => isIndexBinding(binding, ALL_INDEX_BITS));\n setIndexBindingsByContent(content, indexBindings);\n\n if (block.type === 'for' && block.index !== null) {\n const placeholderComment = findPlaceholderComment(root, 'for', block.uuid);\n if (placeholderComment) {\n // 行(listIndex)は配列ごとに 1 組(list/listIndexesByList.ts)。同じリストを回す `for` が 2 つあると、\n // テンプレート(uuid)ごとに鋳造した行の組を後の方が台帳ごと上書きし、先の `for` は以後の差分で自分の\n // 行を引けず(`Content not found for ListIndex`)書き込みに追従しなかった(#258 の調査で発見)。\n // 別のパスでも同じ配列なら同じ組にする — 配列をそのまま返す getter の `for`(`for: items` と\n // `get visible() { return this.items; }` の `for: visible`)がパスごとに鋳造した組は、同じ配列の台帳を\n // 後の方が上書きし、先の `for` が同じ失敗をした(#351)\n let rows = rowsByUuid.get(block.uuid);\n if (!rows) {\n const list = readHydratedList(placeholderComment, block.uuid) ?? block.path;\n rows = rowsByList.get(list);\n if (!rows) {\n rowsByList.set(list, rows = []);\n }\n rowsByUuid.set(block.uuid, rows);\n }\n const listIndex = rows[block.index] ??= createListIndex(null, block.index);\n hydrateSetContent(placeholderComment, listIndex, content);\n hydrateSetLastNode(placeholderComment, content.lastNode as Node);\n setContentByNode(placeholderComment, content);\n\n // ループコンテキストをバインドし、バインディングをアドレスに登録\n const pathInfo = getPathInfo(block.path + '.' + WILDCARD);\n const stateAddress = createStateAddress(pathInfo, listIndex);\n // ILoopContext は IStateAddress + listIndex なので、stateAddress をそのまま使う\n bindLoopContextToContent(content, stateAddress as any);\n\n bindingSession.initialize(bindingInfos, {\n registerAddress: true,\n registerPathInfo: false,\n applyOnReconnect: false,\n });\n collectBlockBindings(blockBindings, bindingInfos);\n // 未定義カスタム要素への `...: path` は行のループ文脈が確定してから予約する\n scheduleBlockSpreads(content, deferredSpreads, stateAddress as unknown as ILoopContext, bindingSession, bindingInfos, indexBindings);\n }\n } else {\n // 行の中の if は行どうしで uuid を共有するので、文書で最初のプレースホルダではなく開始コメントの\n // 直前(サーバーはプレースホルダの直後に開始コメントを置く)から引く。文書で最初のものを引くと、どの行の\n // 枝も行 0 に付き、行 1 以降の切り替えが枝を消せず・重ね・別の行へ移した(#258)。直前に無い出力(手で\n // 整形したもの)は従来どおり文書から探す\n const previous = block.start!.previousSibling as Comment | null;\n const placeholderComment = previous?.data === placeholderData(block.type, block.uuid)\n ? previous\n : findPlaceholderComment(root, block.type, block.uuid);\n if (placeholderComment) {\n setContentByNode(placeholderComment, content);\n // 行の中の枝は置き場(行が文脈を与えた)の行の文脈で束縛する(CSR の applyChangeToIf の活性化と同じ)。\n // 以前は行のブロックが枝の束縛まで持っていたので要らなかった\n const loopContext = getLoopContextByNode(placeholderComment);\n bindLoopContextToContent(content, loopContext);\n\n bindingSession.initialize(bindingInfos, {\n registerAddress: true,\n registerPathInfo: false,\n applyOnReconnect: false,\n });\n collectBlockBindings(blockBindings, bindingInfos);\n scheduleBlockSpreads(content, deferredSpreads, loopContext, bindingSession, bindingInfos, indexBindings);\n }\n }\n }\n\n return blockBindings;\n}\n\n/**\n * `for` のブロックが描いたリスト — state のいまの値に for のフィルタを通したもの(配列でなければ null)。\n * structuralBindings はまだ登録前なので、復帰したテンプレートの解析結果からパスとフィルタを引く。\n */\nfunction readHydratedList(placeholderComment: Comment, uuid: string): unknown[] | null {\n const fragmentInfo = getFragmentInfoByUUID(uuid);\n const stateElement = getStateElement(placeholderComment.getRootNode() as Node);\n let list: unknown[] | null = null;\n if (fragmentInfo && stateElement) {\n const { statePathName, outFilters } = fragmentInfo.parseBindTextResult;\n stateElement.createState(\"readonly\", (state) => {\n const value = getFilteredValue(state[statePathName], planFilters(outFilters, \"output\"));\n if (Array.isArray(value)) {\n list = value;\n }\n });\n }\n return list;\n}\n\nfunction placeholderData(type: string, uuid: string): string {\n const keywordMap: Record<string, string> = {\n 'for': config.commentForPrefix,\n 'if': config.commentIfPrefix,\n 'elseif': config.commentElseIfPrefix,\n 'else': config.commentElsePrefix,\n };\n return `@@${keywordMap[type]}:${uuid}`;\n}\n\nfunction findPlaceholderComment(root: Node, type: string, uuid: string): Comment | null {\n const pattern = placeholderData(type, uuid);\n return collectComments(root, (d) => d === pattern)[0] ?? null;\n}\n\n/**\n * <wcs-ssr> 内のテンプレートを fragmentInfoByUUID に復帰させる。\n */\nfunction restoreFragments(root: Document, ssrEl: Ssr): void {\n const rootNode = root as Node;\n const templates = ssrEl.templates;\n // else は**同じ階層**(同じテンプレートの中身か、文書の直下)で直前の if / elseif の否定(#336)。\n // クライアントの collectStructuralFragments と同じ組み方で、階層は置き場を中身に持つテンプレートで分かる。\n // スナップショットの並び(collectReachableFragments)は描いた文書の文書順なので、外側の枝が描かれて\n // いると内側の置き場が外側の else より前に並ぶ — 並びの直前と組むと、外側の else が内側の if と組んだ\n // (内側に else があると、外側の else は否定の相手を失った)。各階層の中の並びは中身の順のまま\n const levelByUuid = new Map<string, unknown>();\n for (const [uuid, tpl] of templates) {\n for (const placeholder of collectComments(tpl.content, isPlaceholder)) {\n levelByUuid.set(placeholder.data.slice(placeholder.data.indexOf(':') + 1), uuid);\n }\n }\n // Light DOM の `bind-component` の子のテンプレートは、ページの走査が子を外す(collectStructuralFragments)\n // ので、どのテンプレートの中身にも置き場が無い(中身には `<template>` のまま居る)。子は自分のスコープで\n // 組むので、階層は生きている DOM の置き場を囲む一番内側の子。文書の直下とみなすと、ページの else が\n // 子の if と組んだ(#348)。子の居ないページ(大半)は文書をもう一度走査しない\n const components = new Set<Node>(findNestedLightDomComponents(root));\n if (components.size > 0) {\n for (const placeholder of collectComments(rootNode, isPlaceholder)) {\n const uuid = placeholder.data.slice(placeholder.data.indexOf(':') + 1);\n let level = placeholder.parentNode;\n while (level !== null && !components.has(level)) level = level.parentNode;\n if (level !== null && !levelByUuid.has(uuid)) levelByUuid.set(uuid, level);\n }\n }\n // 階層(文書の直下は undefined)ごとの直前の if / elseif\n const lastIfByLevel = new Map<unknown, ParseBindTextResult | null>();\n const restored: [string, HTMLTemplateElement, ParseBindTextResult][] = [];\n\n for (const [uuid, tpl] of templates) {\n const bindText = tpl.getAttribute(config.bindAttributeName) || '';\n const parseBindTextResults = parseBindTextsForElement(bindText);\n let parseBindTextResult = parseBindTextResults[0];\n const bindingType = parseBindTextResult.bindingType;\n const level = levelByUuid.get(uuid);\n const lastIfParseResult = lastIfByLevel.get(level);\n\n // else: 直前の if 条件の not → 条件反転(elseif は独自条件のままでよい)\n if (bindingType === 'else' && lastIfParseResult) {\n parseBindTextResult = {\n ...lastIfParseResult,\n outFilters: [...lastIfParseResult.outFilters, createNotFilter()],\n bindingType: 'else',\n };\n }\n\n // if chain の追跡\n if (bindingType === 'if' || bindingType === 'elseif') {\n lastIfByLevel.set(level, parseBindTextResult);\n } else if (bindingType === 'else') {\n lastIfByLevel.set(level, null);\n }\n restored.push([uuid, tpl, parseBindTextResult]);\n }\n\n // **子を親より先に**登録する(#258)。スナップショットのテンプレートは平らで、入れ子は親の中身に\n // プレースホルダ(`<!--@@wcs-if:<uuid>-->`)として居る。親の fragment を解析する時点で子が台帳に\n // 無いと、そのプレースホルダは `text: <uuid>` と解釈されて空の Text に潰され、親から新しく作る\n // 行・枝(行の追加、初めて真になる if)から入れ子が消えていた(実 Chromium で実測。同じモジュールで\n // サーバー描画する vitest では、サーバーの登録が台帳に残っていて見えない)。並び(Ssr の\n // collectReachableFragments)では、子の置き場は親の置き場より後ろ(描いた親の枝の中)か親の中身でしか\n // 見つからないので、子は必ず親より後ろに居る — 逆順に回せば足りる\n for (const [uuid, tpl, parseBindTextResult] of restored.reverse()) {\n const fragment = document.importNode(tpl.content, true);\n const forPath = parseBindTextResult.bindingType === \"for\" ? parseBindTextResult.statePathName : undefined;\n optimizeFragment(fragment);\n if (typeof forPath === \"string\") {\n expandShorthandPaths(fragment, forPath);\n }\n collectStructuralFragments(rootNode, fragment, forPath);\n\n const fragmentInfo = {\n fragment,\n parseBindTextResult,\n nodeInfos: getFragmentNodeInfos(fragment),\n };\n setFragmentInfoByUUID(uuid, rootNode, fragmentInfo);\n }\n}\n\n/**\n * SSR ハイドレーション用バインディング初期化。\n * バージョン不一致時と、別のブロックの中に `for` のブロックがあるとき(findNestedForBlock)は\n * DOM をクリーンアップして false を返す(呼び出し元で buildBindings にフォールバック)。\n */\nexport async function hydrateBindings(root: Document): Promise<boolean> {\n await waitForStateInitialize(root);\n\n // バージョン検証\n const ssrElements = root.querySelectorAll(config.tagNames.ssr);\n for (const ssrNode of ssrElements) {\n const ssrEl = ssrNode as Ssr;\n if (!ssrEl.verifyVersion()) {\n console.warn(\n `[@wcstack/state] SSR version mismatch: server=\"${ssrEl.version}\", client=\"${VERSION}\". Falling back to full render.`\n );\n Ssr.cleanupDom(root);\n return false;\n }\n }\n\n // 入れ子の for・if の中の for はハイドレーションしない(既知の制限 — findNestedForBlock)。\n // DOM に触る前に判定し、バージョン不一致と同じ経路でクライアントの全描画に倒す。\n // SSR の DOM を捨てて描き直すことになるので、バージョン不一致と同じく黙らずに知らせる\n const nested = findNestedForBlock(document.body);\n if (nested !== null) {\n const [inner, outer] = nested;\n console.warn(\n `[@wcstack/state] SSR: \"for: ${inner.path}\" in \"${outer.type}: ${outer.path}\" (known limitation). Falling back to full render.`\n );\n Ssr.cleanupDom(root);\n return false;\n }\n\n // <wcs-ssr> からテンプレートを fragmentInfoByUUID に復帰\n for (const ssrNode of ssrElements) {\n restoreFragments(root, ssrNode as Ssr);\n }\n\n // SSR テキストバインディングを @@: 形式に復元。\n // **ブロックを集める前に**行う。後回しにしていたので、`for` / `if` の中の `{{ }}` は\n // `collectBindingsFromLiveNodes` の時点でまだ `@@wcs-text-start/end` のコメント対であり、\n // 行のバインディングとして登録されなかった。そのうえで `restoreTextBindings` は start/end の\n // 間(=サーバーが描いたテキスト)を捨てるので、**行の `{{ }}` が空になったまま二度と戻らない**\n // (`data-wcs=\"textContent: …\"` は属性なのでこの穴に落ちない)。\n Ssr.restoreTextBindings(document.body);\n\n // SSR ブロック境界コメントから既存 DOM を Content 化\n const blocks = collectSsrBlocks(document.body);\n const rowsByUuid: Map<string, IListIndex[]> = new Map();\n const blockBindings = hydrateBlocks(document.body, blocks, rowsByUuid);\n\n // ブロック境界コメント (start/end) を除去\n Ssr.removeBlockBoundaryComments(document.body);\n\n // <wcs-ssr> を一時除去(バインディング走査に含めない)\n const ssrParents: { el: Element, parent: Node, next: Node | null }[] = [];\n for (const el of ssrElements) {\n if (el.parentNode) {\n ssrParents.push({ el, parent: el.parentNode, next: el.nextSibling });\n el.remove();\n }\n }\n\n // 構造プレースホルダーコメント (@@wcs-for:uuid 等) は残す\n // → バインディング走査で拾われ、状態変化時の再レンダリングに使われる\n\n // ノードとバインディングを収集(hydrateBlocks で登録済みのブロックのノードは飛ばされる)。\n // ここで集めたノードのループ文脈は触らない(#258)。以前はブロックの外のノードの文脈を空に\n // 戻していたが、この時点で文脈を持つノードは hydrateBlocks が行の文脈を与えたものだけで、\n // 戻す意味は無かった。印(`data-wcs-completed`)の付かないコメントは行のものまで空に戻され、\n // for の行の中の `if` の置き場が文脈を失い、切り替えるたびに `list index is null` で失敗していた\n const [, allBindings, deferredSpreads] = collectNodesAndBindingInfos(document.body);\n\n // バインディングを構造系とそれ以外に分離\n const normalBindings: IBindingInfo[] = [];\n const structuralBindings: IBindingInfo[] = [];\n const bindingSession = getOrCreateBindingSession(document.body);\n const initializedBindings = bindingSession.initialize(allBindings);\n // 未定義カスタム要素への `...: path` を `whenDefined` 後の配線として予約する。\n // 通常経路(`bindings/initializeBindings.ts`)はこれを行うが、ハイドレーション経路は\n // `collectNodesAndBindingInfos` の 3 要素目を捨てていたので、SSR したページでだけ\n // spread が**永久に配線されなかった**(実測: 通常経路は whenDefined を予約、\n // ハイドレーション経路は 1 件も予約しない)\n scheduleDeferredSpreads(deferredSpreads, null, bindingSession);\n\n for (const binding of initializedBindings) {\n if (binding.bindingType === \"event\") continue;\n if (STRUCTURAL_TYPES.has(binding.bindingType)) {\n structuralBindings.push(binding);\n } else if (binding.statePathName.includes(WILDCARD)) {\n // for ブロック内のバインディング → Content のバインディングとして登録済み\n continue;\n } else {\n normalBindings.push(binding);\n }\n }\n\n // for バインディングの lastListValue を初期値として設定\n // (次回の状態変化時に差分計算の基準になる)\n for (const binding of structuralBindings) {\n if (binding.bindingType === 'for') {\n const absAddr = getAbsoluteStateAddressByBinding(binding);\n const rootNode = binding.replaceNode.getRootNode() as Node;\n const stateElement = getStateElement(rootNode);\n if (stateElement) {\n stateElement.createState(\"readonly\", (state) => {\n // 描いた行の並びは for のフィルタ(`for: items|…`)を通した値 — CSR の applyChangeToFor が受け取り、\n // 基準に記録する値と同じ。素の値で組んでいたので、行を減らす・並べ替えるフィルタでは台帳の行が\n // 値の要素より少なく、次の書き込みの差分が投げた\n const value = getFilteredValue(state[binding.statePathName], binding.outFilters);\n if (Array.isArray(value)) {\n // 行(listIndex)は配列ごとに 1 組。同じ配列を描く for は同じ行を紐づける(#258・#351 — hydrateBlocks)\n const rows = rowsByUuid.get(binding.uuid as string);\n if (rows) setListIndexesByList(value, rows);\n setLastListValueByAbsoluteStateAddress(absAddr, value);\n // サーバーが描いた並びを、この for が描いた並びとして記録する(クライアントで描いた for と同じく、\n // 要素の書き込みが描画の基準を書き込む前の写しへ移せるように — #351)\n hydrateSetRenderedList(binding.node, value);\n // 描画の基準と同時に state 側の基準も進める(E1。applyChangeFromBindings と対称)\n setStateListBaseline(absAddr, value);\n }\n });\n }\n }\n }\n\n // 初回値の適用(構造バインディングは SSR 描画済みなので除く)。SSR ブロック(for の行・if の中身)の\n // 中のバインディングも適用する(#258 X6): getter の依存辺は getter を評価したときにしか張られない\n // ので、適用しないと行の `items.*.double` は `items.*.n` を書いても一度も再評価されず、サーバーが\n // 書いたテキストのまま固まる。値は SSR と同じ state から読むのでテキストは変わらない\n applyChangeFromBindings([...normalBindings, ...blockBindings]);\n\n // <wcs-ssr> を元に戻す\n for (const { el, parent, next } of ssrParents) {\n parent.insertBefore(el, next);\n }\n\n // hydrateProps 復元。\n // 索引は **1 回だけ** 作る。props 1 件ごとに `querySelector('[data-wcs-ssr-id=\"…\"]')` を\n // 回していたので、props に載る束縛(textContent 等)の行数に対して二次だった\n // (実測 800 / 1600 / 3200 行で 109 / 297 / 1207 ms。props が 0 件の `value` 行は線形)\n const targetBySsrId = new Map<string, Element>();\n for (const el of root.querySelectorAll('[data-wcs-ssr-id]')) {\n targetBySsrId.set(el.getAttribute('data-wcs-ssr-id') as string, el);\n }\n for (const ssrNode of root.querySelectorAll(config.tagNames.ssr)) {\n for (const [id, propMap] of Object.entries((ssrNode as Ssr).hydrateProps)) {\n const target = targetBySsrId.get(id);\n if (!target) continue;\n for (const [propName, value] of Object.entries(propMap)) {\n // `bind-component` が束ねるプロパティ(丸ごとマウント `state: items.*`)は戻さない(#258)。\n // サーバーでは行が fragment の中で作られ、子の `<wcs-state bind-component>` の宣言より先に\n // ホストの束縛が素の書き込みとして走るので、配線の値がここに載る。戻すと子の完了前に作者の\n // state オブジェクトを親の値の写しで置き換え、全キーが私有に化けて(誤った\n // `mount-own-key-shadow`)親への書き込みに追従しなくなる。宣言済みの (要素, プロパティ) に\n // 書かないのは、親スコープの適用(apply/applyChange.ts の resolveCustomElementApply)と同じ規則\n if (componentApplyHooks?.isDeclared(target, propName)) continue;\n (target as any)[propName] = value;\n }\n }\n }\n\n // SSR の対応付け用属性を除去する。成功経路だけ残していたので、バージョン不一致の\n // フォールバック(`Ssr.cleanupDom`)と非対称だった — ハイドレーション済みの DOM に\n // サーバー側の帳簿が残り、`[data-wcs-ssr-id]` を見る CSS / 再ハイドレーションに漏れる\n for (const el of root.querySelectorAll('[data-wcs-ssr-id]')) {\n el.removeAttribute('data-wcs-ssr-id');\n }\n\n return true;\n}\n\n/** @internal テスト用 */\nexport const __test = {\n collectSsrBlocks,\n collectBindingsFromLiveNodes,\n hydrateBlocks,\n findPlaceholderComment,\n restoreFragments,\n};\n","/**\n * ssr/install.ts — SSR 機能の install(設計案 H8、S5)。core の受け口(core/ssrHooks.ts と\n * registerComponents の definer)へこの機能の実装を置き、ssr-snapshot プロトコルを提供する。\n * 従来 `State` と `stateElementByName` と `registerComponents` に直書きされていた分岐で、\n * 理由のコメントは元の位置から移してある。\n */\nimport { config } from \"../config\";\nimport type { IStateElement } from \"../components/types\";\nimport { ISsrHooks, setSsrHooks } from \"../core/ssrHooks\";\nimport { registerComponentDefiner } from \"../registerComponents\";\nimport { getBindingsReady } from \"../stateElementByName\";\nimport { VERSION } from \"../version\";\nimport { registerSsrSnapshotBuilder } from \"./buildSsrDocument\";\nimport { hydrateBindings } from \"./hydrateBindings\";\nimport { Ssr } from \"./Ssr\";\n\nexport const ssrFeatureHooks: ISsrHooks = {\n hydrate: hydrateBindings,\n loadState(element) {\n const root = element.parentNode;\n if (!root) return null;\n const ssrEl = Ssr.find(root);\n if (!ssrEl) return null;\n const data = ssrEl.stateData;\n return Object.keys(data).length > 0 ? data : null;\n },\n async emitSnapshot(element) {\n await getBindingsReady((element as unknown as IStateElement).rootNode);\n const stateData = Ssr.extractStateData(element);\n const ssrEl = document.createElement(config.tagNames.ssr);\n ssrEl.setAttribute(\"version\", VERSION);\n // スナップショットの範囲はこの state のツリー — モジュール寿命の台帳に残った\n // 別のレンダリングのテンプレートを載せない(リクエスト間のデータ漏れ)\n Ssr.buildContent(ssrEl, stateData, (element as unknown as IStateElement).rootNode);\n element.parentNode?.insertBefore(ssrEl, element);\n },\n};\n\nlet installed = false;\n/** 冪等。full / auto では `bootstrapState()` が呼ぶ */\nexport function installSsr(): void {\n if (installed) return;\n installed = true;\n setSsrHooks(ssrFeatureHooks);\n registerComponentDefiner((registry) => {\n if (!registry.get(config.tagNames.ssr)) {\n registry.define(config.tagNames.ssr, Ssr);\n }\n });\n // ssr-snapshot プロトコルの提供(docs/ssr-router-design.md §5)。renderToString が\n // `<wcs-ssr>` 生成をサーバー主導の最終パスへ回せるようにする。登録は冪等\n registerSsrSnapshotBuilder();\n}\n","/**\n * features/ssr.ts — サーバー描画とハイドレーション(@wcstack/state/features/ssr)。\n */\nimport type { IStateFeature } from \"../core/features\";\nimport { installSsr } from \"../ssr/install\";\n\nexport const ssr: IStateFeature = {\n name: \"ssr\",\n install(): void {\n installSsr();\n },\n};\nexport default ssr;\n"],"names":["SSR_PLACEHOLDER_COMMENT","SSR_BLOCK_START","SSR_BLOCK_END","SSR_TEXT_START","escapeJsonForScript","json","replace","collectComments","root","match","walker","document","createTreeWalker","NodeFilter","SHOW_COMMENT","found","nextNode","comment","currentNode","data","push","isPlaceholder","test","isBlockStart","isBlockBoundary","structuralBindText","result","bindingType","text","statePathName","filter","outFilters","literals","args","filterName","length","map","arg","i","split","join","cloneFragmentForSnapshot","fragmentInfo","clone","fragment","cloneNode","nodeInfo","nodeInfos","commentData","getNormalizedTextCommentData","resolveNodePath","nodePath","target","parentNode","replaceChild","createComment","Ssr","HTMLElementBase","_stateData","_templates","_hydrateProps","version","this","getAttribute","stateData","_loadStateData","templates","_loadTemplates","hydrateProps","_loadHydrateProps","getTemplate","uuid","get","verifyVersion","serverVersion","serverParts","clientParts","VERSION","setStateData","setHydrateProps","props","script","querySelector","JSON","parse","textContent","Map","querySelectorAll","tpl","id","set","find","tagName","config","tagNames","ssr","parentEl","Element","Document","documentElement","extractStateData","stateEl","raw","__state","key","Object","keys","startsWith","descriptor","getOwnPropertyDescriptor","undefined","value","buildContent","ssrEl","scanRoot","ownerDocument","ssrBlockRemoval","seen","rowEnds","start","type","info","exec","prev","previousSibling","end","node","next","nextSibling","remove","removeStaleBlockBoundaries","jsonScript","createElement","setAttribute","stringify","appendChild","pending","placeholder","shift","slice","indexOf","has","getFragmentInfoByUUID","collectReachableFragments","bindAttributeName","parseBindTextResult","content","ssrNodes","getAllSsrPropertyNodes","propsData","isConnected","entries","getSsrProperties","entry","propName","propsScript","clearSsrPropertyStore","removeBlockBoundaryComments","removeStructuralComments","restoreTextBindings","d","path","bindComment","insertBefore","sibling","endPattern","nodeType","Node","COMMENT_NODE","removeChild","cleanupDom","body","ssrElements","templateByUuid","ssrNode","startComment","restorePlaceholders","scope","restored","bindAttr","imported","importNode","childNodes","child","Array","from","ssrIdElements","el","removeAttribute","builder","protocol","build","stateTag","state","ssrTag","stateElements","previousElementSibling","toLowerCase","getRootNode","reset","clearFragmentInfos","STRUCTURAL_TYPES","Set","parseBlockStart","rest","index","parseInt","nodes","getBlockSubscriberNodes","ELEMENT_NODE","element","hasAttribute","children","some","localName","isLightDomMappedStateElement","getSubscriberNodes","parseCommentNode","collectBindingsFromLiveNodes","subscriberNodes","allBindings","deferredSpreads","collectNodesAndBindingInfosOf","bindingSession","BindingSession","bindingInfos","initialize","registerAddress","applyOnReconnect","TEXT_BINDING_COMMENT","collectBlockBindings","out","bindings","binding","collectOwnNodes","block","blockByStart","own","nested","scheduleBlockSpreads","loopContext","session","indexBindings","spreads","markNodeRegistered","scheduleDeferredSpreads","readHydratedList","placeholderComment","stateElement","getStateElement","list","createState","getFilteredValue","planFilters","isArray","placeholderData","for","commentForPrefix","if","commentIfPrefix","elseif","commentElseIfPrefix","else","commentElsePrefix","findPlaceholderComment","pattern","restoreFragments","rootNode","levelByUuid","components","findNestedLightDomComponents","size","level","lastIfByLevel","bindText","parseBindTextsForElement","lastIfParseResult","createNotFilter","reverse","forPath","optimizeFragment","expandShorthandPaths","collectStructuralFragments","getFragmentNodeInfos","setFragmentInfoByUUID","ssrFeatureHooks","hydrate","async","waitForStateInitialize","console","warn","open","pop","outer","at","findNestedForBlock","inner","blocks","collectSsrBlocks","rowsByUuid","blockBindings","rowsByList","claimed","subscribers","add","ranged","marker","after","replaceNode","createContentFromNodes","setBindingSessionByContent","setBindingsByContent","setNodesByContent","isIndexBinding","ALL_INDEX_BITS","setIndexBindingsByContent","rows","listIndex","createListIndex","hydrateSetContent","hydrateSetLastNode","lastNode","setContentByNode","pathInfo","getPathInfo","WILDCARD","stateAddress","createStateAddress","bindLoopContextToContent","registerPathInfo","previous","getLoopContextByNode","hydrateBlocks","ssrParents","parent","collectNodesAndBindingInfos","normalBindings","structuralBindings","getOrCreateBindingSession","initializedBindings","includes","absAddr","getAbsoluteStateAddressByBinding","setListIndexesByList","setLastListValueByAbsoluteStateAddress","hydrateSetRenderedList","setStateListBaseline","applyChangeFromBindings","targetBySsrId","propMap","componentApplyHooks","isDeclared","loadState","emitSnapshot","getBindingsReady","installed","installSsr","setSsrHooks","registerComponentDefiner","registry","define","globals","globalThis","SSR_SNAPSHOT_BUILDER_KEY","registerSsrSnapshotBuilder","name","install"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ssr.js","sources":["../../../../../src/ssr/Ssr.ts","../../../../../src/ssr/buildSsrDocument.ts","../../../../../src/ssr/hydrateBindings.ts","../../../../../src/ssr/install.ts","../../../../../src/features/ssr.ts"],"sourcesContent":["import { config, ssrBlockRemoval } from \"../config\";\nimport { IState } from \"../types\";\nimport { VERSION } from \"../version\";\nimport { getFragmentInfoByUUID } from \"../structural/fragmentInfoByUUID\";\nimport { getNormalizedTextCommentData } from \"../structural/getFragmentNodeInfos\";\nimport { resolveNodePath } from \"../structural/resolveNodePath\";\nimport { IFragmentInfo } from \"../structural/types\";\nimport { ParseBindTextResult } from \"../bindTextParser/types\";\nimport { getAllSsrPropertyNodes, getSsrProperties, clearSsrPropertyStore } from \"../apply/ssrPropertyStore\";\nimport { HTMLElementBase } from \"../platform/HTMLElementBase\";\n\nexport interface ISsrElement {\n readonly version: string;\n readonly stateData: IState;\n readonly templates: Map<string, HTMLTemplateElement>;\n readonly hydrateProps: Record<string, Record<string, unknown>>;\n getTemplate(uuid: string): HTMLTemplateElement | null;\n verifyVersion(): boolean;\n}\n\n// SSR コメントパターン\nconst SSR_PLACEHOLDER_COMMENT = /^@@wcs-(?:for|if|elseif|else):[^-]/;\nconst SSR_BLOCK_START = /^@@wcs-(for|if|elseif|else)-start:(.+)$/;\nconst SSR_BLOCK_END = /^@@wcs-(for|if|elseif|else)-end:(.+)$/;\nconst SSR_TEXT_START = /^@@wcs-text-start:(.+)$/;\n\nexport {\n SSR_PLACEHOLDER_COMMENT,\n SSR_BLOCK_START,\n SSR_BLOCK_END,\n SSR_TEXT_START,\n};\n\n/**\n * script 要素へ埋め込む JSON を HTML パーサから保護する。\n * HTML 直列化時、script の中身は生のまま出力されるため、state 値に\n * \"</script>\" や \"<!--\" を含む文字列があると script を脱出できてしまう。\n * \"<\" \">\" \"&\" と U+2028/U+2029 を JSON の \\uXXXX エスケープへ置換する\n * (JSON.parse では元の文字列と等価に復元される)。\n */\nfunction escapeJsonForScript(json: string): string {\n return json\n .replace(/</g, '\\\\u003c')\n .replace(/>/g, '\\\\u003e')\n .replace(/&/g, '\\\\u0026')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029');\n}\n\n/**\n * **このドキュメントから到達できる**構造テンプレートの uuid だけを、文書順・幅優先で集める。\n *\n * `fragmentInfoByUUID` はモジュール寿命の台帳で削除の口が無く、`getAllFragmentUUIDs()` を\n * そのまま直列化すると、同じプロセスで描いた**別のドキュメント**のテンプレートまで\n * `<wcs-ssr>` に載る(実測: 同じページを繰り返すと 2 → 12 テンプレートに増え、ページ A の\n * `for: secretItems` がページ B の HTML に混入した)。uuid は単調増加で再利用されないので、\n * 「この文書のプレースホルダから辿れるか」は正確な所属判定になる。\n *\n * 入れ子のテンプレートは親の fragment の中にプレースホルダコメントとして居る(`if` が偽で\n * 一度も描かれていない枝の中身も含む)ので、辿りは fragment へ再帰する。\n */\nfunction collectReachableFragments(scanRoot: Node): Map<string, IFragmentInfo> {\n const found = new Map<string, IFragmentInfo>();\n const pending: Node[] = [scanRoot];\n while (pending.length > 0) {\n for (const placeholder of collectComments(pending.shift() as Node, isPlaceholder)) {\n const data = placeholder.data;\n const uuid = data.slice(data.indexOf(':') + 1);\n // 入れ子のプレースホルダは行ごとに現れるので重複する。台帳に無い uuid(別の\n // レンダリングの痕跡・後始末の順序違い)はそのまま落とす\n if (found.has(uuid)) continue;\n const info = getFragmentInfoByUUID(uuid);\n if (info === null) continue;\n found.set(uuid, info);\n pending.push(info.fragment);\n }\n }\n return found;\n}\n\n/**\n * `root` 以下のコメントのうち `match` が真を返すものを文書順で集める。\n *\n * この 1 本に寄せているのは、走査の**途中で DOM を壊す**呼び手が多いからでもある\n * (境界コメントの除去・テキスト束縛の復元・プレースホルダの差し替え)。先に集めてから\n * 触るという規則をここに固定しておくと、各所で TreeWalker を書き写さずに済む。\n */\nexport function collectComments(root: Node, match: (data: string) => boolean): Comment[] {\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT);\n const found: Comment[] = [];\n while (walker.nextNode()) {\n const comment = walker.currentNode as Comment;\n if (match(comment.data)) {\n found.push(comment);\n }\n }\n return found;\n}\n\nexport const isPlaceholder = (data: string): boolean => SSR_PLACEHOLDER_COMMENT.test(data);\nexport const isBlockStart = (data: string): boolean => SSR_BLOCK_START.test(data);\nexport const isBlockBoundary = (data: string): boolean => SSR_BLOCK_START.test(data) || SSR_BLOCK_END.test(data);\n\n/**\n * サーバー出力から、取り残されたブロック境界コメントの組を間に残ったものごと除く(#356)。\n *\n * 境界は枝・行の Content の外に置かれる(apply/applyChangeToIf・applyChangeToFor)ので、サーバー描画中に\n * 祖先の `if:` が隠れる・行が消えると、Content のノード(入れ子の置き場を含む)だけが外れ、入れ子の境界の\n * 組が文書に残る。残った組は、ハイドレーションで「別のブロックの中の `for`」(全描画に倒れる)や、\n * 描いていない枝として読まれていた。隠してから戻した `if:` も、前の組を後ろに残す。\n *\n * 生きている組の開始コメントは自分の置き場の直後に居る(`for:` の行は、同じ `for:` の生きている前の行の\n * 終了コメントの直後)。そうでない組は取り残されたもので、間に残っているのも取り残された組だけ\n * (外した Content のノードは外れている)。組は文書順に読むので、前の行が生きているかは読み終えている。\n * 生きている組の中は辿らない(辿る費用は取り残された組の分だけ)。\n */\nexport function removeStaleBlockBoundaries(root: Node): void {\n // 生きている `for:` の行の終了コメントの data → その `for:` の uuid(行ごとに添字が違うので data で引ける)\n const rowEnds = new Map<string | undefined, string>();\n for (const start of collectComments(root, isBlockStart)) {\n // 外側の取り残された組と一緒に外れた\n if (start.parentNode === null) continue;\n const [, type, info] = SSR_BLOCK_START.exec(start.data) as RegExpExecArray;\n const uuid = info.split(\":\")[0];\n const prev = (start.previousSibling as Comment | null)?.data;\n const end = `@@wcs-${type}-end:${info}`;\n if (prev === `@@wcs-${type}:${uuid}` || rowEnds.get(prev) === uuid) {\n if (type === \"for\") rowEnds.set(end, uuid);\n continue;\n }\n for (let node: ChildNode | null = start; node !== null;) {\n const next: ChildNode | null = node.nextSibling;\n node.remove();\n node = (node as Comment).data === end ? null : next;\n }\n }\n}\n\n/**\n * `<wcs-ssr>` のテンプレートの束縛の文。**出力フィルタも書き戻す** — `${bindingType}: ${statePathName}` と\n * 組み直していたので、`if: x|not` が `if: x` としてハイドレーションされて条件が反転し、`else:`(クライアントが\n * 直前の `if:` の否定として組む)もフィルタの無い条件の否定になっていた。文字列の引数は `'…'` で囲み(`'` は\n * `\"'\"` を挟んで繋ぐ — 引数の文法に逃がしは無く、引用符の区間は連ねられる)、型付きの値(数値・真偽・null)は\n * 原文のまま書くので、読み直すと同じ引数と値(要件 B9)になる。`else:` の条件はクライアントが組み直す。\n */\nexport function structuralBindText(result: ParseBindTextResult): string {\n if (result.bindingType === \"else\") return \"else:\";\n let text = `${result.bindingType}: ${result.statePathName}`;\n for (const filter of result.outFilters) {\n const literals = filter.literals ?? filter.args;\n text += `|${filter.filterName}`;\n if (filter.args.length > 0) {\n text += `(${filter.args.map((arg, i) => typeof literals[i] === \"string\" ? `'${arg.split(\"'\").join(`'\"'\"'`)}'` : arg).join(\",\")})`;\n }\n }\n return text;\n}\n\n/**\n * 直列化用のクローン。`getFragmentNodeInfos` がテンプレート登録時に空 Text へ潰した\n * テキスト束縛のコメントを、**クローンの上でだけ**原文へ戻す。\n *\n * 戻さないと `for` / `if` テンプレートの中の `{{ }}` がマークアップから消え、\n * ハイドレーションが束縛を復元できず、その行のテキストが**恒久的に空**になる。\n * 元の fragment は生きているページの正本なので絶対に壊さない。\n */\nfunction cloneFragmentForSnapshot(fragmentInfo: IFragmentInfo): DocumentFragment {\n const clone = fragmentInfo.fragment.cloneNode(true) as DocumentFragment;\n for (const nodeInfo of fragmentInfo.nodeInfos) {\n const commentData = getNormalizedTextCommentData(\n resolveNodePath(fragmentInfo.fragment, nodeInfo.nodePath));\n if (commentData === null) continue;\n // nodePath はこの fragment から採ったもので、クローンは同形。ここまで来た枝は\n // 必ず解決でき、正規化された Text は必ず親を持つ(fragment 直下でも親は fragment)。\n // 同じ位置への置換なので、以降の nodePath は変わらない(正規化と対称)\n const target = resolveNodePath(clone, nodeInfo.nodePath) as Node;\n (target.parentNode as Node).replaceChild(document.createComment(commentData), target);\n }\n return clone;\n}\n\nexport class Ssr extends HTMLElementBase implements ISsrElement {\n private _stateData: IState | null = null;\n private _templates: Map<string, HTMLTemplateElement> | null = null;\n private _hydrateProps: Record<string, Record<string, unknown>> | null = null;\n\n get version(): string {\n return this.getAttribute('version') || '';\n }\n\n get stateData(): IState {\n if (this._stateData === null) {\n this._stateData = this._loadStateData();\n }\n return this._stateData;\n }\n\n get templates(): Map<string, HTMLTemplateElement> {\n if (this._templates === null) {\n this._templates = this._loadTemplates();\n }\n return this._templates;\n }\n\n get hydrateProps(): Record<string, Record<string, unknown>> {\n if (this._hydrateProps === null) {\n this._hydrateProps = this._loadHydrateProps();\n }\n return this._hydrateProps;\n }\n\n getTemplate(uuid: string): HTMLTemplateElement | null {\n return this.templates.get(uuid) ?? null;\n }\n\n /**\n * サーバーの SSR バージョンとクライアントの state バージョンを検証する。\n * メジャー・マイナーバージョンが一致すればtrue。\n * version 属性がない場合は検証スキップ(true)。\n */\n verifyVersion(): boolean {\n const serverVersion = this.version;\n if (!serverVersion) return true;\n const serverParts = serverVersion.split('.');\n const clientParts = VERSION.split('.');\n // メジャー・マイナーが一致すれば互換\n return serverParts[0] === clientParts[0] && serverParts[1] === clientParts[1];\n }\n\n setStateData(data: IState): void {\n this._stateData = data;\n }\n\n setHydrateProps(props: Record<string, Record<string, unknown>>): void {\n this._hydrateProps = props;\n }\n\n private _loadStateData(): IState {\n const script = this.querySelector(\n `script[type=\"application/json\"]:not([data-wcs-ssr-props])`\n );\n if (!script) return {};\n try {\n return JSON.parse(script.textContent || '{}');\n } catch {\n return {};\n }\n }\n\n private _loadTemplates(): Map<string, HTMLTemplateElement> {\n const map = new Map<string, HTMLTemplateElement>();\n const templates = this.querySelectorAll<HTMLTemplateElement>('template[id]');\n for (const tpl of templates) {\n const id = tpl.getAttribute('id');\n if (id) {\n map.set(id, tpl);\n }\n }\n return map;\n }\n\n private _loadHydrateProps(): Record<string, Record<string, unknown>> {\n const script = this.querySelector('script[data-wcs-ssr-props]');\n if (!script) return {};\n try {\n return JSON.parse(script.textContent || '{}');\n } catch {\n return {};\n }\n }\n\n static find(root: Node): ISsrElement | null {\n const tagName = config.tagNames.ssr;\n const parentEl = root instanceof Element\n ? root\n : root instanceof Document\n ? root.documentElement\n : null;\n if (!parentEl) return null;\n const el = parentEl.querySelector(tagName);\n return el as ISsrElement | null;\n }\n\n /**\n * stateData と構造テンプレート・プロパティから <wcs-ssr> の中身を構築する。\n * server パッケージの renderToString から呼ばれる。\n */\n /**\n * wcs-state 要素から $ プレフィックスや関数を除いたデータを抽出する。\n */\n static extractStateData(stateEl: Element): Record<string, any> {\n const raw = (stateEl as any).__state;\n if (!raw || typeof raw !== 'object') return {};\n const data: Record<string, any> = {};\n for (const key of Object.keys(raw)) {\n if (key.startsWith('$')) continue;\n // **アクセサは評価しない。** スナップショットが運ぶのはデータで、派生値は\n // クライアントが同じ宣言から作り直す。ここは Object.entries で舐めていたので、\n // own かつ enumerable な getter を**生の state オブジェクト**を this にして\n // 評価していた — proxy の上でしか意味を持たない本体(`this[\"items.*.n\"]` や\n // `this.$getAll(...)`)が、パス getter なら NaN → JSON の null で静かに壊れ、\n // `$getAll` を呼ぶ getter なら TypeError でページ全体の SSR を落としていた\n // (docs/state-recursive-path-impl-plan.md §7)。\n const descriptor = Object.getOwnPropertyDescriptor(raw, key);\n if (descriptor !== undefined && typeof descriptor.get === 'function') continue;\n const value = (raw as Record<string, unknown>)[key];\n if (typeof value !== 'function') {\n data[key] = value;\n }\n }\n return data;\n }\n\n /**\n * @param scanRoot このスナップショットが属するツリー(既定は `ssrEl` の document)。\n * テンプレートと props はここから到達できるものだけを載せる — モジュール寿命の台帳に\n * 残った**別のレンダリング**の分を混ぜないため(リクエスト間のデータ漏れ)。\n */\n static buildContent(ssrEl: Element, stateData: Record<string, any>, scanRoot?: Node): void {\n const root: Node = scanRoot ?? (ssrEl.ownerDocument as Document);\n // スナップショットと同じ時点で、出力の本文から取り残された境界を除く(inline 生成・最終パスの両方が通る)。\n // 取り残しは描いた枝・行を外したときにしか生じないので、外していなければ探さない\n if (ssrBlockRemoval.seen) removeStaleBlockBoundaries(root);\n // 初期データ JSON\n const jsonScript = document.createElement('script');\n jsonScript.setAttribute('type', 'application/json');\n jsonScript.textContent = escapeJsonForScript(JSON.stringify(stateData));\n ssrEl.appendChild(jsonScript);\n\n // この文書のプレースホルダから辿れるテンプレートだけを復元して格納\n for (const [uuid, fragmentInfo] of collectReachableFragments(root)) {\n const tpl = document.createElement('template');\n tpl.setAttribute('id', uuid);\n\n tpl.setAttribute(config.bindAttributeName, structuralBindText(fragmentInfo.parseBindTextResult));\n\n tpl.content.appendChild(cloneFragmentForSnapshot(fragmentInfo));\n\n ssrEl.appendChild(tpl);\n }\n\n // 属性で代替不可なプロパティをハイドレーション用に格納。\n // **この文書に今も繋がっているノードだけ**を載せる — props の台帳(apply/ssrPropertyStore)は\n // `buildContent` の末尾でしか空にならないので、`enable-ssr` の無いページを 1 枚描くと\n // 次のレンダリングの props JSON に前のページの値が載っていた(実測)\n const ownerDocument = ssrEl.ownerDocument;\n const ssrNodes = getAllSsrPropertyNodes();\n if (ssrNodes.length > 0) {\n const propsData: Record<string, Record<string, unknown>> = {};\n for (let i = 0; i < ssrNodes.length; i++) {\n const node = ssrNodes[i];\n if (!node.isConnected || node.ownerDocument !== ownerDocument) continue;\n const entries = getSsrProperties(node);\n if (entries.length === 0) continue;\n const id = `wcs-ssr-${i}`;\n (node as Element).setAttribute('data-wcs-ssr-id', id);\n const props: Record<string, unknown> = {};\n for (const entry of entries) {\n props[entry.propName] = entry.value;\n }\n propsData[id] = props;\n }\n if (Object.keys(propsData).length > 0) {\n const propsScript = document.createElement('script');\n propsScript.setAttribute('type', 'application/json');\n propsScript.setAttribute('data-wcs-ssr-props', '');\n propsScript.textContent = escapeJsonForScript(JSON.stringify(propsData));\n ssrEl.appendChild(propsScript);\n }\n }\n\n clearSsrPropertyStore();\n }\n\n /**\n * SSR ブロック境界コメント (@@wcs-*-start/end) を除去する\n */\n static removeBlockBoundaryComments(root: Node): void {\n for (const comment of collectComments(root, isBlockBoundary)) {\n comment.remove();\n }\n }\n\n /**\n * SSR の構造プレースホルダーコメント (@@wcs-for:uuid 等) を除去する\n */\n static removeStructuralComments(root: Node): void {\n for (const comment of collectComments(root, isPlaceholder)) {\n comment.remove();\n }\n }\n\n /**\n * SSR テキストバインディングコメントを復元する。\n * <!--@@wcs-text-start:path-->text<!--@@wcs-text-end:path-->\n * → <!--@@: path--> (バインディングシステムが認識する形式)\n */\n static restoreTextBindings(root: Node): void {\n for (const comment of collectComments(root, (d) => SSR_TEXT_START.test(d))) {\n const path = (SSR_TEXT_START.exec(comment.data) as RegExpExecArray)[1];\n const bindComment = document.createComment(`@@: ${path}`);\n comment.parentNode!.insertBefore(bindComment, comment);\n\n let sibling: Node | null = comment.nextSibling;\n comment.remove();\n\n const endPattern = `@@wcs-text-end:${path}`;\n while (sibling) {\n const next: Node | null = sibling.nextSibling;\n if (sibling.nodeType === Node.COMMENT_NODE && (sibling as Comment).data === endPattern) {\n sibling.parentNode!.removeChild(sibling);\n break;\n }\n sibling.parentNode!.removeChild(sibling);\n sibling = next;\n }\n }\n }\n\n /**\n * SSR DOM をクリーンアップし、buildBindings が動作できる状態に戻す。\n * バージョン不一致時のフォールバック用。\n *\n * 1. SSR ブロック境界コメント間のレンダリング済みノードを除去\n * 2. SSR テキストバインディングを @@: 形式に復元\n * 3. プレースホルダーコメントを <wcs-ssr> 内のテンプレートで差し替え\n * 4. data-wcs-ssr-id 属性を除去\n * 5. <wcs-ssr> を除去\n */\n static cleanupDom(root: Document): void {\n const body = document.body;\n\n // <wcs-ssr> からテンプレート UUID マップを構築(カスタム要素未定義でも動作するよう DOM 直接走査)\n const ssrElements = root.querySelectorAll(config.tagNames.ssr);\n const templateByUuid = new Map<string, HTMLTemplateElement>();\n for (const ssrNode of ssrElements) {\n const templates = ssrNode.querySelectorAll<HTMLTemplateElement>('template[id]');\n for (const tpl of templates) {\n const id = tpl.getAttribute('id');\n if (id) {\n templateByUuid.set(id, tpl);\n }\n }\n }\n\n // SSR ブロック境界コメント間のレンダリング済みノードと境界コメントを除去\n for (const startComment of collectComments(body, isBlockStart)) {\n const match = SSR_BLOCK_START.exec(startComment.data)!;\n const type = match[1];\n const info = match[2];\n const endPattern = `@@wcs-${type}-end:${info}`;\n let sibling = startComment.nextSibling;\n while (sibling) {\n const next = sibling.nextSibling;\n if (sibling.nodeType === Node.COMMENT_NODE && (sibling as Comment).data === endPattern) {\n sibling.remove();\n break;\n }\n sibling.remove();\n sibling = next;\n }\n startComment.remove();\n }\n\n // SSR テキストバインディングを @@: 形式に復元\n Ssr.restoreTextBindings(body);\n\n // プレースホルダーコメント (@@wcs-for:uuid 等) をテンプレートに差し替える。\n // **差し替えたテンプレートの中身にも掛ける**(#258): スナップショットのテンプレートは平らで\n // (入れ子のテンプレートは親の中身にプレースホルダとして居る — collectReachableFragments)、\n // 中身のプレースホルダが指すのはサーバーの uuid。クライアントの台帳には無いので、残すと\n // `text: <uuid>` と解釈され(binding-path-missing)、入れ子の内側が一度も描かれなかった\n // (実 Chromium で実測。同じモジュールでサーバー描画する vitest では台帳が残っていて見えない)\n const restorePlaceholders = (scope: Node): void => {\n for (const comment of collectComments(scope, isPlaceholder)) {\n const tpl = templateByUuid.get(comment.data.split(':')[1]);\n if (tpl) {\n const restored = document.createElement('template') as HTMLTemplateElement;\n const bindAttr = tpl.getAttribute(config.bindAttributeName);\n if (bindAttr) restored.setAttribute(config.bindAttributeName, bindAttr);\n const imported = document.importNode(tpl.content, true);\n if (imported.childNodes.length > 0) {\n restored.content.appendChild(imported);\n } else {\n for (const child of Array.from(tpl.childNodes)) {\n restored.content.appendChild(document.importNode(child, true));\n }\n }\n restorePlaceholders(restored.content);\n comment.parentNode!.replaceChild(restored, comment);\n }\n }\n };\n restorePlaceholders(body);\n\n // data-wcs-ssr-id 属性を除去\n const ssrIdElements = root.querySelectorAll('[data-wcs-ssr-id]');\n for (const el of ssrIdElements) {\n el.removeAttribute('data-wcs-ssr-id');\n }\n\n // <wcs-ssr> を除去\n for (const el of ssrElements) {\n el.remove();\n }\n }\n}\n","import { config, ssrBlockRemoval } from \"../config\";\nimport { Ssr } from \"./Ssr\";\nimport { VERSION } from \"../version\";\nimport { IWcsSsrSnapshotBuilder, SSR_SNAPSHOT_BUILDER_KEY } from \"../protocol/ssrSnapshot\";\nimport { clearSsrPropertyStore } from \"../apply/ssrPropertyStore\";\nimport { clearFragmentInfos } from \"../structural/fragmentInfoByUUID\";\n\n/**\n * ssr-snapshot プロトコルの提供側(docs/ssr-router-design.md §5)。\n *\n * `<wcs-ssr>` スナップショットを document 全体に対する最終パスとして生成する。\n * connectedCallback 内の inline 生成は「その時点の DOM」しか見えず、router が\n * 後から挿入するルート内容の構造テンプレートを取り逃がすレースがあった\n * (state のロード方式と文書順に依存)。renderToString が全要素の完了と\n * バインディング構築の後にこれを呼ぶことで、スナップショットは常に確定後の\n * DOM を見る。\n *\n * 複数 `enable-ssr` state の意味論は inline 生成と同一に保つ(文書順に生成・\n * fragment レジストリはモジュール共有・props store は生成ごとにクリア)。\n * その整理は本プロトコルの範囲外の既存挙動として引き継ぐ。\n */\nexport function buildSsrDocument(root: Document): void {\n const stateTag = config.tagNames.state;\n const ssrTag = config.tagNames.ssr;\n // スナップショットはルートツリーに 1 本(D14): ボリューム(mount=)と bind-component は\n // 独立ツリー(__state)を持たないため、含めると空の <wcs-ssr> を生成してしまう。\n // Ssr.find は文書先頭一致なので、ルートより前の空スナップショットをルートが掴み、\n // ハイドレーション全体が無言で CSR 退化する\n const stateElements = root.querySelectorAll(`${stateTag}[enable-ssr]:not([mount]):not([bind-component])`);\n for (const stateEl of stateElements) {\n // 既に直前へ生成済み(旧 server との組み合わせで inline 生成された等)なら\n // 何もしない — build() は冪等でなければならない(プロトコル契約)\n const prev = stateEl.previousElementSibling;\n if (prev !== null && prev.tagName.toLowerCase() === ssrTag) {\n continue;\n }\n const ssrEl = document.createElement(ssrTag);\n ssrEl.setAttribute(\"version\", VERSION);\n Ssr.buildContent(ssrEl, Ssr.extractStateData(stateEl), stateEl.getRootNode());\n stateEl.parentNode?.insertBefore(ssrEl, stateEl);\n }\n // props の台帳は `buildContent` の末尾でも空にするが、**`enable-ssr` が 1 件も無いページ**は\n // そこを通らない。通らないと強参照の `Set<Node>` が次のレンダリングまで残り、前のページの\n // 値が次のリクエストの props JSON に載る(実測: `{\"wcs-ssr-0\":{\"valueAsNumber\":\"PRIVATE-C\"}}`)。\n // ここはサーバーの最終パスなので、この文書の props をこの後で読む者は居ない。\n // 構造テンプレートの台帳(fragmentInfoByUUID)はここでは消さない — この後に走る\n // 進行中のバインディング構築がまだ読む。プロセスの後始末は `resetSsrRenderState()`\n clearSsrPropertyStore();\n}\n\n/**\n * サーバーのレンダリング 1 回分のモジュール大域を捨てる。**サーバー専用**。\n *\n * `@wcstack/server` の `renderToString` は 1 プロセスで何枚も描くが、state 側の台帳\n * (構造テンプレート・SSR props)はモジュール寿命で削除の口が無い。出力への混入は\n * 到達可能性フィルタ(`Ssr.buildContent`)で閉じてあるので、これは**メモリ**の口である。\n *\n * 呼ぶ位置: `renderToString`(正確には `renderInWindow`)の `finally` の最後 — その\n * レンダリングの DOM をもう誰も触らないことが確定してから。ブラウザでは呼ばない。\n */\nexport function resetSsrRenderState(): void {\n clearFragmentInfos();\n clearSsrPropertyStore();\n ssrBlockRemoval.seen = false;\n}\n\nconst builder: IWcsSsrSnapshotBuilder = {\n protocol: \"wcs-ssr-snapshot\",\n version: 1,\n build: buildSsrDocument,\n // レンダラ(@wcstack/server)が後始末の最後に呼ぶ。パッケージの import ではなく\n // プロトコル越しに渡すのは `build` と同じ理由 — グローバル symbol は「実際に動いた\n // state のコピー」を指すので、捨てるべき台帳を持っている当人に必ず届く。\n // 分割エントリを直接 import すると core がもう 1 つ読み込まれ、**別の**台帳を\n // 空にして終わる\n reset: resetSsrRenderState,\n};\n\n/**\n * グローバル symbol へ自分を載せる。`bootstrapState` から呼ぶ。\n * binder(registerBinder)と同じ規範 — 既に別のコピーが載っているなら譲る\n * (そのコピーのレジストリが、そのページの正本だからである)。\n */\nexport function registerSsrSnapshotBuilder(): void {\n const globals = globalThis as Record<symbol, unknown>;\n if (globals[SSR_SNAPSHOT_BUILDER_KEY] === undefined) {\n globals[SSR_SNAPSHOT_BUILDER_KEY] = builder;\n }\n}\n\n/** テスト用: 登録を外す */\nexport function _unregisterSsrSnapshotBuilder(): void {\n const globals = globalThis as Record<symbol, unknown>;\n if (globals[SSR_SNAPSHOT_BUILDER_KEY] === builder) {\n delete globals[SSR_SNAPSHOT_BUILDER_KEY];\n }\n}\n","import { getAbsoluteStateAddressByBinding } from \"../binding/getAbsoluteStateAddressByBinding\";\nimport { setLastListValueByAbsoluteStateAddress } from \"../list/lastListValueByAbsoluteStateAddress\";\nimport { setStateListBaseline } from \"../list/stateListBaseline\";\nimport { parseBindTextsForElement } from \"../bindTextParser/parseBindTextsForElement\";\nimport { ParseBindTextResult } from \"../bindTextParser/types\";\nimport { BindingSession, getOrCreateBindingSession } from \"../bindings/BindingSession\";\nimport { collectNodesAndBindingInfos, collectNodesAndBindingInfosOf, IDeferredSpreadEntry, markNodeRegistered } from \"../bindings/collectNodesAndBindingInfos\";\nimport { getSubscriberNodes } from \"../bindings/getSubscriberNodes\";\nimport { findNestedLightDomComponents, isLightDomMappedStateElement } from \"../bindings/lightDomComponentScope\";\nimport { parseCommentNode } from \"../bindings/parseCommentNode\";\nimport { componentApplyHooks } from \"../core/componentApplyHooks\";\nimport { scheduleDeferredSpreads } from \"../bindings/initializeBindings\";\nimport { setBindingsByContent } from \"../bindings/bindingsByContent\";\nimport { setBindingSessionByContent } from \"../bindings/bindingSessionByContent\";\nimport { setIndexBindingsByContent } from \"../bindings/indexBindingsByContent\";\nimport { setNodesByContent } from \"../bindings/nodesByContent\";\nimport { bindLoopContextToContent } from \"../bindings/bindLoopContextToContent\";\nimport { config } from \"../config\";\nimport { WILDCARD } from \"../define\";\nimport { Ssr, SSR_BLOCK_START, collectComments, isBlockBoundary, isBlockStart, isPlaceholder } from \"./Ssr\";\nimport { getStateElement } from \"../stateElementByName\";\nimport { applyChangeFromBindings } from \"../apply/applyChangeFromBindings\";\nimport { hydrateSetContent, hydrateSetLastNode, hydrateSetRenderedList } from \"../apply/applyChangeToFor\";\nimport { waitForStateInitialize } from \"../waitForStateInitialize\";\nimport { setFragmentInfoByUUID, getFragmentInfoByUUID } from \"../structural/fragmentInfoByUUID\";\nimport { getFilteredValue } from \"../apply/getFilteredValue\";\nimport { planFilters } from \"../bindings/planFilters\";\nimport { setContentByNode } from \"../structural/contentsByNode\";\nimport { ALL_INDEX_BITS, createContentFromNodes, isIndexBinding } from \"../structural/createContent\";\nimport { IContent } from \"../structural/types\";\nimport { collectStructuralFragments } from \"../structural/collectStructuralFragments\";\nimport { createNotFilter } from \"../structural/createNotFilter\";\nimport { getFragmentNodeInfos } from \"../structural/getFragmentNodeInfos\";\nimport { optimizeFragment } from \"../structural/optimizeFragment\";\nimport { expandShorthandPaths } from \"../structural/expandShorthandPaths\";\nimport { createListIndex } from \"../list/createListIndex\";\nimport { IListIndex, ILoopContext } from \"../list/types\";\nimport { getLoopContextByNode } from \"../list/loopContextByNode\";\nimport { setListIndexesByList } from \"../list/listIndexesByList\";\nimport { getPathInfo } from \"../address/PathInfo\";\nimport { createStateAddress } from \"../address/StateAddress\";\nimport { IBindingInfo } from \"../types\";\nimport { VERSION } from \"../version\";\n\n// ハイドレーション時にスキップするバインディングタイプ\nconst STRUCTURAL_TYPES = new Set(['for', 'if', 'elseif', 'else']);\n\n\ninterface ISsrBlock {\n type: string; // for, if, elseif, else\n uuid: string;\n path: string;\n index: number | null; // for のみ\n nodes: Node[]; // start〜end 間のノード\n start?: Comment; // 開始コメント(collectSsrBlocks が付ける)\n subscribers?: Node[]; // このブロックが自分で持つ購読ノード(hydrateBlocks が付ける)\n}\n\n/**\n * ブロック開始コメントの中身(`@@wcs-for-start:uuid:path:index` / `@@wcs-if-start:uuid:path`)を読む。\n * `nodes` は空で返す(collectSsrBlocks が埋める)。\n */\nfunction parseBlockStart(data: string): ISsrBlock {\n const [, type, info] = SSR_BLOCK_START.exec(data) as RegExpExecArray;\n const [uuid, ...rest] = info.split(':');\n return type === 'for'\n ? { type, uuid, path: rest[0], index: parseInt(rest[1], 10), nodes: [] }\n // if / elseif / else のパスは `:` を含み得るので残りを繋ぐ\n : { type, uuid, path: rest.join(':'), index: null, nodes: [] };\n}\n\n/**\n * SSR ブロック境界コメントを走査して、start〜end 間のノードを収集する\n */\nfunction collectSsrBlocks(root: Node): ISsrBlock[] {\n const blocks: ISsrBlock[] = [];\n // 先に集めてから触る(この後で兄弟を引き剥がすため)\n for (const comment of collectComments(root, isBlockStart)) {\n const block = parseBlockStart(comment.data);\n block.start = comment;\n // start と end の間のノードを収集\n const endPattern = comment.data.replace('-start:', '-end:');\n let sibling = comment.nextSibling;\n while (sibling) {\n if (sibling.nodeType === Node.COMMENT_NODE && (sibling as Comment).data === endPattern) {\n break;\n }\n block.nodes.push(sibling);\n sibling = sibling.nextSibling;\n }\n blocks.push(block);\n }\n\n return blocks;\n}\n\n/**\n * 別のブロックの中にある `for` のブロック(入れ子の for・`if` / `else` の中の for)を探す。\n * 見つかれば `[内側の for, それを囲むブロック]`、無ければ null。\n *\n * このハイドレーションはブロックを文書順に**平らに**集め、行ごとの文脈を 1 段しか持てない。\n * 別のブロックの中の `for` を進めると、外側のブロックが内側の行のノードとバインディングを吸収し、\n * 内側の行の listIndex は親を持たない(#258)。実際のサーバー出力では、入れ子の for は\n * `ListIndex not found` でハイドレーション全体を止め(ready が reject され、ページのどの\n * バインディングも以後の書き込みに追従しない)、if の中の for は行が書き込みに追従せず、\n * 行を足すと SSR の行を残したまま重複した。\n *\n * 境界コメントは文書順に開き・閉じるので、開いているブロックを積んで数える。\n */\nfunction findNestedForBlock(root: Node): [ISsrBlock, ISsrBlock] | null {\n const open: ISsrBlock[] = [];\n for (const comment of collectComments(root, isBlockBoundary)) {\n if (!isBlockStart(comment.data)) {\n open.pop();\n continue;\n }\n const block = parseBlockStart(comment.data);\n // 同じ for(同じテンプレート = uuid)の行が入れ子の順に並ぶのは、サーバーが空でないリストへ\n // 行をまとめて足したときの境界コメントの順序で、入れ子の for ではない(#258)。今のサーバーはこの順に\n // 並べない(#334)が、同じ minor の修正前のサーバーの出力はバージョン検証を通るので残す\n const outer = open.at(-1);\n if (block.type === 'for' && outer && outer.uuid !== block.uuid) {\n return [block, outer];\n }\n open.push(block);\n }\n return null;\n}\n\n/**\n * ノード列の購読ノード(`getSubscriberNodes` をノード列へ広げたもの)。列の要素**自身**も拾い、\n * Light DOM の mapped コンポーネントの内側は除く(子スコープが自分で集める — getSubscriberNodes の注記)。\n * `getSubscriberNodes` は走査の根をコンポーネントとして数えないので、根がそれならここで降りない。\n */\nfunction getBlockSubscriberNodes(nodes: Node[]): Node[] {\n const found: Node[] = [];\n for (const node of nodes) {\n if (node.nodeType === Node.ELEMENT_NODE) {\n const element = node as Element;\n if (element.hasAttribute(config.bindAttributeName)) {\n found.push(element);\n }\n if (!Array.from(element.children).some(\n (child) => child.localName === config.tagNames.state && isLightDomMappedStateElement(child))) {\n found.push(...getSubscriberNodes(element));\n }\n } else if (parseCommentNode(node) !== null) {\n found.push(node);\n }\n }\n return found;\n}\n\n/**\n * live DOM の購読ノード(ブロックが自分で持つもの — hydrateBlocks)からバインディングを収集する。\n *\n * ノードは**動かさない**(#258)。以前は一時的な div へ移して `collectNodesAndBindingInfos` に掛け、\n * 元の位置に戻していた。移すとブロックの中のカスタム要素が切断・再接続され、`bind-component` の子は\n * スコープのバインディングを破棄したまま登録し直さず、親への書き込みに追従しなかった\n * (I/O ノードも切断の後始末と接続の開始をやり直していた)。\n */\nfunction collectBindingsFromLiveNodes(\n nodes: Node[],\n): { bindingInfos: IBindingInfo[], subscriberNodes: Node[], bindingSession: BindingSession, deferredSpreads: IDeferredSpreadEntry[] } {\n // 3 要素目(未定義カスタム要素への `...: path`)は呼び出し側が\n // ループ文脈を確定させてから予約する(`scheduleDeferredSpreads`)\n const [subscriberNodes, allBindings, deferredSpreads] = collectNodesAndBindingInfosOf(nodes);\n const bindingSession = new BindingSession();\n const bindingInfos = bindingSession.initialize(allBindings, {\n registerAddress: false,\n applyOnReconnect: false,\n });\n\n return {\n bindingInfos,\n subscriberNodes,\n bindingSession,\n deferredSpreads,\n };\n}\n\n/**\n * ブロックの中で初回値を適用するバインディングを集める(#258 X6 — hydrateBindings の注記)。\n *\n * 除くもの:\n * - 構造バインディング(SSR が描画済み)とイベント。\n * - コメントに乗ったバインディング。ブロックを集める時点のコメントのバインディングは構造の置き場\n * (`<!--@@wcs-for:uuid-->`)だけで、テキストの `@@:` はこの後で `Ssr.restoreTextBindings` が戻す。\n * テンプレートを復帰できなかった入れ子の置き場は text として解釈される(`text: uuid`)ので、\n * 構造の種別だけでは除けない。\n * コメントのバインディングは、適用しても失敗の報告をハイドレーションのたびに増やすだけになる。\n *\n * 添字のバインディング(`$1` / `$2` …)は除かない(#350)。state に依存しないので依存辺のためには\n * 要らないが、`{{ $1 }}` のサーバーのテキストは `Ssr.restoreTextBindings` が捨てているので、適用しないと\n * 行の添字が変わるまで空のままだった。以前除いていたのは、入れ子の for の内側の `$2` が外側のループ文脈\n * しか持たず読めなかったからで、別のブロックの中の `for` は今はハイドレーションしない(findNestedForBlock)。\n *\n * 以前はループの深さより多いワイルドカードを持つバインディング(外側のブロックに吸収された入れ子の\n * 内側の行)も除いていた。別のブロックの中の `for` は今はハイドレーションせずに全描画へ倒すので\n * (findNestedForBlock)、ここへは来ない。\n */\n/**\n * コメントに乗った**本物のテキスト束縛**の形(`<!--@@: path-->` / `<!--@@wcs-text:path-->`)。\n *\n * コメントの束縛を一律に除いていたのは、テンプレートを復帰できなかった入れ子の構造プレースホルダが\n * `text: uuid` として解釈され、適用すると `binding-path-missing` を量産するからである。それは\n * `@@wcs-for:` のような**構造のキーワード付き**コメントなので、キーワードの有無で precise に分けられる。\n * 分けないと、`{{ }}` から復元したテキスト束縛まで初回適用から落ち、`restoreTextBindings` が\n * 捨てたサーバー側のテキストが戻らない。\n */\nconst TEXT_BINDING_COMMENT = /^\\s*@@\\s*(?:wcs-text)?\\s*:/;\n\nfunction collectBlockBindings(out: IBindingInfo[], bindings: readonly IBindingInfo[]): void {\n for (const binding of bindings) {\n if (binding.bindingType === \"event\" || STRUCTURAL_TYPES.has(binding.bindingType)) {\n continue;\n }\n if (binding.node.nodeType === Node.COMMENT_NODE\n && !(binding.bindingType === \"text\" && TEXT_BINDING_COMMENT.test((binding.node as Comment).data))) {\n continue;\n }\n out.push(binding);\n }\n}\n\n/**\n * ブロックが**自分で**持つトップレベルのノード(#347 / #349)。CSR の Content が持つのはテンプレートの\n * トップレベルのノードだけで、入れ子の `if:`(行の直下・要素で包まない枝の中)の枝は置き場の後ろに\n * 自分の Content として描かれる。ブロックの `nodes` は入れ子のブロックの境界と中身も含むので、それを飛ばす。\n * 含めていたので、外した境界コメントが行の終わりになって末尾に足した行が文書に入らず、行を動かすと\n * 外した境界が文書に戻った。\n */\nfunction collectOwnNodes(block: ISsrBlock, blockByStart: Map<Node | undefined, ISsrBlock>): Node[] {\n const own: Node[] = [];\n for (let i = 0; i < block.nodes.length; i++) {\n const nested = blockByStart.get(block.nodes[i]);\n if (nested) {\n // 開始コメント・中身・終了コメント\n i += nested.nodes.length + 1;\n } else {\n own.push(block.nodes[i]);\n }\n }\n return own;\n}\n\n/**\n * ブロックの中の未定義カスタム要素への `...: path`(#330)を、CSR の行(createContent → activateContent)と\n * 同じくブロックの Content の待ちとして予約する(#358)。\n *\n * - 展開した束縛はブロックの束縛の列(と添字の列)に足す。足さないと行をプールから使い回しても当て直されず、\n * 消した行の値を出し続けた。\n * - `content.spreads` に持たせる。定義前に使い回した行・開き直した枝は活性化が予約し直す。\n * - ノードを登録済みにする。しないとこの後の body 全体の走査が同じノードをもう一度拾い、ループ文脈なしの\n * 2 つ目の展開を予約した。後から発火した方が行のノードの文脈を空にし、要素の出力の書き戻し\n * (`items.*.status`)が `ListIndex not found` で失敗した。\n */\nfunction scheduleBlockSpreads(\n content: IContent,\n deferredSpreads: IDeferredSpreadEntry[],\n loopContext: ILoopContext | null,\n session: BindingSession,\n bindings: IBindingInfo[],\n indexBindings: IBindingInfo[],\n): void {\n if (deferredSpreads.length > 0) content.spreads = deferredSpreads;\n for (const entry of deferredSpreads) markNodeRegistered(entry.node);\n scheduleDeferredSpreads(deferredSpreads, loopContext, session, bindings, indexBindings);\n}\n\n/**\n * SSR ブロックの DOM ノードを Content 化し、バインディングを登録する。\n * 戻り値はブロックの中で初回値を適用するバインディング(`collectBlockBindings`)。\n * `rowsByUuid` には for の行(listIndex)を `for`(uuid)ごとに行の添字順で集める。同じ配列を描く `for` は\n * 同じ組を持つ。リストの値へ紐づけるのは for のバインディングを起こした後(hydrateBindings — for のフィルタを\n * 通した値が行の並び)。\n */\nfunction hydrateBlocks(root: Node, blocks: ISsrBlock[], rowsByUuid: Map<string, IListIndex[]> = new Map()): IBindingInfo[] {\n // 描いたリスト(for のフィルタを通した値。配列でなければパス)→ 行の組\n const rowsByList = new Map<unknown, IListIndex[]>();\n const blockBindings: IBindingInfo[] = [];\n const blockByStart = new Map(blocks.map((block) => [block.start, block]));\n\n // 購読ノードは**内側のブロックから**割り当てる(#349)。ブロックの `nodes` は入れ子のブロックのノードも\n // 含むので、文書順(外側が先)に集めると外側が内側の置き場の束縛まで登録し、内側の Content は束縛を\n // 持たなかった — 外すときに入れ子の枝を連鎖して外さず(Content.unmount は自分の構造の束縛を辿る)、\n // 前の枝が残って 2 つの枝が同時に出た。内側のブロックは必ず外側より文書で後ろに居る\n const claimed = new Set<Node>();\n for (let i = blocks.length - 1; i >= 0; i--) {\n const subscribers = getBlockSubscriberNodes(blocks[i].nodes).filter((node) => !claimed.has(node));\n for (const node of subscribers) claimed.add(node);\n blocks[i].subscribers = subscribers;\n }\n\n for (const block of blocks) {\n const nodes = collectOwnNodes(block, blockByStart);\n // 中身が入れ子の境界だけのブロック(サーバー描画の最後に隠れた枝の残り — #356)は描かれていない\n if (nodes.length === 0) continue;\n // トップレベルに構造の置き場を持つブロックは CSR と同じく範囲モードにし、終端マーカー(ブロックの最後の\n // ノード=入れ子の枝の後ろ)で範囲を閉じる(createContent の resolveRanged)。入れ子の枝は置き場の後ろ=\n // 自分のノードの外に描かれるので、閉じないと差分が次の行を枝の手前へ入れ、行を動かすと枝を置き去りにする\n // (#347)。Text の data は置き場の形にならない\n const ranged = nodes.some((node) => isPlaceholder((node as Comment).data));\n if (ranged) {\n const marker = document.createComment(`wcs-row-end:${block.uuid}`);\n (block.nodes[block.nodes.length - 1] as ChildNode).after(marker);\n nodes.push(marker);\n }\n\n // Content のバインディングを収集\n const { bindingInfos, subscriberNodes, bindingSession, deferredSpreads } = collectBindingsFromLiveNodes(block.subscribers!);\n // トップレベルの `{{ }}` のコメントは初期化で Text に差し替わった。Content は差し替えた後のノードを\n // 持つ(CSR の行と同じ)— コメントを持っていたので、行を外す・動かすと値の Text が取り残された(#347)\n for (const binding of bindingInfos) {\n if (binding.node !== binding.replaceNode) {\n const index = nodes.indexOf(binding.node);\n if (index >= 0) nodes[index] = binding.replaceNode;\n }\n }\n const content = createContentFromNodes(nodes, ranged);\n setBindingSessionByContent(content, bindingSession);\n setBindingsByContent(content, bindingInfos);\n setNodesByContent(content, subscriberNodes);\n\n // 行の位置が変わったときに当て直す列(createContent と同じ振り分け — 添字の束縛と、中に添字の束縛を\n // 持つ入れ子の構造ディレクティブ。後から描いた枝の添字へ辿る入口・#360、#390)。段では絞らない — 入れ子の\n // for を持つブロックは全描画に倒す(findNestedForBlock)ので、ブロックの中の入れ子は if の枝だけ\n const indexBindings = bindingInfos.filter((binding) => isIndexBinding(binding, ALL_INDEX_BITS));\n setIndexBindingsByContent(content, indexBindings);\n\n if (block.type === 'for' && block.index !== null) {\n const placeholderComment = findPlaceholderComment(root, 'for', block.uuid);\n if (placeholderComment) {\n // 行(listIndex)は配列ごとに 1 組(list/listIndexesByList.ts)。同じリストを回す `for` が 2 つあると、\n // テンプレート(uuid)ごとに鋳造した行の組を後の方が台帳ごと上書きし、先の `for` は以後の差分で自分の\n // 行を引けず(`Content not found for ListIndex`)書き込みに追従しなかった(#258 の調査で発見)。\n // 別のパスでも同じ配列なら同じ組にする — 配列をそのまま返す getter の `for`(`for: items` と\n // `get visible() { return this.items; }` の `for: visible`)がパスごとに鋳造した組は、同じ配列の台帳を\n // 後の方が上書きし、先の `for` が同じ失敗をした(#351)\n let rows = rowsByUuid.get(block.uuid);\n if (!rows) {\n const list = readHydratedList(placeholderComment, block.uuid) ?? block.path;\n rows = rowsByList.get(list);\n if (!rows) {\n rowsByList.set(list, rows = []);\n }\n rowsByUuid.set(block.uuid, rows);\n }\n const listIndex = rows[block.index] ??= createListIndex(null, block.index);\n hydrateSetContent(placeholderComment, listIndex, content);\n hydrateSetLastNode(placeholderComment, content.lastNode as Node);\n setContentByNode(placeholderComment, content);\n\n // ループコンテキストをバインドし、バインディングをアドレスに登録\n const pathInfo = getPathInfo(block.path + '.' + WILDCARD);\n const stateAddress = createStateAddress(pathInfo, listIndex);\n // ILoopContext は IStateAddress + listIndex なので、stateAddress をそのまま使う\n bindLoopContextToContent(content, stateAddress as any);\n\n bindingSession.initialize(bindingInfos, {\n registerAddress: true,\n registerPathInfo: false,\n applyOnReconnect: false,\n });\n collectBlockBindings(blockBindings, bindingInfos);\n // 未定義カスタム要素への `...: path` は行のループ文脈が確定してから予約する\n scheduleBlockSpreads(content, deferredSpreads, stateAddress as unknown as ILoopContext, bindingSession, bindingInfos, indexBindings);\n }\n } else {\n // 行の中の if は行どうしで uuid を共有するので、文書で最初のプレースホルダではなく開始コメントの\n // 直前(サーバーはプレースホルダの直後に開始コメントを置く)から引く。文書で最初のものを引くと、どの行の\n // 枝も行 0 に付き、行 1 以降の切り替えが枝を消せず・重ね・別の行へ移した(#258)。直前に無い出力(手で\n // 整形したもの)は従来どおり文書から探す\n const previous = block.start!.previousSibling as Comment | null;\n const placeholderComment = previous?.data === placeholderData(block.type, block.uuid)\n ? previous\n : findPlaceholderComment(root, block.type, block.uuid);\n if (placeholderComment) {\n setContentByNode(placeholderComment, content);\n // 行の中の枝は置き場(行が文脈を与えた)の行の文脈で束縛する(CSR の applyChangeToIf の活性化と同じ)。\n // 以前は行のブロックが枝の束縛まで持っていたので要らなかった\n const loopContext = getLoopContextByNode(placeholderComment);\n bindLoopContextToContent(content, loopContext);\n\n bindingSession.initialize(bindingInfos, {\n registerAddress: true,\n registerPathInfo: false,\n applyOnReconnect: false,\n });\n collectBlockBindings(blockBindings, bindingInfos);\n scheduleBlockSpreads(content, deferredSpreads, loopContext, bindingSession, bindingInfos, indexBindings);\n }\n }\n }\n\n return blockBindings;\n}\n\n/**\n * `for` のブロックが描いたリスト — state のいまの値に for のフィルタを通したもの(配列でなければ null)。\n * structuralBindings はまだ登録前なので、復帰したテンプレートの解析結果からパスとフィルタを引く。\n */\nfunction readHydratedList(placeholderComment: Comment, uuid: string): unknown[] | null {\n const fragmentInfo = getFragmentInfoByUUID(uuid);\n const stateElement = getStateElement(placeholderComment.getRootNode() as Node);\n let list: unknown[] | null = null;\n if (fragmentInfo && stateElement) {\n const { statePathName, outFilters } = fragmentInfo.parseBindTextResult;\n stateElement.createState(\"readonly\", (state) => {\n const value = getFilteredValue(state[statePathName], planFilters(outFilters, \"output\"));\n if (Array.isArray(value)) {\n list = value;\n }\n });\n }\n return list;\n}\n\nfunction placeholderData(type: string, uuid: string): string {\n const keywordMap: Record<string, string> = {\n 'for': config.commentForPrefix,\n 'if': config.commentIfPrefix,\n 'elseif': config.commentElseIfPrefix,\n 'else': config.commentElsePrefix,\n };\n return `@@${keywordMap[type]}:${uuid}`;\n}\n\nfunction findPlaceholderComment(root: Node, type: string, uuid: string): Comment | null {\n const pattern = placeholderData(type, uuid);\n return collectComments(root, (d) => d === pattern)[0] ?? null;\n}\n\n/**\n * <wcs-ssr> 内のテンプレートを fragmentInfoByUUID に復帰させる。\n */\nfunction restoreFragments(root: Document, ssrEl: Ssr): void {\n const rootNode = root as Node;\n const templates = ssrEl.templates;\n // else は**同じ階層**(同じテンプレートの中身か、文書の直下)で直前の if / elseif の否定(#336)。\n // クライアントの collectStructuralFragments と同じ組み方で、階層は置き場を中身に持つテンプレートで分かる。\n // スナップショットの並び(collectReachableFragments)は描いた文書の文書順なので、外側の枝が描かれて\n // いると内側の置き場が外側の else より前に並ぶ — 並びの直前と組むと、外側の else が内側の if と組んだ\n // (内側に else があると、外側の else は否定の相手を失った)。各階層の中の並びは中身の順のまま\n const levelByUuid = new Map<string, unknown>();\n for (const [uuid, tpl] of templates) {\n for (const placeholder of collectComments(tpl.content, isPlaceholder)) {\n levelByUuid.set(placeholder.data.slice(placeholder.data.indexOf(':') + 1), uuid);\n }\n }\n // Light DOM の `bind-component` の子のテンプレートは、ページの走査が子を外す(collectStructuralFragments)\n // ので、どのテンプレートの中身にも置き場が無い(中身には `<template>` のまま居る)。子は自分のスコープで\n // 組むので、階層は生きている DOM の置き場を囲む一番内側の子。文書の直下とみなすと、ページの else が\n // 子の if と組んだ(#348)。子の居ないページ(大半)は文書をもう一度走査しない\n const components = new Set<Node>(findNestedLightDomComponents(root));\n if (components.size > 0) {\n for (const placeholder of collectComments(rootNode, isPlaceholder)) {\n const uuid = placeholder.data.slice(placeholder.data.indexOf(':') + 1);\n let level = placeholder.parentNode;\n while (level !== null && !components.has(level)) level = level.parentNode;\n if (level !== null && !levelByUuid.has(uuid)) levelByUuid.set(uuid, level);\n }\n }\n // 階層(文書の直下は undefined)ごとの直前の if / elseif\n const lastIfByLevel = new Map<unknown, ParseBindTextResult | null>();\n const restored: [string, HTMLTemplateElement, ParseBindTextResult][] = [];\n\n for (const [uuid, tpl] of templates) {\n const bindText = tpl.getAttribute(config.bindAttributeName) || '';\n const parseBindTextResults = parseBindTextsForElement(bindText);\n let parseBindTextResult = parseBindTextResults[0];\n const bindingType = parseBindTextResult.bindingType;\n const level = levelByUuid.get(uuid);\n const lastIfParseResult = lastIfByLevel.get(level);\n\n // else: 直前の if 条件の not → 条件反転(elseif は独自条件のままでよい)\n if (bindingType === 'else' && lastIfParseResult) {\n parseBindTextResult = {\n ...lastIfParseResult,\n outFilters: [...lastIfParseResult.outFilters, createNotFilter()],\n bindingType: 'else',\n };\n }\n\n // if chain の追跡\n if (bindingType === 'if' || bindingType === 'elseif') {\n lastIfByLevel.set(level, parseBindTextResult);\n } else if (bindingType === 'else') {\n lastIfByLevel.set(level, null);\n }\n restored.push([uuid, tpl, parseBindTextResult]);\n }\n\n // **子を親より先に**登録する(#258)。スナップショットのテンプレートは平らで、入れ子は親の中身に\n // プレースホルダ(`<!--@@wcs-if:<uuid>-->`)として居る。親の fragment を解析する時点で子が台帳に\n // 無いと、そのプレースホルダは `text: <uuid>` と解釈されて空の Text に潰され、親から新しく作る\n // 行・枝(行の追加、初めて真になる if)から入れ子が消えていた(実 Chromium で実測。同じモジュールで\n // サーバー描画する vitest では、サーバーの登録が台帳に残っていて見えない)。並び(Ssr の\n // collectReachableFragments)では、子の置き場は親の置き場より後ろ(描いた親の枝の中)か親の中身でしか\n // 見つからないので、子は必ず親より後ろに居る — 逆順に回せば足りる\n for (const [uuid, tpl, parseBindTextResult] of restored.reverse()) {\n const fragment = document.importNode(tpl.content, true);\n const forPath = parseBindTextResult.bindingType === \"for\" ? parseBindTextResult.statePathName : undefined;\n optimizeFragment(fragment);\n if (typeof forPath === \"string\") {\n expandShorthandPaths(fragment, forPath);\n }\n collectStructuralFragments(rootNode, fragment, forPath);\n\n const fragmentInfo = {\n fragment,\n parseBindTextResult,\n nodeInfos: getFragmentNodeInfos(fragment),\n };\n setFragmentInfoByUUID(uuid, rootNode, fragmentInfo);\n }\n}\n\n/**\n * SSR ハイドレーション用バインディング初期化。\n * バージョン不一致時と、別のブロックの中に `for` のブロックがあるとき(findNestedForBlock)は\n * DOM をクリーンアップして false を返す(呼び出し元で buildBindings にフォールバック)。\n */\nexport async function hydrateBindings(root: Document): Promise<boolean> {\n await waitForStateInitialize(root);\n\n // バージョン検証\n const ssrElements = root.querySelectorAll(config.tagNames.ssr);\n for (const ssrNode of ssrElements) {\n const ssrEl = ssrNode as Ssr;\n if (!ssrEl.verifyVersion()) {\n console.warn(\n `[@wcstack/state] SSR version mismatch: server=\"${ssrEl.version}\", client=\"${VERSION}\". Falling back to full render.`\n );\n Ssr.cleanupDom(root);\n return false;\n }\n }\n\n // 入れ子の for・if の中の for はハイドレーションしない(既知の制限 — findNestedForBlock)。\n // DOM に触る前に判定し、バージョン不一致と同じ経路でクライアントの全描画に倒す。\n // SSR の DOM を捨てて描き直すことになるので、バージョン不一致と同じく黙らずに知らせる\n const nested = findNestedForBlock(document.body);\n if (nested !== null) {\n const [inner, outer] = nested;\n console.warn(\n `[@wcstack/state] SSR: \"for: ${inner.path}\" in \"${outer.type}: ${outer.path}\" (known limitation). Falling back to full render.`\n );\n Ssr.cleanupDom(root);\n return false;\n }\n\n // <wcs-ssr> からテンプレートを fragmentInfoByUUID に復帰\n for (const ssrNode of ssrElements) {\n restoreFragments(root, ssrNode as Ssr);\n }\n\n // SSR テキストバインディングを @@: 形式に復元。\n // **ブロックを集める前に**行う。後回しにしていたので、`for` / `if` の中の `{{ }}` は\n // `collectBindingsFromLiveNodes` の時点でまだ `@@wcs-text-start/end` のコメント対であり、\n // 行のバインディングとして登録されなかった。そのうえで `restoreTextBindings` は start/end の\n // 間(=サーバーが描いたテキスト)を捨てるので、**行の `{{ }}` が空になったまま二度と戻らない**\n // (`data-wcs=\"textContent: …\"` は属性なのでこの穴に落ちない)。\n Ssr.restoreTextBindings(document.body);\n\n // SSR ブロック境界コメントから既存 DOM を Content 化\n const blocks = collectSsrBlocks(document.body);\n const rowsByUuid: Map<string, IListIndex[]> = new Map();\n const blockBindings = hydrateBlocks(document.body, blocks, rowsByUuid);\n\n // ブロック境界コメント (start/end) を除去\n Ssr.removeBlockBoundaryComments(document.body);\n\n // <wcs-ssr> を一時除去(バインディング走査に含めない)\n const ssrParents: { el: Element, parent: Node, next: Node | null }[] = [];\n for (const el of ssrElements) {\n if (el.parentNode) {\n ssrParents.push({ el, parent: el.parentNode, next: el.nextSibling });\n el.remove();\n }\n }\n\n // 構造プレースホルダーコメント (@@wcs-for:uuid 等) は残す\n // → バインディング走査で拾われ、状態変化時の再レンダリングに使われる\n\n // ノードとバインディングを収集(hydrateBlocks で登録済みのブロックのノードは飛ばされる)。\n // ここで集めたノードのループ文脈は触らない(#258)。以前はブロックの外のノードの文脈を空に\n // 戻していたが、この時点で文脈を持つノードは hydrateBlocks が行の文脈を与えたものだけで、\n // 戻す意味は無かった。印(`data-wcs-completed`)の付かないコメントは行のものまで空に戻され、\n // for の行の中の `if` の置き場が文脈を失い、切り替えるたびに `list index is null` で失敗していた\n const [, allBindings, deferredSpreads] = collectNodesAndBindingInfos(document.body);\n\n // バインディングを構造系とそれ以外に分離\n const normalBindings: IBindingInfo[] = [];\n const structuralBindings: IBindingInfo[] = [];\n const bindingSession = getOrCreateBindingSession(document.body);\n const initializedBindings = bindingSession.initialize(allBindings);\n // 未定義カスタム要素への `...: path` を `whenDefined` 後の配線として予約する。\n // 通常経路(`bindings/initializeBindings.ts`)はこれを行うが、ハイドレーション経路は\n // `collectNodesAndBindingInfos` の 3 要素目を捨てていたので、SSR したページでだけ\n // spread が**永久に配線されなかった**(実測: 通常経路は whenDefined を予約、\n // ハイドレーション経路は 1 件も予約しない)\n scheduleDeferredSpreads(deferredSpreads, null, bindingSession);\n\n for (const binding of initializedBindings) {\n if (binding.bindingType === \"event\") continue;\n if (STRUCTURAL_TYPES.has(binding.bindingType)) {\n structuralBindings.push(binding);\n } else if (binding.statePathName.includes(WILDCARD)) {\n // for ブロック内のバインディング → Content のバインディングとして登録済み\n continue;\n } else {\n normalBindings.push(binding);\n }\n }\n\n // for バインディングの lastListValue を初期値として設定\n // (次回の状態変化時に差分計算の基準になる)\n for (const binding of structuralBindings) {\n if (binding.bindingType === 'for') {\n const absAddr = getAbsoluteStateAddressByBinding(binding);\n const rootNode = binding.replaceNode.getRootNode() as Node;\n const stateElement = getStateElement(rootNode);\n if (stateElement) {\n stateElement.createState(\"readonly\", (state) => {\n // 描いた行の並びは for のフィルタ(`for: items|…`)を通した値 — CSR の applyChangeToFor が受け取り、\n // 基準に記録する値と同じ。素の値で組んでいたので、行を減らす・並べ替えるフィルタでは台帳の行が\n // 値の要素より少なく、次の書き込みの差分が投げた\n const value = getFilteredValue(state[binding.statePathName], binding.outFilters);\n if (Array.isArray(value)) {\n // 行(listIndex)は配列ごとに 1 組。同じ配列を描く for は同じ行を紐づける(#258・#351 — hydrateBlocks)\n const rows = rowsByUuid.get(binding.uuid as string);\n if (rows) setListIndexesByList(value, rows);\n setLastListValueByAbsoluteStateAddress(absAddr, value);\n // サーバーが描いた並びを、この for が描いた並びとして記録する(クライアントで描いた for と同じく、\n // 要素の書き込みが描画の基準を書き込む前の写しへ移せるように — #351)\n hydrateSetRenderedList(binding.node, value);\n // 描画の基準と同時に state 側の基準も進める(E1。applyChangeFromBindings と対称)\n setStateListBaseline(absAddr, value);\n }\n });\n }\n }\n }\n\n // 初回値の適用(構造バインディングは SSR 描画済みなので除く)。SSR ブロック(for の行・if の中身)の\n // 中のバインディングも適用する(#258 X6): getter の依存辺は getter を評価したときにしか張られない\n // ので、適用しないと行の `items.*.double` は `items.*.n` を書いても一度も再評価されず、サーバーが\n // 書いたテキストのまま固まる。値は SSR と同じ state から読むのでテキストは変わらない\n applyChangeFromBindings([...normalBindings, ...blockBindings]);\n\n // <wcs-ssr> を元に戻す\n for (const { el, parent, next } of ssrParents) {\n parent.insertBefore(el, next);\n }\n\n // hydrateProps 復元。\n // 索引は **1 回だけ** 作る。props 1 件ごとに `querySelector('[data-wcs-ssr-id=\"…\"]')` を\n // 回していたので、props に載る束縛(textContent 等)の行数に対して二次だった\n // (実測 800 / 1600 / 3200 行で 109 / 297 / 1207 ms。props が 0 件の `value` 行は線形)\n const targetBySsrId = new Map<string, Element>();\n for (const el of root.querySelectorAll('[data-wcs-ssr-id]')) {\n targetBySsrId.set(el.getAttribute('data-wcs-ssr-id') as string, el);\n }\n for (const ssrNode of root.querySelectorAll(config.tagNames.ssr)) {\n for (const [id, propMap] of Object.entries((ssrNode as Ssr).hydrateProps)) {\n const target = targetBySsrId.get(id);\n if (!target) continue;\n for (const [propName, value] of Object.entries(propMap)) {\n // `bind-component` が束ねるプロパティ(丸ごとマウント `state: items.*`)は戻さない(#258)。\n // サーバーでは行が fragment の中で作られ、子の `<wcs-state bind-component>` の宣言より先に\n // ホストの束縛が素の書き込みとして走るので、配線の値がここに載る。戻すと子の完了前に作者の\n // state オブジェクトを親の値の写しで置き換え、全キーが私有に化けて(誤った\n // `mount-own-key-shadow`)親への書き込みに追従しなくなる。宣言済みの (要素, プロパティ) に\n // 書かないのは、親スコープの適用(apply/applyChange.ts の resolveCustomElementApply)と同じ規則\n if (componentApplyHooks?.isDeclared(target, propName)) continue;\n (target as any)[propName] = value;\n }\n }\n }\n\n // SSR の対応付け用属性を除去する。成功経路だけ残していたので、バージョン不一致の\n // フォールバック(`Ssr.cleanupDom`)と非対称だった — ハイドレーション済みの DOM に\n // サーバー側の帳簿が残り、`[data-wcs-ssr-id]` を見る CSS / 再ハイドレーションに漏れる\n for (const el of root.querySelectorAll('[data-wcs-ssr-id]')) {\n el.removeAttribute('data-wcs-ssr-id');\n }\n\n return true;\n}\n\n/** @internal テスト用 */\nexport const __test = {\n collectSsrBlocks,\n collectBindingsFromLiveNodes,\n hydrateBlocks,\n findPlaceholderComment,\n restoreFragments,\n};\n","/**\n * ssr/install.ts — SSR 機能の install(設計案 H8、S5)。core の受け口(core/ssrHooks.ts と\n * registerComponents の definer)へこの機能の実装を置き、ssr-snapshot プロトコルを提供する。\n * 従来 `State` と `stateElementByName` と `registerComponents` に直書きされていた分岐で、\n * 理由のコメントは元の位置から移してある。\n */\nimport { config } from \"../config\";\nimport type { IStateElement } from \"../components/types\";\nimport { ISsrHooks, setSsrHooks } from \"../core/ssrHooks\";\nimport { registerComponentDefiner } from \"../registerComponents\";\nimport { getBindingsReady } from \"../stateElementByName\";\nimport { VERSION } from \"../version\";\nimport { registerSsrSnapshotBuilder } from \"./buildSsrDocument\";\nimport { hydrateBindings } from \"./hydrateBindings\";\nimport { Ssr } from \"./Ssr\";\n\nexport const ssrFeatureHooks: ISsrHooks = {\n hydrate: hydrateBindings,\n loadState(element) {\n const root = element.parentNode;\n if (!root) return null;\n const ssrEl = Ssr.find(root);\n if (!ssrEl) return null;\n const data = ssrEl.stateData;\n return Object.keys(data).length > 0 ? data : null;\n },\n async emitSnapshot(element) {\n await getBindingsReady((element as unknown as IStateElement).rootNode);\n const stateData = Ssr.extractStateData(element);\n const ssrEl = document.createElement(config.tagNames.ssr);\n ssrEl.setAttribute(\"version\", VERSION);\n // スナップショットの範囲はこの state のツリー — モジュール寿命の台帳に残った\n // 別のレンダリングのテンプレートを載せない(リクエスト間のデータ漏れ)\n Ssr.buildContent(ssrEl, stateData, (element as unknown as IStateElement).rootNode);\n element.parentNode?.insertBefore(ssrEl, element);\n },\n};\n\nlet installed = false;\n/** 冪等。full / auto では `bootstrapState()` が呼ぶ */\nexport function installSsr(): void {\n if (installed) return;\n installed = true;\n setSsrHooks(ssrFeatureHooks);\n registerComponentDefiner((registry) => {\n if (!registry.get(config.tagNames.ssr)) {\n registry.define(config.tagNames.ssr, Ssr);\n }\n });\n // ssr-snapshot プロトコルの提供(docs/ssr-router-design.md §5)。renderToString が\n // `<wcs-ssr>` 生成をサーバー主導の最終パスへ回せるようにする。登録は冪等\n registerSsrSnapshotBuilder();\n}\n","/**\n * features/ssr.ts — サーバー描画とハイドレーション(@wcstack/state/features/ssr)。\n */\nimport type { IStateFeature } from \"../core/features\";\nimport { installSsr } from \"../ssr/install\";\n\nexport const ssr: IStateFeature = {\n name: \"ssr\",\n install(): void {\n installSsr();\n },\n};\nexport default ssr;\n"],"names":["SSR_PLACEHOLDER_COMMENT","SSR_BLOCK_START","SSR_BLOCK_END","SSR_TEXT_START","escapeJsonForScript","json","replace","collectComments","root","match","walker","document","createTreeWalker","NodeFilter","SHOW_COMMENT","found","nextNode","comment","currentNode","data","push","isPlaceholder","test","isBlockStart","isBlockBoundary","structuralBindText","result","bindingType","text","statePathName","filter","outFilters","literals","args","filterName","length","map","arg","i","split","join","cloneFragmentForSnapshot","fragmentInfo","clone","fragment","cloneNode","nodeInfo","nodeInfos","commentData","getNormalizedTextCommentData","resolveNodePath","nodePath","target","parentNode","replaceChild","createComment","Ssr","HTMLElementBase","_stateData","_templates","_hydrateProps","version","this","getAttribute","stateData","_loadStateData","templates","_loadTemplates","hydrateProps","_loadHydrateProps","getTemplate","uuid","get","verifyVersion","serverVersion","serverParts","clientParts","VERSION","setStateData","setHydrateProps","props","script","querySelector","JSON","parse","textContent","Map","querySelectorAll","tpl","id","set","find","tagName","config","tagNames","ssr","parentEl","Element","Document","documentElement","extractStateData","stateEl","raw","__state","key","Object","keys","startsWith","descriptor","getOwnPropertyDescriptor","undefined","value","buildContent","ssrEl","scanRoot","ownerDocument","ssrBlockRemoval","seen","rowEnds","start","type","info","exec","prev","previousSibling","end","node","next","nextSibling","remove","removeStaleBlockBoundaries","jsonScript","createElement","setAttribute","stringify","appendChild","pending","placeholder","shift","slice","indexOf","has","getFragmentInfoByUUID","collectReachableFragments","bindAttributeName","parseBindTextResult","content","ssrNodes","getAllSsrPropertyNodes","propsData","isConnected","entries","getSsrProperties","entry","propName","propsScript","clearSsrPropertyStore","removeBlockBoundaryComments","removeStructuralComments","restoreTextBindings","d","path","bindComment","insertBefore","sibling","endPattern","nodeType","Node","COMMENT_NODE","removeChild","cleanupDom","body","ssrElements","templateByUuid","ssrNode","startComment","restorePlaceholders","scope","restored","bindAttr","imported","importNode","childNodes","child","Array","from","ssrIdElements","el","removeAttribute","builder","protocol","build","stateTag","state","ssrTag","stateElements","previousElementSibling","toLowerCase","getRootNode","reset","clearFragmentInfos","STRUCTURAL_TYPES","Set","parseBlockStart","rest","index","parseInt","nodes","getBlockSubscriberNodes","ELEMENT_NODE","element","hasAttribute","children","some","localName","isLightDomMappedStateElement","getSubscriberNodes","parseCommentNode","collectBindingsFromLiveNodes","subscriberNodes","allBindings","deferredSpreads","collectNodesAndBindingInfosOf","bindingSession","BindingSession","bindingInfos","initialize","registerAddress","applyOnReconnect","TEXT_BINDING_COMMENT","collectBlockBindings","out","bindings","binding","collectOwnNodes","block","blockByStart","own","nested","scheduleBlockSpreads","loopContext","session","indexBindings","spreads","markNodeRegistered","scheduleDeferredSpreads","readHydratedList","placeholderComment","stateElement","getStateElement","list","createState","getFilteredValue","planFilters","isArray","placeholderData","for","commentForPrefix","if","commentIfPrefix","elseif","commentElseIfPrefix","else","commentElsePrefix","findPlaceholderComment","pattern","restoreFragments","rootNode","levelByUuid","components","findNestedLightDomComponents","size","level","lastIfByLevel","bindText","parseBindTextsForElement","lastIfParseResult","createNotFilter","reverse","forPath","optimizeFragment","expandShorthandPaths","collectStructuralFragments","getFragmentNodeInfos","setFragmentInfoByUUID","ssrFeatureHooks","hydrate","async","waitForStateInitialize","console","warn","open","pop","outer","at","findNestedForBlock","inner","blocks","collectSsrBlocks","rowsByUuid","blockBindings","rowsByList","claimed","subscribers","add","ranged","marker","after","replaceNode","createContentFromNodes","setBindingSessionByContent","setBindingsByContent","setNodesByContent","isIndexBinding","ALL_INDEX_BITS","setIndexBindingsByContent","rows","listIndex","createListIndex","hydrateSetContent","hydrateSetLastNode","lastNode","setContentByNode","pathInfo","getPathInfo","WILDCARD","stateAddress","createStateAddress","bindLoopContextToContent","registerPathInfo","previous","getLoopContextByNode","hydrateBlocks","ssrParents","parent","collectNodesAndBindingInfos","normalBindings","structuralBindings","getOrCreateBindingSession","initializedBindings","includes","absAddr","getAbsoluteStateAddressByBinding","setListIndexesByList","setLastListValueByAbsoluteStateAddress","hydrateSetRenderedList","setStateListBaseline","applyChangeFromBindings","targetBySsrId","propMap","componentApplyHooks","isDeclared","loadState","emitSnapshot","getBindingsReady","installed","installSsr","setSsrHooks","registerComponentDefiner","registry","define","globals","globalThis","SSR_SNAPSHOT_BUILDER_KEY","registerSsrSnapshotBuilder","name","install"],"mappings":"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"}
|
package/package.json
CHANGED