@wcstack/state 3.3.0 → 3.4.0
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 +37 -10
- package/README.md +37 -10
- package/dist/auto.min.js +1 -1
- package/dist/auto.min.js.map +1 -1
- package/dist/index.d.ts +29 -0
- 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/checkDependency.js.map +1 -1
- package/dist/split/chunks/diagnosticsHooks.js.map +1 -1
- package/dist/split/chunks/featureBridge.js +1 -1
- package/dist/split/chunks/filterRegistry.js +1 -1
- package/dist/split/chunks/filterRegistry.js.map +1 -1
- package/dist/split/chunks/getAllPropertyDescriptors.js +1 -1
- package/dist/split/chunks/lifecycleHooks.js +1 -1
- package/dist/split/chunks/pathDiagnostics.js +1 -1
- package/dist/split/chunks/pathDiagnostics.js.map +1 -1
- package/dist/split/chunks/registerComponents.js +1 -1
- package/dist/split/chunks/registerComponents.js.map +1 -1
- package/dist/split/chunks/setAll.js +1 -1
- package/dist/split/chunks/setAll.js.map +1 -1
- package/dist/split/chunks/version.js +1 -1
- package/dist/split/core.d.ts +54 -0
- package/dist/split/core.js +1 -1
- package/dist/split/features/devtools.js +1 -1
- package/dist/split/features/devtools.js.map +1 -1
- package/dist/split/features/diagnostics.js +1 -1
- package/dist/split/features/diagnostics.js.map +1 -1
- package/dist/split/features/formats.js +1 -1
- package/dist/split/features/recursion.js +1 -1
- package/dist/split/features/recursion.js.map +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/dist/split/features/temporal.js +1 -1
- package/dist/split/features/temporal.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{r as e}from"../chunks/declarationHooks.js";import{R as t,D as n,W as r,M as s,s as i,g as o,t as a,r as c}from"../chunks/pathDiagnostics.js";import{g as l,a as h,s as u,b as d,c as f,d as p,e as g}from"../chunks/setAll.js";import{M as m,j as v,l as $,N as w,O as y}from"../chunks/binder.js";import{r as x,N as P,g as _}from"../chunks/getAllPropertyDescriptors.js";import{r as A}from"../chunks/errorGuidance.js";import"../chunks/checkDependency.js";import"../chunks/filterRegistry.js";function b(e){return-1!==e.indexOf(t)}function k(e,t){if(t===e.recursiveAnchor)return"";const s=e.recursiveAnchor+n;if(!t.startsWith(s))return null;const i=t.slice(e.recursiveAnchor.length);if(b(i))return null;const o=i.slice(n.length).split(n);return o[0]===r||o.some(e=>0===e.length)?null:i}function I(e){return 0===e.length?e:n+L(e.slice(n.length))}function j(e,t,r){const s=n+e.repeat,i=t.length<=r.length?t:r,o=t.length<=r.length?r:t;if(!o.endsWith(i))return!1;const a=o.slice(0,o.length-i.length);if(0===a.length)return!0;if(a.length%s.length!==0)return!1;for(let e=0;e<a.length;e+=s.length)if(!a.startsWith(s,e))return!1;return!0}function R(e,t,r){for(let s=r.length;s>0;s=r.lastIndexOf(n,s-1))if(j(e,t,r.slice(0,s)))return!0;return!1}function L(e){const t=e.split(n);for(let e=0;e<t.length;e++)t[e]===r||Number.isNaN(Number(t[e]))||(t[e]=r);return t.join(n)}function O(e,t){const r=e.repeat.split(n),s=n+e.repeat;let i=t;for(;i.startsWith(s);)i=i.slice(s.length);if(0===i.length||i===n+e.repeatList+n+"length")return!0;for(let e=1;e<r.length;e++)if(i===n+r.slice(0,e).join(n))return!0;return!1}function W(e,t,i){i<0&&A(`Recursion depth must not be negative (got ${i}).`);let o=e.anchor;for(let t=0;t<i;t++)o+=n+e.repeat;const a=o+t;let c=0;for(const e of a.split(n))e===r&&c++;return c>s&&A(`[wcs/recursion-depth-exceeded] Recursion on "${e.anchor}" reached depth ${i} ("${a}"), which needs ${c} wildcard levels — the limit is ${s}. Either the data nests deeper than the engine can address, or the tree contains a cycle.`),a}function S(e,t){return W(e,"",t)}function N(e,t,r){if(!r.startsWith(e.anchor))return null;if(t.length>0&&!r.endsWith(t))return null;if(r.length<e.anchor.length+t.length)return null;const s=r.slice(e.anchor.length,r.length-t.length);if(0===s.length)return 0;const i=n+e.repeat;let o=0,a=0;for(;a<s.length;){if(!s.startsWith(i,a))return null;a+=i.length,o++}return o}function B(e,t){if(0===e.addressStackLength)return null;const r=e.lastAddressStack;if(null===r)return null;const s=t.accessorFor(r.pathInfo.path);return null!==s?s.depth:function(e,t){const r=e.spec;if(!t.startsWith(r.anchor))return null;const s=n+r.repeat;let i=0,o=r.anchor.length;for(;t.startsWith(s,o);)o+=s.length,i++;return o!==t.length&&46!==t.charCodeAt(o)?null:i}(t,r.pathInfo.path)}function E(e,t,n){const r=e.recursionRegistry,s=k(r.spec,n);null===s&&A(i(n,r.spec.recursiveAnchor));const o=B(t,r);return null===o&&A(`[wcs/recursion-context] "${n}" uses "**", which is bound to the depth of the recursive getter being evaluated, and there is no recursion context here. Read it from inside a recursive getter or a row getter under "${r.spec.anchor}", or name a concrete depth (for example "${r.spec.anchor}${n.slice(r.spec.recursiveAnchor.length)}"). The depth comes from the innermost frame only: a plain getter reached from a recursive getter has no row of its own, so read "**" in the recursive getter and pass the value on.`),r.concretePathAt(s,o)}function C(e,t,r,s,i){const a=s.spec,c=[],h=new Map,u=[],d=a.repeatList,f=a.anchorList,p=new Set,g=new Set,x=(e,t,n)=>{const r=e.wildcardParentPathInfos;if(t>=r.length)return void c.push(v(e,n));const s=P(r[t],n,null).rows;for(let n=0;n<s.length;n++)x(e,t+1,s[n])};function P(n,s,i){const o=v(n,s),c=$(r.stateElement,o),u=l(e,o,t,r),f=null===i?null:((e,t,n)=>{if(!Array.isArray(t)||0===t.length)return null;const r=t;return p.has(r)&&A(`[wcs/recursion-cycle] "${e}" is reachable from itself: the recursion on "${a.anchor}" walked into a list that one of its own ancestors already owns. The data contains a cycle, which this version does not support.`),n.has(r)&&A(`[wcs/recursion-shared-list] "${e}" is the same array instance as a list reached from another node. The recursion on "${a.anchor}" needs a tree: give each node its own "${d}" array.`),r})(n.path,u,i),g=w(s,y(c),u);return h.set(c,Array.isArray(u)?u:[]),null!==f&&null!==i&&i.add(f),{rows:g.newIndexes,tracked:f}}const _=(e,t,r)=>{const{rows:a,tracked:l}=P(t,r,g);if(0===a.length)return;const h=(e=>{const t=u[e];if(void 0!==t)return t;const r=s.concretePathAt(i,e),a=0===i.length?r:s.concretePathAt("",e),c={nodePath:a,concretePathInfo:o(r),childListPathInfo:o(a+n+d)};return u[e]=c,c})(e),f=l;p.add(f);const m=h.concretePathInfo.wildcardCount===e+1;for(let t=0;t<a.length;t++){const n=a[t];m?c.push(v(h.concretePathInfo,n)):x(h.concretePathInfo,e+1,n),_(e+1,h.childListPathInfo,n)}p.delete(f)};_(0,o(f),null);for(const[e,t]of h)m(e,t);return c}function D(e,t,n,r,s,o,c){h(n);const l=n.stateElement.recursionRegistry,d=k(l.spec,r);null===d&&A(i(r,l.spec.recursiveAnchor));const f=I(d);Array.isArray(s)||A(a(r,'with "**" requires an explicit empty indexes array ([]) — the write API takes no context.')),s.length>0&&A(`[wcs/recursion-setall-form] $setAll("${r}", indexes, …) with "**" takes no partial prefix: a prefix cannot say which depth it applies to. Pass [] to broadcast to every depth.`),"function"==typeof o&&A(a(r,'with "**" does not take a mapper yet — the index tuple has a different length at each depth.')),!0===c?.spread&&A(a(r,'with "**" does not take { spread: true } — handing a flat array to a tree needs the author to know the walk order, which is not a usable contract.')),function(e,t,n){O(e,n)&&A(`[wcs/recursion-structural-write] "${t}" writes the recursion structure itself (a node, its "${e.repeatList}" list or that list's length, or an object on the way to that list). This version broadcasts to leaf properties only — replacing a node would invalidate the child addresses already resolved for this write.`)}(l.spec,r,f);const p=l.conflictingRecursiveGetter(f);null!==p&&A(`[wcs/recursion-readonly] "${r}" writes into the recursive getter "${p}", which has no setter — the two name the same family of concrete paths (or this path points inside the value that getter derives). Write the values it derives from instead.`);const g=C(e,t,n,l,d);let m=0;for(let r=0;r<g.length;r++)void 0!==o&&(u(e,g[r],o,t,n),m++);return m}const G={write(e,t){if(!0!==e.hasRecursion)return P;const n=e.recursionRegistry.recursiveGetterOwningPath(t.pathInfo);return null!==n&&A(`[wcs/recursion-readonly] "${t.pathInfo.path}" writes into the recursive getter "${n}" (this path is that getter at one depth, or a path inside the value it derives), which has no setter. Write the values it derives from instead.`),P},get(e,t,n,r){if(!0!==e.stateElement.hasRecursion)return P;if("$getAll"===t)return(s,o)=>{if(b(s)){if(void 0!==o)return function(e,t,n,r,s){const o=n.stateElement.recursionRegistry,a=k(o.spec,r);null===a&&A(i(r,o.spec.recursiveAnchor)),Array.isArray(s)||A(`[wcs/recursion-getall-form] $getAll("${r}", indexes) with "**" takes either no indexes (to read the depth of the recursive getter being evaluated) or [] (to walk every depth) — got ${null===s?"null":typeof s}.`),s.length>0&&A(`[wcs/recursion-getall-form] $getAll("${r}", indexes) with "**" takes no partial prefix: a prefix cannot say which depth it applies to. Omit the indexes to read the depth of the recursive getter being evaluated, or pass [] to walk every depth.`);const c=C(e,t,n,o,a),h=[];for(let r=0;r<c.length;r++)h.push(l(e,c[r],t,n));return h}(r,n,e,s,o);s=E(e.stateElement,e,s)}return d(r,t,n,e)(s,o)};if("$setAll"===t)return(s,i,o,a)=>b(s)?D(r,n,e,s,i,o,a):f(r,t,n,e)(s,i,o,a);if(36!==t.charCodeAt(0)&&b(t)){const s=p(E(e.stateElement,e,t)),i=g(r,s,n,e);return l(r,v(s.pathInfo,i),n,e)}return P}};let z=!1;function M(e,s){"string"==typeof s&&0!==s.length||A(`[wcs/recursion-declaration-invalid] ${c} ${e} must be a non-empty string.`);const i=s.split(n);i.some(e=>0===e.length)&&A(`[wcs/recursion-declaration-invalid] ${c} ${e} "${s}" must not contain empty path segments.`),i.length<2&&A(`[wcs/recursion-declaration-invalid] ${c} ${e} "${s}" must name a list element: a property path ending with "${n}${r}" (for example "nodes${n}${r}").`),i[i.length-1]!==r&&A(`[wcs/recursion-declaration-invalid] ${c} ${e} "${s}" must end with "${n}${r}" — it names the element of the list, not the list itself.`),36===i[0].charCodeAt(0)&&A(`[wcs/recursion-declaration-invalid] ${c} ${e} "${s}" must not start with "$" — that namespace is reserved.`),-1!==s.indexOf("#")&&A(`[wcs/recursion-declaration-invalid] ${c} ${e} "${s}" must not contain "#" — that segment is reserved for mounts.`);for(let n=0;n<i.length-1;n++)i[n]===r&&A(`[wcs/recursion-declaration-invalid] ${c} ${e} "${s}" must have exactly one "${r}", at the end. Wildcards in the middle are not supported in this version.`),i[n]===t&&A(`[wcs/recursion-declaration-invalid] ${c} ${e} "${s}" must not contain "${t}" — the declaration is what gives "${t}" its meaning.`),isNaN(Number(i[n]))||A(`[wcs/recursion-declaration-invalid] ${c} ${e} "${s}" must not contain an index segment ("${i[n]}") — the recursion is declared over the shape of the tree, not over one row.`)}const T=new WeakSet;function F(e){return"function"==typeof e.get&&T.has(e.get)}const H="[wcs/recursion-declaration-invalid]";class q{spec;_definitions=new Map;_accessors=new Map;_ownerByPath=new Map;_ownerByPathInfo=new WeakMap;_accessorByPathInfo=new WeakMap;_concreteBySuffix=new Map;_registeredListPaths=new Set;constructor(e,t){this.spec=e;const r=_(t);for(const[t,s]of Object.entries(r)){if(!b(t))continue;"function"==typeof s.set&&A(`${H} Recursive setters are not supported in this version: "${t}". Declare a plain path setter, or write through the concrete path.`),"function"!=typeof s.get&&A(`${H} "${t}" contains "**" but is not a getter. The recursion wildcard only names a family of computed paths.`);const r=k(e,t);null===r&&A(i(t,e.recursiveAnchor)),0===r.length&&A(`${H} "${t}" names the recursive node itself. "**" names a computed path under a node (for example "${e.recursiveAnchor}${n}total"), not the node.`),O(e,I(r))&&A(`${H} "${t}" names the recursion structure itself (a node, its "${e.repeatList}" list or that list's length, or an object on the way to that list). A recursive getter would hide the real child list at every depth — "**" names a computed leaf under a node (for example "${e.recursiveAnchor}${n}total").`),this._definitions.set(t,{recursivePath:t,suffix:r,get:s.get})}this._assertNoColliding(),this._assertNoConcreteCollision(r)}_assertNoConcreteCollision(e){for(const[t,n]of Object.entries(e)){if(b(t)||F(n))continue;const e=this._matchExpansion(t);null!==e&&A(`${H} "${t}" is already defined on the state, so the recursive getter "${e}" cannot expand to it. Rename one of them.`)}}_assertNoColliding(){const e=Array.from(this._definitions.values());for(let t=0;t<e.length;t++)for(let n=t+1;n<e.length;n++)j(this.spec,e[t].suffix,e[n].suffix)&&A(`${H} "${e[t].recursivePath}" and "${e[n].recursivePath}" expand to the same concrete path at different depths (they differ by whole repetitions of "${this.spec.repeat}"). Rename one of them.`)}get hasDefinitions(){return this._definitions.size>0}conflictingRecursiveGetter(e){for(const t of this._definitions.values())if(R(this.spec,t.suffix,e))return t.recursivePath;return null}recursiveGetterOwningPath(e){const t=this._ownerByPathInfo.get(e);if(void 0!==t)return t;const n=this.recursiveGetterOwning(e.path);return this._ownerByPathInfo.set(e,n),n}recursiveGetterOwning(e){const t=this._accessors.get(e);if(void 0!==t)return t.recursivePath;const r=L(e),s=this._ownerByPath.get(r);if(void 0!==s)return s;let i=null;if(r.startsWith(this.spec.anchor)){i=this._matchExpansion(r);for(let e=r.lastIndexOf(n);null===i&&e>this.spec.anchor.length;e=r.lastIndexOf(n,e-1))i=this._matchExpansion(r.slice(0,e))}return this._ownerByPath.set(r,i),i}_matchExpansion(e){for(const t of this._definitions.values())if(null!==N(this.spec,t.suffix,e))return t.recursivePath;return null}materializeForPathInfo(e,t){if(0===this._definitions.size)return null;const n=this._accessorByPathInfo.get(t);if(void 0!==n)return n;const r=this.materializeFor(e,t.path);return this._accessorByPathInfo.set(t,r),r}materializeFor(e,t){const n=this._accessors.get(t);if(void 0!==n)return n;if(!t.startsWith(this.spec.anchor))return null;let r=null,s=0;for(const e of this._definitions.values()){const n=N(this.spec,e.suffix,t);null!==n&&(null!==r&&A(`"${t}" matches both "${r.recursivePath}" and "${e.recursivePath}".`),r=e,s=n)}return null===r?null:this._define(e,r,s,t)}_define(e,t,n,r){const s=e.findStateDescriptor(r);void 0===s||F(s)||A(`"${r}" is already defined on the state, so the recursive getter "${t.recursivePath}" cannot expand to it. Rename one of them.`);const i=Object.freeze({recursivePath:t.recursivePath,depth:n}),o=t.get,a=function(){return o.call(this)};var c;return c=a,T.add(c),e.defineTreeAccessor(r,{get:a,enumerable:!1,configurable:!0}),this._registerListPaths(e,n),this._accessors.set(r,i),i}_registerListPaths(e,t){for(const r of function(e,t){const r=[];r.push(e.anchorList);for(let s=0;s<t;s++)r.push(S(e,s)+n+e.repeatList);return r}(this.spec,t))this._registeredListPaths.has(r)||(this._registeredListPaths.add(r),e.addListPath(r))}forgetGenerated(e,t){const n=new Set(this._accessors.keys());return function(e,t,n){if(0!==n.size){for(const e of n){const n=Object.getOwnPropertyDescriptor(t,e);void 0!==n&&F(n)&&delete t[e]}for(const t of[e.staticDependency,e.dynamicDependency]){for(const e of n)t.delete(e);for(const[e,r]of t){let s=null;for(let e=0;e<r.length;e++)n.has(r[e])?s??=r.slice(0,e):s?.push(r[e]);null!==s&&(0===s.length?t.delete(e):t.set(e,s))}}}}(e,t,n),n}concretePathAt(e,t){let n=this._concreteBySuffix.get(e);void 0===n&&(n=[],this._concreteBySuffix.set(e,n));let r=n[t];return void 0===r&&(r=W(this.spec,e,t),n[t]=r),r}accessorFor(e){return this._accessors.get(e)??null}get materializedPaths(){return new Set(this._accessors.keys())}}const J="recursionSpec",K="recursionRegistry",Q={order:5,validateEarly(e,s,i){const o=function(e){const s=e[c];if(void 0===s)return null;"object"==typeof s&&null!==s||A(`[wcs/recursion-declaration-invalid] ${c} must be an object mapping one anchor path to its repeating sub-path (for example { "nodes.*": "children.*" }).`);const i=Object.entries(s);0===i.length&&A(`[wcs/recursion-declaration-invalid] ${c} must declare exactly one anchor; it is empty.`),i.length>1&&A(`[wcs/recursion-declaration-invalid] ${c} declares ${i.length} anchors (${i.map(([e])=>`"${e}"`).join(", ")}). This version supports exactly one self-recursive anchor per state.`);const[o,a]=i[0];M("anchor",o),"string"!=typeof a&&A(`[wcs/recursion-declaration-invalid] ${c} entry "${o}" must map to the repeating sub-path as a string (for example "children${n}${r}").`),M("repeating sub-path",a);const l=o.slice(0,o.lastIndexOf(n)),h=a.slice(0,a.lastIndexOf(n)),u=l+n+t;return Object.freeze({anchor:o,repeat:a,recursiveAnchor:u,anchorList:l,repeatList:h})}(s);i.set(J,o),i.set(K,null===o?null:new q(o,s))},preCommit(e,t,n){const r=e.recursionRegistry;if(null!==r)for(const t of r.forgetGenerated(e,n.get("previousState")))e.addGeneratedPath?.(t);const s=n.get(K)??null;e.setRecursionRegistry?.(s),null!==s&&e.attachAddressHooks?.("recursion",c)},apply(e,t,n){const r=n.get(J)??null;null!==r&&e.addListPath(r.anchorList)}};let U=!1;function V(){U||(U=!0,z||(z=!0,x("recursion",G)),e("recursion",Q))}const X={name:"recursion",install(){V()}};export{X as default,X as recursion};
|
|
1
|
+
import{r as e}from"../chunks/declarationHooks.js";import{R as t,D as n,W as r,M as s,s as i,g as o,t as a,r as c}from"../chunks/pathDiagnostics.js";import{g as l}from"../chunks/checkDependency.js";import{M as h,j as u,l as d,N as f,O as p}from"../chunks/binder.js";import{r as g,N as m,g as v}from"../chunks/getAllPropertyDescriptors.js";import{g as $,a as w,s as y,b as x,c as P,d as _}from"../chunks/setAll.js";import{r as A}from"../chunks/errorGuidance.js";import"../chunks/filterRegistry.js";function b(e){return-1!==e.indexOf(t)}function k(e,t){if(t===e.recursiveAnchor)return"";const s=e.recursiveAnchor+n;if(!t.startsWith(s))return null;const i=t.slice(e.recursiveAnchor.length);if(b(i))return null;const o=i.slice(n.length).split(n);return o[0]===r||o.some(e=>0===e.length)?null:i}function I(e){return 0===e.length?e:n+L(e.slice(n.length))}function j(e,t,r){const s=n+e.repeat,i=t.length<=r.length?t:r,o=t.length<=r.length?r:t;if(!o.endsWith(i))return!1;const a=o.slice(0,o.length-i.length);if(0===a.length)return!0;if(a.length%s.length!==0)return!1;for(let e=0;e<a.length;e+=s.length)if(!a.startsWith(s,e))return!1;return!0}function R(e,t,r){for(let s=r.length;s>0;s=r.lastIndexOf(n,s-1))if(j(e,t,r.slice(0,s)))return!0;return!1}function L(e){const t=e.split(n);for(let e=0;e<t.length;e++)t[e]===r||Number.isNaN(Number(t[e]))||(t[e]=r);return t.join(n)}function O(e,t){const r=e.repeat.split(n),s=n+e.repeat;let i=t;for(;i.startsWith(s);)i=i.slice(s.length);if(0===i.length||i===n+e.repeatList+n+"length")return!0;for(let e=1;e<r.length;e++)if(i===n+r.slice(0,e).join(n))return!0;return!1}function W(e,t,i){i<0&&A(`Recursion depth must not be negative (got ${i}).`);let o=e.anchor;for(let t=0;t<i;t++)o+=n+e.repeat;const a=o+t;let c=0;for(const e of a.split(n))e===r&&c++;return c>s&&A(`[wcs/recursion-depth-exceeded] Recursion on "${e.anchor}" reached depth ${i} ("${a}"), which needs ${c} wildcard levels — the limit is ${s}. Either the data nests deeper than the engine can address, or the tree contains a cycle.`),a}function S(e,t){return W(e,"",t)}function N(e,t,r){if(!r.startsWith(e.anchor))return null;if(t.length>0&&!r.endsWith(t))return null;if(r.length<e.anchor.length+t.length)return null;const s=r.slice(e.anchor.length,r.length-t.length);if(0===s.length)return 0;const i=n+e.repeat;let o=0,a=0;for(;a<s.length;){if(!s.startsWith(i,a))return null;a+=i.length,o++}return o}function B(e,t){if(0===e.addressStackLength)return null;const r=e.lastAddressStack;if(null===r)return null;const s=t.accessorFor(r.pathInfo.path);return null!==s?s.depth:function(e,t){const r=e.spec;if(!t.startsWith(r.anchor))return null;const s=n+r.repeat;let i=0,o=r.anchor.length;for(;t.startsWith(s,o);)o+=s.length,i++;return o!==t.length&&46!==t.charCodeAt(o)?null:i}(t,r.pathInfo.path)}function E(e,t,n){const r=e.recursionRegistry,s=k(r.spec,n);null===s&&A(i(n,r.spec.recursiveAnchor));const o=B(t,r);return null===o&&A(`[wcs/recursion-context] "${n}" uses "**", which is bound to the depth of the recursive getter being evaluated, and there is no recursion context here. Read it from inside a recursive getter or a row getter under "${r.spec.anchor}", or name a concrete depth (for example "${r.spec.anchor}${n.slice(r.spec.recursiveAnchor.length)}"). The depth comes from the innermost frame only: a plain getter reached from a recursive getter has no row of its own, so read "**" in the recursive getter and pass the value on.`),r.concretePathAt(s,o)}function C(e,t,r,s,i){const a=s.spec,c=[],l=new Map,g=[],m=a.repeatList,v=a.anchorList,w=new Set,y=new Set,x=(e,t,n)=>{const r=e.wildcardParentPathInfos;if(t>=r.length)return void c.push(u(e,n));const s=P(r[t],n,null).rows;for(let n=0;n<s.length;n++)x(e,t+1,s[n])};function P(n,s,i){const o=u(n,s),c=d(r.stateElement,o),h=$(e,o,t,r),g=null===i?null:((e,t,n)=>{if(!Array.isArray(t)||0===t.length)return null;const r=t;return w.has(r)&&A(`[wcs/recursion-cycle] "${e}" is reachable from itself: the recursion on "${a.anchor}" walked into a list that one of its own ancestors already owns. The data contains a cycle, which this version does not support.`),n.has(r)&&A(`[wcs/recursion-shared-list] "${e}" is the same array instance as a list reached from another node. The recursion on "${a.anchor}" needs a tree: give each node its own "${m}" array.`),r})(n.path,h,i),v=f(s,p(c),h);return l.set(c,Array.isArray(h)?h:[]),null!==g&&null!==i&&i.add(g),{rows:v.newIndexes,tracked:g}}const _=(e,t,r)=>{const{rows:a,tracked:l}=P(t,r,y);if(0===a.length)return;const h=(e=>{const t=g[e];if(void 0!==t)return t;const r=s.concretePathAt(i,e),a=0===i.length?r:s.concretePathAt("",e),c={nodePath:a,concretePathInfo:o(r),childListPathInfo:o(a+n+m)};return g[e]=c,c})(e),d=l;w.add(d);const f=h.concretePathInfo.wildcardCount===e+1;for(let t=0;t<a.length;t++){const n=a[t];f?c.push(u(h.concretePathInfo,n)):x(h.concretePathInfo,e+1,n),_(e+1,h.childListPathInfo,n)}w.delete(d)};_(0,o(v),null);for(const[e,t]of l)h(e,t);return c}function D(e,t,n,r,s,o,c){w(n);const l=n.stateElement.recursionRegistry,h=k(l.spec,r);null===h&&A(i(r,l.spec.recursiveAnchor));const u=I(h);Array.isArray(s)||A(a(r,'with "**" requires an explicit empty indexes array ([]) — the write API takes no context.')),s.length>0&&A(`[wcs/recursion-setall-form] $setAll("${r}", indexes, …) with "**" takes no partial prefix: a prefix cannot say which depth it applies to. Pass [] to broadcast to every depth.`),"function"==typeof o&&A(a(r,'with "**" does not take a mapper yet — the index tuple has a different length at each depth.')),!0===c?.spread&&A(a(r,'with "**" does not take { spread: true } — handing a flat array to a tree needs the author to know the walk order, which is not a usable contract.')),function(e,t,n){O(e,n)&&A(`[wcs/recursion-structural-write] "${t}" writes the recursion structure itself (a node, its "${e.repeatList}" list or that list's length, or an object on the way to that list). This version broadcasts to leaf properties only — replacing a node would invalidate the child addresses already resolved for this write.`)}(l.spec,r,u);const d=l.conflictingRecursiveGetter(u);null!==d&&A(`[wcs/recursion-readonly] "${r}" writes into the recursive getter "${d}", which has no setter — the two name the same family of concrete paths (or this path points inside the value that getter derives). Write the values it derives from instead.`);const f=C(e,t,n,l,h);let p=0;for(let r=0;r<f.length;r++)void 0!==o&&(y(e,f[r],o,t,n),p++);return p}const G={write(e,t){if(!0!==e.hasRecursion)return m;const n=e.recursionRegistry.recursiveGetterOwningPath(t.pathInfo);return null!==n&&A(`[wcs/recursion-readonly] "${t.pathInfo.path}" writes into the recursive getter "${n}" (this path is that getter at one depth, or a path inside the value it derives), which has no setter. Write the values it derives from instead.`),m},get(e,t,n,r){if(!0!==e.stateElement.hasRecursion)return m;if("$getAll"===t)return(s,o)=>{if(b(s)){if(void 0!==o)return function(e,t,n,r,s){const o=n.stateElement.recursionRegistry,a=k(o.spec,r);null===a&&A(i(r,o.spec.recursiveAnchor)),Array.isArray(s)||A(`[wcs/recursion-getall-form] $getAll("${r}", indexes) with "**" takes either no indexes (to read the depth of the recursive getter being evaluated) or [] (to walk every depth) — got ${null===s?"null":typeof s}.`),s.length>0&&A(`[wcs/recursion-getall-form] $getAll("${r}", indexes) with "**" takes no partial prefix: a prefix cannot say which depth it applies to. Omit the indexes to read the depth of the recursive getter being evaluated, or pass [] to walk every depth.`);const c=C(e,t,n,o,a),l=[];for(let r=0;r<c.length;r++)l.push($(e,c[r],t,n));return l}(r,n,e,s,o);s=E(e.stateElement,e,s)}return x(r,t,n,e)(s,o)};if("$setAll"===t)return(s,i,o,a)=>b(s)?D(r,n,e,s,i,o,a):P(r,t,n,e)(s,i,o,a);if(36!==t.charCodeAt(0)&&b(t)){const s=l(E(e.stateElement,e,t)),i=_(r,s,n,e);return $(r,u(s.pathInfo,i),n,e)}return m}};let z=!1;function M(e,s){"string"==typeof s&&0!==s.length||A(`[wcs/recursion-declaration-invalid] ${c} ${e} must be a non-empty string.`);const i=s.split(n);i.some(e=>0===e.length)&&A(`[wcs/recursion-declaration-invalid] ${c} ${e} "${s}" must not contain empty path segments.`),i.length<2&&A(`[wcs/recursion-declaration-invalid] ${c} ${e} "${s}" must name a list element: a property path ending with "${n}${r}" (for example "nodes${n}${r}").`),i[i.length-1]!==r&&A(`[wcs/recursion-declaration-invalid] ${c} ${e} "${s}" must end with "${n}${r}" — it names the element of the list, not the list itself.`),36===i[0].charCodeAt(0)&&A(`[wcs/recursion-declaration-invalid] ${c} ${e} "${s}" must not start with "$" — that namespace is reserved.`),-1!==s.indexOf("#")&&A(`[wcs/recursion-declaration-invalid] ${c} ${e} "${s}" must not contain "#" — that segment is reserved for mounts.`);for(let n=0;n<i.length-1;n++)i[n]===r&&A(`[wcs/recursion-declaration-invalid] ${c} ${e} "${s}" must have exactly one "${r}", at the end. Wildcards in the middle are not supported in this version.`),i[n]===t&&A(`[wcs/recursion-declaration-invalid] ${c} ${e} "${s}" must not contain "${t}" — the declaration is what gives "${t}" its meaning.`),isNaN(Number(i[n]))||A(`[wcs/recursion-declaration-invalid] ${c} ${e} "${s}" must not contain an index segment ("${i[n]}") — the recursion is declared over the shape of the tree, not over one row.`)}const T=new WeakSet;function F(e){return"function"==typeof e.get&&T.has(e.get)}const H="[wcs/recursion-declaration-invalid]";class q{spec;_definitions=new Map;_accessors=new Map;_ownerByPath=new Map;_ownerByPathInfo=new WeakMap;_accessorByPathInfo=new WeakMap;_concreteBySuffix=new Map;_registeredListPaths=new Set;constructor(e,t){this.spec=e;const r=v(t);for(const[t,s]of Object.entries(r)){if(!b(t))continue;"function"==typeof s.set&&A(`${H} Recursive setters are not supported in this version: "${t}". Declare a plain path setter, or write through the concrete path.`),"function"!=typeof s.get&&A(`${H} "${t}" contains "**" but is not a getter. The recursion wildcard only names a family of computed paths.`);const r=k(e,t);null===r&&A(i(t,e.recursiveAnchor)),0===r.length&&A(`${H} "${t}" names the recursive node itself. "**" names a computed path under a node (for example "${e.recursiveAnchor}${n}total"), not the node.`),O(e,I(r))&&A(`${H} "${t}" names the recursion structure itself (a node, its "${e.repeatList}" list or that list's length, or an object on the way to that list). A recursive getter would hide the real child list at every depth — "**" names a computed leaf under a node (for example "${e.recursiveAnchor}${n}total").`),this._definitions.set(t,{recursivePath:t,suffix:r,get:s.get})}this._assertNoColliding(),this._assertNoConcreteCollision(r)}_assertNoConcreteCollision(e){for(const[t,n]of Object.entries(e)){if(b(t)||F(n))continue;const e=this._matchExpansion(t);null!==e&&A(`${H} "${t}" is already defined on the state, so the recursive getter "${e}" cannot expand to it. Rename one of them.`)}}_assertNoColliding(){const e=Array.from(this._definitions.values());for(let t=0;t<e.length;t++)for(let n=t+1;n<e.length;n++)j(this.spec,e[t].suffix,e[n].suffix)&&A(`${H} "${e[t].recursivePath}" and "${e[n].recursivePath}" expand to the same concrete path at different depths (they differ by whole repetitions of "${this.spec.repeat}"). Rename one of them.`)}get hasDefinitions(){return this._definitions.size>0}conflictingRecursiveGetter(e){for(const t of this._definitions.values())if(R(this.spec,t.suffix,e))return t.recursivePath;return null}recursiveGetterOwningPath(e){const t=this._ownerByPathInfo.get(e);if(void 0!==t)return t;const n=this.recursiveGetterOwning(e.path);return this._ownerByPathInfo.set(e,n),n}recursiveGetterOwning(e){const t=this._accessors.get(e);if(void 0!==t)return t.recursivePath;const r=L(e),s=this._ownerByPath.get(r);if(void 0!==s)return s;let i=null;if(r.startsWith(this.spec.anchor)){i=this._matchExpansion(r);for(let e=r.lastIndexOf(n);null===i&&e>this.spec.anchor.length;e=r.lastIndexOf(n,e-1))i=this._matchExpansion(r.slice(0,e))}return this._ownerByPath.set(r,i),i}_matchExpansion(e){for(const t of this._definitions.values())if(null!==N(this.spec,t.suffix,e))return t.recursivePath;return null}materializeForPathInfo(e,t){if(0===this._definitions.size)return null;const n=this._accessorByPathInfo.get(t);if(void 0!==n)return n;const r=this.materializeFor(e,t.path);return this._accessorByPathInfo.set(t,r),r}materializeFor(e,t){const n=this._accessors.get(t);if(void 0!==n)return n;if(!t.startsWith(this.spec.anchor))return null;let r=null,s=0;for(const e of this._definitions.values()){const n=N(this.spec,e.suffix,t);null!==n&&(null!==r&&A(`"${t}" matches both "${r.recursivePath}" and "${e.recursivePath}".`),r=e,s=n)}return null===r?null:this._define(e,r,s,t)}_define(e,t,n,r){const s=e.findStateDescriptor(r);void 0===s||F(s)||A(`"${r}" is already defined on the state, so the recursive getter "${t.recursivePath}" cannot expand to it. Rename one of them.`);const i=Object.freeze({recursivePath:t.recursivePath,depth:n}),o=t.get,a=function(){return o.call(this)};var c;return c=a,T.add(c),e.defineTreeAccessor(r,{get:a,enumerable:!1,configurable:!0}),this._registerListPaths(e,n),this._accessors.set(r,i),i}_registerListPaths(e,t){for(const r of function(e,t){const r=[];r.push(e.anchorList);for(let s=0;s<t;s++)r.push(S(e,s)+n+e.repeatList);return r}(this.spec,t))this._registeredListPaths.has(r)||(this._registeredListPaths.add(r),e.addListPath(r))}forgetGenerated(e,t){const n=new Set(this._accessors.keys());return function(e,t,n){if(0!==n.size){for(const e of n){const n=Object.getOwnPropertyDescriptor(t,e);void 0!==n&&F(n)&&delete t[e]}for(const t of[e.staticDependency,e.dynamicDependency]){for(const e of n)t.delete(e);for(const[e,r]of t){let s=null;for(let e=0;e<r.length;e++)n.has(r[e])?s??=r.slice(0,e):s?.push(r[e]);null!==s&&(0===s.length?t.delete(e):t.set(e,s))}}}}(e,t,n),n}concretePathAt(e,t){let n=this._concreteBySuffix.get(e);void 0===n&&(n=[],this._concreteBySuffix.set(e,n));let r=n[t];return void 0===r&&(r=W(this.spec,e,t),n[t]=r),r}accessorFor(e){return this._accessors.get(e)??null}get materializedPaths(){return new Set(this._accessors.keys())}}const J="recursionSpec",K="recursionRegistry",Q={order:5,validateEarly(e,s,i){const o=function(e){const s=e[c];if(void 0===s)return null;"object"==typeof s&&null!==s||A(`[wcs/recursion-declaration-invalid] ${c} must be an object mapping one anchor path to its repeating sub-path (for example { "nodes.*": "children.*" }).`);const i=Object.entries(s);0===i.length&&A(`[wcs/recursion-declaration-invalid] ${c} must declare exactly one anchor; it is empty.`),i.length>1&&A(`[wcs/recursion-declaration-invalid] ${c} declares ${i.length} anchors (${i.map(([e])=>`"${e}"`).join(", ")}). This version supports exactly one self-recursive anchor per state.`);const[o,a]=i[0];M("anchor",o),"string"!=typeof a&&A(`[wcs/recursion-declaration-invalid] ${c} entry "${o}" must map to the repeating sub-path as a string (for example "children${n}${r}").`),M("repeating sub-path",a);const l=o.slice(0,o.lastIndexOf(n)),h=a.slice(0,a.lastIndexOf(n)),u=l+n+t;return Object.freeze({anchor:o,repeat:a,recursiveAnchor:u,anchorList:l,repeatList:h})}(s);i.set(J,o),i.set(K,null===o?null:new q(o,s))},preCommit(e,t,n){const r=e.recursionRegistry;if(null!==r)for(const t of r.forgetGenerated(e,n.get("previousState")))e.addGeneratedPath?.(t);const s=n.get(K)??null;e.setRecursionRegistry?.(s),null!==s&&e.attachAddressHooks?.("recursion",c)},apply(e,t,n){const r=n.get(J)??null;null!==r&&e.addListPath(r.anchorList)}};let U=!1;function V(){U||(U=!0,z||(z=!0,g("recursion",G)),e("recursion",Q))}const X={name:"recursion",install(){V()}};export{X as default,X as recursion};
|
|
2
2
|
//# sourceMappingURL=recursion.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recursion.js","sources":["../../../../../src/recursion/expand.ts","../../../../../src/recursion/bind.ts","../../../../../src/recursion/walk.ts","../../../../../src/recursion/setAllRecursive.ts","../../../../../src/recursion/addressHooks.ts","../../../../../src/recursion/getAllRecursive.ts","../../../../../src/recursion/declaration.ts","../../../../../src/recursion/generation.ts","../../../../../src/recursion/registry.ts","../../../../../src/recursion/declarations.ts","../../../../../src/features/recursion.ts"],"sourcesContent":["/**\n * recursion/expand.ts\n *\n * `**` を含むオーサリング層のパスと、エンジンが扱う具体パスの相互変換。\n * **純関数だけ**を置く(state も proxy も触らない)。\n *\n * 変換は 1 対 1 ではなく 1 対多である。`nodes.**.total` は深さごとに\n * `nodes.*.total` / `nodes.*.children.*.total` / … という無限の族を表し、\n * エンジンが見るのは常にそのうちの 1 本だけ(設計書 D2)。\n */\n\nimport { DELIMITER, MAX_WILDCARD_DEPTH, RECURSION_WILDCARD, WILDCARD } from \"../define\";\nimport { raiseError } from \"../raiseError\";\nimport { IRecursionSpec } from \"./types\";\n\n/** `**` を含むか(含まない大多数のパスを 1 回の indexOf で抜ける)。 */\nexport function hasRecursionWildcard(path: string): boolean {\n return path.indexOf(RECURSION_WILDCARD) !== -1;\n}\n\n/**\n * `**` を含むパスを宣言と突き合わせ、接尾辞(`**` より後ろ。無ければ空文字)を返す。\n * 宣言に合致しない `**` は「宣言なしの `**`」として呼び出し側が診断する(null を返す)。\n */\nexport function splitRecursivePath(spec: IRecursionSpec, path: string): string | null {\n if (path === spec.recursiveAnchor) {\n return \"\";\n }\n const prefix = spec.recursiveAnchor + DELIMITER;\n if (!path.startsWith(prefix)) {\n return null;\n }\n const suffix = path.slice(spec.recursiveAnchor.length);\n // 接尾辞に 2 つ目の `**` があるのは初版では未対応(複数の再帰点)。\n if (hasRecursionWildcard(suffix)) {\n return null;\n }\n // 接尾辞は整形されたパスでなければならない: 空セグメント(`nodes.**.` / `nodes.**..x`)と\n // `**` 直後の素の `*`(`nodes.**.*` — 展開すると `nodes.*.*` でアンカー行そのもの)は\n // 受理しない。`assertNodePath` / `$watch` が同じ形を拒否するのと対称(第 4 サイクルで実測:\n // 受理すると `[undefined×n]` や生の `Reflect.set called on non-object` になっていた)。\n const segments = suffix.slice(DELIMITER.length).split(DELIMITER);\n if (segments[0] === WILDCARD || segments.some((segment) => segment.length === 0)) {\n return null;\n }\n return suffix;\n}\n\n/**\n * 接尾辞(`.` で始まる)の添字セグメントだけを `*` に畳む。先頭の空セグメントは区切りの\n * 都合なので畳まない(`indexSegmentsToWildcard` に丸ごと渡すと `Number(\"\") === 0` で `*` になる)。\n * `**` パスの検査(構造・読み取り専用)と `**` getter キーの検査が共有する。\n */\nexport function foldSuffixIndexes(suffix: string): string {\n return suffix.length === 0 ? suffix : DELIMITER + indexSegmentsToWildcard(suffix.slice(DELIMITER.length));\n}\n\n/**\n * 2 つの接尾辞が**同じ具体パス族**を指すか。片方がもう片方の末尾で、差分が反復語の\n * 整数倍(0 回を含む)のとき真。`nodes.**.total` と `nodes.**.children.*.total` は\n * 深さ k と k+1 で同じ `nodes.*.children.*.total` になる、という関係を捉える。\n * 静的側の `recursionPaths.sameFamily` と同じ純関数。\n */\nexport function sameFamily(spec: IRecursionSpec, a: string, b: string): boolean {\n const unit = DELIMITER + spec.repeat;\n const shorter = a.length <= b.length ? a : b;\n const longer = a.length <= b.length ? b : a;\n if (!longer.endsWith(shorter)) {\n return false;\n }\n const gap = longer.slice(0, longer.length - shorter.length);\n if (gap.length === 0) {\n return true;\n }\n if (gap.length % unit.length !== 0) {\n return false;\n }\n for (let cursor = 0; cursor < gap.length; cursor += unit.length) {\n if (!gap.startsWith(unit, cursor)) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * 接尾辞 `suffix` が、`**` getter の接尾辞 `familySuffix` の族そのもの、またはその値の内側を\n * 指しているか。`.` 境界で切った各接頭辞 `p`(全体を含む)について `sameFamily(familySuffix, p)`\n * を見る — `startsWith(familySuffix + \".\")` だけでは、反復語ぶんずれた展開形の値の内側\n * (`nodes.**.children.*.total.x` で `nodes.**.total`)を取りこぼす(第 4 サイクルで実測)。\n */\nexport function coversSuffix(spec: IRecursionSpec, familySuffix: string, suffix: string): boolean {\n for (let end = suffix.length; end > 0; end = suffix.lastIndexOf(DELIMITER, end - 1)) {\n if (sameFamily(spec, familySuffix, suffix.slice(0, end))) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * 添字セグメント(`nodes.1.total` の `1`)を `*` に畳む。判定は `address/ResolvedAddress.ts`\n * と同じ「`Number()` が NaN でない区切り」。API のパス引数(`$getAll` / `$setAll` / `$resolve`)と\n * `**` パスの接尾辞は set トラップと違って `getResolvedAddress` の正規化を経ないので、\n * 再帰の検査(読み取り専用・構造)に掛ける前にここで畳む。\n */\nexport function indexSegmentsToWildcard(path: string): string {\n const segments = path.split(DELIMITER);\n for (let i = 0; i < segments.length; i++) {\n if (segments[i] !== WILDCARD && !Number.isNaN(Number(segments[i]))) {\n segments[i] = WILDCARD;\n }\n }\n return segments.join(DELIMITER);\n}\n\n/**\n * `**` パスの接尾辞が「再帰の構造そのもの」を名指しているか。\n *\n * ノード自身(`nodes.**` / `nodes.**.children.*`)・子リスト(`nodes.**.children`)・その\n * `length`(`arr.length = 0` は配列を切り詰める)・多段の反復サブパスなら子リストへ至る\n * 途中のオブジェクト(`nodes.**.branch`)。書き側(`setAllRecursive`)は確定済みの\n * 子アドレスを壊すので拒否し、宣言側(`**` getter のキー)は生成 getter が実データの\n * 子リストを影にするので拒否する — 同じ述語を両方が使う。\n *\n * 反復サブパスを**途中まで**名指す形もすべて構造。`\".\" + repeatList` との完全一致だけを\n * 見ると、多段の repeat で途中のオブジェクトが素通りし、深さ 0 の `branch` を置き換えた\n * 瞬間に確定済みの深さ 1 のアドレスが宙に浮く(着地後レビューで実測。実装計画 §7-3)。\n */\nexport function isStructuralSuffix(spec: IRecursionSpec, suffix: string): boolean {\n const repeatSegments = spec.repeat.split(DELIMITER);\n const unit = DELIMITER + spec.repeat;\n let rest = suffix;\n while (rest.startsWith(unit)) {\n rest = rest.slice(unit.length);\n }\n if (rest.length === 0 || rest === DELIMITER + spec.repeatList + DELIMITER + \"length\") {\n return true;\n }\n for (let i = 1; i < repeatSegments.length; i++) {\n if (rest === DELIMITER + repeatSegments.slice(0, i).join(DELIMITER)) {\n return true;\n }\n }\n return false;\n}\n\n/** 深さ k の具体パスを作る。上限超過は生成前に throw する(設計書 D11)。 */\nexport function concretePathAt(spec: IRecursionSpec, suffix: string, depth: number): string {\n if (depth < 0) {\n raiseError(`Recursion depth must not be negative (got ${depth}).`);\n }\n let path = spec.anchor;\n for (let i = 0; i < depth; i++) {\n path += DELIMITER + spec.repeat;\n }\n const full = path + suffix;\n // ワイルドカード段数は展開後のパス全体で数える(アンカー・反復・接尾辞をすべて含む)。\n // intern(getPathInfo)より**前**に文字列から数える — 上限超過のパスを永続キャッシュ\n // (PathInfo の `_cache`)に残さない(設計書 D10「毎ノードの固有パスを intern しない」)。\n let wildcardCount = 0;\n for (const segment of full.split(DELIMITER)) {\n if (segment === WILDCARD) {\n wildcardCount++;\n }\n }\n if (wildcardCount > MAX_WILDCARD_DEPTH) {\n raiseError(\n `[wcs/recursion-depth-exceeded] Recursion on \"${spec.anchor}\" reached depth ${depth} ` +\n `(\"${full}\"), which needs ${wildcardCount} wildcard levels — the limit is ${MAX_WILDCARD_DEPTH}. ` +\n `Either the data nests deeper than the engine can address, or the tree contains a cycle.`\n );\n }\n return full;\n}\n\n/** 深さ k のノードパス(接尾辞なし)。リストパスの登録に使う(このモジュール内だけ)。 */\nfunction nodePathAt(spec: IRecursionSpec, depth: number): string {\n return concretePathAt(spec, \"\", depth);\n}\n\n/**\n * 深さ k のノードが持つ子リストのパス(`nodes.*.children` / `nodes.*.children.*.children` …)。\n * `listPaths` へ登録する対象(E4)。深さ 0 のアンカー自身のリスト(`nodes`)も含める。\n */\nexport function listPathsUpTo(spec: IRecursionSpec, depth: number): string[] {\n const paths: string[] = [];\n // アンカー自身のリスト(末尾の `.*` を落とした形)\n paths.push(spec.anchorList);\n for (let k = 0; k < depth; k++) {\n paths.push(nodePathAt(spec, k) + DELIMITER + spec.repeatList);\n }\n return paths;\n}\n\n/**\n * 具体パスが「その再帰 getter の深さ k の展開形」なら深さを返す。違えば null。\n *\n * 文字列中の反復語の出現数で数えない — 接尾辞が反復語と同じ綴りを含む場合に\n * 取り違える。前から `anchor`、後ろから `suffix` を確かめ、間が `repeat` の\n * 反復ちょうどであることを見る。\n */\nexport function depthOfConcretePath(spec: IRecursionSpec, suffix: string, path: string): number | null {\n if (!path.startsWith(spec.anchor)) {\n return null;\n }\n if (suffix.length > 0 && !path.endsWith(suffix)) {\n return null;\n }\n // 接頭辞と接尾辞が**重なって**はならない。重なると slice が空文字に畳まれて\n // 「深さ 0 で一致」に見え、アンカーそのもの(`nodes.*` — 実データの行)が\n // 生成 getter に隠される。接尾辞が `.*` の `nodes.**.*` で実際に踏んだ。\n if (path.length < spec.anchor.length + suffix.length) {\n return null;\n }\n const middle = path.slice(spec.anchor.length, path.length - suffix.length);\n if (middle.length === 0) {\n return 0;\n }\n const unit = DELIMITER + spec.repeat;\n let depth = 0;\n let cursor = 0;\n while (cursor < middle.length) {\n if (!middle.startsWith(unit, cursor)) {\n return null;\n }\n cursor += unit.length;\n depth++;\n }\n return depth;\n}\n","/**\n * recursion/bind.ts\n *\n * オーサリング層の `**` を「いま評価している深さ」へ束縛する。\n *\n * 深さの根拠は**生成アクセサのアドレス**であって、文字列中の反復語の出現数ではない。\n * `getByAddress` は getterPaths に載るパスを読むときアドレスをスタックへ積むので、\n * 深さ k の再帰 getter の本体を評価している最中は、スタック先頭がその具体パスの\n * アドレスになっている。そこから深さを復元する(実装計画 §1-2)。\n *\n * 見るのは**スタック先頭だけ**である。添字(ListIndex)を供給する `getContextListIndex` /\n * `$getAll` の省略形も先頭しか見ないので、深さだけを外側のフレームから拾うと「深さは\n * 束縛されたが行は無い」という定義にない状態になる — `**` getter が別の素の getter を\n * 経由して `**` を読む形(`get \"nodes.**.x\"() { return this.helper }` /\n * `get helper() { return this[\"nodes.**.value\"] }`)がそれで、直接読みは生の\n * `ListIndex not found`、`$getAll` の省略形は「束縛した深さ × 全行」という値を無言で\n * 返していた。深さと行は同じフレームから取る。\n */\n\nimport { IStateElement } from \"../components/types\";\nimport { DELIMITER } from \"../define\";\nimport { IStateHandler } from \"../proxy/types\";\nimport { recursionAnchorMismatchMessage } from \"../pathDiagnostics\";\nimport { raiseError } from \"../raiseError\";\nimport { splitRecursivePath } from \"./expand\";\nimport type { RecursionRegistry } from \"./registry\";\n\n/**\n * 具体パスの**接頭辞**として最深のノードパスを見つけ、その深さを返す。\n * `nodes.*.children.*.label` のような行 getter の文脈から深さ 1 を取り出す用。\n */\nfunction depthOfConcretePathPrefix(registry: RecursionRegistry, path: string): number | null {\n const spec = registry.spec;\n if (!path.startsWith(spec.anchor)) {\n return null;\n }\n const unit = DELIMITER + spec.repeat;\n let depth = 0;\n let cursor = spec.anchor.length;\n while (path.startsWith(unit, cursor)) {\n cursor += unit.length;\n depth++;\n }\n // 接頭辞の直後はパス境界(末尾、または `.`)でなければならない。\n if (cursor !== path.length && path.charCodeAt(cursor) !== 46 /* '.' */) {\n return null;\n }\n return depth;\n}\n\n/**\n * 評価中のアドレス(スタック先頭)から再帰の深さを求める。再帰文脈でなければ null。\n * 先頭が null(ループ文脈の無いイベントハンドラ・初期同期)も再帰文脈ではない。\n */\nexport function currentRecursionDepth(handler: IStateHandler, registry: RecursionRegistry): number | null {\n if (handler.addressStackLength === 0) {\n return null;\n }\n const address = handler.lastAddressStack;\n if (address === null) {\n return null;\n }\n const accessor = registry.accessorFor(address.pathInfo.path);\n if (accessor !== null) {\n return accessor.depth;\n }\n // 生成アクセサでなくても、宣言に合致する具体パス(行 getter・行のイベントハンドラが\n // 積むループのアドレス)ならそこから深さを取れる。\n return depthOfConcretePathPrefix(registry, address.pathInfo.path);\n}\n\n/**\n * `**` を含むパスを、いま評価している深さの具体パスへ書き換える。\n * 再帰文脈が無いところで `**` を直接読むのは、深さが決まらないので診断する。\n */\nexport function bindRecursivePath(\n stateElement: IStateElement,\n handler: IStateHandler,\n path: string,\n): string {\n // 呼び出し元は 2 つとも `hasRecursion === true` をゲートにしているので、\n // ここに来た時点でレジストリは必ずある。到達不能な `??` 分岐は置かない\n // (カバレッジ閾値に効く — walkDependency の `address.listIndex!` と同じ綴り)。\n const registry = stateElement.recursionRegistry!;\n // アンカー照合を先に行う。深さ解決を先にすると、綴り違いのアンカーが\n // 「文脈が無い」と報告されて原因に辿り着けない。\n const suffix = splitRecursivePath(registry.spec, path);\n if (suffix === null) {\n raiseError(recursionAnchorMismatchMessage(path, registry.spec.recursiveAnchor));\n }\n const depth = currentRecursionDepth(handler, registry);\n if (depth === null) {\n raiseError(\n `[wcs/recursion-context] \"${path}\" uses \"**\", which is bound to the depth of the recursive getter ` +\n `being evaluated, and there is no recursion context here. Read it from inside a recursive getter ` +\n `or a row getter under \"${registry.spec.anchor}\", or name a concrete depth ` +\n `(for example \"${registry.spec.anchor}${path.slice(registry.spec.recursiveAnchor.length)}\"). ` +\n `The depth comes from the innermost frame only: a plain getter reached from a recursive getter ` +\n `has no row of its own, so read \"**\" in the recursive getter and pass the value on.`\n );\n }\n // 照合済みの接尾辞をそのまま使う。具体パスは記憶付き(再帰 getter の評価ごとに通る経路)。\n return registry.concretePathAt(suffix, depth);\n}\n","/**\n * recursion/walk.ts\n *\n * 再帰アンカー配下を**全深さ**にわたって走査し、マッチする具体アドレスを列挙する。\n * `$getAll(path, [])` の合併形(設計書 §6-2)と `$setAll` のブロードキャストが共有する。\n *\n * 固定 arity の走査(`proxy/apis/wildcardIndexes.ts`)は「ワイルドカードの本数が\n * 静的に決まっている」ことに立脚しているので、そのままでは深さが動的な族を扱えない。\n * ここは深さ方向だけを自前で降り、**各深さの具体パスは固定 arity のまま**扱う\n * — つまりエンジンが見るパスは常に `**` を含まない普通のパスである(設計書 D2)。\n *\n * 順序は**深さ優先・行きがけ・添字昇順**(§1-2)。ノードを 1 つ出したら、その子へ\n * 降りきってから次の兄弟へ移る。読みと書きが同じ順序を使うことが `$setAll` の\n * 契約の前提になる。\n *\n * 走査が throw したとき、その走査が観測したリスト値は差分基準へ確定**しない**\n * (途中まで進めた基準を残すと、次の読みが「変化なし」と誤認しうる)。\n */\n\nimport { liftAddress } from \"../address/liftAddress\";\nimport { getPathInfo } from \"../address/PathInfo\";\nimport { createStateAddress } from \"../address/StateAddress\";\nimport { IAbsoluteStateAddress, IPathInfo, IStateAddress } from \"../address/types\";\nimport { DELIMITER } from \"../define\";\nimport { createListDiff } from \"../list/createListDiff\";\nimport { getStateListBaseline, setStateListBaseline } from \"../list/stateListBaseline\";\nimport { IListIndex } from \"../list/types\";\nimport { getByAddress } from \"../proxy/methods/getByAddress\";\nimport { IStateHandler } from \"../proxy/types\";\nimport { raiseError } from \"../raiseError\";\nimport type { RecursionRegistry } from \"./registry\";\n\n\n/** 深さごとに 1 回だけ決まるもの。ノードごとに作り直さない。 */\ninterface IDepthPaths {\n readonly nodePath: string;\n readonly concretePathInfo: IPathInfo;\n readonly childListPathInfo: IPathInfo;\n}\n\n/**\n * アンカー配下の全深さを列挙する。深さ優先・行きがけ・添字昇順。\n *\n * 終端は「その深さの子リストが空」。上限超過は `concretePathAt` が**その深さに実際に\n * ノードが居るときだけ**検査する(葉の 1 段先を投機的に見て落ちないように)。\n */\nexport function collectRecursiveAddresses(\n target: object,\n receiver: any,\n handler: IStateHandler,\n registry: RecursionRegistry,\n suffix: string,\n): IStateAddress[] {\n const spec = registry.spec;\n const results: IStateAddress[] = [];\n const observed: Map<IAbsoluteStateAddress, readonly unknown[]> = new Map();\n const pathsByDepth: IDepthPaths[] = [];\n const repeatList = spec.repeatList;\n const anchorList = spec.anchorList;\n\n /**\n * 「同じ配列インスタンスが 2 つ以上の親から到達可能」を**走査そのもの**で判定する\n * (設計書 D12・E6)。台帳の親(`newIndexes[0].parentListIndex`)で見てはならない\n * — 台帳はリスト配列の identity だけをキーにしていて、行オブジェクトを作り直す\n * ふつうのイミュータブル更新(`nodes.map(n => ({...n}))` は children を参照ごと\n * 引き継ぐ)でも親 ListIndex が別物になるため、正当な木を恒久的に拒否してしまう。\n *\n * 走査で見た配列を覚えておけば、共有も循環も「同じ配列に 2 度到達したか」で決まる。\n * 祖先の集合に居れば循環(自分より上へ戻る)、そうでなければ兄弟共有。\n * 空配列は行を持たないので別名化のしようがなく、追跡しない(`[]` の使い回しは正当)。\n */\n const ancestors: Set<readonly unknown[]> = new Set();\n const visited: Set<readonly unknown[]> = new Set();\n\n const guardShape = (\n listPath: string,\n value: unknown,\n seen: Set<readonly unknown[]>,\n ): readonly unknown[] | null => {\n if (!Array.isArray(value) || value.length === 0) {\n return null;\n }\n const list = value as readonly unknown[];\n if (ancestors.has(list)) {\n raiseError(\n `[wcs/recursion-cycle] \"${listPath}\" is reachable from itself: the recursion on ` +\n `\"${spec.anchor}\" walked into a list that one of its own ancestors already owns. ` +\n `The data contains a cycle, which this version does not support.`\n );\n }\n if (seen.has(list)) {\n raiseError(\n `[wcs/recursion-shared-list] \"${listPath}\" is the same array instance as a list reached ` +\n `from another node. The recursion on \"${spec.anchor}\" needs a tree: give each node its own ` +\n `\"${repeatList}\" array.`\n );\n }\n return list;\n };\n\n const pathsAt = (depth: number): IDepthPaths => {\n const known = pathsByDepth[depth];\n if (typeof known !== \"undefined\") {\n return known;\n }\n // 上限検査はここ(=その深さに実際にノードが居ると分かってから)。具体パスはレジストリの\n // 記憶(接尾辞 × 深さ)から引き、走査ごとに文字列連結をやり直さない。\n const concretePath = registry.concretePathAt(suffix, depth);\n const nodePath = suffix.length === 0 ? concretePath : registry.concretePathAt(\"\", depth);\n const paths: IDepthPaths = {\n nodePath,\n concretePathInfo: getPathInfo(concretePath),\n childListPathInfo: getPathInfo(nodePath + DELIMITER + repeatList),\n };\n pathsByDepth[depth] = paths;\n return paths;\n };\n\n /** 接尾辞側に残ったワイルドカード段だけを、行の ListIndex を起点に展開する。 */\n const expandSuffix = (concretePathInfo: IPathInfo, level: number, listIndex: IListIndex): void => {\n const parents = concretePathInfo.wildcardParentPathInfos;\n if (level >= parents.length) {\n results.push(createStateAddress(concretePathInfo, listIndex));\n return;\n }\n // 接尾辞側のリストは検査しない。接尾辞が反復語を含む形(`nodes.**.children.*.value`)\n // では、接尾辞の展開と深さ方向の降下が**同じ配列**を通る — 同じ族を 2 通りに綴れる\n // ことの帰結で、共有ではない。次元をまたいでも、同じ次元の中でも(深さ 0 の接尾辞\n // 展開と深さ 1 の接尾辞展開が同じ配列に当たる)自己衝突するので、共有の判定は\n // 深さ方向にだけ掛ける。\n //\n // 結果として `$setAll(\"nodes.**.tags\", [], arr)` のように**ブロードキャストが作った**\n // 配列共有は、ここでは捕まらない(`[wcs/wildcard-rank]` という無関係な文面で落ちる)。\n // 既知の制限として設計書に記録してある。\n const rows = readRows(parents[level], listIndex, null).rows;\n for (let i = 0; i < rows.length; i++) {\n expandSuffix(concretePathInfo, level + 1, rows[i]);\n }\n };\n\n /**\n * リストを 1 本読んで行と、追跡対象のリスト配列を返す。差分基準は state 側の\n * 共有正本(E1)から取り、観測値は走査の最後にまとめて確定する。`guardPath` が\n * 非 null のときだけ共有・循環の検査を掛ける(接尾辞側の普通のリストは再帰の\n * 対象ではない)。\n */\n function readRows(\n listPathInfo: IPathInfo,\n parentListIndex: IListIndex | null,\n seen: Set<readonly unknown[]> | null,\n ): { rows: IListIndex[], tracked: readonly unknown[] | null } {\n const listAddress = createStateAddress(listPathInfo, parentListIndex);\n const absAddress = liftAddress(handler.stateElement, listAddress);\n const value = getByAddress(target, listAddress, receiver, handler);\n const tracked = seen === null ? null : guardShape(listPathInfo.path, value, seen);\n const listDiff = createListDiff(\n parentListIndex, getStateListBaseline(absAddress), value);\n observed.set(absAddress, Array.isArray(value) ? value : []);\n if (tracked !== null && seen !== null) {\n seen.add(tracked);\n }\n return { rows: listDiff.newIndexes, tracked };\n }\n\n const descend = (depth: number, listPathInfo: IPathInfo, parentListIndex: IListIndex | null): void => {\n const { rows, tracked } = readRows(listPathInfo, parentListIndex, visited);\n if (rows.length === 0) {\n return;\n }\n const paths = pathsAt(depth);\n // 行が 1 つでもある ⟹ そのリストは非空配列だった ⟹ guardShape が追跡対象を返している\n // (非配列も空配列も createListDiff が空の行に畳むので、上の早期 return で抜ける)。\n // このリストは、いま降りている枝の祖先になる。子で同じ配列に当たれば循環。\n const branch = tracked as readonly unknown[];\n ancestors.add(branch);\n const flat = paths.concretePathInfo.wildcardCount === depth + 1;\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i];\n if (flat) {\n // 接尾辞にワイルドカードが無い(大多数)。行の ListIndex がそのまま具体パスの\n // 連鎖長を満たすので、追加の走査は要らない。この行 ListIndex は createListDiff が\n // 台帳へ登録した正本そのものなので、`getListIndexByIndexes` で引き直す必要も無い。\n results.push(createStateAddress(paths.concretePathInfo, row));\n } else {\n expandSuffix(paths.concretePathInfo, depth + 1, row);\n }\n descend(depth + 1, paths.childListPathInfo, row);\n }\n ancestors.delete(branch);\n };\n\n descend(0, getPathInfo(anchorList), null);\n\n // 観測したリスト値を差分基準へ確定する。合併形の `$getAll` も再帰の `$setAll` も必ず確定する\n // (実装計画 §6 — cold な書き込みが ListIndex 世代を鋳造したまま基準を残さないと、次の\n // 構造変更で深い子台帳が孤児になる)。走査が throw したときは上の raise でここに来ない。\n for (const [address, value] of observed) {\n setStateListBaseline(address, value);\n }\n return results;\n}\n","/**\n * recursion/setAllRecursive.ts\n *\n * `$setAll(\"<anchor>.**.<suffix>\", [], value)` — **全深さへのブロードキャスト**\n * (設計書 D8 / §7-3)。\n *\n * 読み(`$getAll` の合併形)と同じ列挙を使い、同じ順序で書く。許すのは `[]` の\n * ブロードキャストだけで、mapper と `{ spread: true }` は受け付けない:\n *\n * - **mapper** の `(current, ...indexes)` は、深さごとに添字の本数が変わるので\n * そのままでは渡せない。深さを渡す別のシグネチャを決めてから入れる。\n * - **`{ spread: true }`** は「マッチ順に 1 件ずつ配る」形。順序は決定的に定義できるが、\n * 木に 1 次元配列を配るのは作者が走査順を知らないと使えず、実用にならない。\n *\n * 添字の省略も受け付けない。`$setAll` は「書き込み API に暗黙の文脈依存を持たせない」\n * という既存の決定(docs/state-set-all-design.md の D4)を継ぐので、読み側にある\n * 省略形(文脈束縛)の対応物を書き側には置かない。\n */\n\nimport { recursionAnchorMismatchMessage, setAllValueKindMessage } from \"../pathDiagnostics\";\nimport { setByAddress } from \"../proxy/methods/setByAddress\";\nimport { IStateHandler } from \"../proxy/types\";\nimport { raiseError } from \"../raiseError\";\nimport { assertWritable } from \"../proxy/assertWritable\";\nimport { foldSuffixIndexes, isStructuralSuffix, splitRecursivePath } from \"./expand\";\nimport { IRecursionSpec } from \"./types\";\nimport { collectRecursiveAddresses } from \"./walk\";\n\n/**\n * 接尾辞が「再帰の構造そのもの」を名指していないか(述語は expand.ts の `isStructuralSuffix`)。\n *\n * ノード自身(`nodes.**`)と子リスト(`nodes.**.children`)と子ノード\n * (`nodes.**.children.*`)と子リストの `length` は、書き換えると確定済みの子アドレスを壊す。\n * 初版は葉の属性の更新に限る(実装計画 §1-3)。判定対象は宣言から導出する。\n */\nfunction assertNotStructural(spec: IRecursionSpec, path: string, suffix: string): void {\n if (isStructuralSuffix(spec, suffix)) {\n raiseError(\n `[wcs/recursion-structural-write] \"${path}\" writes the recursion structure itself ` +\n `(a node, its \"${spec.repeatList}\" list or that list's length, or an object on the way to that list). ` +\n `This version broadcasts to leaf properties only — ` +\n `replacing a node would invalidate the child addresses already resolved for this write.`\n );\n }\n}\n\nexport function setAllRecursive(\n target: object,\n receiver: any,\n handler: IStateHandler,\n path: string,\n indexes: unknown,\n value: any,\n options: { readonly spread?: boolean } | undefined,\n): number {\n assertWritable(handler);\n // 呼び出し元(setAll.ts)は `hasRecursion === true` をゲートにしているので必ずある。\n const registry = handler.stateElement.recursionRegistry!;\n const suffix = splitRecursivePath(registry.spec, path);\n if (suffix === null) {\n raiseError(recursionAnchorMismatchMessage(path, registry.spec.recursiveAnchor));\n }\n // 検査には添字を `*` に畳んだ接尾辞を掛ける。`nodes.**.children.0`(子ノード)・\n // `nodes.**.children.0.children`(孫リスト)・`nodes.**.children.0.total`(getter の展開形)は\n // 添字綴りのままだと素の文字列一致をすり抜け、構造を置き換えたり部分書き込みの途中で\n // 生の TypeError になったりしていた(第 2 サイクルのレビューで実測)。列挙は綴りのまま\n // 行う — 接尾辞の添字は「その子だけ」を指す意味を持つ。\n const checkedSuffix = foldSuffixIndexes(suffix);\n\n // --- 形の検査は列挙より前(1 件も書かないことを保証する。設計 §7-3) ---\n if (!Array.isArray(indexes)) {\n raiseError(setAllValueKindMessage(\n path, `with \"**\" requires an explicit empty indexes array ([]) — the write API takes no context.`));\n }\n if (indexes.length > 0) {\n raiseError(\n `[wcs/recursion-setall-form] $setAll(\"${path}\", indexes, …) with \"**\" takes no partial prefix: ` +\n `a prefix cannot say which depth it applies to. Pass [] to broadcast to every depth.`\n );\n }\n if (typeof value === \"function\") {\n raiseError(setAllValueKindMessage(\n path, `with \"**\" does not take a mapper yet — the index tuple has a different length at each depth.`));\n }\n if (options?.spread === true) {\n raiseError(setAllValueKindMessage(\n path, `with \"**\" does not take { spread: true } — handing a flat array to a tree needs the author ` +\n `to know the walk order, which is not a usable contract.`));\n }\n assertNotStructural(registry.spec, path, checkedSuffix);\n const conflicting = registry.conflictingRecursiveGetter(checkedSuffix);\n if (conflicting !== null) {\n raiseError(\n `[wcs/recursion-readonly] \"${path}\" writes into the recursive getter \"${conflicting}\", which has ` +\n `no setter — the two name the same family of concrete paths (or this path points inside the value ` +\n `that getter derives). Write the values it derives from instead.`\n );\n }\n\n // --- 第 1 相: 書き込み先を全部確定する ---\n // **観測したリスト値は基準へ確定する**(走査が必ず行う — walk.ts)。固定 arity の\n // `$setAll` は `commitDiffBaseline: false` で走るが、あれは「読みの私有基準を書きから\n // 動かさない」という E1 以前の所有権モデルの話で、いまの基準は読み・描画・依存ウォークが\n // 共有する state 側の正本である(実装計画 §3-2 の E1)。\n //\n // 確定しないと cold(読みも描画も一度も走っていない)状態の `$setAll` が全深さぶんの\n // ListIndex 世代を鋳造したまま基準を残さず、次の構造変更でその世代が見えない diff が\n // 行を鋳造し直す。生き残った深い children の台帳だけが死んだ世代の親を指し、以後\n // 再帰 getter の読みが恒久的に落ちる(値の合併は動き続けるので無症状のまま進む)。\n // 1 件も書かない `undefined` のブロードキャストでも同じなので、「書き込み 0 件」は\n // 「状態が動いていない」を意味しない。\n const addresses = collectRecursiveAddresses(target, receiver, handler, registry, suffix);\n\n // --- 第 2 相: 確定したアドレスにだけ書く ---\n let written = 0;\n for (let i = 0; i < addresses.length; i++) {\n // undefined は常にスキップ(設計 §5)。クリアは null。\n if (typeof value === \"undefined\") {\n continue;\n }\n setByAddress(target, addresses[i], value, receiver, handler);\n written++;\n }\n return written;\n}\n","/**\n * recursion/addressHooks.ts — `$recursion` を宣言した state に付く hook(設計案 H1、S3)。\n * 従来 core(get トラップ・`$getAll` / `$setAll`・setByAddress)が直接 import していた `**` の\n * 束縛・合併形・書き込み禁止をここへ移し、宣言の無い state では一切走らない。\n * (`$trackDependency` の `**` 拒否は宣言の有無に関わらないので core に残る)\n */\nimport { getResolvedAddress } from \"../address/ResolvedAddress\";\nimport { createStateAddress } from \"../address/StateAddress\";\nimport { IAddressHooks, NOT_HANDLED, registerFeatureHooks } from \"../core/addressHooks\";\nimport { getAll } from \"../proxy/apis/getAll\";\nimport { ISetAllOptions, setAll } from \"../proxy/apis/setAll\";\nimport { getByAddress } from \"../proxy/methods/getByAddress\";\nimport { getListIndex } from \"../proxy/methods/getListIndex\";\nimport { raiseError } from \"../raiseError\";\nimport { bindRecursivePath } from \"./bind\";\nimport { hasRecursionWildcard } from \"./expand\";\nimport { getAllRecursive } from \"./getAllRecursive\";\nimport { setAllRecursive } from \"./setAllRecursive\";\n\n// hook は要素の寿命の間は付いたまま(再セットで `$recursion` が消えても外れない)ので、\n// 宣言が消えた後は `hasRecursion` の boolean 判定 1 個で core と同じ経路へ戻す\nexport const recursionAddressHooks: IAddressHooks = {\n // 再帰 getter の展開形(`nodes.*.children.*.total`)とその値の内側への書き込みは、`**` を\n // 含まないので `setAllRecursive` の読み取り専用検査を通らない。未実体化なら fast path が\n // 「親オブジェクトの未存在キー」として行オブジェクトへ素の値を書き、代入値を `dirty:false` で\n // キャッシュに載せる — ノードが汚れ、実体化後も getter が評価されず、深さ 0 の集計まで\n // 巻き込む(レビュー P18 で実測)。読み側の遅延実体化(getByAddress の E5)と対称に、書き側はここで止める\n write(stateElement, address) {\n if (stateElement.hasRecursion !== true) {\n return NOT_HANDLED;\n }\n const owner = stateElement.recursionRegistry!.recursiveGetterOwningPath(address.pathInfo);\n if (owner !== null) {\n raiseError(\n `[wcs/recursion-readonly] \"${address.pathInfo.path}\" writes into the recursive getter \"${owner}\" ` +\n `(this path is that getter at one depth, or a path inside the value it derives), which has ` +\n `no setter. Write the values it derives from instead.`\n );\n }\n return NOT_HANDLED;\n },\n get(handler, prop, receiver, target) {\n if (handler.stateElement.hasRecursion !== true) {\n return NOT_HANDLED;\n }\n if (prop === \"$getAll\") {\n // オーサリング層の `**`。省略形は「いま評価している深さ」に束縛し、`[]` 明示は\n // 全深さの合併になる(設計書 §6-2)。部分接頭辞は `**` に対して定義できない。\n return (path: string, indexes?: number[]): any[] => {\n if (hasRecursionWildcard(path)) {\n if (typeof indexes === \"undefined\") {\n path = bindRecursivePath(handler.stateElement, handler, path);\n } else {\n // アンカー照合と添字の形の検査は合併形の側で行う(判定順を静的側と揃えるため)\n return getAllRecursive(target, receiver, handler, path, indexes);\n }\n }\n return getAll(target, prop, receiver, handler)(path, indexes);\n };\n }\n if (prop === \"$setAll\") {\n // 書き側は `[]` のブロードキャストだけを受け付ける(形の検査は列挙より前に行い、\n // 1 件も書かないことを保証する。設計 §7-3)\n return (path: string, indexes: number[], value: any, options?: ISetAllOptions): number => {\n if (hasRecursionWildcard(path)) {\n return setAllRecursive(target, receiver, handler, path, indexes, value, options);\n }\n return setAll(target, prop, receiver, handler)(path, indexes, value, options);\n };\n }\n if (prop.charCodeAt(0) !== 36 /* '$' */ && hasRecursionWildcard(prop)) {\n // オーサリング層の `**` を、いま評価している再帰 getter の深さへ束縛して通常解決する\n const resolvedAddress = getResolvedAddress(bindRecursivePath(handler.stateElement, handler, prop));\n const listIndex = getListIndex(target, resolvedAddress, receiver, handler);\n return getByAddress(target, createStateAddress(resolvedAddress.pathInfo, listIndex), receiver, handler);\n }\n return NOT_HANDLED;\n },\n};\n\nlet installed = false;\n/** 冪等。full エントリでは State が `$recursion` の宣言時に呼ぶ(分割エントリでは `install` が担う) */\nexport function installRecursionHooks(): void {\n if (installed) return;\n installed = true;\n registerFeatureHooks(\"recursion\", recursionAddressHooks);\n}\n","/**\n * recursion/getAllRecursive.ts\n *\n * `$getAll(\"<anchor>.**.<suffix>\", [])` — **全深さの合併**(設計書 D7 / §6-2)。\n *\n * 省略形(文脈束縛)とは別経路にする。省略形は「いま評価している深さの 1 本」を\n * 具体パスに直して既存の固定 arity 走査へ渡すだけだが、合併形は深さそのものを\n * 走査対象にするので、返る添字タプルの長さが結果ごとに変わる。だから合併形は\n * **値の配列しか返さない**(`$resolve` への往復は保証しない。設計書 §7-2)。\n */\n\nimport { getByAddress } from \"../proxy/methods/getByAddress\";\nimport { IStateHandler } from \"../proxy/types\";\nimport { splitRecursivePath } from \"./expand\";\nimport { collectRecursiveAddresses } from \"./walk\";\nimport { recursionAnchorMismatchMessage } from \"../pathDiagnostics\";\nimport { raiseError } from \"../raiseError\";\n\nexport function getAllRecursive(\n target: object,\n receiver: any,\n handler: IStateHandler,\n path: string,\n indexes: unknown,\n): any[] {\n // 呼び出し元(getAll.ts)は `hasRecursion === true` をゲートにしている。\n const registry = handler.stateElement.recursionRegistry!;\n // 判定順はアンカー照合 → 添字の形。静的側(vscode-wcs recursionValidator)と同じ順に\n // しておかないと、綴り違いのアンカーに `[0]` を渡した呼び出しが片側では\n // `recursion-anchor`、もう片側では `recursion-getall-form` になる。\n const suffix = splitRecursivePath(registry.spec, path);\n if (suffix === null) {\n raiseError(recursionAnchorMismatchMessage(path, registry.spec.recursiveAnchor));\n }\n // 合併形の添字は `[]` だけ。`null` 等の非配列は素の TypeError にせず、形の診断にする。\n if (!Array.isArray(indexes)) {\n raiseError(\n `[wcs/recursion-getall-form] $getAll(\"${path}\", indexes) with \"**\" takes either no indexes ` +\n `(to read the depth of the recursive getter being evaluated) or [] (to walk every depth) — ` +\n `got ${indexes === null ? \"null\" : typeof indexes}.`\n );\n }\n if (indexes.length > 0) {\n raiseError(\n `[wcs/recursion-getall-form] $getAll(\"${path}\", indexes) with \"**\" takes no partial ` +\n `prefix: a prefix cannot say which depth it applies to. Omit the indexes to read the ` +\n `depth of the recursive getter being evaluated, or pass [] to walk every depth.`\n );\n }\n // 走査は観測したリスト値を差分基準へ確定する(再帰の `$setAll` も同じ。\n // 固定 arity の `$setAll` だけが確定しない — setAllRecursive.ts 第 1 相の注記)。\n const addresses = collectRecursiveAddresses(target, receiver, handler, registry, suffix);\n const values: any[] = [];\n for (let i = 0; i < addresses.length; i++) {\n // `**` は依存グラフに載らない(D2)。呼び出し元の getter は「触れた深さの\n // 具体パス」に依存する — その登録は getByAddress の checkDependency が行う\n // (他行読み取りの検出も含む)。ここで書き写すと untrack を見ない劣化版になる。\n values.push(getByAddress(target, addresses[i], receiver, handler));\n }\n return values;\n}\n","/**\n * recursion/declaration.ts\n *\n * `$recursion: { <anchor>: <repeat> }` 宣言を検証して仕様に落とす\n * (docs/state-recursive-path-impl-plan.md §1-1)。宣言が無ければ null で、\n * その state は再帰の経路にまったく入らない(`$listKeys` と同じゼロコスト規約)。\n *\n * 初版が受け付けるのは **単一の自己再帰** だけ。アンカーも反復サブパスも\n * 「固定プロパティ列 + 末尾の `.*` ひとつ」に限る。途中のワイルドカード・複数宣言・\n * 相互再帰は、黙って別の意味に解釈せず明示的に拒否する。\n */\n\nimport { DELIMITER, RECURSION_WILDCARD, STATE_RECURSION_NAME, WILDCARD } from \"../define\";\nimport { raiseError } from \"../raiseError\";\nimport type { IState } from \"../types\";\nimport { IRecursionSpec } from \"./types\";\n\n/** `a.b.*` の形(末尾だけがワイルドカード・空セグメント無し・`**` 無し・添字無し)か。 */\nfunction assertNodePath(kind: string, path: string): void {\n if (typeof path !== \"string\" || path.length === 0) {\n raiseError(`[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} ${kind} must be a non-empty string.`);\n }\n const segments = path.split(DELIMITER);\n if (segments.some((segment) => segment.length === 0)) {\n raiseError(`[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} ${kind} \"${path}\" must not contain empty path segments.`);\n }\n if (segments.length < 2) {\n raiseError(\n `[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} ${kind} \"${path}\" must name a list element: ` +\n `a property path ending with \"${DELIMITER}${WILDCARD}\" (for example \"nodes${DELIMITER}${WILDCARD}\").`\n );\n }\n if (segments[segments.length - 1] !== WILDCARD) {\n raiseError(\n `[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} ${kind} \"${path}\" must end with \"${DELIMITER}${WILDCARD}\" ` +\n `— it names the element of the list, not the list itself.`\n );\n }\n // 予約セグメント。マウントのマーカー(`#m1`)と `$` 名前空間は raw state に実体を\n // 持たないので、再帰のアンカーにはなり得ない(checkDeclaredPath が同じ 2 つで\n // 早期 return しているのと対称)。\n if (segments[0].charCodeAt(0) === 36 /* '$' */) {\n raiseError(\n `[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} ${kind} \"${path}\" must not start with \"$\" — that namespace is reserved.`\n );\n }\n if (path.indexOf(\"#\") !== -1) {\n raiseError(\n `[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} ${kind} \"${path}\" must not contain \"#\" — that segment is reserved for mounts.`\n );\n }\n for (let i = 0; i < segments.length - 1; i++) {\n if (segments[i] === WILDCARD) {\n raiseError(\n `[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} ${kind} \"${path}\" must have exactly one \"${WILDCARD}\", at the end. ` +\n `Wildcards in the middle are not supported in this version.`\n );\n }\n if (segments[i] === RECURSION_WILDCARD) {\n raiseError(\n `[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} ${kind} \"${path}\" must not contain \"${RECURSION_WILDCARD}\" — ` +\n `the declaration is what gives \"${RECURSION_WILDCARD}\" its meaning.`\n );\n }\n // 添字セグメント(`children.0.*`)。エンジンは具体パスの添字を `*` に畳むので\n // (`indexSegmentsToWildcard` — ResolvedAddress と同じ規則)、宣言の途中に書かれた\n // 添字は意味を持たない奇形になる。黙って `*` と同じに読み替えず、ここで落とす。\n if (!isNaN(Number(segments[i]))) {\n raiseError(\n `[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} ${kind} \"${path}\" must not contain an index segment ` +\n `(\"${segments[i]}\") — the recursion is declared over the shape of the tree, not over one row.`\n );\n }\n }\n}\n\n/**\n * `$recursion` 宣言を検証して仕様にする。宣言が無ければ null(=ゼロコスト経路)。\n */\nexport function processRecursionDeclaration(state: IState): IRecursionSpec | null {\n const declared = (state as Record<string, unknown>)[STATE_RECURSION_NAME];\n if (typeof declared === \"undefined\") {\n return null;\n }\n if (typeof declared !== \"object\" || declared === null) {\n raiseError(\n `[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} must be an object mapping one anchor path to its repeating sub-path ` +\n `(for example { \"nodes.*\": \"children.*\" }).`\n );\n }\n const entries = Object.entries(declared as Record<string, unknown>);\n if (entries.length === 0) {\n raiseError(`[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} must declare exactly one anchor; it is empty.`);\n }\n if (entries.length > 1) {\n raiseError(\n `[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} declares ${entries.length} anchors (${entries.map(([k]) => `\"${k}\"`).join(\", \")}). ` +\n `This version supports exactly one self-recursive anchor per state.`\n );\n }\n const [anchor, repeat] = entries[0];\n assertNodePath(\"anchor\", anchor);\n if (typeof repeat !== \"string\") {\n raiseError(\n `[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} entry \"${anchor}\" must map to the repeating sub-path as a string ` +\n `(for example \"children${DELIMITER}${WILDCARD}\").`\n );\n }\n assertNodePath(\"repeating sub-path\", repeat);\n // 反復サブパスが相対か絶対かは**名前の形では判定できない**。`{ \"nodes.*\": \"nodes.*\" }`\n // は `{ nodes: [{ nodes: [...] }] }` という自己相似な木の最も自然な綴りなので、\n // 「アンカーと同じ語で始まる」ことを理由に拒否してはならない。\n const anchorList = anchor.slice(0, anchor.lastIndexOf(DELIMITER));\n const repeatList = repeat.slice(0, repeat.lastIndexOf(DELIMITER));\n const recursiveAnchor = anchorList + DELIMITER + RECURSION_WILDCARD;\n return Object.freeze({ anchor, repeat, recursiveAnchor, anchorList, repeatList });\n}\n","/**\n * recursion/generation.ts\n *\n * 再帰レジストリの**世代の後始末**。state の再セットで前世代のレジストリが捨てられるとき、\n * その世代が生やしたもの — own の生成アクセサ・依存表の辺・評価結果のキャッシュ — を忘れる。\n * レジストリ本体(宣言の検証・パス族の代数・遅延実体化)から切り出してある: ここだけが\n * 依存表・キャッシュ・台帳という state 全体の構造に触る。\n */\n\nimport { IStateElement } from \"../components/types\";\n\n/**\n * この機構が生やした getter。作者が手で書いた同名 getter と見分けるために使う\n * (前者は忘れてよい・後者は衝突として拒否する)。\n */\nconst generatedGetters: WeakSet<object> = new WeakSet();\n\nexport function markGeneratedGetter(getter: object): void {\n generatedGetters.add(getter);\n}\n\n/** この機構の生成物か(own に残った生成 getter)。 */\nexport function isGeneratedGetter(descriptor: PropertyDescriptor): boolean {\n return typeof descriptor.get === \"function\" && generatedGetters.has(descriptor.get);\n}\n\n/**\n * 前世代が生やしたものを忘れる(state の再セット時に呼ぶ)。忘れるのは 2 つ。\n *\n * **own の生成アクセサ。** 生成 getter は state オブジェクトの own プロパティとして残る。\n * 同じオブジェクトを `$recursion` 無し(または別アンカー)で再セットしたとき、残したままだと\n * `getStateInfo` が `getterPaths` に拾い直し、読むと作者が書いていない `nodes.**.value` を\n * 名指す `wcs/recursion-unsupported` になる(第 4 サイクルで実測)。`getStateInfo` の\n * **前**に消す。\n *\n * **依存辺。** `_state` のセッタは `_listPaths` / `_getterPaths` / `_pathSet` をクリアするが、\n * 依存表(`_staticDependency` / `_dynamicDependency`)は state の寿命を越えて残る。\n * 通常のパスはそれで正しい — 同じ綴りのパスは新しい state でも同じ意味を持つ。\n * だが**生成アクセサは違う**。新しい世代ではまだ実体化されておらず、それを指す辺だけが\n * 残ると、次の構造書き込みで依存ウォークが「アクセサの無い具体パス」へ降りて落ちる。\n * 依存表そのものをクリアしてはならない(既存バインディングの辺まで消えて、再セット後の\n * 集計が更新されなくなる — 実測済み)。この世代が作った辺だけを外す。\n *\n * **評価結果のキャッシュは忘れない。** 同じ state オブジェクト(または同じ配列)の再セットでは\n * 台帳が配列の identity をキーにしているので ListIndex も絶対アドレスも世代を跨いで同一のまま残り、\n * かつては旧世代の `dirty:false` の値がそのまま次の読みに返っていた(第 2・第 4 サイクルで実測)。\n * これは後から入った**世代印**(`cache/types.ts` の `generation`。`3bfb92a6`)が構造的に塞いでいる:\n * キャッシュを載せる 2 か所(`getByAddress` / `setByAddress`)が必ず現世代の印を付け、読みは\n * `cacheEntry.generation === stateElement.stateGeneration` の項目しかヒットにしない。この関数は\n * `runPreCommit` から呼ばれ、`_stateGeneration++` はその**直後**(`components/State.ts`)なので、\n * ここで消せる項目はどれみち必ず世代不一致で miss になる。掃き出しは `O(生成パス数 × 行数)` の\n * 純粋な無駄仕事だったので外した(番人は `integration.recursionGetter.test.ts` の再セット 4 本 —\n * 世代印を壊すとこの 4 本が落ちる)。\n */\nexport function forgetGeneration(\n stateElement: IStateElement,\n previousState: object,\n generatedPaths: ReadonlySet<string>,\n): void {\n if (generatedPaths.size === 0) {\n return;\n }\n for (const path of generatedPaths) {\n const descriptor = Object.getOwnPropertyDescriptor(previousState, path);\n if (typeof descriptor !== \"undefined\" && isGeneratedGetter(descriptor)) {\n delete (previousState as Record<string, unknown>)[path];\n }\n }\n for (const map of [stateElement.staticDependency, stateElement.dynamicDependency]) {\n for (const path of generatedPaths) {\n map.delete(path);\n }\n for (const [source, targets] of map) {\n let kept: string[] | null = null;\n for (let i = 0; i < targets.length; i++) {\n if (generatedPaths.has(targets[i])) {\n kept ??= targets.slice(0, i);\n continue;\n }\n kept?.push(targets[i]);\n }\n if (kept !== null) {\n if (kept.length === 0) {\n map.delete(source);\n } else {\n map.set(source, kept);\n }\n }\n }\n }\n}\n","/**\n * recursion/registry.ts\n *\n * state 1 つぶんの再帰レジストリ。宣言・`**` getter の定義・展開済みアクセサの台帳を\n * 持ち、「具体パスを読む直前に、その深さのアクセサを生やす」遅延実体化を担う。\n *\n * 遅延であることは実装の**不変条件**である(Phase A の A6/A7)。そのパスを一度でも\n * 読んでから生やしても、`isCacheable` が `wildcardCount > 0` だけでキャッシュ可を返す\n * ため `undefined` が `dirty:false` で固定され、以後どう書いても回復しない。\n * したがって実体化は `getByAddress` のキャッシュ参照**前**に置く(E5)。\n *\n * 寿命は state の世代と共にする。`_state` の再セットで `getterPaths` / `listPaths` は\n * クリアされるので、レジストリも作り直す(§1-3)。ただし**生やしたアクセサは state\n * オブジェクトの側に残る**ので、同じ state を再セットすると `getStateInfo` がそれを\n * `getterPaths` に復元する。そのとき「もう生えているから何もしない」と早期 return して\n * しまうと `listPaths` の登録だけが抜け落ちるため、生成物は WeakSet で見分けて\n * 登録だけをやり直す。\n */\n\nimport { IPathInfo } from \"../address/types\";\nimport { IStateElement } from \"../components/types\";\nimport { DELIMITER } from \"../define\";\nimport { getAllPropertyDescriptors } from \"../getAllPropertyDescriptors\";\nimport { recursionAnchorMismatchMessage } from \"../pathDiagnostics\";\nimport { raiseError } from \"../raiseError\";\nimport {\n concretePathAt, coversSuffix, depthOfConcretePath, foldSuffixIndexes, hasRecursionWildcard,\n indexSegmentsToWildcard, isStructuralSuffix, listPathsUpTo, sameFamily, splitRecursivePath,\n} from \"./expand\";\nimport { forgetGeneration, isGeneratedGetter, markGeneratedGetter } from \"./generation\";\nimport { IRecursionAccessor, IRecursionSpec } from \"./types\";\n\n/** 宣言時(構築時)の診断コード。lint(vscode-wcs)が同じコードで先に出す。 */\nconst DECLARATION_INVALID = \"[wcs/recursion-declaration-invalid]\";\n\n/** `**` getter 1 本ぶんの定義(本体は評価しない — descriptor だけを持つ)。 */\ninterface IRecursiveGetterDefinition {\n readonly recursivePath: string;\n readonly suffix: string;\n readonly get: () => unknown;\n}\n\nexport class RecursionRegistry {\n readonly spec: IRecursionSpec;\n private readonly _definitions: Map<string, IRecursiveGetterDefinition> = new Map();\n private readonly _accessors: Map<string, IRecursionAccessor> = new Map();\n /**\n * `recursiveGetterOwning` の記憶。キーは添字を `*` に畳んだ形(`nodes.1.total` と `nodes.2.total`\n * は 1 つ)、値は「その具体パスを展開形(またはその値の内側)として持つ `**` getter」、\n * 無ければ null。\n *\n * 有界である: キーは添字を畳んだワイルドカード形のパス文字列で、`PathInfo` が intern する集合\n * (バインディング・getter・API 引数に綴られたパスと、その展開形)の部分集合にしかならない。\n * intern 済みパスの集合が有界であることは D10 で受け入れ済みなので、ここも同じ上限に収まる。\n * 文字列は WeakSet に入らないので、寿命はレジストリ(= state の世代)と共にする。\n */\n private readonly _ownerByPath: Map<string, string | null> = new Map();\n /**\n * 書き込みのホットパス(`setByAddress`)向けの記憶。キーは intern 済みの `PathInfo` なので\n * 寿命と上限は PathInfo の intern 集合と同じ(WeakMap)。畳み(split + Number + join)は\n * miss のときだけ払う — 宣言のある state では**アンカー外を含む全書き込み**がここを通る\n * (第 4 サイクルで実測: 畳みを毎回払うと `s.counter = i` で +100ns/書き込み)。\n */\n private readonly _ownerByPathInfo: WeakMap<IPathInfo, string | null> = new WeakMap();\n /**\n * 読みのホットパス(`getByAddress`)向けの記憶。`_ownerByPathInfo` と対称で、キーは\n * intern 済みの `PathInfo`、値は「そのパスの展開アクセサ」、展開形でなければ null。\n * 宣言のある state では**アンカー外を含む全読み**(親ウォークの各段を含む)がここを\n * 通るので、文字列キーの `Map.get` + `Set.has` + `startsWith` を毎回払わせない\n * (第 5 サイクルで実測)。\n *\n * 読みの否定判定の記憶は**ここ 1 つ**(第 5 サイクル再検証で文字列キーの `_nonAccessors` を撤去 —\n * 前段にこの記憶を置いた後は、PathInfo とパス文字列が 1:1 なので二重に持つだけだった)。\n * 否定を記憶してよい根拠は、定義集合が state の世代内で不変であること — \n * 同じ `PathInfo` は同じパス文字列なので、いちど「展開形でない」と決まった PathInfo が\n * 後から実体化されることはない。実体化した側は `materializeForPathInfo` が\n * `_define` の戻り値でそのまま記憶を更新する(否定が実体化を隠さない)。\n */\n private readonly _accessorByPathInfo: WeakMap<IPathInfo, IRecursionAccessor | null> = new WeakMap();\n /** `concretePathAt` の記憶(接尾辞 → 深さ順の具体パス)。 */\n private readonly _concreteBySuffix: Map<string, string[]> = new Map();\n private readonly _registeredListPaths: Set<string> = new Set();\n\n constructor(spec: IRecursionSpec, state: object) {\n this.spec = spec;\n // getter 本体は実行しない。descriptor だけを見て `**` を含むキーを拾う。\n const descriptors = getAllPropertyDescriptors(state);\n for (const [key, descriptor] of Object.entries(descriptors)) {\n if (!hasRecursionWildcard(key)) {\n continue;\n }\n if (typeof descriptor.set === \"function\") {\n raiseError(\n `${DECLARATION_INVALID} Recursive setters are not supported in this version: \"${key}\". ` +\n `Declare a plain path setter, or write through the concrete path.`\n );\n }\n if (typeof descriptor.get !== \"function\") {\n raiseError(\n `${DECLARATION_INVALID} \"${key}\" contains \"**\" but is not a getter. ` +\n `The recursion wildcard only names a family of computed paths.`\n );\n }\n const suffix = splitRecursivePath(spec, key);\n if (suffix === null) {\n raiseError(recursionAnchorMismatchMessage(key, spec.recursiveAnchor));\n }\n if (suffix.length === 0) {\n // `get \"nodes.**\"` は展開すると `nodes.*` そのもの。`getByAddress` は\n // 「パスが target にあるか」を先に見るので、実データの行が丸ごと隠れる。\n raiseError(\n `${DECLARATION_INVALID} \"${key}\" names the recursive node itself. \"**\" names a computed path ` +\n `under a node (for example \"${spec.recursiveAnchor}${DELIMITER}total\"), not the node.`\n );\n }\n // 構造の判定は添字綴り(`get \"nodes.**.children.0\"()`)も畳んでから掛ける(書き側と同じ)\n if (isStructuralSuffix(spec, foldSuffixIndexes(suffix))) {\n // `get \"nodes.**.children\"` / `.children.*` / `.children.length` / 多段なら `.branch` は\n // 展開すると実データの子リスト(子ノード・その length・途中のオブジェクト)そのもの。\n // 生成 getter が `getByAddress` の「パスが target にあるか」で勝ち、実データの木を\n // 深さ 1 以下ごと無言で影にする(第 2 サイクルのレビューで実測: `$getAll(\"nodes.**.value\", [])`\n // が `[1, 2]` に縮んだ)。書き側が同じ形を `recursion-structural-write` で拒否するのと対称。\n raiseError(\n `${DECLARATION_INVALID} \"${key}\" names the recursion structure itself (a node, its ` +\n `\"${spec.repeatList}\" list or that list's length, or an ` +\n `object on the way to that list). A recursive getter would hide the real child list at every ` +\n `depth — \"**\" names a computed leaf under a node (for example \"${spec.recursiveAnchor}${DELIMITER}total\").`\n );\n }\n this._definitions.set(key, {\n recursivePath: key,\n suffix,\n get: descriptor.get as () => unknown,\n });\n }\n this._assertNoColliding();\n this._assertNoConcreteCollision(descriptors);\n }\n\n /**\n * 作者が手で書いた具体パス(`get \"nodes.*.children.*.total\"()` / データプロパティ)が、宣言済み\n * `**` getter の展開形と同名でないことを**構築時に**確かめる。\n *\n * `_define` の衝突検査は「その深さを最初に読んだとき」にしか走らないので、データが浅い間は\n * 通り、木が 1 段深くなった瞬間にバインディングが落ちていた(第 3 サイクルのレビューで実測)。\n * 前世代の生成物(own に残った生成 getter)は衝突ではない — 同じ state の再セットで必ず居る。\n */\n private _assertNoConcreteCollision(descriptors: Record<string, PropertyDescriptor>): void {\n for (const [key, descriptor] of Object.entries(descriptors)) {\n if (hasRecursionWildcard(key) || isGeneratedGetter(descriptor)) {\n continue;\n }\n const owner = this._matchExpansion(key);\n if (owner !== null) {\n raiseError(\n `${DECLARATION_INVALID} \"${key}\" is already defined on the state, so the recursive getter ` +\n `\"${owner}\" cannot expand to it. Rename one of them.`\n );\n }\n }\n }\n\n /**\n * 2 本の `**` getter が同じ具体パスへ展開しないことを、宣言だけから静的に確かめる。\n *\n * 衝突するのは「片方の接尾辞がもう片方の接尾辞の末尾で、差分が反復語の整数倍」の\n * ときだけ(`nodes.**.total` と `nodes.**.children.*.total` は深さ k と k+1 で\n * 同じ `nodes.*.children.*.total` になる)。検出しないと `_definitions` の挿入順で\n * 最初に一致した方が無言で勝つ。\n */\n private _assertNoColliding(): void {\n const definitions = Array.from(this._definitions.values());\n for (let i = 0; i < definitions.length; i++) {\n for (let j = i + 1; j < definitions.length; j++) {\n if (sameFamily(this.spec, definitions[i].suffix, definitions[j].suffix)) {\n raiseError(\n `${DECLARATION_INVALID} \"${definitions[i].recursivePath}\" and \"${definitions[j].recursivePath}\" ` +\n `expand to the same concrete path at different depths (they differ by whole repetitions of ` +\n `\"${this.spec.repeat}\"). Rename one of them.`\n );\n }\n }\n }\n }\n\n /**\n * `**` getter を 1 本でも宣言しているか。\n * **テスト・診断専用**(ランタイムの経路は `_definitions.size` を直接見る)。\n */\n get hasDefinitions(): boolean {\n return this._definitions.size > 0;\n }\n /**\n * その接尾辞が宣言済みの `**` getter と衝突するなら、その getter のパスを返す。\n *\n * 完全一致だけでは足りない。①反復語の整数倍だけ違う接尾辞は同じ族を指す\n * (`_assertNoColliding` が宣言どうしについて既に見ている条件)②getter の**下**を\n * 指す形(`nodes.**.total.x` / 反復語ぶんずれた `nodes.**.children.*.total.x`)は、\n * getter が返したオブジェクトへ書いてキャッシュを汚し、次の無効化で無言に戻る。\n * どちらも書き込みの入口(列挙より前)で止める — 述語は expand.ts の `coversSuffix`。\n */\n conflictingRecursiveGetter(suffix: string): string | null {\n for (const definition of this._definitions.values()) {\n if (coversSuffix(this.spec, definition.suffix, suffix)) {\n return definition.recursivePath;\n }\n }\n return null;\n }\n\n /**\n * `recursiveGetterOwning` の intern 済み `PathInfo` 版(書き込みのホットパス用)。\n * WeakMap の hit なら畳みも照合も払わない。\n */\n recursiveGetterOwningPath(pathInfo: IPathInfo): string | null {\n const known = this._ownerByPathInfo.get(pathInfo);\n if (typeof known !== \"undefined\") {\n return known;\n }\n const owner = this.recursiveGetterOwning(pathInfo.path);\n this._ownerByPathInfo.set(pathInfo, owner);\n return owner;\n }\n\n /**\n * 具体パスを展開形(またはその値の内側)として持つ `**` getter のパス。無ければ null。\n * **実体化はしない。**\n *\n * `conflictingRecursiveGetter` の**具体パス版**で、`**` を経ない 2 つの入口が使う:\n *\n * - バインド確立時のパス存在検査(`checkDeclaredPath`)。あの時点ではまだ生えて\n * いないので、素の存在検査では必ず「解決できない」になる。展開形そのもの\n * (`nodes.*.total`)だけでなく、その値の中を指す形(`nodes.*.stats.count` で\n * `get \"nodes.**.stats\"()` がオブジェクトを返す)も、通常の getter の下と同じく\n * 評価しないと分からないので黙る側に倒す。\n * - 書き込みの入口(`setByAddress`)。`$setAll(\"nodes.*.children.*.total\", [], v)` や\n * `this[\"nodes.1.total\"] = v` は `**` を含まないので `setAllRecursive` の\n * 読み取り専用検査を通らず、未実体化なら fast path が行オブジェクトへ素の\n * プロパティとして書いてしまう(ノードを汚し、代入値が `dirty:false` で載って\n * 以後 getter が評価されない)。展開形への書き込みは、実体化の前後に関わらず\n * `wcs/recursion-readonly` で止める。\n */\n recursiveGetterOwning(concretePath: string): string | null {\n const accessor = this._accessors.get(concretePath);\n if (typeof accessor !== \"undefined\") {\n return accessor.recursivePath;\n }\n // 添字綴り(`$setAll(\"nodes.1.total\", [], v)` — API のパス引数は set トラップと違って\n // getResolvedAddress の正規化を経ない)は、添字を `*` に畳んでから照合する。畳まないと\n // `nodes[1].total` へ素の値が書かれる(第 3 回レビューで実測)。**無条件に**畳む —\n // 「アンカーで始まらないときだけ」にすると、ワイルドカードと添字の混在綴り\n // (`nodes.*.children.0.total`)がアンカーで始まるせいで畳まれず、`depthOfConcretePath` が\n // `.children.0` を反復単位と認めずに素通りする(第 4 回レビューで実測)。\n // 記憶のキーは畳んだ形 — 添字綴りのまま記憶すると綴りの数だけ単調に増える。\n const pattern = indexSegmentsToWildcard(concretePath);\n const known = this._ownerByPath.get(pattern);\n if (typeof known !== \"undefined\") {\n return known;\n }\n let owner: string | null = null;\n if (pattern.startsWith(this.spec.anchor)) {\n // 展開形そのもの → その値の内側(`.` 境界で切った接頭辞を長い方から)の順に照合する。\n // 接頭辞はアンカーより長いものだけ — アンカー自身は接尾辞が空なので getter になり得ない。\n owner = this._matchExpansion(pattern);\n for (let end = pattern.lastIndexOf(DELIMITER);\n owner === null && end > this.spec.anchor.length;\n end = pattern.lastIndexOf(DELIMITER, end - 1)) {\n owner = this._matchExpansion(pattern.slice(0, end));\n }\n }\n // 定義集合は state の世代内で不変なので、判定は記憶してよい(アンカー外の否定も含む)。\n this._ownerByPath.set(pattern, owner);\n return owner;\n }\n\n /** 具体パスが宣言済み `**` getter の展開形そのものなら、その getter のパス。 */\n private _matchExpansion(concretePath: string): string | null {\n for (const definition of this._definitions.values()) {\n if (depthOfConcretePath(this.spec, definition.suffix, concretePath) !== null) {\n return definition.recursivePath;\n }\n }\n return null;\n }\n\n /**\n * `materializeFor` の `PathInfo` 版。**読みのホットパス(`getByAddress`)専用**で、\n * 判定そのものは `materializeFor` に委ね、結果(否定を含む)を PathInfo に記憶する。\n * 書き側の `recursiveGetterOwningPath` と対称。\n */\n materializeForPathInfo(stateElement: IStateElement, pathInfo: IPathInfo): IRecursionAccessor | null {\n // `**` getter の無い宣言(レジストリは空)は、記憶を作らずに抜ける\n if (this._definitions.size === 0) {\n return null;\n }\n const known = this._accessorByPathInfo.get(pathInfo);\n if (typeof known !== \"undefined\") {\n return known;\n }\n const accessor = this.materializeFor(stateElement, pathInfo.path);\n this._accessorByPathInfo.set(pathInfo, accessor);\n return accessor;\n }\n\n /**\n * 具体パスが再帰 getter の展開形なら、そのアクセサを(未登録なら生やして)返す。\n * 該当しなければ null。読みは `materializeForPathInfo` を通るので、ここへ来るのは\n * 記憶が外れたときだけ — 判定は接頭辞 1 回で抜け、ここでは否定を記憶しない(記憶は\n * `materializeForPathInfo` の PathInfo キーの 1 か所)。\n * (`**` getter の無い空レジストリを弾くのは呼び出し側の役目。)\n */\n materializeFor(stateElement: IStateElement, concretePath: string): IRecursionAccessor | null {\n const known = this._accessors.get(concretePath);\n if (typeof known !== \"undefined\") {\n return known;\n }\n if (!concretePath.startsWith(this.spec.anchor)) {\n return null;\n }\n let matched: IRecursiveGetterDefinition | null = null;\n let matchedDepth = 0;\n for (const definition of this._definitions.values()) {\n const depth = depthOfConcretePath(this.spec, definition.suffix, concretePath);\n if (depth === null) {\n continue;\n }\n if (matched !== null) {\n // コンストラクタの静的検査で弾いているはずの形。保険として先着を無言で採らない。\n raiseError(\n `\"${concretePath}\" matches both \"${matched.recursivePath}\" and \"${definition.recursivePath}\".`\n );\n }\n matched = definition;\n matchedDepth = depth;\n }\n if (matched === null) {\n return null;\n }\n return this._define(stateElement, matched, matchedDepth, concretePath);\n }\n\n private _define(\n stateElement: IStateElement,\n definition: IRecursiveGetterDefinition,\n depth: number,\n concretePath: string,\n ): IRecursionAccessor {\n // 作者が同じ具体パスを手で定義していないか。**プロトタイプチェーンまで**見る —\n // class 構文の getter は own ではなく prototype に載る(`getStateInfo` が\n // `getterPaths` に拾うのと同じ範囲)。own しか見ないと、生成アクセサが own に\n // 定義されて作者の getter を無言で影にする。前世代の生成物(own・WeakSet に載る\n // get)だけは上書きしてよい。\n const existing = stateElement.findStateDescriptor(concretePath);\n if (typeof existing !== \"undefined\" && !isGeneratedGetter(existing)) {\n raiseError(\n `\"${concretePath}\" is already defined on the state, so the recursive getter ` +\n `\"${definition.recursivePath}\" cannot expand to it. Rename one of them.`\n );\n }\n const accessor: IRecursionAccessor = Object.freeze({\n recursivePath: definition.recursivePath,\n depth,\n });\n const body = definition.get;\n const generated = function (this: unknown): unknown {\n return body.call(this);\n };\n markGeneratedGetter(generated);\n // 前世代の生成物が残っていても、登録(getterPaths / setPathInfo / listPaths)は\n // この世代でやり直す必要があるので、descriptor ごと定義し直す。\n stateElement.defineTreeAccessor(concretePath, {\n get: generated,\n enumerable: false,\n configurable: true,\n });\n this._registerListPaths(stateElement, depth);\n this._accessors.set(concretePath, accessor);\n return accessor;\n }\n\n /**\n * 経路上のリストパスを `listPaths` に載せる(E4)。`setPathInfo(path, \"for\")` は\n * 使えない — あちらは `elementPaths` にも入れて `setByAddress` の swap 経路\n * (`isSwappable`)を変えてしまう。ここで要るのは「依存ウォークがこのパスを\n * リストとして展開する」ことだけ。\n */\n private _registerListPaths(stateElement: IStateElement, depth: number): void {\n for (const listPath of listPathsUpTo(this.spec, depth)) {\n if (this._registeredListPaths.has(listPath)) {\n continue;\n }\n this._registeredListPaths.add(listPath);\n stateElement.addListPath(listPath);\n }\n }\n\n /**\n * この世代が生やしたもの(own の生成アクセサ・依存辺・キャッシュ)を忘れる(state の\n * 再セット時、`getStateInfo` の再収集より**前**に呼ぶ)。実体は generation.ts。\n */\n forgetGenerated(stateElement: IStateElement, previousState: object): ReadonlySet<string> {\n const generatedPaths: ReadonlySet<string> = new Set(this._accessors.keys());\n forgetGeneration(stateElement, previousState, generatedPaths);\n // 忘れた具体パスを返す。`_state` のセッタは経路情報を作り直すときにこれを除く —\n // この世代ではまだ実体化されていないので、辺だけ張り直してはならない。\n return generatedPaths;\n }\n\n /**\n * `**` 接尾辞の深さ `depth` の具体パス(`concretePathAt` の記憶付き版)。\n * 束縛形の読み(`this[\"nodes.**.value\"]` / 省略形 `$getAll`)は再帰 getter の評価ごとに\n * ここを通るので、深さぶんの文字列連結とワイルドカード数えを毎回やり直さない。\n * 上限は「接尾辞の種類 × 128」で有界(上限超過は `concretePathAt` が throw するので載らない)。\n */\n concretePathAt(suffix: string, depth: number): string {\n let byDepth = this._concreteBySuffix.get(suffix);\n if (typeof byDepth === \"undefined\") {\n byDepth = [];\n this._concreteBySuffix.set(suffix, byDepth);\n }\n let path = byDepth[depth];\n if (typeof path === \"undefined\") {\n path = concretePathAt(this.spec, suffix, depth);\n byDepth[depth] = path;\n }\n return path;\n }\n\n /** 展開済みアクセサのメタデータ(深さ解決・診断・テスト用)。 */\n accessorFor(concretePath: string): IRecursionAccessor | null {\n return this._accessors.get(concretePath) ?? null;\n }\n\n /**\n * これまでに実体化した具体パスの一覧。**テスト専用**(「読んだ深さだけが生える」という\n * 遅延実体化の不変条件を外から確かめる口。ランタイムはどの経路からも呼ばない)。\n */\n get materializedPaths(): ReadonlySet<string> {\n return new Set(this._accessors.keys());\n }\n}\n\n","/**\n * recursion/declarations.ts — `$recursion` の宣言(設計案 H4、S4)。\n *\n * 文脈袋の作り手でもある: 構築したレジストリを袋に置き、`$scan` の検証がそれを読む\n * (`**` getter の展開形を `from` に書いた形を落とすため — D5)。core は「ある宣言が別の宣言に\n * 値を渡す」ことを知らなくてよくなった。\n *\n * 段の位置は従来の `_state` セッターのまま:\n * validateEarly core 自身のトークン / `$listKeys` の解析より前(`value` しか読まない)\n * preCommit 旧世代の生成アクセサ・依存辺・キャッシュを忘れてから差し替える。世代を進める前\n * apply アンカーのリストパスの登録(`_listPaths` のクリアより後)\n */\nimport type { IState } from \"../types\";\nimport { IDeclarationHooks, registerDeclarationHooks } from \"../core/declarationHooks\";\nimport { STATE_RECURSION_NAME } from \"../define\";\nimport { installRecursionHooks } from \"./addressHooks\";\nimport { processRecursionDeclaration } from \"./declaration\";\nimport { RecursionRegistry } from \"./registry\";\nimport type { IRecursionSpec } from \"./types\";\n\nconst SPEC = \"recursionSpec\";\nconst REGISTRY = \"recursionRegistry\";\n\nexport const recursionDeclarationHooks: IDeclarationHooks = {\n // scan(8)より先に走り、袋にレジストリを置く\n order: 5,\n validateEarly(_element, value, ctx) {\n const spec = processRecursionDeclaration(value);\n ctx.set(SPEC, spec);\n ctx.set(REGISTRY, spec === null ? null : new RecursionRegistry(spec, value));\n },\n preCommit(element, _value, ctx) {\n // 旧世代の生成アクセサ(own)・それを指す依存辺・評価結果のキャッシュを忘れてから\n // 差し替える(recursion/generation.ts)。own の生成アクセサは、同じオブジェクトを再セットする\n // ときに `getStateInfo` が `getterPaths` へ拾い直す前に消えていなければならない。\n // 前世代の再帰レジストリが生やした具体パスは要素の除外集合に積む。経路情報の作り直し\n // (`_rebuildPathInfo`)はそこを除く — 新しい世代ではまだ実体化されていないため。\n const previous = element.recursionRegistry;\n if (previous !== null) {\n for (const path of previous.forgetGenerated(element, ctx.get<IState>(\"previousState\") as IState)) {\n element.addGeneratedPath?.(path);\n }\n }\n const registry = ctx.get<RecursionRegistry | null>(REGISTRY) ?? null;\n element.setRecursionRegistry?.(registry);\n if (registry !== null) {\n // `$recursion` を宣言した state にだけ再帰の hook(`**` の束縛・再帰 getter の書き込み禁止)を付ける\n element.attachAddressHooks?.(\"recursion\", STATE_RECURSION_NAME);\n }\n },\n apply(element, _value, ctx) {\n const spec = ctx.get<IRecursionSpec | null>(SPEC) ?? null;\n if (spec === null) {\n return;\n }\n // アンカーのリストパス(`nodes.*` なら `nodes`)は**宣言から静的に分かる**ので、\n // 展開を待たずに今すぐ登録する。\n //\n // これが無いと、再帰パスを一度読んだ後の再セットで構造書き込みが恒久的に落ちる。\n // 生成アクセサの `setPathInfo` が張った静的辺(`nodes` → `nodes.*`)は依存グラフに\n // 残るのに、`_listPaths` はセッターでクリアされ、次に再帰パスを読むまで張り直されない。\n // その隙間に構造書き込みが来ると `walkDependency` が「リストではないパス」として\n // `nodes.*` に到達し、listIndex を持たないアドレスで `Cannot expand dynamic dependency…`\n // になる(値は書かれるので、データと表示が乖離したまま自己回復しない)。\n element.addListPath(spec.anchorList);\n },\n};\n\nlet installed = false;\n/** 冪等。full / auto では `bootstrapState()` が呼ぶ */\nexport function installRecursionDeclarations(): void {\n if (installed) return;\n installed = true;\n installRecursionHooks();\n registerDeclarationHooks(\"recursion\", recursionDeclarationHooks);\n}\n","/**\n * features/recursion.ts — `$recursion` と `**`(@wcstack/state/features/recursion)。\n */\nimport type { IStateFeature } from \"../core/features\";\nimport { installRecursionDeclarations } from \"../recursion/declarations\";\n\nexport const recursion: IStateFeature = {\n name: \"recursion\",\n install(): void {\n installRecursionDeclarations();\n },\n};\nexport default recursion;\n"],"names":["hasRecursionWildcard","path","indexOf","RECURSION_WILDCARD","splitRecursivePath","spec","recursiveAnchor","prefix","DELIMITER","startsWith","suffix","slice","length","segments","split","WILDCARD","some","segment","foldSuffixIndexes","indexSegmentsToWildcard","sameFamily","a","b","unit","repeat","shorter","longer","endsWith","gap","cursor","coversSuffix","familySuffix","end","lastIndexOf","i","Number","isNaN","join","isStructuralSuffix","repeatSegments","rest","repeatList","concretePathAt","depth","raiseError","anchor","full","wildcardCount","MAX_WILDCARD_DEPTH","nodePathAt","depthOfConcretePath","middle","currentRecursionDepth","handler","registry","addressStackLength","address","lastAddressStack","accessor","accessorFor","pathInfo","charCodeAt","depthOfConcretePathPrefix","bindRecursivePath","stateElement","recursionRegistry","recursionAnchorMismatchMessage","collectRecursiveAddresses","target","receiver","results","observed","Map","pathsByDepth","anchorList","ancestors","Set","visited","expandSuffix","concretePathInfo","level","listIndex","parents","wildcardParentPathInfos","push","createStateAddress","rows","readRows","listPathInfo","parentListIndex","seen","listAddress","absAddress","liftAddress","value","getByAddress","tracked","listPath","Array","isArray","list","has","guardShape","listDiff","createListDiff","getStateListBaseline","set","add","newIndexes","descend","paths","known","concretePath","nodePath","getPathInfo","childListPathInfo","pathsAt","branch","flat","row","delete","setStateListBaseline","setAllRecursive","indexes","options","assertWritable","checkedSuffix","setAllValueKindMessage","spread","assertNotStructural","conflicting","conflictingRecursiveGetter","addresses","written","setByAddress","recursionAddressHooks","write","hasRecursion","NOT_HANDLED","owner","recursiveGetterOwningPath","get","prop","values","getAllRecursive","getAll","setAll","resolvedAddress","getResolvedAddress","getListIndex","installed","assertNodePath","kind","STATE_RECURSION_NAME","generatedGetters","WeakSet","isGeneratedGetter","descriptor","DECLARATION_INVALID","RecursionRegistry","_definitions","_accessors","_ownerByPath","_ownerByPathInfo","WeakMap","_accessorByPathInfo","_concreteBySuffix","_registeredListPaths","constructor","state","this","descriptors","getAllPropertyDescriptors","key","Object","entries","recursivePath","_assertNoColliding","_assertNoConcreteCollision","_matchExpansion","definitions","from","j","hasDefinitions","size","definition","recursiveGetterOwning","pattern","materializeForPathInfo","materializeFor","matched","matchedDepth","_define","existing","findStateDescriptor","freeze","body","generated","call","getter","defineTreeAccessor","enumerable","configurable","_registerListPaths","k","listPathsUpTo","addListPath","forgetGenerated","previousState","generatedPaths","keys","getOwnPropertyDescriptor","map","staticDependency","dynamicDependency","source","targets","kept","forgetGeneration","byDepth","materializedPaths","SPEC","REGISTRY","recursionDeclarationHooks","order","validateEarly","_element","ctx","declared","processRecursionDeclaration","preCommit","element","_value","previous","addGeneratedPath","setRecursionRegistry","attachAddressHooks","apply","installRecursionDeclarations","registerFeatureHooks","registerDeclarationHooks","recursion","name","install"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"recursion.js","sources":["../../../../../src/recursion/expand.ts","../../../../../src/recursion/bind.ts","../../../../../src/recursion/walk.ts","../../../../../src/recursion/setAllRecursive.ts","../../../../../src/recursion/addressHooks.ts","../../../../../src/recursion/getAllRecursive.ts","../../../../../src/recursion/declaration.ts","../../../../../src/recursion/generation.ts","../../../../../src/recursion/registry.ts","../../../../../src/recursion/declarations.ts","../../../../../src/features/recursion.ts"],"sourcesContent":["/**\n * recursion/expand.ts\n *\n * `**` を含むオーサリング層のパスと、エンジンが扱う具体パスの相互変換。\n * **純関数だけ**を置く(state も proxy も触らない)。\n *\n * 変換は 1 対 1 ではなく 1 対多である。`nodes.**.total` は深さごとに\n * `nodes.*.total` / `nodes.*.children.*.total` / … という無限の族を表し、\n * エンジンが見るのは常にそのうちの 1 本だけ(設計書 D2)。\n */\n\nimport { DELIMITER, MAX_WILDCARD_DEPTH, RECURSION_WILDCARD, WILDCARD } from \"../define\";\nimport { raiseError } from \"../raiseError\";\nimport { IRecursionSpec } from \"./types\";\n\n/** `**` を含むか(含まない大多数のパスを 1 回の indexOf で抜ける)。 */\nexport function hasRecursionWildcard(path: string): boolean {\n return path.indexOf(RECURSION_WILDCARD) !== -1;\n}\n\n/**\n * `**` を含むパスを宣言と突き合わせ、接尾辞(`**` より後ろ。無ければ空文字)を返す。\n * 宣言に合致しない `**` は「宣言なしの `**`」として呼び出し側が診断する(null を返す)。\n */\nexport function splitRecursivePath(spec: IRecursionSpec, path: string): string | null {\n if (path === spec.recursiveAnchor) {\n return \"\";\n }\n const prefix = spec.recursiveAnchor + DELIMITER;\n if (!path.startsWith(prefix)) {\n return null;\n }\n const suffix = path.slice(spec.recursiveAnchor.length);\n // 接尾辞に 2 つ目の `**` があるのは初版では未対応(複数の再帰点)。\n if (hasRecursionWildcard(suffix)) {\n return null;\n }\n // 接尾辞は整形されたパスでなければならない: 空セグメント(`nodes.**.` / `nodes.**..x`)と\n // `**` 直後の素の `*`(`nodes.**.*` — 展開すると `nodes.*.*` でアンカー行そのもの)は\n // 受理しない。`assertNodePath` / `$watch` が同じ形を拒否するのと対称(第 4 サイクルで実測:\n // 受理すると `[undefined×n]` や生の `Reflect.set called on non-object` になっていた)。\n const segments = suffix.slice(DELIMITER.length).split(DELIMITER);\n if (segments[0] === WILDCARD || segments.some((segment) => segment.length === 0)) {\n return null;\n }\n return suffix;\n}\n\n/**\n * 接尾辞(`.` で始まる)の添字セグメントだけを `*` に畳む。先頭の空セグメントは区切りの\n * 都合なので畳まない(`indexSegmentsToWildcard` に丸ごと渡すと `Number(\"\") === 0` で `*` になる)。\n * `**` パスの検査(構造・読み取り専用)と `**` getter キーの検査が共有する。\n */\nexport function foldSuffixIndexes(suffix: string): string {\n return suffix.length === 0 ? suffix : DELIMITER + indexSegmentsToWildcard(suffix.slice(DELIMITER.length));\n}\n\n/**\n * 2 つの接尾辞が**同じ具体パス族**を指すか。片方がもう片方の末尾で、差分が反復語の\n * 整数倍(0 回を含む)のとき真。`nodes.**.total` と `nodes.**.children.*.total` は\n * 深さ k と k+1 で同じ `nodes.*.children.*.total` になる、という関係を捉える。\n * 静的側の `recursionPaths.sameFamily` と同じ純関数。\n */\nexport function sameFamily(spec: IRecursionSpec, a: string, b: string): boolean {\n const unit = DELIMITER + spec.repeat;\n const shorter = a.length <= b.length ? a : b;\n const longer = a.length <= b.length ? b : a;\n if (!longer.endsWith(shorter)) {\n return false;\n }\n const gap = longer.slice(0, longer.length - shorter.length);\n if (gap.length === 0) {\n return true;\n }\n if (gap.length % unit.length !== 0) {\n return false;\n }\n for (let cursor = 0; cursor < gap.length; cursor += unit.length) {\n if (!gap.startsWith(unit, cursor)) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * 接尾辞 `suffix` が、`**` getter の接尾辞 `familySuffix` の族そのもの、またはその値の内側を\n * 指しているか。`.` 境界で切った各接頭辞 `p`(全体を含む)について `sameFamily(familySuffix, p)`\n * を見る — `startsWith(familySuffix + \".\")` だけでは、反復語ぶんずれた展開形の値の内側\n * (`nodes.**.children.*.total.x` で `nodes.**.total`)を取りこぼす(第 4 サイクルで実測)。\n */\nexport function coversSuffix(spec: IRecursionSpec, familySuffix: string, suffix: string): boolean {\n for (let end = suffix.length; end > 0; end = suffix.lastIndexOf(DELIMITER, end - 1)) {\n if (sameFamily(spec, familySuffix, suffix.slice(0, end))) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * 添字セグメント(`nodes.1.total` の `1`)を `*` に畳む。判定は `address/ResolvedAddress.ts`\n * と同じ「`Number()` が NaN でない区切り」。API のパス引数(`$getAll` / `$setAll` / `$resolve`)と\n * `**` パスの接尾辞は set トラップと違って `getResolvedAddress` の正規化を経ないので、\n * 再帰の検査(読み取り専用・構造)に掛ける前にここで畳む。\n */\nexport function indexSegmentsToWildcard(path: string): string {\n const segments = path.split(DELIMITER);\n for (let i = 0; i < segments.length; i++) {\n if (segments[i] !== WILDCARD && !Number.isNaN(Number(segments[i]))) {\n segments[i] = WILDCARD;\n }\n }\n return segments.join(DELIMITER);\n}\n\n/**\n * `**` パスの接尾辞が「再帰の構造そのもの」を名指しているか。\n *\n * ノード自身(`nodes.**` / `nodes.**.children.*`)・子リスト(`nodes.**.children`)・その\n * `length`(`arr.length = 0` は配列を切り詰める)・多段の反復サブパスなら子リストへ至る\n * 途中のオブジェクト(`nodes.**.branch`)。書き側(`setAllRecursive`)は確定済みの\n * 子アドレスを壊すので拒否し、宣言側(`**` getter のキー)は生成 getter が実データの\n * 子リストを影にするので拒否する — 同じ述語を両方が使う。\n *\n * 反復サブパスを**途中まで**名指す形もすべて構造。`\".\" + repeatList` との完全一致だけを\n * 見ると、多段の repeat で途中のオブジェクトが素通りし、深さ 0 の `branch` を置き換えた\n * 瞬間に確定済みの深さ 1 のアドレスが宙に浮く(着地後レビューで実測。実装計画 §7-3)。\n */\nexport function isStructuralSuffix(spec: IRecursionSpec, suffix: string): boolean {\n const repeatSegments = spec.repeat.split(DELIMITER);\n const unit = DELIMITER + spec.repeat;\n let rest = suffix;\n while (rest.startsWith(unit)) {\n rest = rest.slice(unit.length);\n }\n if (rest.length === 0 || rest === DELIMITER + spec.repeatList + DELIMITER + \"length\") {\n return true;\n }\n for (let i = 1; i < repeatSegments.length; i++) {\n if (rest === DELIMITER + repeatSegments.slice(0, i).join(DELIMITER)) {\n return true;\n }\n }\n return false;\n}\n\n/** 深さ k の具体パスを作る。上限超過は生成前に throw する(設計書 D11)。 */\nexport function concretePathAt(spec: IRecursionSpec, suffix: string, depth: number): string {\n if (depth < 0) {\n raiseError(`Recursion depth must not be negative (got ${depth}).`);\n }\n let path = spec.anchor;\n for (let i = 0; i < depth; i++) {\n path += DELIMITER + spec.repeat;\n }\n const full = path + suffix;\n // ワイルドカード段数は展開後のパス全体で数える(アンカー・反復・接尾辞をすべて含む)。\n // intern(getPathInfo)より**前**に文字列から数える — 上限超過のパスを永続キャッシュ\n // (PathInfo の `_cache`)に残さない(設計書 D10「毎ノードの固有パスを intern しない」)。\n let wildcardCount = 0;\n for (const segment of full.split(DELIMITER)) {\n if (segment === WILDCARD) {\n wildcardCount++;\n }\n }\n if (wildcardCount > MAX_WILDCARD_DEPTH) {\n raiseError(\n `[wcs/recursion-depth-exceeded] Recursion on \"${spec.anchor}\" reached depth ${depth} ` +\n `(\"${full}\"), which needs ${wildcardCount} wildcard levels — the limit is ${MAX_WILDCARD_DEPTH}. ` +\n `Either the data nests deeper than the engine can address, or the tree contains a cycle.`\n );\n }\n return full;\n}\n\n/** 深さ k のノードパス(接尾辞なし)。リストパスの登録に使う(このモジュール内だけ)。 */\nfunction nodePathAt(spec: IRecursionSpec, depth: number): string {\n return concretePathAt(spec, \"\", depth);\n}\n\n/**\n * 深さ k のノードが持つ子リストのパス(`nodes.*.children` / `nodes.*.children.*.children` …)。\n * `listPaths` へ登録する対象(E4)。深さ 0 のアンカー自身のリスト(`nodes`)も含める。\n */\nexport function listPathsUpTo(spec: IRecursionSpec, depth: number): string[] {\n const paths: string[] = [];\n // アンカー自身のリスト(末尾の `.*` を落とした形)\n paths.push(spec.anchorList);\n for (let k = 0; k < depth; k++) {\n paths.push(nodePathAt(spec, k) + DELIMITER + spec.repeatList);\n }\n return paths;\n}\n\n/**\n * 具体パスが「その再帰 getter の深さ k の展開形」なら深さを返す。違えば null。\n *\n * 文字列中の反復語の出現数で数えない — 接尾辞が反復語と同じ綴りを含む場合に\n * 取り違える。前から `anchor`、後ろから `suffix` を確かめ、間が `repeat` の\n * 反復ちょうどであることを見る。\n */\nexport function depthOfConcretePath(spec: IRecursionSpec, suffix: string, path: string): number | null {\n if (!path.startsWith(spec.anchor)) {\n return null;\n }\n if (suffix.length > 0 && !path.endsWith(suffix)) {\n return null;\n }\n // 接頭辞と接尾辞が**重なって**はならない。重なると slice が空文字に畳まれて\n // 「深さ 0 で一致」に見え、アンカーそのもの(`nodes.*` — 実データの行)が\n // 生成 getter に隠される。接尾辞が `.*` の `nodes.**.*` で実際に踏んだ。\n if (path.length < spec.anchor.length + suffix.length) {\n return null;\n }\n const middle = path.slice(spec.anchor.length, path.length - suffix.length);\n if (middle.length === 0) {\n return 0;\n }\n const unit = DELIMITER + spec.repeat;\n let depth = 0;\n let cursor = 0;\n while (cursor < middle.length) {\n if (!middle.startsWith(unit, cursor)) {\n return null;\n }\n cursor += unit.length;\n depth++;\n }\n return depth;\n}\n","/**\n * recursion/bind.ts\n *\n * オーサリング層の `**` を「いま評価している深さ」へ束縛する。\n *\n * 深さの根拠は**生成アクセサのアドレス**であって、文字列中の反復語の出現数ではない。\n * `getByAddress` は getterPaths に載るパスを読むときアドレスをスタックへ積むので、\n * 深さ k の再帰 getter の本体を評価している最中は、スタック先頭がその具体パスの\n * アドレスになっている。そこから深さを復元する(実装計画 §1-2)。\n *\n * 見るのは**スタック先頭だけ**である。添字(ListIndex)を供給する `getContextListIndex` /\n * `$getAll` の省略形も先頭しか見ないので、深さだけを外側のフレームから拾うと「深さは\n * 束縛されたが行は無い」という定義にない状態になる — `**` getter が別の素の getter を\n * 経由して `**` を読む形(`get \"nodes.**.x\"() { return this.helper }` /\n * `get helper() { return this[\"nodes.**.value\"] }`)がそれで、直接読みは生の\n * `ListIndex not found`、`$getAll` の省略形は「束縛した深さ × 全行」という値を無言で\n * 返していた。深さと行は同じフレームから取る。\n */\n\nimport { IStateElement } from \"../components/types\";\nimport { DELIMITER } from \"../define\";\nimport { IStateHandler } from \"../proxy/types\";\nimport { recursionAnchorMismatchMessage } from \"../pathDiagnostics\";\nimport { raiseError } from \"../raiseError\";\nimport { splitRecursivePath } from \"./expand\";\nimport type { RecursionRegistry } from \"./registry\";\n\n/**\n * 具体パスの**接頭辞**として最深のノードパスを見つけ、その深さを返す。\n * `nodes.*.children.*.label` のような行 getter の文脈から深さ 1 を取り出す用。\n */\nfunction depthOfConcretePathPrefix(registry: RecursionRegistry, path: string): number | null {\n const spec = registry.spec;\n if (!path.startsWith(spec.anchor)) {\n return null;\n }\n const unit = DELIMITER + spec.repeat;\n let depth = 0;\n let cursor = spec.anchor.length;\n while (path.startsWith(unit, cursor)) {\n cursor += unit.length;\n depth++;\n }\n // 接頭辞の直後はパス境界(末尾、または `.`)でなければならない。\n if (cursor !== path.length && path.charCodeAt(cursor) !== 46 /* '.' */) {\n return null;\n }\n return depth;\n}\n\n/**\n * 評価中のアドレス(スタック先頭)から再帰の深さを求める。再帰文脈でなければ null。\n * 先頭が null(ループ文脈の無いイベントハンドラ・初期同期)も再帰文脈ではない。\n */\nexport function currentRecursionDepth(handler: IStateHandler, registry: RecursionRegistry): number | null {\n if (handler.addressStackLength === 0) {\n return null;\n }\n const address = handler.lastAddressStack;\n if (address === null) {\n return null;\n }\n const accessor = registry.accessorFor(address.pathInfo.path);\n if (accessor !== null) {\n return accessor.depth;\n }\n // 生成アクセサでなくても、宣言に合致する具体パス(行 getter・行のイベントハンドラが\n // 積むループのアドレス)ならそこから深さを取れる。\n return depthOfConcretePathPrefix(registry, address.pathInfo.path);\n}\n\n/**\n * `**` を含むパスを、いま評価している深さの具体パスへ書き換える。\n * 再帰文脈が無いところで `**` を直接読むのは、深さが決まらないので診断する。\n */\nexport function bindRecursivePath(\n stateElement: IStateElement,\n handler: IStateHandler,\n path: string,\n): string {\n // 呼び出し元は 2 つとも `hasRecursion === true` をゲートにしているので、\n // ここに来た時点でレジストリは必ずある。到達不能な `??` 分岐は置かない\n // (カバレッジ閾値に効く — walkDependency の `address.listIndex!` と同じ綴り)。\n const registry = stateElement.recursionRegistry!;\n // アンカー照合を先に行う。深さ解決を先にすると、綴り違いのアンカーが\n // 「文脈が無い」と報告されて原因に辿り着けない。\n const suffix = splitRecursivePath(registry.spec, path);\n if (suffix === null) {\n raiseError(recursionAnchorMismatchMessage(path, registry.spec.recursiveAnchor));\n }\n const depth = currentRecursionDepth(handler, registry);\n if (depth === null) {\n raiseError(\n `[wcs/recursion-context] \"${path}\" uses \"**\", which is bound to the depth of the recursive getter ` +\n `being evaluated, and there is no recursion context here. Read it from inside a recursive getter ` +\n `or a row getter under \"${registry.spec.anchor}\", or name a concrete depth ` +\n `(for example \"${registry.spec.anchor}${path.slice(registry.spec.recursiveAnchor.length)}\"). ` +\n `The depth comes from the innermost frame only: a plain getter reached from a recursive getter ` +\n `has no row of its own, so read \"**\" in the recursive getter and pass the value on.`\n );\n }\n // 照合済みの接尾辞をそのまま使う。具体パスは記憶付き(再帰 getter の評価ごとに通る経路)。\n return registry.concretePathAt(suffix, depth);\n}\n","/**\n * recursion/walk.ts\n *\n * 再帰アンカー配下を**全深さ**にわたって走査し、マッチする具体アドレスを列挙する。\n * `$getAll(path, [])` の合併形(設計書 §6-2)と `$setAll` のブロードキャストが共有する。\n *\n * 固定 arity の走査(`proxy/apis/wildcardIndexes.ts`)は「ワイルドカードの本数が\n * 静的に決まっている」ことに立脚しているので、そのままでは深さが動的な族を扱えない。\n * ここは深さ方向だけを自前で降り、**各深さの具体パスは固定 arity のまま**扱う\n * — つまりエンジンが見るパスは常に `**` を含まない普通のパスである(設計書 D2)。\n *\n * 順序は**深さ優先・行きがけ・添字昇順**(§1-2)。ノードを 1 つ出したら、その子へ\n * 降りきってから次の兄弟へ移る。読みと書きが同じ順序を使うことが `$setAll` の\n * 契約の前提になる。\n *\n * 走査が throw したとき、その走査が観測したリスト値は差分基準へ確定**しない**\n * (途中まで進めた基準を残すと、次の読みが「変化なし」と誤認しうる)。\n */\n\nimport { liftAddress } from \"../address/liftAddress\";\nimport { getPathInfo } from \"../address/PathInfo\";\nimport { createStateAddress } from \"../address/StateAddress\";\nimport { IAbsoluteStateAddress, IPathInfo, IStateAddress } from \"../address/types\";\nimport { DELIMITER } from \"../define\";\nimport { createListDiff } from \"../list/createListDiff\";\nimport { getStateListBaseline, setStateListBaseline } from \"../list/stateListBaseline\";\nimport { IListIndex } from \"../list/types\";\nimport { getByAddress } from \"../proxy/methods/getByAddress\";\nimport { IStateHandler } from \"../proxy/types\";\nimport { raiseError } from \"../raiseError\";\nimport type { RecursionRegistry } from \"./registry\";\n\n\n/** 深さごとに 1 回だけ決まるもの。ノードごとに作り直さない。 */\ninterface IDepthPaths {\n readonly nodePath: string;\n readonly concretePathInfo: IPathInfo;\n readonly childListPathInfo: IPathInfo;\n}\n\n/**\n * アンカー配下の全深さを列挙する。深さ優先・行きがけ・添字昇順。\n *\n * 終端は「その深さの子リストが空」。上限超過は `concretePathAt` が**その深さに実際に\n * ノードが居るときだけ**検査する(葉の 1 段先を投機的に見て落ちないように)。\n */\nexport function collectRecursiveAddresses(\n target: object,\n receiver: any,\n handler: IStateHandler,\n registry: RecursionRegistry,\n suffix: string,\n): IStateAddress[] {\n const spec = registry.spec;\n const results: IStateAddress[] = [];\n const observed: Map<IAbsoluteStateAddress, readonly unknown[]> = new Map();\n const pathsByDepth: IDepthPaths[] = [];\n const repeatList = spec.repeatList;\n const anchorList = spec.anchorList;\n\n /**\n * 「同じ配列インスタンスが 2 つ以上の親から到達可能」を**走査そのもの**で判定する\n * (設計書 D12・E6)。台帳の親(`newIndexes[0].parentListIndex`)で見てはならない\n * — 台帳はリスト配列の identity だけをキーにしていて、行オブジェクトを作り直す\n * ふつうのイミュータブル更新(`nodes.map(n => ({...n}))` は children を参照ごと\n * 引き継ぐ)でも親 ListIndex が別物になるため、正当な木を恒久的に拒否してしまう。\n *\n * 走査で見た配列を覚えておけば、共有も循環も「同じ配列に 2 度到達したか」で決まる。\n * 祖先の集合に居れば循環(自分より上へ戻る)、そうでなければ兄弟共有。\n * 空配列は行を持たないので別名化のしようがなく、追跡しない(`[]` の使い回しは正当)。\n */\n const ancestors: Set<readonly unknown[]> = new Set();\n const visited: Set<readonly unknown[]> = new Set();\n\n const guardShape = (\n listPath: string,\n value: unknown,\n seen: Set<readonly unknown[]>,\n ): readonly unknown[] | null => {\n if (!Array.isArray(value) || value.length === 0) {\n return null;\n }\n const list = value as readonly unknown[];\n if (ancestors.has(list)) {\n raiseError(\n `[wcs/recursion-cycle] \"${listPath}\" is reachable from itself: the recursion on ` +\n `\"${spec.anchor}\" walked into a list that one of its own ancestors already owns. ` +\n `The data contains a cycle, which this version does not support.`\n );\n }\n if (seen.has(list)) {\n raiseError(\n `[wcs/recursion-shared-list] \"${listPath}\" is the same array instance as a list reached ` +\n `from another node. The recursion on \"${spec.anchor}\" needs a tree: give each node its own ` +\n `\"${repeatList}\" array.`\n );\n }\n return list;\n };\n\n const pathsAt = (depth: number): IDepthPaths => {\n const known = pathsByDepth[depth];\n if (typeof known !== \"undefined\") {\n return known;\n }\n // 上限検査はここ(=その深さに実際にノードが居ると分かってから)。具体パスはレジストリの\n // 記憶(接尾辞 × 深さ)から引き、走査ごとに文字列連結をやり直さない。\n const concretePath = registry.concretePathAt(suffix, depth);\n const nodePath = suffix.length === 0 ? concretePath : registry.concretePathAt(\"\", depth);\n const paths: IDepthPaths = {\n nodePath,\n concretePathInfo: getPathInfo(concretePath),\n childListPathInfo: getPathInfo(nodePath + DELIMITER + repeatList),\n };\n pathsByDepth[depth] = paths;\n return paths;\n };\n\n /** 接尾辞側に残ったワイルドカード段だけを、行の ListIndex を起点に展開する。 */\n const expandSuffix = (concretePathInfo: IPathInfo, level: number, listIndex: IListIndex): void => {\n const parents = concretePathInfo.wildcardParentPathInfos;\n if (level >= parents.length) {\n results.push(createStateAddress(concretePathInfo, listIndex));\n return;\n }\n // 接尾辞側のリストは検査しない。接尾辞が反復語を含む形(`nodes.**.children.*.value`)\n // では、接尾辞の展開と深さ方向の降下が**同じ配列**を通る — 同じ族を 2 通りに綴れる\n // ことの帰結で、共有ではない。次元をまたいでも、同じ次元の中でも(深さ 0 の接尾辞\n // 展開と深さ 1 の接尾辞展開が同じ配列に当たる)自己衝突するので、共有の判定は\n // 深さ方向にだけ掛ける。\n //\n // 結果として `$setAll(\"nodes.**.tags\", [], arr)` のように**ブロードキャストが作った**\n // 配列共有は、ここでは捕まらない(`[wcs/wildcard-rank]` という無関係な文面で落ちる)。\n // 既知の制限として設計書に記録してある。\n const rows = readRows(parents[level], listIndex, null).rows;\n for (let i = 0; i < rows.length; i++) {\n expandSuffix(concretePathInfo, level + 1, rows[i]);\n }\n };\n\n /**\n * リストを 1 本読んで行と、追跡対象のリスト配列を返す。差分基準は state 側の\n * 共有正本(E1)から取り、観測値は走査の最後にまとめて確定する。`guardPath` が\n * 非 null のときだけ共有・循環の検査を掛ける(接尾辞側の普通のリストは再帰の\n * 対象ではない)。\n */\n function readRows(\n listPathInfo: IPathInfo,\n parentListIndex: IListIndex | null,\n seen: Set<readonly unknown[]> | null,\n ): { rows: IListIndex[], tracked: readonly unknown[] | null } {\n const listAddress = createStateAddress(listPathInfo, parentListIndex);\n const absAddress = liftAddress(handler.stateElement, listAddress);\n const value = getByAddress(target, listAddress, receiver, handler);\n const tracked = seen === null ? null : guardShape(listPathInfo.path, value, seen);\n const listDiff = createListDiff(\n parentListIndex, getStateListBaseline(absAddress), value);\n observed.set(absAddress, Array.isArray(value) ? value : []);\n if (tracked !== null && seen !== null) {\n seen.add(tracked);\n }\n return { rows: listDiff.newIndexes, tracked };\n }\n\n const descend = (depth: number, listPathInfo: IPathInfo, parentListIndex: IListIndex | null): void => {\n const { rows, tracked } = readRows(listPathInfo, parentListIndex, visited);\n if (rows.length === 0) {\n return;\n }\n const paths = pathsAt(depth);\n // 行が 1 つでもある ⟹ そのリストは非空配列だった ⟹ guardShape が追跡対象を返している\n // (非配列も空配列も createListDiff が空の行に畳むので、上の早期 return で抜ける)。\n // このリストは、いま降りている枝の祖先になる。子で同じ配列に当たれば循環。\n const branch = tracked as readonly unknown[];\n ancestors.add(branch);\n const flat = paths.concretePathInfo.wildcardCount === depth + 1;\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i];\n if (flat) {\n // 接尾辞にワイルドカードが無い(大多数)。行の ListIndex がそのまま具体パスの\n // 連鎖長を満たすので、追加の走査は要らない。この行 ListIndex は createListDiff が\n // 台帳へ登録した正本そのものなので、`getListIndexByIndexes` で引き直す必要も無い。\n results.push(createStateAddress(paths.concretePathInfo, row));\n } else {\n expandSuffix(paths.concretePathInfo, depth + 1, row);\n }\n descend(depth + 1, paths.childListPathInfo, row);\n }\n ancestors.delete(branch);\n };\n\n descend(0, getPathInfo(anchorList), null);\n\n // 観測したリスト値を差分基準へ確定する。合併形の `$getAll` も再帰の `$setAll` も必ず確定する\n // (実装計画 §6 — cold な書き込みが ListIndex 世代を鋳造したまま基準を残さないと、次の\n // 構造変更で深い子台帳が孤児になる)。走査が throw したときは上の raise でここに来ない。\n for (const [address, value] of observed) {\n setStateListBaseline(address, value);\n }\n return results;\n}\n","/**\n * recursion/setAllRecursive.ts\n *\n * `$setAll(\"<anchor>.**.<suffix>\", [], value)` — **全深さへのブロードキャスト**\n * (設計書 D8 / §7-3)。\n *\n * 読み(`$getAll` の合併形)と同じ列挙を使い、同じ順序で書く。許すのは `[]` の\n * ブロードキャストだけで、mapper と `{ spread: true }` は受け付けない:\n *\n * - **mapper** の `(current, ...indexes)` は、深さごとに添字の本数が変わるので\n * そのままでは渡せない。深さを渡す別のシグネチャを決めてから入れる。\n * - **`{ spread: true }`** は「マッチ順に 1 件ずつ配る」形。順序は決定的に定義できるが、\n * 木に 1 次元配列を配るのは作者が走査順を知らないと使えず、実用にならない。\n *\n * 添字の省略も受け付けない。`$setAll` は「書き込み API に暗黙の文脈依存を持たせない」\n * という既存の決定(docs/state-set-all-design.md の D4)を継ぐので、読み側にある\n * 省略形(文脈束縛)の対応物を書き側には置かない。\n */\n\nimport { recursionAnchorMismatchMessage, setAllValueKindMessage } from \"../pathDiagnostics\";\nimport { setByAddress } from \"../proxy/methods/setByAddress\";\nimport { IStateHandler } from \"../proxy/types\";\nimport { raiseError } from \"../raiseError\";\nimport { assertWritable } from \"../proxy/assertWritable\";\nimport { foldSuffixIndexes, isStructuralSuffix, splitRecursivePath } from \"./expand\";\nimport { IRecursionSpec } from \"./types\";\nimport { collectRecursiveAddresses } from \"./walk\";\n\n/**\n * 接尾辞が「再帰の構造そのもの」を名指していないか(述語は expand.ts の `isStructuralSuffix`)。\n *\n * ノード自身(`nodes.**`)と子リスト(`nodes.**.children`)と子ノード\n * (`nodes.**.children.*`)と子リストの `length` は、書き換えると確定済みの子アドレスを壊す。\n * 初版は葉の属性の更新に限る(実装計画 §1-3)。判定対象は宣言から導出する。\n */\nfunction assertNotStructural(spec: IRecursionSpec, path: string, suffix: string): void {\n if (isStructuralSuffix(spec, suffix)) {\n raiseError(\n `[wcs/recursion-structural-write] \"${path}\" writes the recursion structure itself ` +\n `(a node, its \"${spec.repeatList}\" list or that list's length, or an object on the way to that list). ` +\n `This version broadcasts to leaf properties only — ` +\n `replacing a node would invalidate the child addresses already resolved for this write.`\n );\n }\n}\n\nexport function setAllRecursive(\n target: object,\n receiver: any,\n handler: IStateHandler,\n path: string,\n indexes: unknown,\n value: any,\n options: { readonly spread?: boolean } | undefined,\n): number {\n assertWritable(handler);\n // 呼び出し元(setAll.ts)は `hasRecursion === true` をゲートにしているので必ずある。\n const registry = handler.stateElement.recursionRegistry!;\n const suffix = splitRecursivePath(registry.spec, path);\n if (suffix === null) {\n raiseError(recursionAnchorMismatchMessage(path, registry.spec.recursiveAnchor));\n }\n // 検査には添字を `*` に畳んだ接尾辞を掛ける。`nodes.**.children.0`(子ノード)・\n // `nodes.**.children.0.children`(孫リスト)・`nodes.**.children.0.total`(getter の展開形)は\n // 添字綴りのままだと素の文字列一致をすり抜け、構造を置き換えたり部分書き込みの途中で\n // 生の TypeError になったりしていた(第 2 サイクルのレビューで実測)。列挙は綴りのまま\n // 行う — 接尾辞の添字は「その子だけ」を指す意味を持つ。\n const checkedSuffix = foldSuffixIndexes(suffix);\n\n // --- 形の検査は列挙より前(1 件も書かないことを保証する。設計 §7-3) ---\n if (!Array.isArray(indexes)) {\n raiseError(setAllValueKindMessage(\n path, `with \"**\" requires an explicit empty indexes array ([]) — the write API takes no context.`));\n }\n if (indexes.length > 0) {\n raiseError(\n `[wcs/recursion-setall-form] $setAll(\"${path}\", indexes, …) with \"**\" takes no partial prefix: ` +\n `a prefix cannot say which depth it applies to. Pass [] to broadcast to every depth.`\n );\n }\n if (typeof value === \"function\") {\n raiseError(setAllValueKindMessage(\n path, `with \"**\" does not take a mapper yet — the index tuple has a different length at each depth.`));\n }\n if (options?.spread === true) {\n raiseError(setAllValueKindMessage(\n path, `with \"**\" does not take { spread: true } — handing a flat array to a tree needs the author ` +\n `to know the walk order, which is not a usable contract.`));\n }\n assertNotStructural(registry.spec, path, checkedSuffix);\n const conflicting = registry.conflictingRecursiveGetter(checkedSuffix);\n if (conflicting !== null) {\n raiseError(\n `[wcs/recursion-readonly] \"${path}\" writes into the recursive getter \"${conflicting}\", which has ` +\n `no setter — the two name the same family of concrete paths (or this path points inside the value ` +\n `that getter derives). Write the values it derives from instead.`\n );\n }\n\n // --- 第 1 相: 書き込み先を全部確定する ---\n // **観測したリスト値は基準へ確定する**(走査が必ず行う — walk.ts)。固定 arity の\n // `$setAll` は `commitDiffBaseline: false` で走るが、あれは「読みの私有基準を書きから\n // 動かさない」という E1 以前の所有権モデルの話で、いまの基準は読み・描画・依存ウォークが\n // 共有する state 側の正本である(実装計画 §3-2 の E1)。\n //\n // 確定しないと cold(読みも描画も一度も走っていない)状態の `$setAll` が全深さぶんの\n // ListIndex 世代を鋳造したまま基準を残さず、次の構造変更でその世代が見えない diff が\n // 行を鋳造し直す。生き残った深い children の台帳だけが死んだ世代の親を指し、以後\n // 再帰 getter の読みが恒久的に落ちる(値の合併は動き続けるので無症状のまま進む)。\n // 1 件も書かない `undefined` のブロードキャストでも同じなので、「書き込み 0 件」は\n // 「状態が動いていない」を意味しない。\n const addresses = collectRecursiveAddresses(target, receiver, handler, registry, suffix);\n\n // --- 第 2 相: 確定したアドレスにだけ書く ---\n let written = 0;\n for (let i = 0; i < addresses.length; i++) {\n // undefined は常にスキップ(設計 §5)。クリアは null。\n if (typeof value === \"undefined\") {\n continue;\n }\n setByAddress(target, addresses[i], value, receiver, handler);\n written++;\n }\n return written;\n}\n","/**\n * recursion/addressHooks.ts — `$recursion` を宣言した state に付く hook(設計案 H1、S3)。\n * 従来 core(get トラップ・`$getAll` / `$setAll`・setByAddress)が直接 import していた `**` の\n * 束縛・合併形・書き込み禁止をここへ移し、宣言の無い state では一切走らない。\n * (`$trackDependency` の `**` 拒否は宣言の有無に関わらないので core に残る)\n */\nimport { getResolvedAddress } from \"../address/ResolvedAddress\";\nimport { createStateAddress } from \"../address/StateAddress\";\nimport { IAddressHooks, NOT_HANDLED, registerFeatureHooks } from \"../core/addressHooks\";\nimport { getAll } from \"../proxy/apis/getAll\";\nimport { ISetAllOptions, setAll } from \"../proxy/apis/setAll\";\nimport { getByAddress } from \"../proxy/methods/getByAddress\";\nimport { getListIndex } from \"../proxy/methods/getListIndex\";\nimport { raiseError } from \"../raiseError\";\nimport { bindRecursivePath } from \"./bind\";\nimport { hasRecursionWildcard } from \"./expand\";\nimport { getAllRecursive } from \"./getAllRecursive\";\nimport { setAllRecursive } from \"./setAllRecursive\";\n\n// hook は要素の寿命の間は付いたまま(再セットで `$recursion` が消えても外れない)ので、\n// 宣言が消えた後は `hasRecursion` の boolean 判定 1 個で core と同じ経路へ戻す\nexport const recursionAddressHooks: IAddressHooks = {\n // 再帰 getter の展開形(`nodes.*.children.*.total`)とその値の内側への書き込みは、`**` を\n // 含まないので `setAllRecursive` の読み取り専用検査を通らない。未実体化なら fast path が\n // 「親オブジェクトの未存在キー」として行オブジェクトへ素の値を書き、代入値を `dirty:false` で\n // キャッシュに載せる — ノードが汚れ、実体化後も getter が評価されず、深さ 0 の集計まで\n // 巻き込む(レビュー P18 で実測)。読み側の遅延実体化(getByAddress の E5)と対称に、書き側はここで止める\n write(stateElement, address) {\n if (stateElement.hasRecursion !== true) {\n return NOT_HANDLED;\n }\n const owner = stateElement.recursionRegistry!.recursiveGetterOwningPath(address.pathInfo);\n if (owner !== null) {\n raiseError(\n `[wcs/recursion-readonly] \"${address.pathInfo.path}\" writes into the recursive getter \"${owner}\" ` +\n `(this path is that getter at one depth, or a path inside the value it derives), which has ` +\n `no setter. Write the values it derives from instead.`\n );\n }\n return NOT_HANDLED;\n },\n get(handler, prop, receiver, target) {\n if (handler.stateElement.hasRecursion !== true) {\n return NOT_HANDLED;\n }\n if (prop === \"$getAll\") {\n // オーサリング層の `**`。省略形は「いま評価している深さ」に束縛し、`[]` 明示は\n // 全深さの合併になる(設計書 §6-2)。部分接頭辞は `**` に対して定義できない。\n return (path: string, indexes?: number[]): any[] => {\n if (hasRecursionWildcard(path)) {\n if (typeof indexes === \"undefined\") {\n path = bindRecursivePath(handler.stateElement, handler, path);\n } else {\n // アンカー照合と添字の形の検査は合併形の側で行う(判定順を静的側と揃えるため)\n return getAllRecursive(target, receiver, handler, path, indexes);\n }\n }\n return getAll(target, prop, receiver, handler)(path, indexes);\n };\n }\n if (prop === \"$setAll\") {\n // 書き側は `[]` のブロードキャストだけを受け付ける(形の検査は列挙より前に行い、\n // 1 件も書かないことを保証する。設計 §7-3)\n return (path: string, indexes: number[], value: any, options?: ISetAllOptions): number => {\n if (hasRecursionWildcard(path)) {\n return setAllRecursive(target, receiver, handler, path, indexes, value, options);\n }\n return setAll(target, prop, receiver, handler)(path, indexes, value, options);\n };\n }\n if (prop.charCodeAt(0) !== 36 /* '$' */ && hasRecursionWildcard(prop)) {\n // オーサリング層の `**` を、いま評価している再帰 getter の深さへ束縛して通常解決する\n const resolvedAddress = getResolvedAddress(bindRecursivePath(handler.stateElement, handler, prop));\n const listIndex = getListIndex(target, resolvedAddress, receiver, handler);\n return getByAddress(target, createStateAddress(resolvedAddress.pathInfo, listIndex), receiver, handler);\n }\n return NOT_HANDLED;\n },\n};\n\nlet installed = false;\n/** 冪等。full エントリでは State が `$recursion` の宣言時に呼ぶ(分割エントリでは `install` が担う) */\nexport function installRecursionHooks(): void {\n if (installed) return;\n installed = true;\n registerFeatureHooks(\"recursion\", recursionAddressHooks);\n}\n","/**\n * recursion/getAllRecursive.ts\n *\n * `$getAll(\"<anchor>.**.<suffix>\", [])` — **全深さの合併**(設計書 D7 / §6-2)。\n *\n * 省略形(文脈束縛)とは別経路にする。省略形は「いま評価している深さの 1 本」を\n * 具体パスに直して既存の固定 arity 走査へ渡すだけだが、合併形は深さそのものを\n * 走査対象にするので、返る添字タプルの長さが結果ごとに変わる。だから合併形は\n * **値の配列しか返さない**(`$resolve` への往復は保証しない。設計書 §7-2)。\n */\n\nimport { getByAddress } from \"../proxy/methods/getByAddress\";\nimport { IStateHandler } from \"../proxy/types\";\nimport { splitRecursivePath } from \"./expand\";\nimport { collectRecursiveAddresses } from \"./walk\";\nimport { recursionAnchorMismatchMessage } from \"../pathDiagnostics\";\nimport { raiseError } from \"../raiseError\";\n\nexport function getAllRecursive(\n target: object,\n receiver: any,\n handler: IStateHandler,\n path: string,\n indexes: unknown,\n): any[] {\n // 呼び出し元(getAll.ts)は `hasRecursion === true` をゲートにしている。\n const registry = handler.stateElement.recursionRegistry!;\n // 判定順はアンカー照合 → 添字の形。静的側(vscode-wcs recursionValidator)と同じ順に\n // しておかないと、綴り違いのアンカーに `[0]` を渡した呼び出しが片側では\n // `recursion-anchor`、もう片側では `recursion-getall-form` になる。\n const suffix = splitRecursivePath(registry.spec, path);\n if (suffix === null) {\n raiseError(recursionAnchorMismatchMessage(path, registry.spec.recursiveAnchor));\n }\n // 合併形の添字は `[]` だけ。`null` 等の非配列は素の TypeError にせず、形の診断にする。\n if (!Array.isArray(indexes)) {\n raiseError(\n `[wcs/recursion-getall-form] $getAll(\"${path}\", indexes) with \"**\" takes either no indexes ` +\n `(to read the depth of the recursive getter being evaluated) or [] (to walk every depth) — ` +\n `got ${indexes === null ? \"null\" : typeof indexes}.`\n );\n }\n if (indexes.length > 0) {\n raiseError(\n `[wcs/recursion-getall-form] $getAll(\"${path}\", indexes) with \"**\" takes no partial ` +\n `prefix: a prefix cannot say which depth it applies to. Omit the indexes to read the ` +\n `depth of the recursive getter being evaluated, or pass [] to walk every depth.`\n );\n }\n // 走査は観測したリスト値を差分基準へ確定する(再帰の `$setAll` も同じ。\n // 固定 arity の `$setAll` だけが確定しない — setAllRecursive.ts 第 1 相の注記)。\n const addresses = collectRecursiveAddresses(target, receiver, handler, registry, suffix);\n const values: any[] = [];\n for (let i = 0; i < addresses.length; i++) {\n // `**` は依存グラフに載らない(D2)。呼び出し元の getter は「触れた深さの\n // 具体パス」に依存する — その登録は getByAddress の checkDependency が行う\n // (他行読み取りの検出も含む)。ここで書き写すと untrack を見ない劣化版になる。\n values.push(getByAddress(target, addresses[i], receiver, handler));\n }\n return values;\n}\n","/**\n * recursion/declaration.ts\n *\n * `$recursion: { <anchor>: <repeat> }` 宣言を検証して仕様に落とす\n * (docs/state-recursive-path-impl-plan.md §1-1)。宣言が無ければ null で、\n * その state は再帰の経路にまったく入らない(`$listKeys` と同じゼロコスト規約)。\n *\n * 初版が受け付けるのは **単一の自己再帰** だけ。アンカーも反復サブパスも\n * 「固定プロパティ列 + 末尾の `.*` ひとつ」に限る。途中のワイルドカード・複数宣言・\n * 相互再帰は、黙って別の意味に解釈せず明示的に拒否する。\n */\n\nimport { DELIMITER, RECURSION_WILDCARD, STATE_RECURSION_NAME, WILDCARD } from \"../define\";\nimport { raiseError } from \"../raiseError\";\nimport type { IState } from \"../types\";\nimport { IRecursionSpec } from \"./types\";\n\n/** `a.b.*` の形(末尾だけがワイルドカード・空セグメント無し・`**` 無し・添字無し)か。 */\nfunction assertNodePath(kind: string, path: string): void {\n if (typeof path !== \"string\" || path.length === 0) {\n raiseError(`[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} ${kind} must be a non-empty string.`);\n }\n const segments = path.split(DELIMITER);\n if (segments.some((segment) => segment.length === 0)) {\n raiseError(`[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} ${kind} \"${path}\" must not contain empty path segments.`);\n }\n if (segments.length < 2) {\n raiseError(\n `[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} ${kind} \"${path}\" must name a list element: ` +\n `a property path ending with \"${DELIMITER}${WILDCARD}\" (for example \"nodes${DELIMITER}${WILDCARD}\").`\n );\n }\n if (segments[segments.length - 1] !== WILDCARD) {\n raiseError(\n `[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} ${kind} \"${path}\" must end with \"${DELIMITER}${WILDCARD}\" ` +\n `— it names the element of the list, not the list itself.`\n );\n }\n // 予約セグメント。マウントのマーカー(`#m1`)と `$` 名前空間は raw state に実体を\n // 持たないので、再帰のアンカーにはなり得ない(checkDeclaredPath が同じ 2 つで\n // 早期 return しているのと対称)。\n if (segments[0].charCodeAt(0) === 36 /* '$' */) {\n raiseError(\n `[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} ${kind} \"${path}\" must not start with \"$\" — that namespace is reserved.`\n );\n }\n if (path.indexOf(\"#\") !== -1) {\n raiseError(\n `[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} ${kind} \"${path}\" must not contain \"#\" — that segment is reserved for mounts.`\n );\n }\n for (let i = 0; i < segments.length - 1; i++) {\n if (segments[i] === WILDCARD) {\n raiseError(\n `[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} ${kind} \"${path}\" must have exactly one \"${WILDCARD}\", at the end. ` +\n `Wildcards in the middle are not supported in this version.`\n );\n }\n if (segments[i] === RECURSION_WILDCARD) {\n raiseError(\n `[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} ${kind} \"${path}\" must not contain \"${RECURSION_WILDCARD}\" — ` +\n `the declaration is what gives \"${RECURSION_WILDCARD}\" its meaning.`\n );\n }\n // 添字セグメント(`children.0.*`)。エンジンは具体パスの添字を `*` に畳むので\n // (`indexSegmentsToWildcard` — ResolvedAddress と同じ規則)、宣言の途中に書かれた\n // 添字は意味を持たない奇形になる。黙って `*` と同じに読み替えず、ここで落とす。\n if (!isNaN(Number(segments[i]))) {\n raiseError(\n `[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} ${kind} \"${path}\" must not contain an index segment ` +\n `(\"${segments[i]}\") — the recursion is declared over the shape of the tree, not over one row.`\n );\n }\n }\n}\n\n/**\n * `$recursion` 宣言を検証して仕様にする。宣言が無ければ null(=ゼロコスト経路)。\n */\nexport function processRecursionDeclaration(state: IState): IRecursionSpec | null {\n const declared = (state as Record<string, unknown>)[STATE_RECURSION_NAME];\n if (typeof declared === \"undefined\") {\n return null;\n }\n if (typeof declared !== \"object\" || declared === null) {\n raiseError(\n `[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} must be an object mapping one anchor path to its repeating sub-path ` +\n `(for example { \"nodes.*\": \"children.*\" }).`\n );\n }\n const entries = Object.entries(declared as Record<string, unknown>);\n if (entries.length === 0) {\n raiseError(`[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} must declare exactly one anchor; it is empty.`);\n }\n if (entries.length > 1) {\n raiseError(\n `[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} declares ${entries.length} anchors (${entries.map(([k]) => `\"${k}\"`).join(\", \")}). ` +\n `This version supports exactly one self-recursive anchor per state.`\n );\n }\n const [anchor, repeat] = entries[0];\n assertNodePath(\"anchor\", anchor);\n if (typeof repeat !== \"string\") {\n raiseError(\n `[wcs/recursion-declaration-invalid] ${STATE_RECURSION_NAME} entry \"${anchor}\" must map to the repeating sub-path as a string ` +\n `(for example \"children${DELIMITER}${WILDCARD}\").`\n );\n }\n assertNodePath(\"repeating sub-path\", repeat);\n // 反復サブパスが相対か絶対かは**名前の形では判定できない**。`{ \"nodes.*\": \"nodes.*\" }`\n // は `{ nodes: [{ nodes: [...] }] }` という自己相似な木の最も自然な綴りなので、\n // 「アンカーと同じ語で始まる」ことを理由に拒否してはならない。\n const anchorList = anchor.slice(0, anchor.lastIndexOf(DELIMITER));\n const repeatList = repeat.slice(0, repeat.lastIndexOf(DELIMITER));\n const recursiveAnchor = anchorList + DELIMITER + RECURSION_WILDCARD;\n return Object.freeze({ anchor, repeat, recursiveAnchor, anchorList, repeatList });\n}\n","/**\n * recursion/generation.ts\n *\n * 再帰レジストリの**世代の後始末**。state の再セットで前世代のレジストリが捨てられるとき、\n * その世代が生やしたもの — own の生成アクセサ・依存表の辺・評価結果のキャッシュ — を忘れる。\n * レジストリ本体(宣言の検証・パス族の代数・遅延実体化)から切り出してある: ここだけが\n * 依存表・キャッシュ・台帳という state 全体の構造に触る。\n */\n\nimport { IStateElement } from \"../components/types\";\n\n/**\n * この機構が生やした getter。作者が手で書いた同名 getter と見分けるために使う\n * (前者は忘れてよい・後者は衝突として拒否する)。\n */\nconst generatedGetters: WeakSet<object> = new WeakSet();\n\nexport function markGeneratedGetter(getter: object): void {\n generatedGetters.add(getter);\n}\n\n/** この機構の生成物か(own に残った生成 getter)。 */\nexport function isGeneratedGetter(descriptor: PropertyDescriptor): boolean {\n return typeof descriptor.get === \"function\" && generatedGetters.has(descriptor.get);\n}\n\n/**\n * 前世代が生やしたものを忘れる(state の再セット時に呼ぶ)。忘れるのは 2 つ。\n *\n * **own の生成アクセサ。** 生成 getter は state オブジェクトの own プロパティとして残る。\n * 同じオブジェクトを `$recursion` 無し(または別アンカー)で再セットしたとき、残したままだと\n * `getStateInfo` が `getterPaths` に拾い直し、読むと作者が書いていない `nodes.**.value` を\n * 名指す `wcs/recursion-unsupported` になる(第 4 サイクルで実測)。`getStateInfo` の\n * **前**に消す。\n *\n * **依存辺。** `_state` のセッタは `_listPaths` / `_getterPaths` / `_pathSet` をクリアするが、\n * 依存表(`_staticDependency` / `_dynamicDependency`)は state の寿命を越えて残る。\n * 通常のパスはそれで正しい — 同じ綴りのパスは新しい state でも同じ意味を持つ。\n * だが**生成アクセサは違う**。新しい世代ではまだ実体化されておらず、それを指す辺だけが\n * 残ると、次の構造書き込みで依存ウォークが「アクセサの無い具体パス」へ降りて落ちる。\n * 依存表そのものをクリアしてはならない(既存バインディングの辺まで消えて、再セット後の\n * 集計が更新されなくなる — 実測済み)。この世代が作った辺だけを外す。\n *\n * **評価結果のキャッシュは忘れない。** 同じ state オブジェクト(または同じ配列)の再セットでは\n * 台帳が配列の identity をキーにしているので ListIndex も絶対アドレスも世代を跨いで同一のまま残り、\n * かつては旧世代の `dirty:false` の値がそのまま次の読みに返っていた(第 2・第 4 サイクルで実測)。\n * これは後から入った**世代印**(`cache/types.ts` の `generation`。`3bfb92a6`)が構造的に塞いでいる:\n * キャッシュを載せる 2 か所(`getByAddress` / `setByAddress`)が必ず現世代の印を付け、読みは\n * `cacheEntry.generation === stateElement.stateGeneration` の項目しかヒットにしない。この関数は\n * `runPreCommit` から呼ばれ、`_stateGeneration++` はその**直後**(`components/State.ts`)なので、\n * ここで消せる項目はどれみち必ず世代不一致で miss になる。掃き出しは `O(生成パス数 × 行数)` の\n * 純粋な無駄仕事だったので外した(番人は `integration.recursionGetter.test.ts` の再セット 4 本 —\n * 世代印を壊すとこの 4 本が落ちる)。\n */\nexport function forgetGeneration(\n stateElement: IStateElement,\n previousState: object,\n generatedPaths: ReadonlySet<string>,\n): void {\n if (generatedPaths.size === 0) {\n return;\n }\n for (const path of generatedPaths) {\n const descriptor = Object.getOwnPropertyDescriptor(previousState, path);\n if (typeof descriptor !== \"undefined\" && isGeneratedGetter(descriptor)) {\n delete (previousState as Record<string, unknown>)[path];\n }\n }\n for (const map of [stateElement.staticDependency, stateElement.dynamicDependency]) {\n for (const path of generatedPaths) {\n map.delete(path);\n }\n for (const [source, targets] of map) {\n let kept: string[] | null = null;\n for (let i = 0; i < targets.length; i++) {\n if (generatedPaths.has(targets[i])) {\n kept ??= targets.slice(0, i);\n continue;\n }\n kept?.push(targets[i]);\n }\n if (kept !== null) {\n if (kept.length === 0) {\n map.delete(source);\n } else {\n map.set(source, kept);\n }\n }\n }\n }\n}\n","/**\n * recursion/registry.ts\n *\n * state 1 つぶんの再帰レジストリ。宣言・`**` getter の定義・展開済みアクセサの台帳を\n * 持ち、「具体パスを読む直前に、その深さのアクセサを生やす」遅延実体化を担う。\n *\n * 遅延であることは実装の**不変条件**である(Phase A の A6/A7)。そのパスを一度でも\n * 読んでから生やしても、`isCacheable` が `wildcardCount > 0` だけでキャッシュ可を返す\n * ため `undefined` が `dirty:false` で固定され、以後どう書いても回復しない。\n * したがって実体化は `getByAddress` のキャッシュ参照**前**に置く(E5)。\n *\n * 寿命は state の世代と共にする。`_state` の再セットで `getterPaths` / `listPaths` は\n * クリアされるので、レジストリも作り直す(§1-3)。ただし**生やしたアクセサは state\n * オブジェクトの側に残る**ので、同じ state を再セットすると `getStateInfo` がそれを\n * `getterPaths` に復元する。そのとき「もう生えているから何もしない」と早期 return して\n * しまうと `listPaths` の登録だけが抜け落ちるため、生成物は WeakSet で見分けて\n * 登録だけをやり直す。\n */\n\nimport { IPathInfo } from \"../address/types\";\nimport { IStateElement } from \"../components/types\";\nimport { DELIMITER } from \"../define\";\nimport { getAllPropertyDescriptors } from \"../getAllPropertyDescriptors\";\nimport { recursionAnchorMismatchMessage } from \"../pathDiagnostics\";\nimport { raiseError } from \"../raiseError\";\nimport {\n concretePathAt, coversSuffix, depthOfConcretePath, foldSuffixIndexes, hasRecursionWildcard,\n indexSegmentsToWildcard, isStructuralSuffix, listPathsUpTo, sameFamily, splitRecursivePath,\n} from \"./expand\";\nimport { forgetGeneration, isGeneratedGetter, markGeneratedGetter } from \"./generation\";\nimport { IRecursionAccessor, IRecursionSpec } from \"./types\";\n\n/** 宣言時(構築時)の診断コード。lint(vscode-wcs)が同じコードで先に出す。 */\nconst DECLARATION_INVALID = \"[wcs/recursion-declaration-invalid]\";\n\n/** `**` getter 1 本ぶんの定義(本体は評価しない — descriptor だけを持つ)。 */\ninterface IRecursiveGetterDefinition {\n readonly recursivePath: string;\n readonly suffix: string;\n readonly get: () => unknown;\n}\n\nexport class RecursionRegistry {\n readonly spec: IRecursionSpec;\n private readonly _definitions: Map<string, IRecursiveGetterDefinition> = new Map();\n private readonly _accessors: Map<string, IRecursionAccessor> = new Map();\n /**\n * `recursiveGetterOwning` の記憶。キーは添字を `*` に畳んだ形(`nodes.1.total` と `nodes.2.total`\n * は 1 つ)、値は「その具体パスを展開形(またはその値の内側)として持つ `**` getter」、\n * 無ければ null。\n *\n * 有界である: キーは添字を畳んだワイルドカード形のパス文字列で、`PathInfo` が intern する集合\n * (バインディング・getter・API 引数に綴られたパスと、その展開形)の部分集合にしかならない。\n * intern 済みパスの集合が有界であることは D10 で受け入れ済みなので、ここも同じ上限に収まる。\n * 文字列は WeakSet に入らないので、寿命はレジストリ(= state の世代)と共にする。\n */\n private readonly _ownerByPath: Map<string, string | null> = new Map();\n /**\n * 書き込みのホットパス(`setByAddress`)向けの記憶。キーは intern 済みの `PathInfo` なので\n * 寿命と上限は PathInfo の intern 集合と同じ(WeakMap)。畳み(split + Number + join)は\n * miss のときだけ払う — 宣言のある state では**アンカー外を含む全書き込み**がここを通る\n * (第 4 サイクルで実測: 畳みを毎回払うと `s.counter = i` で +100ns/書き込み)。\n */\n private readonly _ownerByPathInfo: WeakMap<IPathInfo, string | null> = new WeakMap();\n /**\n * 読みのホットパス(`getByAddress`)向けの記憶。`_ownerByPathInfo` と対称で、キーは\n * intern 済みの `PathInfo`、値は「そのパスの展開アクセサ」、展開形でなければ null。\n * 宣言のある state では**アンカー外を含む全読み**(親ウォークの各段を含む)がここを\n * 通るので、文字列キーの `Map.get` + `Set.has` + `startsWith` を毎回払わせない\n * (第 5 サイクルで実測)。\n *\n * 読みの否定判定の記憶は**ここ 1 つ**(第 5 サイクル再検証で文字列キーの `_nonAccessors` を撤去 —\n * 前段にこの記憶を置いた後は、PathInfo とパス文字列が 1:1 なので二重に持つだけだった)。\n * 否定を記憶してよい根拠は、定義集合が state の世代内で不変であること — \n * 同じ `PathInfo` は同じパス文字列なので、いちど「展開形でない」と決まった PathInfo が\n * 後から実体化されることはない。実体化した側は `materializeForPathInfo` が\n * `_define` の戻り値でそのまま記憶を更新する(否定が実体化を隠さない)。\n */\n private readonly _accessorByPathInfo: WeakMap<IPathInfo, IRecursionAccessor | null> = new WeakMap();\n /** `concretePathAt` の記憶(接尾辞 → 深さ順の具体パス)。 */\n private readonly _concreteBySuffix: Map<string, string[]> = new Map();\n private readonly _registeredListPaths: Set<string> = new Set();\n\n constructor(spec: IRecursionSpec, state: object) {\n this.spec = spec;\n // getter 本体は実行しない。descriptor だけを見て `**` を含むキーを拾う。\n const descriptors = getAllPropertyDescriptors(state);\n for (const [key, descriptor] of Object.entries(descriptors)) {\n if (!hasRecursionWildcard(key)) {\n continue;\n }\n if (typeof descriptor.set === \"function\") {\n raiseError(\n `${DECLARATION_INVALID} Recursive setters are not supported in this version: \"${key}\". ` +\n `Declare a plain path setter, or write through the concrete path.`\n );\n }\n if (typeof descriptor.get !== \"function\") {\n raiseError(\n `${DECLARATION_INVALID} \"${key}\" contains \"**\" but is not a getter. ` +\n `The recursion wildcard only names a family of computed paths.`\n );\n }\n const suffix = splitRecursivePath(spec, key);\n if (suffix === null) {\n raiseError(recursionAnchorMismatchMessage(key, spec.recursiveAnchor));\n }\n if (suffix.length === 0) {\n // `get \"nodes.**\"` は展開すると `nodes.*` そのもの。`getByAddress` は\n // 「パスが target にあるか」を先に見るので、実データの行が丸ごと隠れる。\n raiseError(\n `${DECLARATION_INVALID} \"${key}\" names the recursive node itself. \"**\" names a computed path ` +\n `under a node (for example \"${spec.recursiveAnchor}${DELIMITER}total\"), not the node.`\n );\n }\n // 構造の判定は添字綴り(`get \"nodes.**.children.0\"()`)も畳んでから掛ける(書き側と同じ)\n if (isStructuralSuffix(spec, foldSuffixIndexes(suffix))) {\n // `get \"nodes.**.children\"` / `.children.*` / `.children.length` / 多段なら `.branch` は\n // 展開すると実データの子リスト(子ノード・その length・途中のオブジェクト)そのもの。\n // 生成 getter が `getByAddress` の「パスが target にあるか」で勝ち、実データの木を\n // 深さ 1 以下ごと無言で影にする(第 2 サイクルのレビューで実測: `$getAll(\"nodes.**.value\", [])`\n // が `[1, 2]` に縮んだ)。書き側が同じ形を `recursion-structural-write` で拒否するのと対称。\n raiseError(\n `${DECLARATION_INVALID} \"${key}\" names the recursion structure itself (a node, its ` +\n `\"${spec.repeatList}\" list or that list's length, or an ` +\n `object on the way to that list). A recursive getter would hide the real child list at every ` +\n `depth — \"**\" names a computed leaf under a node (for example \"${spec.recursiveAnchor}${DELIMITER}total\").`\n );\n }\n this._definitions.set(key, {\n recursivePath: key,\n suffix,\n get: descriptor.get as () => unknown,\n });\n }\n this._assertNoColliding();\n this._assertNoConcreteCollision(descriptors);\n }\n\n /**\n * 作者が手で書いた具体パス(`get \"nodes.*.children.*.total\"()` / データプロパティ)が、宣言済み\n * `**` getter の展開形と同名でないことを**構築時に**確かめる。\n *\n * `_define` の衝突検査は「その深さを最初に読んだとき」にしか走らないので、データが浅い間は\n * 通り、木が 1 段深くなった瞬間にバインディングが落ちていた(第 3 サイクルのレビューで実測)。\n * 前世代の生成物(own に残った生成 getter)は衝突ではない — 同じ state の再セットで必ず居る。\n */\n private _assertNoConcreteCollision(descriptors: Record<string, PropertyDescriptor>): void {\n for (const [key, descriptor] of Object.entries(descriptors)) {\n if (hasRecursionWildcard(key) || isGeneratedGetter(descriptor)) {\n continue;\n }\n const owner = this._matchExpansion(key);\n if (owner !== null) {\n raiseError(\n `${DECLARATION_INVALID} \"${key}\" is already defined on the state, so the recursive getter ` +\n `\"${owner}\" cannot expand to it. Rename one of them.`\n );\n }\n }\n }\n\n /**\n * 2 本の `**` getter が同じ具体パスへ展開しないことを、宣言だけから静的に確かめる。\n *\n * 衝突するのは「片方の接尾辞がもう片方の接尾辞の末尾で、差分が反復語の整数倍」の\n * ときだけ(`nodes.**.total` と `nodes.**.children.*.total` は深さ k と k+1 で\n * 同じ `nodes.*.children.*.total` になる)。検出しないと `_definitions` の挿入順で\n * 最初に一致した方が無言で勝つ。\n */\n private _assertNoColliding(): void {\n const definitions = Array.from(this._definitions.values());\n for (let i = 0; i < definitions.length; i++) {\n for (let j = i + 1; j < definitions.length; j++) {\n if (sameFamily(this.spec, definitions[i].suffix, definitions[j].suffix)) {\n raiseError(\n `${DECLARATION_INVALID} \"${definitions[i].recursivePath}\" and \"${definitions[j].recursivePath}\" ` +\n `expand to the same concrete path at different depths (they differ by whole repetitions of ` +\n `\"${this.spec.repeat}\"). Rename one of them.`\n );\n }\n }\n }\n }\n\n /**\n * `**` getter を 1 本でも宣言しているか。\n * **テスト・診断専用**(ランタイムの経路は `_definitions.size` を直接見る)。\n */\n get hasDefinitions(): boolean {\n return this._definitions.size > 0;\n }\n /**\n * その接尾辞が宣言済みの `**` getter と衝突するなら、その getter のパスを返す。\n *\n * 完全一致だけでは足りない。①反復語の整数倍だけ違う接尾辞は同じ族を指す\n * (`_assertNoColliding` が宣言どうしについて既に見ている条件)②getter の**下**を\n * 指す形(`nodes.**.total.x` / 反復語ぶんずれた `nodes.**.children.*.total.x`)は、\n * getter が返したオブジェクトへ書いてキャッシュを汚し、次の無効化で無言に戻る。\n * どちらも書き込みの入口(列挙より前)で止める — 述語は expand.ts の `coversSuffix`。\n */\n conflictingRecursiveGetter(suffix: string): string | null {\n for (const definition of this._definitions.values()) {\n if (coversSuffix(this.spec, definition.suffix, suffix)) {\n return definition.recursivePath;\n }\n }\n return null;\n }\n\n /**\n * `recursiveGetterOwning` の intern 済み `PathInfo` 版(書き込みのホットパス用)。\n * WeakMap の hit なら畳みも照合も払わない。\n */\n recursiveGetterOwningPath(pathInfo: IPathInfo): string | null {\n const known = this._ownerByPathInfo.get(pathInfo);\n if (typeof known !== \"undefined\") {\n return known;\n }\n const owner = this.recursiveGetterOwning(pathInfo.path);\n this._ownerByPathInfo.set(pathInfo, owner);\n return owner;\n }\n\n /**\n * 具体パスを展開形(またはその値の内側)として持つ `**` getter のパス。無ければ null。\n * **実体化はしない。**\n *\n * `conflictingRecursiveGetter` の**具体パス版**で、`**` を経ない 2 つの入口が使う:\n *\n * - バインド確立時のパス存在検査(`checkDeclaredPath`)。あの時点ではまだ生えて\n * いないので、素の存在検査では必ず「解決できない」になる。展開形そのもの\n * (`nodes.*.total`)だけでなく、その値の中を指す形(`nodes.*.stats.count` で\n * `get \"nodes.**.stats\"()` がオブジェクトを返す)も、通常の getter の下と同じく\n * 評価しないと分からないので黙る側に倒す。\n * - 書き込みの入口(`setByAddress`)。`$setAll(\"nodes.*.children.*.total\", [], v)` や\n * `this[\"nodes.1.total\"] = v` は `**` を含まないので `setAllRecursive` の\n * 読み取り専用検査を通らず、未実体化なら fast path が行オブジェクトへ素の\n * プロパティとして書いてしまう(ノードを汚し、代入値が `dirty:false` で載って\n * 以後 getter が評価されない)。展開形への書き込みは、実体化の前後に関わらず\n * `wcs/recursion-readonly` で止める。\n */\n recursiveGetterOwning(concretePath: string): string | null {\n const accessor = this._accessors.get(concretePath);\n if (typeof accessor !== \"undefined\") {\n return accessor.recursivePath;\n }\n // 添字綴り(`$setAll(\"nodes.1.total\", [], v)` — API のパス引数は set トラップと違って\n // getResolvedAddress の正規化を経ない)は、添字を `*` に畳んでから照合する。畳まないと\n // `nodes[1].total` へ素の値が書かれる(第 3 回レビューで実測)。**無条件に**畳む —\n // 「アンカーで始まらないときだけ」にすると、ワイルドカードと添字の混在綴り\n // (`nodes.*.children.0.total`)がアンカーで始まるせいで畳まれず、`depthOfConcretePath` が\n // `.children.0` を反復単位と認めずに素通りする(第 4 回レビューで実測)。\n // 記憶のキーは畳んだ形 — 添字綴りのまま記憶すると綴りの数だけ単調に増える。\n const pattern = indexSegmentsToWildcard(concretePath);\n const known = this._ownerByPath.get(pattern);\n if (typeof known !== \"undefined\") {\n return known;\n }\n let owner: string | null = null;\n if (pattern.startsWith(this.spec.anchor)) {\n // 展開形そのもの → その値の内側(`.` 境界で切った接頭辞を長い方から)の順に照合する。\n // 接頭辞はアンカーより長いものだけ — アンカー自身は接尾辞が空なので getter になり得ない。\n owner = this._matchExpansion(pattern);\n for (let end = pattern.lastIndexOf(DELIMITER);\n owner === null && end > this.spec.anchor.length;\n end = pattern.lastIndexOf(DELIMITER, end - 1)) {\n owner = this._matchExpansion(pattern.slice(0, end));\n }\n }\n // 定義集合は state の世代内で不変なので、判定は記憶してよい(アンカー外の否定も含む)。\n this._ownerByPath.set(pattern, owner);\n return owner;\n }\n\n /** 具体パスが宣言済み `**` getter の展開形そのものなら、その getter のパス。 */\n private _matchExpansion(concretePath: string): string | null {\n for (const definition of this._definitions.values()) {\n if (depthOfConcretePath(this.spec, definition.suffix, concretePath) !== null) {\n return definition.recursivePath;\n }\n }\n return null;\n }\n\n /**\n * `materializeFor` の `PathInfo` 版。**読みのホットパス(`getByAddress`)専用**で、\n * 判定そのものは `materializeFor` に委ね、結果(否定を含む)を PathInfo に記憶する。\n * 書き側の `recursiveGetterOwningPath` と対称。\n */\n materializeForPathInfo(stateElement: IStateElement, pathInfo: IPathInfo): IRecursionAccessor | null {\n // `**` getter の無い宣言(レジストリは空)は、記憶を作らずに抜ける\n if (this._definitions.size === 0) {\n return null;\n }\n const known = this._accessorByPathInfo.get(pathInfo);\n if (typeof known !== \"undefined\") {\n return known;\n }\n const accessor = this.materializeFor(stateElement, pathInfo.path);\n this._accessorByPathInfo.set(pathInfo, accessor);\n return accessor;\n }\n\n /**\n * 具体パスが再帰 getter の展開形なら、そのアクセサを(未登録なら生やして)返す。\n * 該当しなければ null。読みは `materializeForPathInfo` を通るので、ここへ来るのは\n * 記憶が外れたときだけ — 判定は接頭辞 1 回で抜け、ここでは否定を記憶しない(記憶は\n * `materializeForPathInfo` の PathInfo キーの 1 か所)。\n * (`**` getter の無い空レジストリを弾くのは呼び出し側の役目。)\n */\n materializeFor(stateElement: IStateElement, concretePath: string): IRecursionAccessor | null {\n const known = this._accessors.get(concretePath);\n if (typeof known !== \"undefined\") {\n return known;\n }\n if (!concretePath.startsWith(this.spec.anchor)) {\n return null;\n }\n let matched: IRecursiveGetterDefinition | null = null;\n let matchedDepth = 0;\n for (const definition of this._definitions.values()) {\n const depth = depthOfConcretePath(this.spec, definition.suffix, concretePath);\n if (depth === null) {\n continue;\n }\n if (matched !== null) {\n // コンストラクタの静的検査で弾いているはずの形。保険として先着を無言で採らない。\n raiseError(\n `\"${concretePath}\" matches both \"${matched.recursivePath}\" and \"${definition.recursivePath}\".`\n );\n }\n matched = definition;\n matchedDepth = depth;\n }\n if (matched === null) {\n return null;\n }\n return this._define(stateElement, matched, matchedDepth, concretePath);\n }\n\n private _define(\n stateElement: IStateElement,\n definition: IRecursiveGetterDefinition,\n depth: number,\n concretePath: string,\n ): IRecursionAccessor {\n // 作者が同じ具体パスを手で定義していないか。**プロトタイプチェーンまで**見る —\n // class 構文の getter は own ではなく prototype に載る(`getStateInfo` が\n // `getterPaths` に拾うのと同じ範囲)。own しか見ないと、生成アクセサが own に\n // 定義されて作者の getter を無言で影にする。前世代の生成物(own・WeakSet に載る\n // get)だけは上書きしてよい。\n const existing = stateElement.findStateDescriptor(concretePath);\n if (typeof existing !== \"undefined\" && !isGeneratedGetter(existing)) {\n raiseError(\n `\"${concretePath}\" is already defined on the state, so the recursive getter ` +\n `\"${definition.recursivePath}\" cannot expand to it. Rename one of them.`\n );\n }\n const accessor: IRecursionAccessor = Object.freeze({\n recursivePath: definition.recursivePath,\n depth,\n });\n const body = definition.get;\n const generated = function (this: unknown): unknown {\n return body.call(this);\n };\n markGeneratedGetter(generated);\n // 前世代の生成物が残っていても、登録(getterPaths / setPathInfo / listPaths)は\n // この世代でやり直す必要があるので、descriptor ごと定義し直す。\n stateElement.defineTreeAccessor(concretePath, {\n get: generated,\n enumerable: false,\n configurable: true,\n });\n this._registerListPaths(stateElement, depth);\n this._accessors.set(concretePath, accessor);\n return accessor;\n }\n\n /**\n * 経路上のリストパスを `listPaths` に載せる(E4)。`setPathInfo(path, \"for\")` は\n * 使えない — あちらは `elementPaths` にも入れて `setByAddress` の swap 経路\n * (`isSwappable`)を変えてしまう。ここで要るのは「依存ウォークがこのパスを\n * リストとして展開する」ことだけ。\n */\n private _registerListPaths(stateElement: IStateElement, depth: number): void {\n for (const listPath of listPathsUpTo(this.spec, depth)) {\n if (this._registeredListPaths.has(listPath)) {\n continue;\n }\n this._registeredListPaths.add(listPath);\n stateElement.addListPath(listPath);\n }\n }\n\n /**\n * この世代が生やしたもの(own の生成アクセサ・依存辺・キャッシュ)を忘れる(state の\n * 再セット時、`getStateInfo` の再収集より**前**に呼ぶ)。実体は generation.ts。\n */\n forgetGenerated(stateElement: IStateElement, previousState: object): ReadonlySet<string> {\n const generatedPaths: ReadonlySet<string> = new Set(this._accessors.keys());\n forgetGeneration(stateElement, previousState, generatedPaths);\n // 忘れた具体パスを返す。`_state` のセッタは経路情報を作り直すときにこれを除く —\n // この世代ではまだ実体化されていないので、辺だけ張り直してはならない。\n return generatedPaths;\n }\n\n /**\n * `**` 接尾辞の深さ `depth` の具体パス(`concretePathAt` の記憶付き版)。\n * 束縛形の読み(`this[\"nodes.**.value\"]` / 省略形 `$getAll`)は再帰 getter の評価ごとに\n * ここを通るので、深さぶんの文字列連結とワイルドカード数えを毎回やり直さない。\n * 上限は「接尾辞の種類 × 128」で有界(上限超過は `concretePathAt` が throw するので載らない)。\n */\n concretePathAt(suffix: string, depth: number): string {\n let byDepth = this._concreteBySuffix.get(suffix);\n if (typeof byDepth === \"undefined\") {\n byDepth = [];\n this._concreteBySuffix.set(suffix, byDepth);\n }\n let path = byDepth[depth];\n if (typeof path === \"undefined\") {\n path = concretePathAt(this.spec, suffix, depth);\n byDepth[depth] = path;\n }\n return path;\n }\n\n /** 展開済みアクセサのメタデータ(深さ解決・診断・テスト用)。 */\n accessorFor(concretePath: string): IRecursionAccessor | null {\n return this._accessors.get(concretePath) ?? null;\n }\n\n /**\n * これまでに実体化した具体パスの一覧。**テスト専用**(「読んだ深さだけが生える」という\n * 遅延実体化の不変条件を外から確かめる口。ランタイムはどの経路からも呼ばない)。\n */\n get materializedPaths(): ReadonlySet<string> {\n return new Set(this._accessors.keys());\n }\n}\n\n","/**\n * recursion/declarations.ts — `$recursion` の宣言(設計案 H4、S4)。\n *\n * 文脈袋の作り手でもある: 構築したレジストリを袋に置き、`$scan` の検証がそれを読む\n * (`**` getter の展開形を `from` に書いた形を落とすため — D5)。core は「ある宣言が別の宣言に\n * 値を渡す」ことを知らなくてよくなった。\n *\n * 段の位置は従来の `_state` セッターのまま:\n * validateEarly core 自身のトークン / `$listKeys` の解析より前(`value` しか読まない)\n * preCommit 旧世代の生成アクセサ・依存辺・キャッシュを忘れてから差し替える。世代を進める前\n * apply アンカーのリストパスの登録(`_listPaths` のクリアより後)\n */\nimport type { IState } from \"../types\";\nimport { IDeclarationHooks, registerDeclarationHooks } from \"../core/declarationHooks\";\nimport { STATE_RECURSION_NAME } from \"../define\";\nimport { installRecursionHooks } from \"./addressHooks\";\nimport { processRecursionDeclaration } from \"./declaration\";\nimport { RecursionRegistry } from \"./registry\";\nimport type { IRecursionSpec } from \"./types\";\n\nconst SPEC = \"recursionSpec\";\nconst REGISTRY = \"recursionRegistry\";\n\nexport const recursionDeclarationHooks: IDeclarationHooks = {\n // scan(8)より先に走り、袋にレジストリを置く\n order: 5,\n validateEarly(_element, value, ctx) {\n const spec = processRecursionDeclaration(value);\n ctx.set(SPEC, spec);\n ctx.set(REGISTRY, spec === null ? null : new RecursionRegistry(spec, value));\n },\n preCommit(element, _value, ctx) {\n // 旧世代の生成アクセサ(own)・それを指す依存辺・評価結果のキャッシュを忘れてから\n // 差し替える(recursion/generation.ts)。own の生成アクセサは、同じオブジェクトを再セットする\n // ときに `getStateInfo` が `getterPaths` へ拾い直す前に消えていなければならない。\n // 前世代の再帰レジストリが生やした具体パスは要素の除外集合に積む。経路情報の作り直し\n // (`_rebuildPathInfo`)はそこを除く — 新しい世代ではまだ実体化されていないため。\n const previous = element.recursionRegistry;\n if (previous !== null) {\n for (const path of previous.forgetGenerated(element, ctx.get<IState>(\"previousState\") as IState)) {\n element.addGeneratedPath?.(path);\n }\n }\n const registry = ctx.get<RecursionRegistry | null>(REGISTRY) ?? null;\n element.setRecursionRegistry?.(registry);\n if (registry !== null) {\n // `$recursion` を宣言した state にだけ再帰の hook(`**` の束縛・再帰 getter の書き込み禁止)を付ける\n element.attachAddressHooks?.(\"recursion\", STATE_RECURSION_NAME);\n }\n },\n apply(element, _value, ctx) {\n const spec = ctx.get<IRecursionSpec | null>(SPEC) ?? null;\n if (spec === null) {\n return;\n }\n // アンカーのリストパス(`nodes.*` なら `nodes`)は**宣言から静的に分かる**ので、\n // 展開を待たずに今すぐ登録する。\n //\n // これが無いと、再帰パスを一度読んだ後の再セットで構造書き込みが恒久的に落ちる。\n // 生成アクセサの `setPathInfo` が張った静的辺(`nodes` → `nodes.*`)は依存グラフに\n // 残るのに、`_listPaths` はセッターでクリアされ、次に再帰パスを読むまで張り直されない。\n // その隙間に構造書き込みが来ると `walkDependency` が「リストではないパス」として\n // `nodes.*` に到達し、listIndex を持たないアドレスで `Cannot expand dynamic dependency…`\n // になる(値は書かれるので、データと表示が乖離したまま自己回復しない)。\n element.addListPath(spec.anchorList);\n },\n};\n\nlet installed = false;\n/** 冪等。full / auto では `bootstrapState()` が呼ぶ */\nexport function installRecursionDeclarations(): void {\n if (installed) return;\n installed = true;\n installRecursionHooks();\n registerDeclarationHooks(\"recursion\", recursionDeclarationHooks);\n}\n","/**\n * features/recursion.ts — `$recursion` と `**`(@wcstack/state/features/recursion)。\n */\nimport type { IStateFeature } from \"../core/features\";\nimport { installRecursionDeclarations } from \"../recursion/declarations\";\n\nexport const recursion: IStateFeature = {\n name: \"recursion\",\n install(): void {\n installRecursionDeclarations();\n },\n};\nexport default recursion;\n"],"names":["hasRecursionWildcard","path","indexOf","RECURSION_WILDCARD","splitRecursivePath","spec","recursiveAnchor","prefix","DELIMITER","startsWith","suffix","slice","length","segments","split","WILDCARD","some","segment","foldSuffixIndexes","indexSegmentsToWildcard","sameFamily","a","b","unit","repeat","shorter","longer","endsWith","gap","cursor","coversSuffix","familySuffix","end","lastIndexOf","i","Number","isNaN","join","isStructuralSuffix","repeatSegments","rest","repeatList","concretePathAt","depth","raiseError","anchor","full","wildcardCount","MAX_WILDCARD_DEPTH","nodePathAt","depthOfConcretePath","middle","currentRecursionDepth","handler","registry","addressStackLength","address","lastAddressStack","accessor","accessorFor","pathInfo","charCodeAt","depthOfConcretePathPrefix","bindRecursivePath","stateElement","recursionRegistry","recursionAnchorMismatchMessage","collectRecursiveAddresses","target","receiver","results","observed","Map","pathsByDepth","anchorList","ancestors","Set","visited","expandSuffix","concretePathInfo","level","listIndex","parents","wildcardParentPathInfos","push","createStateAddress","rows","readRows","listPathInfo","parentListIndex","seen","listAddress","absAddress","liftAddress","value","getByAddress","tracked","listPath","Array","isArray","list","has","guardShape","listDiff","createListDiff","getStateListBaseline","set","add","newIndexes","descend","paths","known","concretePath","nodePath","getPathInfo","childListPathInfo","pathsAt","branch","flat","row","delete","setStateListBaseline","setAllRecursive","indexes","options","assertWritable","checkedSuffix","setAllValueKindMessage","spread","assertNotStructural","conflicting","conflictingRecursiveGetter","addresses","written","setByAddress","recursionAddressHooks","write","hasRecursion","NOT_HANDLED","owner","recursiveGetterOwningPath","get","prop","values","getAllRecursive","getAll","setAll","resolvedAddress","getResolvedAddress","getListIndex","installed","assertNodePath","kind","STATE_RECURSION_NAME","generatedGetters","WeakSet","isGeneratedGetter","descriptor","DECLARATION_INVALID","RecursionRegistry","_definitions","_accessors","_ownerByPath","_ownerByPathInfo","WeakMap","_accessorByPathInfo","_concreteBySuffix","_registeredListPaths","constructor","state","this","descriptors","getAllPropertyDescriptors","key","Object","entries","recursivePath","_assertNoColliding","_assertNoConcreteCollision","_matchExpansion","definitions","from","j","hasDefinitions","size","definition","recursiveGetterOwning","pattern","materializeForPathInfo","materializeFor","matched","matchedDepth","_define","existing","findStateDescriptor","freeze","body","generated","call","getter","defineTreeAccessor","enumerable","configurable","_registerListPaths","k","listPathsUpTo","addListPath","forgetGenerated","previousState","generatedPaths","keys","getOwnPropertyDescriptor","map","staticDependency","dynamicDependency","source","targets","kept","forgetGeneration","byDepth","materializedPaths","SPEC","REGISTRY","recursionDeclarationHooks","order","validateEarly","_element","ctx","declared","processRecursionDeclaration","preCommit","element","_value","previous","addGeneratedPath","setRecursionRegistry","attachAddressHooks","apply","installRecursionDeclarations","registerFeatureHooks","registerDeclarationHooks","recursion","name","install"],"mappings":"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"}
|