@wcstack/state 3.5.4 → 4.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +669 -428
- package/README.md +667 -426
- package/dist/auto.min.js +1 -2
- package/dist/define.d.ts +4 -8
- package/dist/define.js +1 -1
- package/dist/index.d.ts +139 -1483
- package/dist/index.esm.js +1 -2
- package/dist/manifest.d.ts +18 -59
- package/dist/manifest.esm.js +542 -1202
- package/dist/parser.d.ts +49 -103
- package/dist/parser.esm.js +662 -831
- package/dist/split/auto.js +1 -0
- package/dist/split/chunks/chunk-732CB4QN.js +1 -0
- package/dist/split/chunks/chunk-7PN5YNZZ.js +1 -0
- package/dist/split/chunks/chunk-FF6KHTYS.js +1 -0
- package/dist/split/chunks/chunk-HFKGUDDJ.js +1 -0
- package/dist/split/chunks/chunk-PKDBVBAP.js +1 -0
- package/dist/split/chunks/chunk-QI7P7YPP.js +1 -0
- package/dist/split/chunks/chunk-QQH6N5CJ.js +1 -0
- package/dist/split/chunks/chunk-UM3O6QXD.js +1 -0
- package/dist/split/chunks/chunk-WTD5TVPZ.js +1 -0
- package/dist/split/chunks/chunk-WWJNAZVP.js +1 -0
- package/dist/split/chunks/chunk-YOPPVWPQ.js +1 -0
- package/dist/split/core.d.ts +114 -1168
- package/dist/split/core.js +1 -2
- package/dist/split/features/devtools.d.ts +23 -3
- package/dist/split/features/devtools.js +1 -2
- package/dist/split/features/diagnostics.d.ts +27 -5
- package/dist/split/features/diagnostics.js +1 -2
- package/dist/split/features/formats.d.ts +21 -5
- package/dist/split/features/formats.js +1 -2
- package/dist/split/features/list-keys.d.ts +24 -0
- package/dist/split/features/list-keys.js +1 -0
- package/dist/split/features/recursion.d.ts +23 -3
- package/dist/split/features/recursion.js +1 -2
- package/dist/split/features/scopes.d.ts +25 -4
- package/dist/split/features/scopes.js +1 -2
- package/dist/split/features/ssr.d.ts +23 -3
- package/dist/split/features/ssr.js +1 -2
- package/dist/split/features/temporal.d.ts +19 -4
- package/dist/split/features/temporal.js +1 -2
- package/dist/wcs-manifest.json +43 -49
- package/package.json +15 -17
- package/dist/auto.min.js.map +0 -1
- package/dist/index.esm.js.map +0 -1
- package/dist/split/chunks/binder.js +0 -2
- package/dist/split/chunks/binder.js.map +0 -1
- package/dist/split/chunks/checkDependency.js +0 -2
- package/dist/split/chunks/checkDependency.js.map +0 -1
- package/dist/split/chunks/declarationAliases.js +0 -2
- package/dist/split/chunks/declarationAliases.js.map +0 -1
- package/dist/split/chunks/declarationHooks.js +0 -2
- package/dist/split/chunks/declarationHooks.js.map +0 -1
- package/dist/split/chunks/diagnosticsHooks.js +0 -2
- package/dist/split/chunks/diagnosticsHooks.js.map +0 -1
- package/dist/split/chunks/errorGuidance.js +0 -2
- package/dist/split/chunks/errorGuidance.js.map +0 -1
- package/dist/split/chunks/featureBridge.js +0 -2
- package/dist/split/chunks/featureBridge.js.map +0 -1
- package/dist/split/chunks/features.d.ts +0 -29
- package/dist/split/chunks/filterRegistry.js +0 -2
- package/dist/split/chunks/filterRegistry.js.map +0 -1
- package/dist/split/chunks/getAllPropertyDescriptors.js +0 -2
- package/dist/split/chunks/getAllPropertyDescriptors.js.map +0 -1
- package/dist/split/chunks/lifecycleHooks.js +0 -2
- package/dist/split/chunks/lifecycleHooks.js.map +0 -1
- package/dist/split/chunks/pathDiagnostics.js +0 -2
- package/dist/split/chunks/pathDiagnostics.js.map +0 -1
- package/dist/split/chunks/registerComponents.js +0 -2
- package/dist/split/chunks/registerComponents.js.map +0 -1
- package/dist/split/chunks/setAll.js +0 -2
- package/dist/split/chunks/setAll.js.map +0 -1
- package/dist/split/chunks/version.js +0 -2
- package/dist/split/chunks/version.js.map +0 -1
- package/dist/split/core.js.map +0 -1
- package/dist/split/features/devtools.js.map +0 -1
- package/dist/split/features/diagnostics.js.map +0 -1
- package/dist/split/features/formats.js.map +0 -1
- package/dist/split/features/recursion.js.map +0 -1
- package/dist/split/features/scopes.js.map +0 -1
- package/dist/split/features/ssr.js.map +0 -1
- package/dist/split/features/temporal.js.map +0 -1
package/dist/split/core.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
import{
|
|
2
|
-
//# sourceMappingURL=core.js.map
|
|
1
|
+
import{a as s}from"./chunks/chunk-WTD5TVPZ.js";import{a as n,d as t,e as u}from"./chunks/chunk-FF6KHTYS.js";import"./chunks/chunk-PKDBVBAP.js";import"./chunks/chunk-7PN5YNZZ.js";import"./chunks/chunk-HFKGUDDJ.js";import{g as a,h as c,i as h}from"./chunks/chunk-UM3O6QXD.js";import{c as i}from"./chunks/chunk-732CB4QN.js";import"./chunks/chunk-QI7P7YPP.js";import"./chunks/chunk-QQH6N5CJ.js";import"./chunks/chunk-WWJNAZVP.js";import{g as o}from"./chunks/chunk-YOPPVWPQ.js";function r(s){return s}export{a as TRUSTED_TYPES_POLICY_SLOT,s as VERSION,t as bootstrapState,u as buildBindings,r as defineState,n as getBindingsReady,i as getConfig,c as getTrustedTypesPolicy,o as installFeatures,h as setTrustedTypesPolicy};
|
|
@@ -1,9 +1,29 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The places the core calls into add-ons (docs/state-engine-rewrite/addons-plan.ja.md §1.2).
|
|
3
|
+
*
|
|
4
|
+
* Add-ons ship as separate entries of the same build as the core (`features/*`): they reach
|
|
5
|
+
* the core's internals directly, and the core only calls out through these slots. A slot is
|
|
6
|
+
* empty until an installed feature fills it (the object starts with none: a list of null slots
|
|
7
|
+
* would be the core's bytes), so a page without the feature pays one `?.` check. A feature
|
|
8
|
+
* restoring a slot may set it to null.
|
|
9
|
+
* Slots are added with the first feature that needs them; several features share one through
|
|
10
|
+
* chain / first. The slots `element` and `detail` keep their names (a DevTools-facing field and a DOM
|
|
11
|
+
* name share them); the others are shortened by the build. An empty slot is read through
|
|
12
|
+
* Object.prototype: a page that polluted it (a value under `element`, say) breaks the core loudly
|
|
13
|
+
* there, as it does wherever the core reads a plain object's keys (`$behavior`); not defended.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** An add-on entry: `installFeatures([temporal, diagnostics])` before the state is defined. */
|
|
17
|
+
interface Feature {
|
|
18
|
+
readonly name: string;
|
|
19
|
+
install(): void;
|
|
20
|
+
}
|
|
2
21
|
|
|
3
22
|
/**
|
|
4
|
-
*
|
|
23
|
+
* The DevTools add-on (@wcstack/state/features/devtools): `@wcstack/devtools` over the hook
|
|
24
|
+
* protocol v2 — see src/devtools/devtools.ts.
|
|
5
25
|
*/
|
|
6
26
|
|
|
7
|
-
declare const devtools:
|
|
27
|
+
declare const devtools: Feature;
|
|
8
28
|
|
|
9
29
|
export { devtools as default, devtools };
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
import{
|
|
2
|
-
//# sourceMappingURL=devtools.js.map
|
|
1
|
+
import{a as e}from"../chunks/chunk-WTD5TVPZ.js";import{c as t,d as n,e as l,f as o,g as s,h as r,i as a,n as i}from"../chunks/chunk-7PN5YNZZ.js";import"../chunks/chunk-HFKGUDDJ.js";import"../chunks/chunk-UM3O6QXD.js";import"../chunks/chunk-732CB4QN.js";import"../chunks/chunk-QI7P7YPP.js";import"../chunks/chunk-QQH6N5CJ.js";import"../chunks/chunk-WWJNAZVP.js";import{a as u,b as d}from"../chunks/chunk-YOPPVWPQ.js";var f="__WCSTACK_DEVTOOLS_HOOK__",c=null,m=new Set,p=(e,t,n)=>({absolutePathInfo:{pathInfo:{path:t.t},stateElement:e.element},listIndex:null===n?null:{indexes:e.D(n)}}),h=new WeakMap,k=0;var v=new WeakMap;function g(e){if(null===c)return;let i=v.get(e),u=m.has(e)?function(e,i){let u=new Map,d=new Set,f=(r,a,d,f,c,m)=>{if(r===s)return;let v=function(e,s){return e===t?"textContent":e===n?`class.${s}`:e===l?`attr.${s}`:e===o?`style.${s}`:s}(r,a),g=0===f.n?null:c,w=`${(e=>{let t=h.get(e);return void 0===t&&h.set(e,t=++k),t})(d)}|${v}|${f.t}|${null===g?"":e.D(g).join(",")}`;if(u.has(w))return;let y=i?.get(w);u.set(w,y??{binding:{propName:v,statePathName:f.t,bindingType:m,node:d,replaceNode:d},absoluteAddress:p(e,f,g)})},c=e=>f(e.i,e.name,e.a,e.o,e.r,e.Zt()),m=e=>{if(!d.has(e)){if(d.add(e),null!==e.de)for(let t of e.de)c(t);if(e instanceof r&&null!==e.se){let n=e.T.Ke;for(let l=0;l<n.length;l++){let o=e.K?.[l];void 0!==o?c(o):f(n[l].i,n[l].name,e.se[2*l],n[l].o,e.r,n[l].i===t?"text":"prop")}}if(null!==e.u)for(let t of e.u)v(t)}},v=e=>{if(!d.has(e))if(d.add(e),e instanceof a){f(-1,"for",e.S,e.s.o,e.s.te,"for");for(let t of e.ve)m(t)}else null!==e.F&&m(e.F)};for(let t of e.re.values())for(let e of t)c(e),null!==e.B&&v(e.B);for(let t of e.oe.values())if(null!==t.E&&v(t.E),null!==t.j)for(let e of t.j)v(e);return u}(e,i):new Map;if(void 0!==i)for(let[e,t]of i)u.has(e)||c({type:"state:binding-removed",...t});for(let[e,t]of u)(void 0===i||!i.has(e))&&c({type:"state:binding-added",...t});v.set(e,u)}function w(e){let t=i.get(e);if(void 0===t)throw new Error("[@wcstack/state] devtools: no state tree on this root");return t}function y(e){let t=new Set,n=new Set,l=new Set,o=new Set;for(let s of e.L.all()){for(let e=1;e<=s.n;e++)t.add(s.c[e].t);"*"===s.l&&n.add(s.t),null!==s.getter&&l.add(s.t),null!==s.Z&&o.add(s.t)}let s=e.target;return{rootNode:e.root,element:e.element,paths:{list:t,element:n,getter:l,setter:o},commandTokenNames:new Set(Object.keys(e.commands)),eventTokenNames:new Set(e.Se.keys()),staticDependency:new Map,dynamicDependency:new Map,watchPaths:null!==s.$watch&&"object"==typeof s.$watch?new Set(Object.keys(s.$watch)):null,keyedListPaths:null!==s.$listKeys&&"object"==typeof s.$listKeys?new Set(Object.keys(s.$listKeys)):null}}var S=new WeakSet,b=new WeakMap;function j(e,t){if(("mounting"===t||"reset"===t)&&function(e){let t=(t,n)=>{if(S.has(t))return;S.add(t);let l=t.emit;t.emit=(...o)=>(null!==c&&c({type:"state:token-emit",kind:n,tokenName:t.name,args:o,subscriberCount:t.size,stateElement:e.element}),l.apply(t,o))};for(let n of Object.values(e.commands))t(n,"command");for(let n of e.Se.values())t(n,"event")}(e),"connected"===t){if(m.has(e))return;m.add(e),c?.({type:"state:element-registered",rootNode:e.root,element:e.element}),g(e)}else"disconnected"===t&&(m.delete(e),g(e),c?.({type:"state:element-unregistered",rootNode:e.root,element:e.element}))}function $(e,t,n,l,o,s){if(null===c)return;let r=p(e,t,0===t.n?null:n),a=b.get(e);void 0===a&&b.set(e,a=new Set),a.add(r),s&&c({type:"state:write",absoluteAddress:r,value:o,oldValue:l,hasOldValue:!0})}function P(e){if(null===c)return;let t=b.get(e);b.delete(e),void 0!==t&&c({type:"state:update-batch",addresses:t}),g(e)}function N(e,t,n){c?.({type:"state:binding-apply-error",path:n.o.t,bindingType:n.Zt(),error:t})}var O={name:"devtools",install(){u.element=d(u.element,j),u.pe=d(u.pe,$),u.Pe=d(u.Pe,P),u._e=d(u._e,N),function(){if(typeof document>"u"||document.documentElement?.hasAttribute("data-wcs-server"))return;let t=globalThis,n=t[f]??(t[f]=function(){let e=new Map,t=new Set,n=e=>{0===t.size?e._setSink(null):e._setSink(n=>{for(let l of t)l.onEvent?.(e.id,n)})};return{version:2,sources:e,register(l){if(!e.has(l.id)){e.set(l.id,l),n(l);for(let e of t)e.onSourceRegistered?.(l)}},unregister(n){let l=e.get(n);if(void 0!==l){l._setSink(null),e.delete(n);for(let e of t)e.onSourceUnregistered?.(n)}},addListener(l){t.add(l);for(let t of e.values())n(t),l.onSourceRegistered?.(t);return()=>{if(t.delete(l))for(let t of e.values())n(t)}}}}());2!==n.version&&console.warn(`[@wcstack/state] devtools hook registry version ${n.version}, expected 2: keeping the existing one.`),n.register({id:`state:${Math.random().toString(36).slice(2,10)}`,kind:"state",packageVersion:e,getStateElements:()=>[...m].map(y),overlays:()=>[],keyedSubscriptions:e=>function(e){let t=[];for(let n of e.L.all()){let l=n.V,o=n.Fe?.length??0;if((null===l||0===l.size)&&0===o)continue;let s,r=0;if(null!==l)for(let e of l.values())r+=e.size;try{s=0===n.n?e.v(n,null):void 0}catch{s=void 0}t.push({path:n.t,tracked:!1,rows:r,keys:null===l?0:l.size,lists:o,lastValue:s})}return t}(w(e)),keys(e){let t=w(e).target;return Object.keys(t).filter(e=>{if(e.includes("*")||"$"===e[0])return!1;let n=Object.getOwnPropertyDescriptor(t,e);return void 0!==n.get||"function"!=typeof n.value})},read(e,t,n){let l;return w(e).element.createState("readonly",e=>{l=e.$resolve(t,n??[])}),l},write(e,t,n,l){w(e).element.createState("writable",e=>{e.$resolve(t,l??[],n)})},_setSink(e){let t=null===c&&null!==e;c=e,null===e&&(v=new WeakMap),u.tt=e&&((e,t)=>c?.({...t,stateElement:e.element})),t&&queueMicrotask(()=>{for(let e of m)g(e)})}})}()}},M=O;export{M as default,O as devtools};
|
|
@@ -1,11 +1,33 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The places the core calls into add-ons (docs/state-engine-rewrite/addons-plan.ja.md §1.2).
|
|
3
|
+
*
|
|
4
|
+
* Add-ons ship as separate entries of the same build as the core (`features/*`): they reach
|
|
5
|
+
* the core's internals directly, and the core only calls out through these slots. A slot is
|
|
6
|
+
* empty until an installed feature fills it (the object starts with none: a list of null slots
|
|
7
|
+
* would be the core's bytes), so a page without the feature pays one `?.` check. A feature
|
|
8
|
+
* restoring a slot may set it to null.
|
|
9
|
+
* Slots are added with the first feature that needs them; several features share one through
|
|
10
|
+
* chain / first. The slots `element` and `detail` keep their names (a DevTools-facing field and a DOM
|
|
11
|
+
* name share them); the others are shortened by the build. An empty slot is read through
|
|
12
|
+
* Object.prototype: a page that polluted it (a value under `element`, say) breaks the core loudly
|
|
13
|
+
* there, as it does wherever the core reads a plain object's keys (`$behavior`); not defended.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** An add-on entry: `installFeatures([temporal, diagnostics])` before the state is defined. */
|
|
17
|
+
interface Feature {
|
|
18
|
+
readonly name: string;
|
|
19
|
+
install(): void;
|
|
20
|
+
}
|
|
2
21
|
|
|
3
22
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
23
|
+
* The diagnostics add-on (@wcstack/state/features/diagnostics): the sentences and the self-fix
|
|
24
|
+
* guidance of error messages. The core states the code, the message number and the values
|
|
25
|
+
* (`[wcs/index-arity] #901 "$resolve" "m.*.*" 2 1`); with this installed, the message is the
|
|
26
|
+
* sentence (`[wcs/index-arity] $resolve("m.*.*") takes 2 index(es), got 1.`), followed by the
|
|
27
|
+
* nearest name (did-you-mean, the same rule as lint), how to fix it, and a pointer to lint where
|
|
28
|
+
* lint really detects the case. The full `auto` bundle installs it.
|
|
7
29
|
*/
|
|
8
30
|
|
|
9
|
-
declare const diagnostics:
|
|
31
|
+
declare const diagnostics: Feature;
|
|
10
32
|
|
|
11
33
|
export { diagnostics as default, diagnostics };
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
import{s as e}from"../chunks/diagnosticsHooks.js";import{g as t,E as n,W as s,y as i,aa as r,ab as a,ac as o,d as c,D as d}from"../chunks/pathDiagnostics.js";import{d as u,L as g}from"../chunks/errorGuidance.js";const f=Object.freeze({existence:"unknown",missingSegment:"",candidates:Object.freeze([])}),l=Object.freeze({existence:"exists",missingSegment:"",candidates:Object.freeze([])});const m=new WeakMap;const h=new WeakMap,p=new WeakSet,k=new WeakMap;function w(e,t,n,s){console.warn(`[@wcstack/state] [${a[n]}] ${o[n]} "${t}" does not resolve on the state tree: "${s.missingSegment}" is not declared.${u(s.missingSegment,s.candidates)} Updates to this path will be silently dropped.${g}`),null!==c&&c({type:"state:path-unresolved",source:n,path:t,missingSegment:s.missingSegment})}const v={check:function(e,a,o,c,u){if("internal"===c||void 0===a)return;if(o.startsWith("$"))return;if(-1!==o.indexOf("#"))return;const g=e.addressHooks;if(g){const t=g.suppressPathDiagnostic;for(let n=0;n<t.length;n++)if(t[n](e,o))return}const v=t(o).segments;if("binding"===c&&v.length<2)return;if(function(e,t){let n=m.get(e);return void 0===n&&(n=new Set,m.set(e,n)),!!n.has(t)||(n.add(t),!1)}(e,o))return;if(!0===e.hasRecursion&&null!==e.recursionRegistry.recursiveGetterOwning(o))return;const b=function(e,a,o,c){if(void 0!==n(e,a))return l;const u=t(a).segments;let g=e,m="";for(let t=0;t<u.length;t++){const a=c&&Array.isArray(g)&&+u[t]>=0?s:u[t],h=m;m=0===t?a:m+d+a;const p=t>0&&n(e,m),k=p&&i.get(p.get);if(p&&(!k||n(e,k)))return t<u.length-1?f:l;if(Object(g)!==g)return f;if(a===s){if(!Array.isArray(g)||0===g.length)return f;g=g[0];continue}const w=n(g,a);if(void 0===w)return{existence:"missing",missingSegment:a,candidates:r(g,h,o,e)};if("function"==typeof w.get)return t===u.length-1?l:f;g=w.value}return l}(a,o,e.getterPaths,u);"missing"===b.existence&&(function(e,t){return!0===k.get(e)?.has(t)}(e,o)||("binding"!==c?w(e,o,c,b):function(e,t,n){let s=h.get(e);void 0===s&&(s=new Map,h.set(e,s));if(s.set(t,n),p.has(e))return;p.add(e),setTimeout(()=>function(e){p.delete(e);const t=h.get(e);if(void 0===t)return;h.delete(e);for(const[n,s]of t)w(e,n,"binding",s)}(e),0)}(e,o,b)))},reset:function(e){m.delete(e),h.delete(e)},markExported:function(e,t){let n=k.get(e);void 0===n&&(n=new Set,k.set(e,n)),n.add(t),h.get(e)?.delete(t)}};let b=!1;const S={name:"diagnostics",install(){b||(b=!0,e(v))}};export{S as default,S as diagnostics};
|
|
2
|
-
//# sourceMappingURL=diagnostics.js.map
|
|
1
|
+
import{b as e,c as t,h as n,j as i}from"../chunks/chunk-UM3O6QXD.js";import{a,d as s,f as r}from"../chunks/chunk-732CB4QN.js";import{e as o}from"../chunks/chunk-QI7P7YPP.js";import"../chunks/chunk-QQH6N5CJ.js";import{a as l}from"../chunks/chunk-WWJNAZVP.js";import{a as d,b as c,j as f}from"../chunks/chunk-YOPPVWPQ.js";function u(e,t,n){if(Math.abs(e.length-t.length)>n)return n+1;let i=new Array(t.length+1),a=new Array(t.length+1);for(let e=0;e<=t.length;e++)i[e]=e;for(let n=1;n<=e.length;n++){a[0]=n;for(let s=1;s<=t.length;s++){let r=e[n-1]===t[s-1]?0:1;a[s]=Math.min(i[s]+1,a[s-1]+1,i[s-1]+r)}for(let e=0;e<=t.length;e++)i[e]=a[e]}return i[t.length]}function h(e,t){if(0===e.length)return"";let n=e.toLowerCase(),i=null,a=3;for(let e of t){let t=u(n,e.toLowerCase(),2);t<a&&(i=e,a=t)}return null!==i?` Did you mean "${i}"?`:""}var p=" Validate statically: npx @wcstack/lint <file>.",$=["enableMustache","sameValueGuard","enableDirectionalInitialSync"],m=(e,t)=>`<${e}${t.map((e,t)=>t%2?`="${e}"`:` ${e}`).join("")}>`,g="https://github.com/wcstack/wcstack/blob/main/docs/csp.md",w={1:()=>"$scan was removed (use $watch or $on)",2:e=>`"${e}" is a getter without a setter`,3:e=>`no row for "${e}"`,4:(e,t)=>`cannot write "${e}": its parent is ${t}`,5:e=>`"${e}" is not a method`,6:e=>`$getAll("${e}"): no loop level in common with the context`,7:e=>`$eqIndex("${e}") needs a list row scope.`,8:()=>"This state is readonly.",9:e=>`$setAll("${e}") needs indexes ([] for every match)`,10:(e,t)=>`$setAll("${e}", …, { spread: true }) needs an array of ${t} values`,11:()=>`updates did not settle after ${e} passes`,41:()=>`render chain depth limit exceeded (${t} drains that rendering itself started); bindings for this batch were not applied.`,12:(e,t)=>`binding "${e}: ${t}" failed to apply.`,13:(e,t)=>`failed to load "${e}": ${t}`,14:()=>"this <wcs-state> failed to initialize; create a new one",15:()=>"state is not initialized",16:e=>`no <script> with id "${e}"`,42:()=>`The inline <script> of <wcs-state> was blocked by Content-Security-Policy. Inline state is evaluated through a blob: URL: give the page's nonce to the <script> that loads @wcstack/state, or allow blob: in script-src. Moving the state into an external file (src="./state.js") needs neither. See ${g}`,43:e=>`Failed to evaluate the inline <script> of <wcs-state>: ${e}. If this page sets a Content-Security-Policy, see ${g}`,17:e=>`a subscriber of token "${e}" threw.`,18:e=>`${e} must be an array of strings.`,19:e=>`${e} entries must be non-empty strings.`,20:(e,t,n)=>`${e} entry "${t}" conflicts with the reserved namespace name "${n}".`,21:(e,t)=>`${e} entry "${t}" is duplicated.`,22:()=>"$on must be an object of handlers.",23:e=>`$on entry "${e}" is not declared in $eventTokens.`,24:e=>`$on entry "${e}" must be a function.`,25:e=>`view-transition naming-limit (${e}) reached.`,26:e=>`filter ${e} requires at least one option`,27:e=>`filter ${e} requires a number as option`,28:e=>`filter ${e} requires a number value`,29:e=>`filter ${e} requires a date value`,30:e=>`filter ${e} requires an array value`,31:()=>"init=/sync= modifiers require enableDirectionalInitialSync.",33:(e,t)=>`Unknown binding modifier "${e}" in "${t}".`,34:e=>`Binding modifier "${e}" may only be specified once.`,35:(e,t)=>`Invalid ${e} modifier value "${t}".`,36:()=>"Event bindings only allow init=none.",37:(e,t)=>`Binding type "${e}" does not support init=${t}.`,38:e=>`Property "${e}" is not declared by wcBindable.`,39:(e,t)=>`init=${e} is incompatible with wcBindable member "${t}".`,40:e=>`sync=connect requires observable property "${e}".`,44:(e,t)=>`${e}: "${t}" is not one of its options, or not of the option's type.${"bootstrapState"===e&&$.includes(t)?" 4.0 moved it to the state's $behavior.":""}`,45:()=>"a re-set state may not change $behavior: create the element again.",47:()=>'a second <wcs-state> on the same root: there is one state tree per root — graft a subtree with <wcs-state mount="path"> (v1\'s name="…" is gone: read the mounted state by its path).',48:e=>`the locale "${e}" (<html lang> or bootstrapState's locale) is not a language tag Intl takes (en-US, not en_US): the locale filters use "en".`,46:()=>'$features must be an array of add-on names (["temporal", "formats"]).',49:(e,...t)=>`${m(e,t)} failed to initialize.`,50:(e,...t)=>`${m(e,t)} $connectedCallback failed.`,101:e=>`Invalid bindText: "${e}". Missing ':' separator between propPart and statePart.`,102:(e,t)=>`"${e}": "${t}" takes no modifiers or filters on its left side — write "${t}:".`,103:e=>`"${e}": "else" takes no value — write "else:".`,104:e=>`Invalid spread binding "${e}": spread target path is required.`,105:e=>`Invalid spread binding "${e}": filters are not allowed on spread targets.`,106:e=>`"${e}": a leading "." binds an element property by name — write a non-empty property that is not a namespace (class, attr, style, command, eventToken, state).`,107:(e,t)=>`unterminated ${e} quote in the filter arguments "(${t})". Close the quote.`,108:e=>`Invalid filter format: missing closing parenthesis in "${e}".`,109:e=>`Invalid filter format: missing opening parenthesis in "${e}".`,110:e=>`Invalid filter format: ")" comes before "(" in "${e}".`,111:(e,t)=>`"${e}": unexpected "${t}" after the filter's closing ")" — separate filters with "|" (write "${e.slice(0,e.lastIndexOf(")")+1)}|${t}").`,112:e=>`an empty filter in "${e}" — remove the extra "|" or name the filter.`,113:(e,t)=>`"${e}" is not a filter name: a modifier list "#${t}" comes before the input filters, not inside one`,114:e=>`"${e}" is not a filter name: "#" cannot appear in one.`,115:e=>`"${e}": a binding takes one modifier list after a single "#"`,116:e=>`"${e}": the left side of a binding must name a property — write "<property>: <path>" (modifiers and input filters come after the name).`,117:(e,t)=>`"${e}" has ${t} path segments — the limit is 512.`,32:e=>`"${e}": the "@name" selector was removed in v2 — there is a single state tree. Mount the named state onto the tree (<wcs-state mount="...">) and read it by its path prefix instead.`,120:e=>`"${e}": a state path cannot go through "__proto__" or "prototype" (it would reach every object's prototype).`,121:e=>`"${e}": "for:" takes no filters — a row is "<path>.<index>", so the rows of a filtered list would name other elements. Declare a getter that returns the filtered list and loop over it ("for: <getter>").`,119:e=>`"${e}": the right side of a binding must name a state path — write "<property>: <path>" (a path segment cannot be empty; "." alone and a leading "." are the loop-relative shorthand).`,201:e=>`Invalid bindText: "${e}". 'if', 'elseif', 'else', and 'for' bindings must be single binding.`,202:e=>`"${e}:" must follow an "if:" template`,204:e=>`a "${e}:" template at the top of inserted content was not rendered, as it would render beside itself out of the inserter's reach: wrap it in an element.`,203:e=>`"${e}:" replaces its element, so it cannot be used inside a "for" / "if" template (a row or branch keeps its nodes by position): bind innerHTML: on a wrapper element instead.`,301:e=>`Path "${e}" does not exist on the state tree.`,401:(e,t)=>`class.${e} needs a boolean, got ${t}.`,501:e=>`filter not found: ${e}.`,601:(e,t,n)=>`filter "${e}" requires at least ${t} argument(s) (${n} given).`,602:(e,t,n)=>`filter "${e}" accepts at most ${t} argument(s) (${n} given).`,701:e=>`"${e}" depends on itself`,801:e=>`"${e}"`,901:(e,t,n,i)=>`${e}("${t}") takes ${n} index(es), got ${i}.`,902:(e,t,n,i)=>`${e}("${t}") takes at most ${n} index(es), got ${i}.`,1001:e=>`"${e}": list index parameters run from $1 to $128.`,1101:e=>`"${e}" uses "**", which is not accepted here.`,1201:(e,t)=>`"${e}: ${t}": the right-hand side must be $command.<name>`,1202:(e,t)=>`<${e}> declares no static wcBindable (${t}).`,1203:(e,t)=>`<${e}> declares no command "${t}".`,1204:(e,t)=>`<${e}> declares no property "${t}".`,1301:e=>`eventToken "${e}" is not declared in $eventTokens.`,1302:e=>`"$command.${e}" is not declared in $commandTokens.`,1401:(e,t,n=0)=>`"${e}" needs ${t} enclosing loop level(s); the scope provides ${n}.`,1402:e=>`"${e}" is relative: it needs an enclosing "for" template`,1403:(e,t,n)=>`"${e}" ranges over the rows of "${t}", but the enclosing "for" template at that level renders "${n}".`,1501:(e,t)=>`<${e}> declares no static wcBindable (${t}).`,1601:(e,t)=>`${e} was removed: write ${t}.`,1701:(e,t)=>`${e} was removed: write ${t}.`};function b(e,t){let n=w[e];return void 0===n?`${l(e)}#${e} ${t.join(" ")}`:l(e)+n(...t)}var y=new Set(["binding-syntax","template-syntax","filter-unknown","filter-arity","index-arity","wildcard-rank","token-undeclared","binding-path-missing","index-param-range"]),v=[[/no loop level in common with the context/,"; pass indexes ([] for all)."],[/"([^"#]+)#([^"]*)" is not a filter name: a modifier list .* comes before the input filters/,' — write "<property>#$2|$1".'],[/\[wcs\/recursion-unsupported\]/," It is only meaningful in a $recursion declaration, in a recursive getter key, and in the path argument of $getAll / $setAll — and only when the state declares a $recursion anchor."],[/must be single binding/,' Put the structural binding alone in its own data-wcs (e.g. <template data-wcs="for: items">).'],[/\[wcs\/wildcard-rank\] .* needs \d+ enclosing/,' Wrap it in that many "for" templates, or use $resolve(path, indexes) to name the row explicitly.'],[/\[wcs\/wildcard-rank\] .* ranges over the rows of/,' A "*" in a binding is the row of the loop around it: read a row of another list in a getter, with $resolve(path, indexes).'],[/\[wcs\/binding-type-expectation\] class\.([^ ]+)/,' Write "class.$1: path|truthy" to toggle on truthiness.'],[/path segments — the limit/," Every prefix of a path is interned, so the cost grows with the square of the depth."],[/\[wcs\/index-arity\] \$resolve/,' $resolve takes one index per "*"; $getAll / $setAll take at most that many (fewer expands the rest).'],[/"([^"#]+)#[^"]*" is not a filter name: "#" cannot appear in one/,' Modifiers belong on the left side of the binding, before the ":" — write "$1" here.']],k={inc:"add",dec:"sub",fix:"toFixed",uc:"upper",lc:"lower",cap:"capitalize",rep:"repeat",rev:"reverse",pad:"padStart",null:"nullIfEmpty"};function x(e,t,n){let i=(void 0!==t&&e.includes("[wcs/filter-unknown]")?function(e){if("substr"===e)return' "substr" was removed in 4.0 — write slice(start, start + length): slice takes the end index, not a length.';let t=Object.hasOwn(k,e)?k[e]:null;return null===t?null:` "${e}" was renamed "${t}" in 3.2 and removed in 4.0 — write "${t}".`}(t):null)??(void 0!==t&&void 0!==n?h(t,n):"");for(let[t,n]of v){let a=t.exec(e);null!==a&&(i+=n.replace(/\$(\d)/g,(e,t)=>a[Number(t)]))}let a=/"([^"#]+)#([^"]+)": a binding takes one modifier list/.exec(e);null!==a&&(i+=` — write "${a[1]}#${a[2].split("#").join(",")}".`),e.includes("[wcs/filter-unknown]")&&(e.includes("formats add-on")?i+=' On a split auto page: features="formats" on the root, or "$features": ["formats"].':s.some(r)||(i+=' No formatting filters are installed — add the formats add-on: installFeatures([formats]) from "@wcstack/state/features/formats" (a split auto page: features="formats", or "$features").'));let o=/\[wcs\/([\w-]+)\]/.exec(e);return null!==o&&y.has(o[1])&&!/ path segments — the limit is |inserted content was not rendered|formats add-on/.test(e)&&(i+=p),i}var j=new WeakMap,T=new WeakMap,P=new WeakSet,O=new WeakSet;function S(e,t){for(let n=e;null!==n&&n!==Object.prototype;n=Object.getPrototypeOf(n)){let e=Object.getOwnPropertyDescriptor(n,t);if(void 0!==e)return e}}function I(e){let t=new Set;for(let n=e;null!==n&&n!==Object.prototype;n=Object.getPrototypeOf(n))for(let e of Object.getOwnPropertyNames(n))"$"!==e[0]&&"constructor"!==e&&t.add(e);return[...t]}function M(e,t){let n=[];for(let e=t;null!==e;e=e.w)n.unshift(e);let i=e.target,a=t=>null===t?null:function(e,t){let n=t.t.split("."),i=n.findIndex((e,t)=>t>0&&/^\d/.test(e));return i<0||n.indexOf("*",i)>=0||void 0!==S(e.target,t.t)?.get?t:e.L.Ft(o(t.t).o)}(e,t);for(let t of n){if(null!=a(t)?.getter||null===i||"object"!=typeof i)return null;if("*"===t.l){if(!Array.isArray(i)||0===i.length)return null;i=i[0];continue}if(Array.isArray(i)&&/^\d+$/.test(t.l)){if(Number(t.l)>=i.length)return null;i=i[Number(t.l)];continue}let n=S(i,t.l);if(void 0===n&&null===t.w&&e.pt.has(t.l))return null;if(void 0===n){let n=I(i),s=a(t.w);for(let t of e.L.all())t.w===s&&null!==t.getter&&n.push(t.l);return{seg:t.l,names:n}}if(void 0!==n.get||void 0!==n.set)return null;i=n.value}return null}function A(e){P.has(e)||(P.add(e),setTimeout(()=>function(e){P.delete(e);let t=j.get(e);if(void 0===t)return;let n=T.get(e);void 0===n&&T.set(e,n=new Set);for(let[i,s]of t){if(n.has(i))continue;n.add(i);let t=M(e,i);if(null===t)continue;let r=[...e.root?.querySelectorAll(`${a.tagNames.state}[mount]`)??[]].find(e=>!O.has(e)&&(i.t+".").startsWith(e.getAttribute("mount")+"."));if(void 0!==r){n.delete(i),r.initializePromise.then(()=>{O.add(r),A(e)});continue}let[l,c]=s?["watch-path-missing","$watch path"]:["binding-path-missing","Bound path"];d.tt?.(e,{type:"state:path-unresolved",source:s?"watch":"binding",path:i.t,missingSegment:t.seg});let f=e.L.Ft(o(i.t).o),u="";if(void 0!==f&&f!==i&&null!==f.getter){let e=f.c.slice(1).map((e,t)=>`for: ${0===t?e.t:e.t.slice(f.c[t].t.length+2)}`);u=` The getter "${f.t}" is declared for the rows of ${e.join(" → ")}; a list named by an index has rows of its own.`}console.warn(`[@wcstack/state] [wcs/${l}] ${c} "${i.t}" does not resolve on the state tree: "${t.seg}" is not declared.${h(t.seg,t.names)}${u} Updates to this path will be silently dropped.${p}`)}}(e),0))}function W(e,t,n=!1){if("$"===t.t[0]||t.t.includes("#")||!n&&null===t.w)return;let i=j.get(e);void 0===i&&j.set(e,i=new Map),i.has(t)||i.set(t,n),A(e)}var q=e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),L=!1;function N(e,t,a){let s="html"===a.name?"innerHTML":a.name;if(L||!(t instanceof TypeError)||!i(s)||!("trustedTypes"in globalThis))return;L=!0;let r="function"==typeof n()?.createHTML?"The injected policy's createHTML() did not return a TrustedHTML.":"No sanitizing policy is installed, and @wcstack/state deliberately does not pass state values through an identity policy — that would defeat the CSP.";console.error(`[@wcstack/state] Writing to "${s}" was blocked by Trusted Types (require-trusted-types-for 'script'). ${r}\nInstall a sanitizing policy before the first binding is applied:\n globalThis[Symbol.for("wcstack.trustedTypes.policy")] =\n trustedTypes.createPolicy("my-app", { createHTML: (s) => DOMPurify.sanitize(s) });\nOr bind the value as text instead of HTML. See docs/csp.md section 7.`,{element:a.a,property:s})}var B=new WeakMap;function C(e,t,n){let i=e[t],a=void 0===n?void 0===i?null:`the event carried no detail (undefined) while element.${t} is ${typeof i}`:null===n||"object"!=typeof n||!Object.prototype.hasOwnProperty.call(n,t)||null!==i&&"object"==typeof i?null:`the event's detail is an object with a "${t}" key while element.${t} is ${typeof i}`;if(null===a)return;let s=B.get(e);void 0===s&&B.set(e,s=new Set),!s.has(t)&&(s.add(t),console.warn(`[@wcstack/state] [wcs/default-getter-mismatch] <${e.localName}> "${t}": ${a}. With no getter, state receives e.detail as-is. Dispatch the value itself as detail, or declare getter (e.g. (e) => e.detail.${t}, or (e) => e.target.${t}) on that wcBindable property.`))}var z={name:"diagnostics",install(){d.Ao=x,d.Fo=b,d.yo=W,d.detail=C,d._e=c(d._e,N),d.ie=c(d.ie,(e,t)=>{(function(e){let t=e.$recursion;if(null===t||"object"!=typeof t)return;let n=Object.entries(t);if(1!==n.length||"string"!=typeof n[0][1])return;let[i,a]=n[0];if(!i.endsWith(".*")||!a.endsWith(".*"))return;let s=i.slice(0,-2),r=a.slice(0,-2),o=`.${a}`,l=`${s}.**`,d=I(e),c=d.filter(e=>e.startsWith(l)).map(e=>e.slice(l.length)),u=e=>f(`[wcs/recursion-declaration-invalid] ${e}`);for(let e of c){(e===`.${r}`||e.startsWith(`.${r}.`))&&u(`"${l}${e}" names the recursion structure itself (the "${r}" lists): recursive getters compute values over the nodes.`);for(let t of c)t.length>e.length&&t.endsWith(e)&&new RegExp(`^(?:${q(o)})+$`).test(t.slice(0,t.length-e.length))&&u(`"${l}${e}" and "${l}${t}" expand to the same concrete path at different depths (they differ by whole repetitions of "${a}"). Rename one of them.`);let t=new RegExp(`^${q(i)}(?:${q(o)})*${q(e)}$`);for(let n of d)!n.includes("**")&&t.test(n)&&u(`"${n}" is already defined on the state, so the recursive getter "${l}${e}" cannot expand to it.`)}})(t),function(e){T.delete(e),j.has(e)&&A(e)}(e)})}},D=z;export{D as default,z as diagnostics};
|
|
@@ -1,10 +1,26 @@
|
|
|
1
|
-
import { I as IStateFeature } from '../chunks/features.js';
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* The places the core calls into add-ons (docs/state-engine-rewrite/addons-plan.ja.md §1.2).
|
|
3
|
+
*
|
|
4
|
+
* Add-ons ship as separate entries of the same build as the core (`features/*`): they reach
|
|
5
|
+
* the core's internals directly, and the core only calls out through these slots. A slot is
|
|
6
|
+
* empty until an installed feature fills it (the object starts with none: a list of null slots
|
|
7
|
+
* would be the core's bytes), so a page without the feature pays one `?.` check. A feature
|
|
8
|
+
* restoring a slot may set it to null.
|
|
9
|
+
* Slots are added with the first feature that needs them; several features share one through
|
|
10
|
+
* chain / first. The slots `element` and `detail` keep their names (a DevTools-facing field and a DOM
|
|
11
|
+
* name share them); the others are shortened by the build. An empty slot is read through
|
|
12
|
+
* Object.prototype: a page that polluted it (a value under `element`, say) breaks the core loudly
|
|
13
|
+
* there, as it does wherever the core reads a plain object's keys (`$behavior`); not defended.
|
|
6
14
|
*/
|
|
7
15
|
|
|
8
|
-
|
|
16
|
+
/** An add-on entry: `installFeatures([temporal, diagnostics])` before the state is defined. */
|
|
17
|
+
interface Feature {
|
|
18
|
+
readonly name: string;
|
|
19
|
+
install(): void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** The formats add-on (@wcstack/state/features/formats): the 23 formatting filters (locale-aware). */
|
|
23
|
+
|
|
24
|
+
declare const formats: Feature;
|
|
9
25
|
|
|
10
26
|
export { formats as default, formats };
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
import{
|
|
2
|
-
//# sourceMappingURL=formats.js.map
|
|
1
|
+
import{a as t,c as r,d as e,e as a,g as n,h as o}from"../chunks/chunk-HFKGUDDJ.js";import{a as i,e as c}from"../chunks/chunk-732CB4QN.js";import{b as l}from"../chunks/chunk-WWJNAZVP.js";import"../chunks/chunk-YOPPVWPQ.js";var y,u=t=>r=>{let e=t(r);return t=>null==t?t:e(t)},s="en";function f(){if(i.locale!==y){y=i.locale;try{s=Intl.getCanonicalLocales(y)[0]}catch{console.warn(`[@wcstack/state] ${l(48,[y])}`),s="en"}}return s}var p={toFixed:{factory:t=>{let e=n(t?.[0]??"0","toFixed");return t=>("number"!=typeof t&&r("toFixed"),t.toFixed(e))},arity:[0,1]},locale:{factory:t=>{let e=t?.[0];return t=>("number"!=typeof t&&r("locale"),t.toLocaleString(e??f()))},arity:[0,1]},upper:{factory:u(()=>t=>String(t).toUpperCase()),arity:[0,0]},lower:{factory:u(()=>t=>String(t).toLowerCase()),arity:[0,0]},capitalize:{factory:u(()=>t=>{let r=String(t);return 0===r.length?r:1===r.length?r.toUpperCase():r.charAt(0).toUpperCase()+r.slice(1)}),arity:[0,0]},trim:{factory:u(()=>t=>String(t).trim()),arity:[0,0]},slice:{factory:u(t=>{let r=[o(t,0,"slice")],e=t?.[1];return typeof e<"u"&&r.push(n(e,"slice")),t=>String(t).slice(...r)}),arity:[1,2]},padStart:{factory:u(t=>{let r=o(t,0,"padStart"),e=t?.[1]??"0";return t=>String(t).padStart(r,e)}),arity:[1,2]},padEnd:{factory:u(t=>{let r=o(t,0,"padEnd"),e=t?.[1]??" ";return t=>String(t).padEnd(r,e)}),arity:[1,2]},repeat:{factory:u(t=>{let r=o(t,0,"repeat");return t=>String(t).repeat(r)}),arity:[1,1]},reverse:{factory:u(()=>t=>String(t).split("").reverse().join("")),arity:[0,0]},truncate:{factory:u(t=>{let r=o(t,0,"truncate"),e=t?.[1]??"…";return t=>{let a=String(t);return a.length<=r?a:a.slice(0,r)+e}}),arity:[1,2]},join:{factory:t=>{let r=t?.[0]??", ";return t=>(Array.isArray(t)||a("join"),t.join(r))},arity:[0,1]},round:{factory:t=>{let e=Math.pow(10,n(t?.[0]??"0","round"));return t=>("number"!=typeof t&&r("round"),Math.round(t*e)/e)},arity:[0,1]},floor:{factory:t=>{let e=Math.pow(10,n(t?.[0]??"0","floor"));return t=>("number"!=typeof t&&r("floor"),Math.floor(t*e)/e)},arity:[0,1]},ceil:{factory:t=>{let e=Math.pow(10,n(t?.[0]??"0","ceil"));return t=>("number"!=typeof t&&r("ceil"),Math.ceil(t*e)/e)},arity:[0,1]},percent:{factory:t=>{let e=n(t?.[0]??"0","percent");return t=>("number"!=typeof t&&r("percent"),`${(100*t).toFixed(e)}%`)},arity:[0,1]},unit:{factory:u(r=>{let e=r?.[0]??t("unit");return t=>String(t)+e}),arity:[1,1]},date:{factory:t=>{let r=t?.[0];return t=>(t instanceof Date||e("date"),t.toLocaleDateString(r??f()))},arity:[0,1]},time:{factory:t=>{let r=t?.[0];return t=>(t instanceof Date||e("time"),t.toLocaleTimeString(r??f()))},arity:[0,1]},datetime:{factory:t=>{let r=t?.[0];return t=>(t instanceof Date||e("datetime"),t.toLocaleString(r??f()))},arity:[0,1]},ymd:{factory:t=>{let r=t?.[0]??"-";return t=>{t instanceof Date||e("ymd");let a=t.getFullYear().toString(),n=(t.getMonth()+1).toString().padStart(2,"0"),o=t.getDate().toString().padStart(2,"0");return`${a}${r}${n}${r}${o}`}},arity:[0,1]},hms:{factory:t=>{let r=t?.[0]??":";return t=>{t instanceof Date||e("hms");let a=t.getHours().toString().padStart(2,"0"),n=t.getMinutes().toString().padStart(2,"0"),o=t.getSeconds().toString().padStart(2,"0");return`${a}${r}${n}${r}${o}`}},arity:[0,1]}},d=!1,g={name:"formats",install:function(){d||(d=!0,c(p))}},S=g;export{S as default,g as formats};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The places the core calls into add-ons (docs/state-engine-rewrite/addons-plan.ja.md §1.2).
|
|
3
|
+
*
|
|
4
|
+
* Add-ons ship as separate entries of the same build as the core (`features/*`): they reach
|
|
5
|
+
* the core's internals directly, and the core only calls out through these slots. A slot is
|
|
6
|
+
* empty until an installed feature fills it (the object starts with none: a list of null slots
|
|
7
|
+
* would be the core's bytes), so a page without the feature pays one `?.` check. A feature
|
|
8
|
+
* restoring a slot may set it to null.
|
|
9
|
+
* Slots are added with the first feature that needs them; several features share one through
|
|
10
|
+
* chain / first. The slots `element` and `detail` keep their names (a DevTools-facing field and a DOM
|
|
11
|
+
* name share them); the others are shortened by the build. An empty slot is read through
|
|
12
|
+
* Object.prototype: a page that polluted it (a value under `element`, say) breaks the core loudly
|
|
13
|
+
* there, as it does wherever the core reads a plain object's keys (`$behavior`); not defended.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** An add-on entry: `installFeatures([temporal, diagnostics])` before the state is defined. */
|
|
17
|
+
interface Feature {
|
|
18
|
+
readonly name: string;
|
|
19
|
+
install(): void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
declare const listKeys: Feature;
|
|
23
|
+
|
|
24
|
+
export { listKeys as default, listKeys };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as t,b as e,c as l,d as n,j as o}from"../chunks/chunk-YOPPVWPQ.js";var s=new WeakMap,r=!1,i=/^(?!prototype$)[^\d.*$][^.*]*$/;function f(t,e){let l=e.$listKeys,n=new Map;if(void 0!==l){(null===l||"object"!=typeof l)&&o("$listKeys must be an object mapping list paths to a key field or function.");for(let e of Object.keys(l)){let s=l[e];"string"==typeof s?n.set(t.o(e),t=>t[s]):"function"==typeof s?n.set(t.o(e),s):o(`$listKeys "${e}" must be a field name or a function.`)}}s.set(e,n)}function u(t){if(null===t||"object"!=typeof t)return!1;let e=Object.getPrototypeOf(t);return e===Object.prototype||null===e}function a(t,e,l){let n=new Map;for(let s of e){u(s)||o(`$listKeys "${t}": rows must be plain objects.`);let e=l(s);null==e&&o(`$listKeys "${t}": a row has no key.`),n.has(e)&&o(`$listKeys "${t}": duplicate key ${JSON.stringify(e)}.`),n.set(e,s)}return n}function y(t,e,l,n){if(r||!Array.isArray(n))return!1;let o=s.get(t.target)?.get(e);if(void 0===o)return!1;let f=t.zt(e,l);if(!Array.isArray(f)||f===n)return!1;let u=a(e.t,f,o);a(e.t,n,o);let y=[],p=[],c=f.length===n.length;for(let t=0;t<n.length;t++){let e=n[t],l=u.get(o(e));y.push(l??e),void 0!==l&&p.push([t,l,e]),y[t]!==f[t]&&(c=!1)}let $=[];for(let[t,e,l]of p){for(let n of Object.keys(l))Object.is(e[n],l[n])||$.push([t,n,l[n]]);for(let n of Object.keys(e))!(n in l)&&null!==e[n]&&$.push([t,n,null])}if(c&&0===$.length)return!0;if(!c){r=!0;try{t.P(e,l,y)}finally{r=!1}}if($.length>0){let n=t.De(0===e.n?null:l,e);for(let[l,o,s]of $){if("__proto__"===o)continue;let r=n.f[l],f=i.test(o)?t.o(`${e.t}.*.${o}`):null;null===f?.getter?t.P(f,r,s):(r.O[o]=s,t.P(t.o(`${e.t}.*`),r,r.O,!0))}}return!0}var p={name:"list-keys",install(){t.ie=e(t.ie,f),t.Re=l(n,t.Re,y)}},c=p;export{c as default,p as listKeys};
|
|
@@ -1,9 +1,29 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The places the core calls into add-ons (docs/state-engine-rewrite/addons-plan.ja.md §1.2).
|
|
3
|
+
*
|
|
4
|
+
* Add-ons ship as separate entries of the same build as the core (`features/*`): they reach
|
|
5
|
+
* the core's internals directly, and the core only calls out through these slots. A slot is
|
|
6
|
+
* empty until an installed feature fills it (the object starts with none: a list of null slots
|
|
7
|
+
* would be the core's bytes), so a page without the feature pays one `?.` check. A feature
|
|
8
|
+
* restoring a slot may set it to null.
|
|
9
|
+
* Slots are added with the first feature that needs them; several features share one through
|
|
10
|
+
* chain / first. The slots `element` and `detail` keep their names (a DevTools-facing field and a DOM
|
|
11
|
+
* name share them); the others are shortened by the build. An empty slot is read through
|
|
12
|
+
* Object.prototype: a page that polluted it (a value under `element`, say) breaks the core loudly
|
|
13
|
+
* there, as it does wherever the core reads a plain object's keys (`$behavior`); not defended.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** An add-on entry: `installFeatures([temporal, diagnostics])` before the state is defined. */
|
|
17
|
+
interface Feature {
|
|
18
|
+
readonly name: string;
|
|
19
|
+
install(): void;
|
|
20
|
+
}
|
|
2
21
|
|
|
3
22
|
/**
|
|
4
|
-
*
|
|
23
|
+
* The recursion add-on (@wcstack/state/features/recursion): `$recursion` and `**` — see
|
|
24
|
+
* src/recursion/recursion.ts.
|
|
5
25
|
*/
|
|
6
26
|
|
|
7
|
-
declare const recursion:
|
|
27
|
+
declare const recursion: Feature;
|
|
8
28
|
|
|
9
29
|
export { recursion as default, recursion };
|
|
@@ -1,2 +1 @@
|
|
|
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{N as h,j as u,l as d,O as f,P 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
|
-
//# sourceMappingURL=recursion.js.map
|
|
1
|
+
import{m as e}from"../chunks/chunk-QQH6N5CJ.js";import{c as t}from"../chunks/chunk-WWJNAZVP.js";import{a as r,b as s,c as n,d as l,j as i}from"../chunks/chunk-YOPPVWPQ.js";var a="$recursion",o=new WeakMap,c=new WeakSet,u=new WeakSet,h=0,d=e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),$=e=>`[wcs/recursion-${e}]`;function f(e,t){let r=r=>i(`${$("declaration-invalid")} ${a} ${e} "${String(t)}" ${r}`);("string"!=typeof t||""===t)&&i(`${$("declaration-invalid")} ${a} ${e} must be a non-empty string.`);let s=t.split(".");(s.length<2||"*"!==s[s.length-1])&&r('must end with ".*" (a list element).');for(let e=0;e<s.length-1;e++){let t=s[e];""===t&&r("must not contain empty path segments."),("*"===t||"**"===t||/^\d/.test(t))&&r('must have exactly one "*", at the end.'),t.includes("#")&&r('must not contain "#".')}return"$"===t[0]&&r('must not start with "$".'),t}var p=(e,t)=>`${e.s}.*${e.step.repeat(t)}`;function g(e,t){let r=`${e.s}.**`,s=t.slice(r.length);return(!t.startsWith(r)||""!==s&&"."!==s[0]||s.includes("**"))&&i(`[wcs/recursion-anchor] "${t}" does not start at the recursion anchor "${e.s}.*".`),s}function m(e,t,r){let s=g(e,t),n=function(e,t){for(let r=t;null!==r;r=r.s.te){let t=e.nodeList.exec(r.s.o.t);if(null!==t)return{k:t[1].length/(e.key.length+3),r}}return null}(e,r);return null===n&&i(`[wcs/recursion-context] "${t}" uses "**", which is bound to the depth of the row it is evaluated in; there is none here — use $getAll("${t}", []) for every depth.`),p(e,n.k)+s}function y(e,t,r){let s=new Set,n=new Set,l=(e,r,l)=>!(!Array.isArray(e)||0===e.length||(s.has(e)&&i(`${$("cycle")} "${r}" is reachable from itself: the data under "${t.s}" must be a tree.`),n.has(e)&&i(`${$("shared-list")} "${r}" is the same array instance as a list reached before: the data under "${t.s}" must be a tree.`),l+1>128&&i(`${$("depth-exceeded")} Recursion on "${t.s}.*" reached depth ${l+1} (the limit is 128).`),n.add(e),0)),a=(n,i)=>{for(let o of n){r(i,o);let n=e.o(`${p(t,i)}.${t.key}`),c=e.read(n,o);l(c,n.t,i+1)&&(s.add(c),a(e.De(o,n).f,i+1),s.delete(c))}},o=e.o(t.s),c=e.read(o,null);l(c,t.s,0)&&(s.add(c),a(e.De(null,o).f,0))}function w(r,s){let n=function(t){let r=t[a],s=[],n=new Set;for(let e=t;null!==e&&e!==Object.prototype;e=Object.getPrototypeOf(e))for(let t of Object.getOwnPropertyNames(e))!n.has(t)&&t.includes("**")&&s.push([t,Object.getOwnPropertyDescriptor(e,t)]),n.add(t);if(void 0===r)return s.length>0&&e(s[0][0]),null;(null===r||"object"!=typeof r||Array.isArray(r))&&i(`${$("declaration-invalid")} ${a} must be an object mapping one anchor path to its repeating sub-path.`);let l=Object.entries(r);1!==l.length&&i(`${$("declaration-invalid")} ${a} must declare exactly one anchor (it declares ${l.length}).`);let o=f("anchor",l[0][0]),c=f("repeat",l[0][1]),u=o.slice(0,-2),h=c.slice(0,-2),p=`.${c}`,g=new Map,m=[],y=`${u}.**`;for(let[e,t]of s){let r=e.slice(y.length);(!e.startsWith(y)||""!==r&&"."!==r[0]||r.includes("**"))&&i(`[wcs/recursion-anchor] "${e}": a recursive key is "${y}" followed by a path (the anchor is "${o}").`),(""===r||r.split(".").slice(1).some(e=>""===e))&&i(`[wcs/recursion-anchor] "${e}" needs a path after "**".`),(void 0===t.get||void 0!==t.set)&&i(`${$("declaration-invalid")} "${e}": a recursive key is a getter without a setter.`),g.set(r,t.get),m.push([new RegExp(`^${d(o)}((?:${d(p)})*)${d(r)}$`),r])}return{s:u,step:p,key:h,families:g,matchers:m,owners:new Map,nodeList:new RegExp(`^${d(u)}((?:${d(`.*.${h}`)})*)$`)}}(s),l=o.has(r);null!==n?(l||h++,o.set(r,n),u.add(r),c.has(r)||function(r){c.add(r);let s=r,n=s.Ze;s.Ze=t=>{let l=o.get(r);if(t.t.includes("**")){let s=r.L.Ft(t.t)===t;return void(u.has(r)||void 0===l&&s?t.getter=()=>e(t.t):s||n.call(r,t))}if(void 0!==l&&null===t.getter)for(let[e,r]of l.matchers)if(e.test(t.t)){t.getter=l.families.get(r),t.n>0&&(t.A=s.Oe++),l.owners.set(t,l.s+".**"+r);break}n.call(r,t)};let l=s.resolve;s.resolve=(e,t)=>{let s=o.get(r);return l.call(r,void 0!==s&&e.includes("**")?m(s,e,t):e,t)};let a=s.getAll;s.getAll=(e,t)=>{let n=o.get(r);if(void 0===n||!e.includes("**"))return a.call(r,e,t);if(void 0===t)return a.call(r,m(n,e,s.h));(!Array.isArray(t)||t.length>0)&&i(`${$("getall-form")} $getAll("${e}", indexes) with "**" takes either no indexes (this depth) or [] (every depth).`);let l=g(n,e),c=[];return y(r,n,(e,t)=>{for(let s of a.call(r,p(n,e)+l,r.D(t)))c.push(s)}),c};let h=s.pn;s.pn=(e,n,l,a)=>{let c=o.get(r);if(void 0===c||!e.includes("**"))return h.call(r,e,n,l,a);Array.isArray(n)||t(9,[e]),n.length>0&&i(`${$("setall-form")} $setAll("${e}", indexes, …) with "**" takes no partial prefix: pass [] to write every node.`),("function"==typeof l||!0===a?.spread)&&i(`${$("setall-form")} $setAll("${e}", [], value) with "**" takes a plain value (no mapper, no spread).`),s.Ce>0&&t(8);let u=g(c,e),d=u.replace(/\.\d+(?=\.|$)/g,".*");for(;d.startsWith(c.step);)d=d.slice(c.step.length);let f=c.key.split(".");(""===d||d===`.${c.key}.length`||f.some((e,t)=>d===`.${f.slice(0,t+1).join(".")}`))&&i(`${$("structural-write")} "${e}" writes the recursion structure itself (a node, its "${c.key}" list or that list's length, or an object on the way to it).`);for(let t of c.families.keys()){let r=t;for(;r.startsWith(c.step);)r=r.slice(c.step.length);(d===r||d.startsWith(`${r}.`))&&i(`${$("readonly")} "${e}" writes into the recursive getter "${c.s}.**${t}".`)}let m=[];y(r,c,(e,t)=>m.push([e,t]));let w=0;for(let[e,t]of m)w+=h.call(r,p(c,e)+u,r.D(t),l);return w}}(r)):l&&(o.delete(r),h--)}function v(e,t){if(0===h)return!1;let r=o.get(e);if(void 0===r)return!1;for(let e=t;null!==e;e=e.w){let s=r.owners.get(e);void 0!==s&&i(`${$("readonly")} "${t.t}" writes into the recursive getter "${s}".`)}return!1}var k={name:"recursion",install(){r.ie=s(r.ie,w),r.element=s(r.element,(e,t)=>{("mounting"===t||"reset"===t)&&function(e){u.delete(e)}(e)}),r.Re=n(l,r.Re,v)}},b=k;export{b as default,k as recursion};
|
|
@@ -1,10 +1,31 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The places the core calls into add-ons (docs/state-engine-rewrite/addons-plan.ja.md §1.2).
|
|
3
|
+
*
|
|
4
|
+
* Add-ons ship as separate entries of the same build as the core (`features/*`): they reach
|
|
5
|
+
* the core's internals directly, and the core only calls out through these slots. A slot is
|
|
6
|
+
* empty until an installed feature fills it (the object starts with none: a list of null slots
|
|
7
|
+
* would be the core's bytes), so a page without the feature pays one `?.` check. A feature
|
|
8
|
+
* restoring a slot may set it to null.
|
|
9
|
+
* Slots are added with the first feature that needs them; several features share one through
|
|
10
|
+
* chain / first. The slots `element` and `detail` keep their names (a DevTools-facing field and a DOM
|
|
11
|
+
* name share them); the others are shortened by the build. An empty slot is read through
|
|
12
|
+
* Object.prototype: a page that polluted it (a value under `element`, say) breaks the core loudly
|
|
13
|
+
* there, as it does wherever the core reads a plain object's keys (`$behavior`); not defended.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** An add-on entry: `installFeatures([temporal, diagnostics])` before the state is defined. */
|
|
17
|
+
interface Feature {
|
|
18
|
+
readonly name: string;
|
|
19
|
+
install(): void;
|
|
20
|
+
}
|
|
2
21
|
|
|
3
22
|
/**
|
|
4
|
-
* features/scopes
|
|
5
|
-
*
|
|
23
|
+
* The scopes add-on (@wcstack/state/features/scopes): `<wcs-state>` elements that are not roots.
|
|
24
|
+
* Volumes (`<wcs-state mount="p">`, src/scopes/volume.ts), Declarative Custom Components
|
|
25
|
+
* (`[data-wc-definition]`, src/scopes/dcc.ts) and component mounts (`<wcs-state
|
|
26
|
+
* bind-component>`, src/scopes/component.ts).
|
|
6
27
|
*/
|
|
7
28
|
|
|
8
|
-
declare const scopes:
|
|
29
|
+
declare const scopes: Feature;
|
|
9
30
|
|
|
10
31
|
export { scopes as default, scopes };
|