@wcstack/state 3.4.0 → 3.5.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.
@@ -1,2 +1,2 @@
1
- const o="3.4.0";export{o as V};
1
+ const o="3.5.0";export{o as V};
2
2
  //# sourceMappingURL=version.js.map
@@ -771,6 +771,7 @@ interface IBindingErrorInfo {
771
771
  }
772
772
  interface IWritableConfig {
773
773
  bindAttributeName?: string;
774
+ /** @deprecated Removed in 4.0, whose `bootstrapState` throws on it (3.5 warns `wcs/v4-migration`). */
774
775
  commentTextPrefix?: string;
775
776
  commentForPrefix?: string;
776
777
  commentIfPrefix?: string;
@@ -778,11 +779,16 @@ interface IWritableConfig {
778
779
  commentElsePrefix?: string;
779
780
  tagNames?: IWritableTagNames;
780
781
  locale?: string;
782
+ /** @deprecated Removed in 4.0, whose `bootstrapState` throws on it (3.5 warns `wcs/v4-migration`). */
781
783
  debug?: boolean;
784
+ /** Moves to the state's `$behavior` in 4.0 (3.5 warns `wcs/v4-migration`); in 3.x, set it here. */
782
785
  enableMustache?: boolean;
786
+ /** Moves to the state's `$behavior` in 4.0 (3.5 warns `wcs/v4-migration`); in 3.x, set it here. */
783
787
  enableDirectionalInitialSync?: boolean;
788
+ /** @deprecated Removed in 4.0, whose `bootstrapState` throws on it (3.5 warns `wcs/v4-migration`). */
784
789
  enablePropagationContext?: boolean;
785
790
  enableContractAnalyzer?: boolean;
791
+ /** Moves to the state's `$behavior` in 4.0 (3.5 warns `wcs/v4-migration`); in 3.x, set it here. */
786
792
  sameValueGuard?: boolean;
787
793
  }
788
794
 
@@ -1252,7 +1258,23 @@ declare class State extends HTMLElementBase implements IStateElement {
1252
1258
  private set _state(value);
1253
1259
  attributeChangedCallback(_name: string, oldValue: string | null, newValue: string | null): void;
1254
1260
  private _loadFromSsrElement;
1255
- /** state / src / json / inner <script> / API set のソース解決(_initialize とボリュームで共用)。 */
1261
+ /**
1262
+ * state / src / json / inner <script> / API set のソース解決(_initialize とボリュームで共用)。
1263
+ *
1264
+ * A load failure is not wrapped, here or in the loaders: what was thrown propagates as is —
1265
+ * the SyntaxError of `JSON.parse` (`state=` / `json=`), the `import()` rejection or the
1266
+ * module's own throw (`src="*.js"`), the inline-script loader's Error (the import failure is
1267
+ * its `cause`), the unsupported-extension error, or a non-Error value. On a root,
1268
+ * `_failInitializeLoudly` logs it under the element's "failed to initialize" line and rejects
1269
+ * connectedCallbackPromise with that same value (the README contract); on a volume,
1270
+ * volumeLifecycle logs it under its "failed to load" line. The old wrappers
1271
+ * (`Failed to initialize state: ${e}` here, `Failed to load script file` /
1272
+ * `Failed to parse JSON from script element` in the loaders) were new Errors that kept the
1273
+ * original only as text, losing its type, stack and cause.
1274
+ *
1275
+ * Two sources do not fail at all in 3.x (README): `src="*.json"` that cannot be fetched or
1276
+ * parsed, and `state=` naming no JSON script. Both log and start with an empty state.
1277
+ */
1256
1278
  private _loadStateFromSource;
1257
1279
  /**
1258
1280
  * 初回マウントのロードと登録。戻り値は「この接続で初期化を**完了**したか」で、
@@ -1 +1 @@
1
- {"version":3,"file":"formats.js","sources":["../../../../../src/formats/errorMessages.ts","../../../../../src/filters/filterAliases.ts","../../../../../src/formats/builtinFilters.ts","../../../../../src/formats/install.ts","../../../../../src/features/formats.ts"],"sourcesContent":["/**\n * errorMessages.ts\n *\n * Error message generation utilities used by filter functions.\n *\n * Main responsibilities:\n * - Throws clear error messages when filter options or value type checks fail\n * - Takes function name as argument to specify which filter caused the error\n *\n * Design points:\n * - optionsRequired: Error when required option is not specified\n * - optionMustBeNumber: Error when option value is not a number\n * - valueMustBeNumber: Error when value is not a number\n * - valueMustBeDate: Error when value is not a Date\n * - valueMustBeArray: Error when value is not an array\n */\nimport { raiseError } from \"../raiseError\";\n\n/**\n * Throws error when filter requires at least one option but none provided.\n * \n * @param fnName - Name of the filter function\n * @returns Never returns (always throws)\n */\nexport function optionsRequired(fnName:string): never {\n raiseError(`filter ${fnName} requires at least one option`);\n}\n\n/**\n * Throws error when filter option must be a number but invalid value provided.\n * \n * @param fnName - Name of the filter function\n * @returns Never returns (always throws)\n */\nexport function optionMustBeNumber(fnName:string): never {\n raiseError(`filter ${fnName} requires a number as option`);\n}\n\n/**\n * Throws error when filter requires numeric value but non-number provided.\n * \n * @param fnName - Name of the filter function\n * @returns Never returns (always throws)\n */\nexport function valueMustBeNumber(fnName:string): never {\n raiseError(`filter ${fnName} requires a number value`);\n}\n\n/**\n * Throws error when filter requires Date value but non-Date provided.\n *\n * @param fnName - Name of the filter function\n * @returns Never returns (always throws)\n */\nexport function valueMustBeDate(fnName:string): never {\n raiseError(`filter ${fnName} requires a date value`);\n}\n\n/**\n * Throws error when filter requires array value but non-array provided.\n *\n * @param fnName - Name of the filter function\n * @returns Never returns (always throws)\n */\nexport function valueMustBeArray(fnName:string): never {\n raiseError(`filter ${fnName} requires an array value`);\n}","/**\n * filters/filterAliases.ts — 組み込みフィルタの旧名 → 正式名(要件 B12・docs/state-3x-naming.ja.md V1〜V9)。\n *\n * 旧名は 3.x の間エイリアスとして残り、4.0 で外す(D4)。解決は登録簿(core/filterRegistry)が行い、\n * 実装・引数の個数・メタデータは正式名だけが持つ。formats の install と manifest(tooling)の両方が読むので、\n * 実装にもメタデータにも依存しない小さな表として独立させている。\n */\nexport const builtinFilterAliases: Readonly<Record<string, string>> = {\n inc: \"add\",\n dec: \"sub\",\n fix: \"toFixed\",\n uc: \"upper\",\n lc: \"lower\",\n cap: \"capitalize\",\n rep: \"repeat\",\n rev: \"reverse\",\n pad: \"padStart\",\n null: \"nullIfEmpty\",\n};\n","/**\n * builtinFilters.ts\n *\n * Implementation file for built-in filter functions available in Structive.\n *\n * Main responsibilities:\n * - Provides filters for conversion, comparison, formatting, and validation of numbers, strings, dates, booleans, etc.\n * - Defines functions with options for each filter name, enabling flexible use during binding\n * - Designed for common use as both input and output filters\n *\n * Design points:\n * - Comprehensive coverage of diverse filters: eq, ne, lt, gt, inc, abs, clamp, fix, locale, uc, lc, cap, trim, slice, pad, truncate, join, int, float, round, percent, unit, date, time, ymd, hms, falsy, truthy, defaults, boolean, number, string, null, etc.\n * - Rich type checking and error handling for option values\n * - Centralized management of filter functions with FilterWithOptions type, easy to extend\n * - Dynamic retrieval of filter functions from filter names and options via builtinFilterFn\n */\nimport { config } from \"../config.js\";\nimport { didYouMean, LINT_HINT } from \"../errorGuidance.js\";\nimport { raiseError } from \"../raiseError.js\";\nimport { optionMustBeNumber, optionsRequired, valueMustBeArray, valueMustBeDate, valueMustBeNumber } from \"./errorMessages.js\";\nimport { FilterFn, FilterWithOptions, FilterWithOptionsFn } from \"../filters/types\";\nimport { builtinFilterAliases } from \"../filters/filterAliases\";\n\nfunction validateNumberString(value: string): boolean {\n if (!value || isNaN(Number(value))) {\n return false;\n }\n return true;\n}\n\n/**\n * Reads one numeric option **at construction time** and returns the number itself.\n *\n * Every numeric filter used to write out the same three lines (`options?.[i] ?? optionsRequired`,\n * `validateNumberString`, `optionMustBeNumber`) and then call `Number(opt)` again on **every\n * apply**. Folding it here keeps the option checks in one place and takes the conversion off the\n * hot path.\n */\nfunction numberOption(value: string, fnName: string): number {\n if (!validateNumberString(value)) {optionMustBeNumber(fnName);}\n return Number(value);\n}\n\n/** A required numeric option: missing → `optionsRequired`, non-numeric → `optionMustBeNumber`. */\nfunction requiredNumberOption(options: string[] | undefined, index: number, fnName: string): number {\n return numberOption(options?.[index] ?? optionsRequired(fnName), fnName);\n}\n\n/**\n * Extends the display-side empty-value contract (requirement B8) to the formatting filters.\n *\n * A filter that builds its result with `String(value)` turns `undefined` / `null` into the\n * *characters* `\"undefined\"` / `\"null\"`, so `attr.title: x|trim` wrote `title=\"undefined\"` where\n * the unfiltered `attr.title: x` correctly removes the attribute — one filter was enough to undo\n * what B8 established. This family therefore passes an absent value straight through and leaves\n * the decision to the apply side (attribute removed, class cleared, style cleared, text emptied).\n *\n * Deliberately **not** wrapped:\n * - filters for which an absent value *is* the input: `defaults` / `coalesce` / `nullIfEmpty` /\n * `boolean` / `truthy` / `falsy` / `not` / `eq` / `ne`;\n * - the conversions, whose whole job is to convert: `int` / `float` / `number` / `string`;\n * - the filters that reject a value of the wrong type (the number, date and array families).\n * Their throw is confined to the one binding and reported through `$errorCallback`\n * (`apply/applyChangeFromBindings.ts`), which is a different quality of failure from silently\n * painting the word \"undefined\" into the page.\n */\nconst nullishPassthrough = (factory: (options?: string[]) => FilterFn<string>): FilterWithOptionsFn =>\n (options?: string[]): FilterFn => {\n const filterFn = factory(options);\n // `== null` は null と undefined の両方(意図的な緩い比較)\n return (value: unknown): unknown => (value == null ? value : filterFn(value));\n };\n\n/**\n * Equality filter - compares value with option.\n * \n * @param options - Array with comparison value as first element\n * @returns Filter function that returns boolean\n */\nconst eq = (options?:string[], literals?: readonly unknown[]): FilterFn<boolean> => {\n const opt = options?.[0] ?? optionsRequired('eq');\n // The typed literal (B9): unquoted true / false / null / numbers are typed, quoted arguments are strings\n const literal = literals !== undefined && literals.length > 0 ? literals[0] : opt;\n return (value: unknown): boolean => {\n // Align types for comparison\n if (typeof value === 'number') {\n // A typed literal that is not a string compares as itself (B9). A number is never equal to\n // `true` / `false` / `null`, so `selectedId|eq(null)` is simply false once the id is a\n // number — it used to throw `optionMustBeNumber` on **every apply**, which broke every\n // binding on a path that is sometimes null and sometimes numeric. Only an unquoted\n // non-number (a bare string such as `eq(abc)`) still reports the type mismatch, and it has\n // to stay inside the closure: `eq` accepts values of any type, so `status|eq(active)` is\n // perfectly valid and cannot be rejected at construction the way `lt` / `add` can.\n if (typeof literal !== 'string') {return value === literal;}\n if (!validateNumberString(opt)) {optionMustBeNumber('eq');}\n return value === Number(opt);\n }\n if (typeof value === 'string') {\n return value === opt;\n }\n // Booleans, null and the rest compare with the typed literal: eq(true) matches true (B9)\n return value === literal;\n }\n}\n\n/**\n * Inequality filter - compares value with option.\n * \n * @param options - Array with comparison value as first element\n * @returns Filter function that returns boolean\n */\nconst ne = (options?:string[], literals?: readonly unknown[]): FilterFn<boolean> => {\n const opt = options?.[0] ?? optionsRequired('ne');\n const literal = literals !== undefined && literals.length > 0 ? literals[0] : opt;\n return (value: unknown): boolean => {\n // Align types for comparison\n if (typeof value === 'number') {\n // Same as `eq`: a typed `true` / `false` / `null` compares as itself instead of being\n // forced through `Number()` (B9)\n if (typeof literal !== 'string') {return value !== literal;}\n if (!validateNumberString(opt)) {optionMustBeNumber('ne');}\n return value !== Number(opt);\n }\n if (typeof value === 'string') {\n return value !== opt;\n }\n // Booleans, null and the rest compare with the typed literal (B9)\n return value !== literal;\n }\n}\n\n/**\n * Boolean NOT filter - inverts the truthiness of the value.\n *\n * Deliberately the same lenient `!value` as the engine-owned copy in\n * `core/filterRegistry.ts` (`CORE_FILTERS.not`). `if:` / `else:` are built as one\n * `if` parse result plus an engine-injected `not` (`structural/createNotFilter.ts`),\n * and `apply/applyChangeToIf.ts` coerces the `if` side with `Boolean()`. A strict\n * `not` therefore made `else:` throw — and render neither branch — whenever the\n * condition was a falsy non-boolean (`0` / `\"\"` / `undefined` / `null`). Keeping the\n * two implementations identical also means a page behaves the same whether or not\n * `features/formats` is installed (the split core entry registers no `not`).\n *\n * @param options - Unused\n * @returns Filter function that returns the inverted truthiness\n */\nconst not = (_options?:string[]): FilterFn<boolean> => {\n return (value: unknown): boolean => !value;\n}\n\n/**\n * Less than filter - checks if value is less than option.\n * \n * @param options - Array with comparison number as first element\n * @returns Filter function that returns boolean\n */\nconst lt = (options?:string[]): FilterFn<boolean> => {\n const opt = requiredNumberOption(options, 0, 'lt');\n return (value: unknown): boolean => {\n if (typeof value !== 'number') {valueMustBeNumber('lt');}\n return value < opt;\n }\n}\n\n/**\n * Less than or equal filter - checks if value is less than or equal to option.\n * \n * @param options - Array with comparison number as first element\n * @returns Filter function that returns boolean\n */\nconst le = (options?:string[]): FilterFn<boolean> => {\n const opt = requiredNumberOption(options, 0, 'le');\n return (value: unknown): boolean => {\n if (typeof value !== 'number') {valueMustBeNumber('le');}\n return value <= opt;\n }\n}\n\n/**\n * Greater than filter - checks if value is greater than option.\n * \n * @param options - Array with comparison number as first element\n * @returns Filter function that returns boolean\n */\nconst gt = (options?:string[]): FilterFn<boolean> => {\n const opt = requiredNumberOption(options, 0, 'gt');\n return (value: unknown): boolean => {\n if (typeof value !== 'number') {valueMustBeNumber('gt');}\n return value > opt;\n }\n}\n\n/**\n * Greater than or equal filter - checks if value is greater than or equal to option.\n * \n * @param options - Array with comparison number as first element\n * @returns Filter function that returns boolean\n */\nconst ge = (options?:string[]): FilterFn<boolean> => {\n const opt = requiredNumberOption(options, 0, 'ge');\n return (value: unknown): boolean => {\n if (typeof value !== 'number') {valueMustBeNumber('ge');}\n return value >= opt;\n }\n}\n\n/**\n * Increment filter - adds option value to input value.\n * \n * @param options - Array with increment number as first element\n * @returns Filter function that returns incremented number\n */\nconst inc = (options?:string[]): FilterFn<number> => {\n const opt = requiredNumberOption(options, 0, 'add');\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('add');}\n return value + opt;\n }\n}\n\n/**\n * Decrement filter - subtracts option value from input value.\n * \n * @param options - Array with decrement number as first element\n * @returns Filter function that returns decremented number\n */\nconst dec = (options?:string[]): FilterFn<number> => {\n const opt = requiredNumberOption(options, 0, 'sub');\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('sub');}\n return value - opt;\n }\n}\n\n/**\n * Multiply filter - multiplies value by option.\n * \n * @param options - Array with multiplier number as first element\n * @returns Filter function that returns multiplied number\n */\nconst mul = (options?:string[]): FilterFn<number> => {\n const opt = requiredNumberOption(options, 0, 'mul');\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('mul');}\n return value * opt;\n }\n}\n\n/**\n * Divide filter - divides value by option.\n * \n * @param options - Array with divisor number as first element\n * @returns Filter function that returns divided number\n */\nconst div = (options?:string[]): FilterFn<number> => {\n const opt = requiredNumberOption(options, 0, 'div');\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('div');}\n return value / opt;\n }\n}\n\n/**\n * Modulo filter - returns remainder of division.\n * \n * @param options - Array with divisor number as first element\n * @returns Filter function that returns remainder\n */\nconst mod = (options?:string[]): FilterFn<number> => {\n const opt = requiredNumberOption(options, 0, 'mod');\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('mod');}\n return value % opt;\n }\n}\n\n/**\n * Absolute value filter - returns the magnitude of a number.\n *\n * @param options - Unused\n * @returns Filter function that returns the absolute value\n */\nconst abs = (_options?:string[]): FilterFn<number> => {\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('abs');}\n return Math.abs(value);\n }\n}\n\n/**\n * Clamp filter - constrains a number to the inclusive range [min, max].\n *\n * Saturating conversion in the same family as round/floor/ceil, so it stays on\n * the wire rather than in state. Pairs with `unit` for style bindings:\n * `style.width: ratio|clamp(0,1)|percent(0)`.\n *\n * @param options - Array with minimum as first element and maximum as second (both required)\n * @returns Filter function that returns the clamped number\n */\nconst clamp = (options?:string[]): FilterFn<number> => {\n const min = requiredNumberOption(options, 0, 'clamp');\n const max = requiredNumberOption(options, 1, 'clamp');\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('clamp');}\n return Math.min(Math.max(value, min), max);\n }\n}\n\n/**\n * Fixed decimal filter - formats number to fixed decimal places.\n *\n * @param options - Array with decimal places as first element (default: 0)\n * @returns Filter function that returns formatted string\n */\nconst fix = (options?:string[]): FilterFn<string> => {\n const opt = numberOption(options?.[0] ?? \"0\", 'toFixed');\n return (value: unknown): string => {\n if (typeof value !== 'number') {valueMustBeNumber('toFixed');}\n return value.toFixed(opt);\n }\n}\n\n/**\n * Locale number filter - formats number according to locale.\n *\n * ロケール依存フィルタ(`locale` / `date` / `time` / `datetime`)は\n * **明示引数だけを構築時に確定し、既定の `config.locale` は適用のたびに読む**。\n *\n * 以前は `options?.[0] ?? config.locale` を返り値の関数の**外**で解決していた。\n * フィルタ関数はバインド構築時に一度だけ作られるので、これはロケールを\n * クロージャに焼き込むことを意味する。`config.locale` の確定がバインド構築より\n * 遅れると、それ以降どう直しても「同じページの中で日付だけ既定ロケール」が\n * 永続し、しかも `config.locale` は依存グラフに載らないので再描画で回復もしない。\n * 症状(日付だけ英語)は原因(起動順序)から遠く、追いにくい。\n *\n * 適用のたびに読めば、少なくとも**再適用されたバインドは回復する**。ロケールは\n * 起動時に確定する前提(docs/i18n-design.md D1)なので通常この差は現れず、\n * これは順序事故から復帰できるようにするための保険である。\n *\n * 明示引数(`|date(ja-JP)`)は構築時に固定でよい — バインド式の一部であり、\n * 実行中に変わらない。\n *\n * @param options - Array with locale string as first element (default: config.locale)\n * @returns Filter function that returns localized number string\n */\nconst locale = (options?:string[]): FilterFn<string> => {\n const explicit = options?.[0];\n return (value: unknown): string => {\n if (typeof value !== 'number') {valueMustBeNumber('locale');}\n return value.toLocaleString(explicit ?? config.locale);\n }\n}\n\n/**\n * Uppercase filter - converts string to uppercase.\n * \n * @param options - Unused\n * @returns Filter function that returns uppercase string\n */\nconst uc = (_options?:string[]): FilterFn<string> => {\n return (value: unknown): string => {\n return String(value).toUpperCase();\n }\n}\n\n/**\n * Lowercase filter - converts string to lowercase.\n * \n * @param options - Unused\n * @returns Filter function that returns lowercase string\n */\nconst lc = (_options?:string[]): FilterFn<string> => {\n return (value: unknown): string => {\n return String(value).toLowerCase();\n }\n}\n\n/**\n * Capitalize filter - capitalizes first character of string.\n * \n * @param options - Unused\n * @returns Filter function that returns capitalized string\n */\nconst cap = (_options?:string[]): FilterFn<string> => {\n return (value: unknown): string => {\n const v = String(value);\n if (v.length === 0) {return v;}\n if (v.length === 1) {return v.toUpperCase();}\n return v.charAt(0).toUpperCase() + v.slice(1);\n }\n}\n\n/**\n * Trim filter - removes whitespace from both ends of string.\n * \n * @param options - Unused\n * @returns Filter function that returns trimmed string\n */\nconst trim = (_options?:string[]): FilterFn<string> => {\n return (value: unknown): string => {\n return String(value).trim();\n }\n}\n\n/**\n * Slice filter - extracts portion of string from specified index.\n * \n * @param options - Array with start index and optional end index\n * @returns Filter function that returns sliced string\n */\nconst slice = (options?:string[]): FilterFn<string> => {\n const numberedOpts: number[] = [requiredNumberOption(options, 0, 'slice')];\n const opt2 = options?.[1];\n if (typeof opt2 !== 'undefined') {\n numberedOpts.push(numberOption(opt2, 'slice'));\n }\n return (value: unknown): string => {\n return String(value).slice(...numberedOpts);\n }\n}\n\n/**\n * Substring filter - extracts substring from specified position and length.\n * \n * @param options - Array with start index and length\n * @returns Filter function that returns substring\n */\nconst substr = (options?:string[]): FilterFn<string> => {\n const opt1 = requiredNumberOption(options, 0, 'substr');\n const opt2 = requiredNumberOption(options, 1, 'substr');\n return (value: unknown): string => {\n return String(value).substr(opt1, opt2);\n }\n}\n\n/**\n * Pad filter - pads string to specified length from start.\n * \n * @param options - Array with target length and pad string (default: '0')\n * @returns Filter function that returns padded string\n */\nconst pad = (options?:string[]): FilterFn<string> => {\n const opt1 = requiredNumberOption(options, 0, 'padStart');\n const opt2 = options?.[1] ?? '0';\n return (value: unknown): string => {\n return String(value).padStart(opt1, opt2);\n }\n}\n\n/**\n * padEnd filter - pads string to specified length from the end (the pair of `padStart`, requirement B12).\n *\n * @param options - Array with target length and pad string (default: ' ')\n * @returns Filter function that returns padded string\n */\nconst padEnd = (options?:string[]): FilterFn<string> => {\n const opt1 = requiredNumberOption(options, 0, 'padEnd');\n const opt2 = options?.[1] ?? ' ';\n return (value: unknown): string => {\n return String(value).padEnd(opt1, opt2);\n }\n}\n\n/**\n * Repeat filter - repeats string specified number of times.\n * \n * @param options - Array with repeat count as first element\n * @returns Filter function that returns repeated string\n */\nconst rep = (options?:string[]): FilterFn<string> => {\n const opt = requiredNumberOption(options, 0, 'repeat');\n return (value: unknown): string => {\n return String(value).repeat(opt);\n }\n}\n\n/**\n * Reverse filter - reverses character order in string.\n * \n * @param options - Unused\n * @returns Filter function that returns reversed string\n */\nconst rev = (_options?:string[]): FilterFn<string> => {\n return (value: unknown): string => {\n return String(value).split('').reverse().join('');\n }\n}\n\n/**\n * Integer filter - parses value to integer.\n * \n * @param options - Unused\n * @returns Filter function that returns integer\n */\nconst int = (_options?:string[]): FilterFn<number> => {\n return (value: unknown): number => {\n return parseInt(String(value), 10);\n }\n}\n\n/**\n * Float filter - parses value to floating point number.\n * \n * @param options - Unused\n * @returns Filter function that returns float\n */\nconst float = (_options?:string[]): FilterFn<number> => {\n return (value: unknown): number => {\n return parseFloat(String(value));\n }\n}\n\n/**\n * Round filter - rounds number to specified decimal places.\n * \n * @param options - Array with decimal places as first element (default: 0)\n * @returns Filter function that returns rounded number\n */\nconst round = (options?:string[]): FilterFn<number> => {\n const optValue = Math.pow(10, numberOption(options?.[0] ?? '0', 'round'));\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('round');}\n return Math.round(value * optValue) / optValue;\n }\n}\n\n/**\n * Floor filter - rounds number down to specified decimal places.\n * \n * @param options - Array with decimal places as first element (default: 0)\n * @returns Filter function that returns floored number\n */\nconst floor = (options?:string[]): FilterFn<number> => {\n const optValue = Math.pow(10, numberOption(options?.[0] ?? '0', 'floor'));\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('floor');}\n return Math.floor(value * optValue) / optValue;\n }\n}\n\n/**\n * Ceiling filter - rounds number up to specified decimal places.\n * \n * @param options - Array with decimal places as first element (default: 0)\n * @returns Filter function that returns ceiled number\n */\nconst ceil = (options?:string[]): FilterFn<number> => {\n const optValue = Math.pow(10, numberOption(options?.[0] ?? '0', 'ceil'));\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('ceil');}\n return Math.ceil(value * optValue) / optValue;\n }\n}\n\n/**\n * Percent filter - formats number as percentage string.\n * \n * @param options - Array with decimal places as first element (default: 0)\n * @returns Filter function that returns percentage string with '%'\n */\nconst percent = (options?:string[]): FilterFn<string> => {\n const opt = numberOption(options?.[0] ?? '0', 'percent');\n return (value: unknown): string => {\n if (typeof value !== 'number') {valueMustBeNumber('percent');}\n return `${(value * 100).toFixed(opt)}%`;\n }\n}\n\n/**\n * Unit filter - appends a CSS unit (or any suffix) to the value.\n *\n * A number alone does nothing in CSS, so without this the unit has to be built in\n * state — which drags presentation into the source of truth, and in the worst case\n * forces a whole derived array just to carry `\"42%\"` strings.\n * `style.height: samples.*.cpu|clamp(0,100)|fix(0)|unit(%)` keeps it on the wire.\n *\n * Accepts strings as well as numbers **on purpose**: the useful chains run through\n * `fix` / `percent`, which already return strings. Rejecting non-numbers here would\n * break exactly the combination this filter exists for.\n *\n * `null` / `undefined` pass through untouched rather than becoming `\"undefinedpx\"`, so the\n * binding layer's \"undefined skips the write, null clears\" semantics survive. That guard is no\n * longer written here: it is `nullishPassthrough`, shared with the rest of the `String(value)`\n * family, which used to paint `\"undefined\"` into the page for exactly the same reason.\n *\n * @param options - Array with the unit/suffix as first element (required)\n * @returns Filter function that returns the value with the unit appended\n */\nconst unit = (options?:string[]): FilterFn<string> => {\n const opt = options?.[0] ?? optionsRequired('unit');\n return (value: unknown): string => {\n return String(value) + opt;\n }\n}\n\n/**\n * Join filter - joins array elements into a string.\n *\n * The default separator is `\", \"` rather than `\",\"`: a bare comma is what `String()`\n * already produces without any filter, so defaulting to it would make `|join` a no-op.\n *\n * @param options - Array with separator as first element (default: ', ')\n * @returns Filter function that returns the joined string\n */\nconst join = (options?:string[]): FilterFn<string> => {\n const opt = options?.[0] ?? ', ';\n return (value: unknown): string => {\n if (!Array.isArray(value)) {valueMustBeArray('join');}\n return value.join(opt);\n }\n}\n\n/**\n * Truncate filter - shortens a string and appends an ellipsis.\n *\n * The length option counts **kept characters**, not the total including the suffix,\n * matching the existing `slice(0, n)` reading. A string at or below the limit is\n * returned untouched (no suffix).\n *\n * @param options - Array with max kept length as first element and suffix as second (default: '…')\n * @returns Filter function that returns the truncated string\n */\nconst truncate = (options?:string[]): FilterFn<string> => {\n const maxLength = requiredNumberOption(options, 0, 'truncate');\n const suffix = options?.[1] ?? '…';\n return (value: unknown): string => {\n const v = String(value);\n if (v.length <= maxLength) {return v;}\n return v.slice(0, maxLength) + suffix;\n }\n}\n\n/**\n * Date filter - formats Date object as localized date string.\n *\n * @param options - Array with locale string as first element (default: config.locale)\n * @returns Filter function that returns date string\n */\nconst date = (options?:string[]): FilterFn<string> => {\n // 既定ロケールは適用のたびに読む(`locale` フィルタの注記を参照)\n const explicit = options?.[0];\n return (value: unknown): string => {\n if (!(value instanceof Date)) {valueMustBeDate('date');}\n return value.toLocaleDateString(explicit ?? config.locale);\n }\n}\n\n/**\n * Time filter - formats Date object as localized time string.\n * \n * @param options - Array with locale string as first element (default: config.locale)\n * @returns Filter function that returns time string\n */\nconst time = (options?:string[]): FilterFn<string> => {\n // 既定ロケールは適用のたびに読む(`locale` フィルタの注記を参照)\n const explicit = options?.[0];\n return (value: unknown): string => {\n if (!(value instanceof Date)) {valueMustBeDate('time');}\n return value.toLocaleTimeString(explicit ?? config.locale);\n }\n}\n\n/**\n * DateTime filter - formats Date object as localized date and time string.\n * \n * @param options - Array with locale string as first element (default: config.locale)\n * @returns Filter function that returns datetime string\n */\nconst datetime = (options?:string[]): FilterFn<string> => {\n // 既定ロケールは適用のたびに読む(`locale` フィルタの注記を参照)\n const explicit = options?.[0];\n return (value: unknown): string => {\n if (!(value instanceof Date)) {valueMustBeDate('datetime');}\n return value.toLocaleString(explicit ?? config.locale);\n }\n}\n\n/**\n * Year-Month-Day filter - formats Date object as YYYY-MM-DD string.\n * \n * @param options - Array with separator string as first element (default: '-')\n * @returns Filter function that returns formatted date string\n */\nconst ymd = (options?:string[]): FilterFn<string> => {\n const opt = options?.[0] ?? '-';\n return (value: unknown): string => {\n if (!(value instanceof Date)) {valueMustBeDate('ymd');}\n const year = value.getFullYear().toString();\n const month = (value.getMonth() + 1).toString().padStart(2, '0');\n const day = value.getDate().toString().padStart(2, '0');\n return `${year}${opt}${month}${opt}${day}`;\n }\n}\n\n/**\n * Hour-Minute-Second filter - formats Date object as HH:MM:SS string.\n *\n * The counterpart of `ymd`: a fixed, zero-padded, locale-independent rendering with a\n * configurable separator, for when `time` (locale-formatted) is not stable enough.\n *\n * @param options - Array with separator string as first element (default: ':')\n * @returns Filter function that returns formatted time string\n */\nconst hms = (options?:string[]): FilterFn<string> => {\n const opt = options?.[0] ?? ':';\n return (value: unknown): string => {\n if (!(value instanceof Date)) {valueMustBeDate('hms');}\n const hours = value.getHours().toString().padStart(2, '0');\n const minutes = value.getMinutes().toString().padStart(2, '0');\n const seconds = value.getSeconds().toString().padStart(2, '0');\n return `${hours}${opt}${minutes}${opt}${seconds}`;\n }\n}\n\n/**\n * Falsy filter - checks if value is falsy, by JavaScript's own truthiness (`!value`: false, null,\n * undefined, 0, -0, 0n, '' and NaN). Before 3.0 the list was spelled out and missed 0n (B10).\n *\n * @param options - Unused\n * @returns Filter function that returns true for falsy values\n */\nconst falsy = (_options?:string[]): FilterFn<boolean> => {\n return (value: unknown): boolean => !value;\n}\n\n/**\n * Truthy filter - checks if value is truthy.\n * \n * @param options - Unused\n * @returns Filter function that returns true for non-falsy values\n */\nconst truthy = (_options?:string[]): FilterFn<boolean> => {\n // JavaScript's truthiness, the same as the `boolean` filter (B10)\n return (value: unknown): boolean => !!value;\n}\n\n/**\n * Default filter - returns default value if input is falsy (JavaScript's truthiness, as `falsy`).\n * \n * @param options - Array with default value as first element\n * @returns Filter function that returns value or default\n */\nconst defaults = (options?:string[], literals?: readonly unknown[]): FilterFn<unknown> => {\n const opt = options?.[0] ?? optionsRequired('defaults');\n // The fallback is the typed literal (B9): defaults(0) gives 0, defaults(null) gives null, defaults('0') gives \"0\"\n const fallback = literals !== undefined && literals.length > 0 ? literals[0] : opt;\n return (value: unknown): unknown => {\n if (!value) {return fallback;}\n return value;\n }\n}\n\n/**\n * coalesce filter - returns the default only for null / undefined (`defaults` also replaces 0, false and \"\").\n * Requirement B12: the nullish counterpart of `defaults`, read like SQL COALESCE.\n *\n * @param options - Array with default value as first element\n * @returns Filter function that returns value or default\n */\nconst coalesce = (options?:string[], literals?: readonly unknown[]): FilterFn<unknown> => {\n const opt = options?.[0] ?? optionsRequired('coalesce');\n const fallback = literals !== undefined && literals.length > 0 ? literals[0] : opt;\n return (value: unknown): unknown => value ?? fallback;\n}\n\n/**\n * Boolean filter - converts value to boolean.\n * \n * @param options - Unused\n * @returns Filter function that returns boolean\n */\nconst boolean = (_options?:string[]): FilterFn<boolean> => {\n return (value: unknown): boolean => {\n return Boolean(value);\n }\n}\n\n/**\n * Number filter - converts value to number.\n * \n * @param options - Unused\n * @returns Filter function that returns number\n */\nconst number = (_options?:string[]): FilterFn<number> => {\n return (value: unknown): number => {\n return Number(value);\n }\n}\n\n/**\n * String filter - converts value to string.\n * \n * @param options - Unused\n * @returns Filter function that returns string\n */\nconst string = (_options?:string[]): FilterFn<string> => {\n return (value: unknown): string => {\n return String(value);\n }\n}\n\n/**\n * Null filter - converts empty string to null.\n * \n * @param options - Unused\n * @returns Filter function that returns null for empty string, otherwise original value\n */\nconst _null = (_options?:string[]): FilterFn<unknown> => {\n return (value: unknown): unknown => {\n return (value === \"\") ? null : value;\n } \n}\n\nconst builtinFilters: FilterWithOptions = {\n \"eq\": eq,\n \"ne\": ne,\n \"not\": not,\n\n \"lt\": lt,\n \"le\": le,\n \"gt\": gt,\n \"ge\": ge,\n\n \"add\": inc,\n \"sub\": dec,\n \"mul\": mul,\n \"div\": div,\n \"mod\": mod,\n \"abs\": abs,\n \"clamp\": clamp,\n\n \"toFixed\": fix,\n \"locale\": locale,\n // `String(value)` で組み立てる族は、値が無いときに素通しする(要件 B8 — nullishPassthrough を参照)\n \"upper\": nullishPassthrough(uc),\n \"lower\": nullishPassthrough(lc),\n \"capitalize\": nullishPassthrough(cap),\n \"trim\": nullishPassthrough(trim),\n \"slice\": nullishPassthrough(slice),\n \"substr\": nullishPassthrough(substr),\n \"padStart\": nullishPassthrough(pad),\n \"padEnd\": nullishPassthrough(padEnd),\n \"repeat\": nullishPassthrough(rep),\n \"reverse\": nullishPassthrough(rev),\n \"truncate\": nullishPassthrough(truncate),\n \"join\": join,\n\n \"int\": int,\n \"float\": float,\n \"round\": round,\n \"floor\": floor,\n \"ceil\": ceil,\n \"percent\": percent,\n \"unit\": nullishPassthrough(unit),\n\n \"date\": date,\n \"time\": time,\n \"datetime\": datetime,\n \"ymd\": ymd,\n \"hms\": hms,\n\n \"falsy\": falsy,\n \"truthy\": truthy,\n \"defaults\": defaults,\n \"coalesce\": coalesce,\n\n \"boolean\": boolean,\n \"number\": number,\n \"string\": string,\n \"nullIfEmpty\": _null,\n};\n\n/**\n * The argument count each built-in accepts, [min, max] — checked when the bindings are planned\n * (`[wcs/filter-arity]`, requirement B3), with the same bounds lint uses. It is the same data as\n * `builtinFilterMeta` (filters/filterMeta.ts) without the descriptions, so that installing the formats\n * does not pull the metadata into the page; a test keeps the two equal.\n */\nexport const builtinFilterArity: Readonly<Record<string, readonly [number, number]>> = {\n eq: [1, 1],\n not: [0, 0],\n ne: [1, 1],\n lt: [1, 1],\n le: [1, 1],\n gt: [1, 1],\n ge: [1, 1],\n add: [1, 1],\n sub: [1, 1],\n mul: [1, 1],\n div: [1, 1],\n mod: [1, 1],\n abs: [0, 0],\n clamp: [2, 2],\n toFixed: [0, 1],\n locale: [0, 1],\n upper: [0, 0],\n lower: [0, 0],\n capitalize: [0, 0],\n trim: [0, 0],\n slice: [1, 2],\n // `substr` は長さも必須(実装が両方読む・README も `substr(start, length)`)。\n // [1, 2] だったころは `substr(0)` が引数の個数の検査を素通りし、工場の\n // 「requires at least one option」という的外れな文言で落ちていた\n substr: [2, 2],\n padStart: [1, 2],\n padEnd: [1, 2],\n repeat: [1, 1],\n reverse: [0, 0],\n truncate: [1, 2],\n join: [0, 1],\n int: [0, 0],\n float: [0, 0],\n round: [0, 1],\n floor: [0, 1],\n ceil: [0, 1],\n percent: [0, 1],\n unit: [1, 1],\n // ロケール依存の 3 つは `locale` と同じく引数 1 つ(`date(ja-JP)`)を受ける。\n // [0, 0] だったころは、README が規範として書いている `timestamp|date(ja-JP)` が\n // 束縛計画の段で必ず `[wcs/filter-arity]` になっていた(2.x には検査自体が無かった)\n date: [0, 1],\n time: [0, 1],\n datetime: [0, 1],\n ymd: [0, 1],\n hms: [0, 1],\n falsy: [0, 0],\n truthy: [0, 0],\n defaults: [1, 1],\n coalesce: [1, 1],\n boolean: [0, 0],\n number: [0, 0],\n string: [0, 0],\n nullIfEmpty: [0, 0],\n};\n\nexport const outputBuiltinFilters = builtinFilters;\nexport const inputBuiltinFilters = builtinFilters;\n\nexport const builtinFiltersByFilterIOType = {\n \"input\": inputBuiltinFilters,\n \"output\": outputBuiltinFilters,\n} as const;\n\n/**\n * Retrieves built-in filter function by name and options.\n *\n * **Test / tooling only.** The binding pipeline never goes through here: it resolves\n * filters from the registry with `core/filterRegistry.ts#resolveFilterFn`, which also\n * checks `builtinFilterArity` and passes the **typed literals** (requirement B9).\n * This helper takes raw option strings only, so `builtinFilterFn(\"coalesce\", [\"0\"])`\n * yields the string `\"0\"` where the runtime yields the number `0`. Prefer\n * `resolveFilterFn` in any new code, and treat a difference between the two as a\n * limitation of this helper rather than of the runtime.\n *\n * @param name - Filter name (a 3.x alias such as `uc` resolves to its canonical name)\n * @param options - Array of option strings\n * @returns Function that takes FilterWithOptions and returns filter function\n */\nexport const builtinFilterFn = (name:string, options: string[]) => (filters: FilterWithOptions) => {\n // 自前のキーだけを引く。素のオブジェクトへのブラケット参照だと `Object.prototype` のメンバが\n // フィルタとして通り(`toString` / `constructor` / `valueOf`)、`[wcs/filter-unknown]` の代わりに\n // `\"[object Undefined]\"` や素の TypeError が出ていた。登録簿(core/filterRegistry.ts)が\n // まさにこの穴のために `Map` を採っているのと同じ規準\n const own = Object.prototype.hasOwnProperty;\n const canonical = own.call(builtinFilterAliases, name) ? builtinFilterAliases[name] : name;\n const filter = own.call(filters, canonical) ? filters[canonical] : undefined;\n if (!filter) {\n // lint の wcs/filter-unknown と同じ語彙・同じ did-you-mean 規準(三面同語彙)。\n raiseError(`[wcs/filter-unknown] filter not found: ${name}.${didYouMean(name, Object.keys(filters))}${LINT_HINT}`);\n }\n return filter(options);\n}\n\n","/**\n * formats/install.ts — 書式フィルタ群の install(設計案 §4、要件 D16)。\n *\n * `uc` / `date` / `round` / `truncate` … の実装を core の登録簿へ置く。core 自身が持つのは\n * エンジンが差し込む `not` だけなので、この機能を入れないページでは、宣言されたフィルタが\n * 束縛計画の段で `[wcs/filter-unknown]` として名指しで落ちる(黙って素通ししない)。\n */\nimport { registerFilters } from \"../core/filterRegistry\";\nimport { builtinFilterArity, inputBuiltinFilters, outputBuiltinFilters } from \"./builtinFilters\";\nimport { builtinFilterAliases } from \"../filters/filterAliases\";\n\nlet installed = false;\n/** 冪等。full / auto では `bootstrapState()` が呼ぶ */\nexport function installFormats(): void {\n if (installed) return;\n installed = true;\n registerFilters(\"input\", inputBuiltinFilters, builtinFilterArity, builtinFilterAliases);\n registerFilters(\"output\", outputBuiltinFilters, builtinFilterArity, builtinFilterAliases);\n}\n","/**\n * features/formats.ts — 書式フィルタ群(@wcstack/state/features/formats)。\n * `|uc` `|date(…)` `|round(…)` のような宣言が要求する実関数を core の登録簿へ置く。\n */\nimport type { IStateFeature } from \"../core/features\";\nimport { installFormats } from \"../formats/install\";\n\nexport const formats: IStateFeature = {\n name: \"formats\",\n install(): void {\n installFormats();\n },\n};\nexport default formats;\n"],"names":["optionsRequired","fnName","raiseError","optionMustBeNumber","valueMustBeNumber","valueMustBeDate","builtinFilterAliases","inc","dec","fix","uc","lc","cap","rep","rev","pad","null","validateNumberString","value","isNaN","Number","numberOption","requiredNumberOption","options","index","nullishPassthrough","factory","filterFn","builtinFilters","eq","literals","opt","literal","undefined","length","ne","not","_options","lt","le","gt","ge","add","sub","mul","div","mod","abs","Math","clamp","min","max","toFixed","locale","explicit","toLocaleString","config","upper","String","toUpperCase","lower","toLowerCase","capitalize","v","charAt","slice","trim","numberedOpts","opt2","push","substr","opt1","padStart","padEnd","repeat","reverse","split","join","truncate","maxLength","suffix","Array","isArray","int","parseInt","float","parseFloat","round","optValue","pow","floor","ceil","percent","unit","date","Date","toLocaleDateString","time","toLocaleTimeString","datetime","ymd","year","getFullYear","toString","month","getMonth","day","getDate","hms","hours","getHours","minutes","getMinutes","seconds","getSeconds","falsy","truthy","defaults","fallback","coalesce","boolean","Boolean","number","string","nullIfEmpty","builtinFilterArity","outputBuiltinFilters","inputBuiltinFilters","installed","formats","name","install","registerFilters"],"mappings":"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"}
1
+ {"version":3,"file":"formats.js","sources":["../../../../../src/formats/errorMessages.ts","../../../../../src/filters/filterAliases.ts","../../../../../src/formats/builtinFilters.ts","../../../../../src/formats/install.ts","../../../../../src/features/formats.ts"],"sourcesContent":["/**\n * errorMessages.ts\n *\n * Error message generation utilities used by filter functions.\n *\n * Main responsibilities:\n * - Throws clear error messages when filter options or value type checks fail\n * - Takes function name as argument to specify which filter caused the error\n *\n * Design points:\n * - optionsRequired: Error when required option is not specified\n * - optionMustBeNumber: Error when option value is not a number\n * - valueMustBeNumber: Error when value is not a number\n * - valueMustBeDate: Error when value is not a Date\n * - valueMustBeArray: Error when value is not an array\n */\nimport { raiseError } from \"../raiseError\";\n\n/**\n * Throws error when filter requires at least one option but none provided.\n * \n * @param fnName - Name of the filter function\n * @returns Never returns (always throws)\n */\nexport function optionsRequired(fnName:string): never {\n raiseError(`filter ${fnName} requires at least one option`);\n}\n\n/**\n * Throws error when filter option must be a number but invalid value provided.\n * \n * @param fnName - Name of the filter function\n * @returns Never returns (always throws)\n */\nexport function optionMustBeNumber(fnName:string): never {\n raiseError(`filter ${fnName} requires a number as option`);\n}\n\n/**\n * Throws error when filter requires numeric value but non-number provided.\n * \n * @param fnName - Name of the filter function\n * @returns Never returns (always throws)\n */\nexport function valueMustBeNumber(fnName:string): never {\n raiseError(`filter ${fnName} requires a number value`);\n}\n\n/**\n * Throws error when filter requires Date value but non-Date provided.\n *\n * @param fnName - Name of the filter function\n * @returns Never returns (always throws)\n */\nexport function valueMustBeDate(fnName:string): never {\n raiseError(`filter ${fnName} requires a date value`);\n}\n\n/**\n * Throws error when filter requires array value but non-array provided.\n *\n * @param fnName - Name of the filter function\n * @returns Never returns (always throws)\n */\nexport function valueMustBeArray(fnName:string): never {\n raiseError(`filter ${fnName} requires an array value`);\n}","/**\n * filters/filterAliases.ts — 組み込みフィルタの旧名 → 正式名(要件 B12・docs/state-3x-naming.ja.md V1〜V9)。\n *\n * 旧名は 3.x の間エイリアスとして残り、4.0 で外す(D4)。解決は登録簿(core/filterRegistry)が行い、\n * 実装・引数の個数・メタデータは正式名だけが持つ。formats の install と manifest(tooling)の両方が読むので、\n * 実装にもメタデータにも依存しない小さな表として独立させている。\n */\nexport const builtinFilterAliases: Readonly<Record<string, string>> = {\n inc: \"add\",\n dec: \"sub\",\n fix: \"toFixed\",\n uc: \"upper\",\n lc: \"lower\",\n cap: \"capitalize\",\n rep: \"repeat\",\n rev: \"reverse\",\n pad: \"padStart\",\n null: \"nullIfEmpty\",\n};\n","/**\n * builtinFilters.ts\n *\n * Implementation file for built-in filter functions available in Structive.\n *\n * Main responsibilities:\n * - Provides filters for conversion, comparison, formatting, and validation of numbers, strings, dates, booleans, etc.\n * - Defines functions with options for each filter name, enabling flexible use during binding\n * - Designed for common use as both input and output filters\n *\n * Design points:\n * - Comprehensive coverage of diverse filters: eq, ne, lt, gt, inc, abs, clamp, fix, locale, uc, lc, cap, trim, slice, pad, truncate, join, int, float, round, percent, unit, date, time, ymd, hms, falsy, truthy, defaults, boolean, number, string, null, etc.\n * - Rich type checking and error handling for option values\n * - Centralized management of filter functions with FilterWithOptions type, easy to extend\n * - Dynamic retrieval of filter functions from filter names and options via builtinFilterFn\n */\nimport { config } from \"../config.js\";\nimport { didYouMean, LINT_HINT } from \"../errorGuidance.js\";\nimport { raiseError } from \"../raiseError.js\";\nimport { optionMustBeNumber, optionsRequired, valueMustBeArray, valueMustBeDate, valueMustBeNumber } from \"./errorMessages.js\";\nimport { FilterFn, FilterWithOptions, FilterWithOptionsFn } from \"../filters/types\";\nimport { builtinFilterAliases } from \"../filters/filterAliases\";\nimport { v4Migration } from \"../core/v4MigrationHooks\";\n\nfunction validateNumberString(value: string): boolean {\n if (!value || isNaN(Number(value))) {\n return false;\n }\n return true;\n}\n\n/**\n * Reads one numeric option **at construction time** and returns the number itself.\n *\n * Every numeric filter used to write out the same three lines (`options?.[i] ?? optionsRequired`,\n * `validateNumberString`, `optionMustBeNumber`) and then call `Number(opt)` again on **every\n * apply**. Folding it here keeps the option checks in one place and takes the conversion off the\n * hot path.\n */\nfunction numberOption(value: string, fnName: string): number {\n if (!validateNumberString(value)) {optionMustBeNumber(fnName);}\n return Number(value);\n}\n\n/** A required numeric option: missing → `optionsRequired`, non-numeric → `optionMustBeNumber`. */\nfunction requiredNumberOption(options: string[] | undefined, index: number, fnName: string): number {\n return numberOption(options?.[index] ?? optionsRequired(fnName), fnName);\n}\n\n/**\n * Extends the display-side empty-value contract (requirement B8) to the formatting filters.\n *\n * A filter that builds its result with `String(value)` turns `undefined` / `null` into the\n * *characters* `\"undefined\"` / `\"null\"`, so `attr.title: x|trim` wrote `title=\"undefined\"` where\n * the unfiltered `attr.title: x` correctly removes the attribute — one filter was enough to undo\n * what B8 established. This family therefore passes an absent value straight through and leaves\n * the decision to the apply side (attribute removed, class cleared, style cleared, text emptied).\n *\n * Deliberately **not** wrapped:\n * - filters for which an absent value *is* the input: `defaults` / `coalesce` / `nullIfEmpty` /\n * `boolean` / `truthy` / `falsy` / `not` / `eq` / `ne`;\n * - the conversions, whose whole job is to convert: `int` / `float` / `number` / `string`;\n * - the filters that reject a value of the wrong type (the number, date and array families).\n * Their throw is confined to the one binding and reported through `$errorCallback`\n * (`apply/applyChangeFromBindings.ts`), which is a different quality of failure from silently\n * painting the word \"undefined\" into the page.\n */\nconst nullishPassthrough = (factory: (options?: string[]) => FilterFn<string>): FilterWithOptionsFn =>\n (options?: string[]): FilterFn => {\n const filterFn = factory(options);\n // `== null` は null と undefined の両方(意図的な緩い比較)\n return (value: unknown): unknown => (value == null ? value : filterFn(value));\n };\n\n/**\n * Equality filter - compares value with option.\n * \n * @param options - Array with comparison value as first element\n * @returns Filter function that returns boolean\n */\nconst eq = (options?:string[], literals?: readonly unknown[]): FilterFn<boolean> => {\n const opt = options?.[0] ?? optionsRequired('eq');\n // The typed literal (B9): unquoted true / false / null / numbers are typed, quoted arguments are strings\n const literal = literals !== undefined && literals.length > 0 ? literals[0] : opt;\n return (value: unknown): boolean => {\n // Align types for comparison\n if (typeof value === 'number') {\n // A typed literal that is not a string compares as itself (B9). A number is never equal to\n // `true` / `false` / `null`, so `selectedId|eq(null)` is simply false once the id is a\n // number — it used to throw `optionMustBeNumber` on **every apply**, which broke every\n // binding on a path that is sometimes null and sometimes numeric. Only an unquoted\n // non-number (a bare string such as `eq(abc)`) still reports the type mismatch, and it has\n // to stay inside the closure: `eq` accepts values of any type, so `status|eq(active)` is\n // perfectly valid and cannot be rejected at construction the way `lt` / `add` can.\n if (typeof literal !== 'string') {return value === literal;}\n if (!validateNumberString(opt)) {optionMustBeNumber('eq');}\n return value === Number(opt);\n }\n if (typeof value === 'string') {\n return value === opt;\n }\n // Booleans, null and the rest compare with the typed literal: eq(true) matches true (B9)\n return value === literal;\n }\n}\n\n/**\n * Inequality filter - compares value with option.\n * \n * @param options - Array with comparison value as first element\n * @returns Filter function that returns boolean\n */\nconst ne = (options?:string[], literals?: readonly unknown[]): FilterFn<boolean> => {\n const opt = options?.[0] ?? optionsRequired('ne');\n const literal = literals !== undefined && literals.length > 0 ? literals[0] : opt;\n return (value: unknown): boolean => {\n // Align types for comparison\n if (typeof value === 'number') {\n // Same as `eq`: a typed `true` / `false` / `null` compares as itself instead of being\n // forced through `Number()` (B9)\n if (typeof literal !== 'string') {return value !== literal;}\n if (!validateNumberString(opt)) {optionMustBeNumber('ne');}\n return value !== Number(opt);\n }\n if (typeof value === 'string') {\n return value !== opt;\n }\n // Booleans, null and the rest compare with the typed literal (B9)\n return value !== literal;\n }\n}\n\n/**\n * Boolean NOT filter - inverts the truthiness of the value.\n *\n * Deliberately the same lenient `!value` as the engine-owned copy in\n * `core/filterRegistry.ts` (`CORE_FILTERS.not`). `if:` / `else:` are built as one\n * `if` parse result plus an engine-injected `not` (`structural/createNotFilter.ts`),\n * and `apply/applyChangeToIf.ts` coerces the `if` side with `Boolean()`. A strict\n * `not` therefore made `else:` throw — and render neither branch — whenever the\n * condition was a falsy non-boolean (`0` / `\"\"` / `undefined` / `null`). Keeping the\n * two implementations identical also means a page behaves the same whether or not\n * `features/formats` is installed (the split core entry registers no `not`).\n *\n * @param options - Unused\n * @returns Filter function that returns the inverted truthiness\n */\nconst not = (_options?:string[]): FilterFn<boolean> => {\n return (value: unknown): boolean => !value;\n}\n\n/**\n * Less than filter - checks if value is less than option.\n * \n * @param options - Array with comparison number as first element\n * @returns Filter function that returns boolean\n */\nconst lt = (options?:string[]): FilterFn<boolean> => {\n const opt = requiredNumberOption(options, 0, 'lt');\n return (value: unknown): boolean => {\n if (typeof value !== 'number') {valueMustBeNumber('lt');}\n return value < opt;\n }\n}\n\n/**\n * Less than or equal filter - checks if value is less than or equal to option.\n * \n * @param options - Array with comparison number as first element\n * @returns Filter function that returns boolean\n */\nconst le = (options?:string[]): FilterFn<boolean> => {\n const opt = requiredNumberOption(options, 0, 'le');\n return (value: unknown): boolean => {\n if (typeof value !== 'number') {valueMustBeNumber('le');}\n return value <= opt;\n }\n}\n\n/**\n * Greater than filter - checks if value is greater than option.\n * \n * @param options - Array with comparison number as first element\n * @returns Filter function that returns boolean\n */\nconst gt = (options?:string[]): FilterFn<boolean> => {\n const opt = requiredNumberOption(options, 0, 'gt');\n return (value: unknown): boolean => {\n if (typeof value !== 'number') {valueMustBeNumber('gt');}\n return value > opt;\n }\n}\n\n/**\n * Greater than or equal filter - checks if value is greater than or equal to option.\n * \n * @param options - Array with comparison number as first element\n * @returns Filter function that returns boolean\n */\nconst ge = (options?:string[]): FilterFn<boolean> => {\n const opt = requiredNumberOption(options, 0, 'ge');\n return (value: unknown): boolean => {\n if (typeof value !== 'number') {valueMustBeNumber('ge');}\n return value >= opt;\n }\n}\n\n/**\n * Increment filter - adds option value to input value.\n * \n * @param options - Array with increment number as first element\n * @returns Filter function that returns incremented number\n */\nconst inc = (options?:string[]): FilterFn<number> => {\n const opt = requiredNumberOption(options, 0, 'add');\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('add');}\n return value + opt;\n }\n}\n\n/**\n * Decrement filter - subtracts option value from input value.\n * \n * @param options - Array with decrement number as first element\n * @returns Filter function that returns decremented number\n */\nconst dec = (options?:string[]): FilterFn<number> => {\n const opt = requiredNumberOption(options, 0, 'sub');\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('sub');}\n return value - opt;\n }\n}\n\n/**\n * Multiply filter - multiplies value by option.\n * \n * @param options - Array with multiplier number as first element\n * @returns Filter function that returns multiplied number\n */\nconst mul = (options?:string[]): FilterFn<number> => {\n const opt = requiredNumberOption(options, 0, 'mul');\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('mul');}\n return value * opt;\n }\n}\n\n/**\n * Divide filter - divides value by option.\n * \n * @param options - Array with divisor number as first element\n * @returns Filter function that returns divided number\n */\nconst div = (options?:string[]): FilterFn<number> => {\n const opt = requiredNumberOption(options, 0, 'div');\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('div');}\n return value / opt;\n }\n}\n\n/**\n * Modulo filter - returns remainder of division.\n * \n * @param options - Array with divisor number as first element\n * @returns Filter function that returns remainder\n */\nconst mod = (options?:string[]): FilterFn<number> => {\n const opt = requiredNumberOption(options, 0, 'mod');\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('mod');}\n return value % opt;\n }\n}\n\n/**\n * Absolute value filter - returns the magnitude of a number.\n *\n * @param options - Unused\n * @returns Filter function that returns the absolute value\n */\nconst abs = (_options?:string[]): FilterFn<number> => {\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('abs');}\n return Math.abs(value);\n }\n}\n\n/**\n * Clamp filter - constrains a number to the inclusive range [min, max].\n *\n * Saturating conversion in the same family as round/floor/ceil, so it stays on\n * the wire rather than in state. Pairs with `unit` for style bindings:\n * `style.width: ratio|clamp(0,1)|percent(0)`.\n *\n * @param options - Array with minimum as first element and maximum as second (both required)\n * @returns Filter function that returns the clamped number\n */\nconst clamp = (options?:string[]): FilterFn<number> => {\n const min = requiredNumberOption(options, 0, 'clamp');\n const max = requiredNumberOption(options, 1, 'clamp');\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('clamp');}\n return Math.min(Math.max(value, min), max);\n }\n}\n\n/**\n * Fixed decimal filter - formats number to fixed decimal places.\n *\n * @param options - Array with decimal places as first element (default: 0)\n * @returns Filter function that returns formatted string\n */\nconst fix = (options?:string[]): FilterFn<string> => {\n const opt = numberOption(options?.[0] ?? \"0\", 'toFixed');\n return (value: unknown): string => {\n if (typeof value !== 'number') {valueMustBeNumber('toFixed');}\n return value.toFixed(opt);\n }\n}\n\n/**\n * Locale number filter - formats number according to locale.\n *\n * ロケール依存フィルタ(`locale` / `date` / `time` / `datetime`)は\n * **明示引数だけを構築時に確定し、既定の `config.locale` は適用のたびに読む**。\n *\n * 以前は `options?.[0] ?? config.locale` を返り値の関数の**外**で解決していた。\n * フィルタ関数はバインド構築時に一度だけ作られるので、これはロケールを\n * クロージャに焼き込むことを意味する。`config.locale` の確定がバインド構築より\n * 遅れると、それ以降どう直しても「同じページの中で日付だけ既定ロケール」が\n * 永続し、しかも `config.locale` は依存グラフに載らないので再描画で回復もしない。\n * 症状(日付だけ英語)は原因(起動順序)から遠く、追いにくい。\n *\n * 適用のたびに読めば、少なくとも**再適用されたバインドは回復する**。ロケールは\n * 起動時に確定する前提(docs/i18n-design.md D1)なので通常この差は現れず、\n * これは順序事故から復帰できるようにするための保険である。\n *\n * 明示引数(`|date(ja-JP)`)は構築時に固定でよい — バインド式の一部であり、\n * 実行中に変わらない。\n *\n * @param options - Array with locale string as first element (default: config.locale)\n * @returns Filter function that returns localized number string\n */\nconst locale = (options?:string[]): FilterFn<string> => {\n const explicit = options?.[0];\n return (value: unknown): string => {\n if (typeof value !== 'number') {valueMustBeNumber('locale');}\n return value.toLocaleString(explicit ?? config.locale);\n }\n}\n\n/**\n * Uppercase filter - converts string to uppercase.\n * \n * @param options - Unused\n * @returns Filter function that returns uppercase string\n */\nconst uc = (_options?:string[]): FilterFn<string> => {\n return (value: unknown): string => {\n return String(value).toUpperCase();\n }\n}\n\n/**\n * Lowercase filter - converts string to lowercase.\n * \n * @param options - Unused\n * @returns Filter function that returns lowercase string\n */\nconst lc = (_options?:string[]): FilterFn<string> => {\n return (value: unknown): string => {\n return String(value).toLowerCase();\n }\n}\n\n/**\n * Capitalize filter - capitalizes first character of string.\n * \n * @param options - Unused\n * @returns Filter function that returns capitalized string\n */\nconst cap = (_options?:string[]): FilterFn<string> => {\n return (value: unknown): string => {\n const v = String(value);\n if (v.length === 0) {return v;}\n if (v.length === 1) {return v.toUpperCase();}\n return v.charAt(0).toUpperCase() + v.slice(1);\n }\n}\n\n/**\n * Trim filter - removes whitespace from both ends of string.\n * \n * @param options - Unused\n * @returns Filter function that returns trimmed string\n */\nconst trim = (_options?:string[]): FilterFn<string> => {\n return (value: unknown): string => {\n return String(value).trim();\n }\n}\n\n/**\n * Slice filter - extracts portion of string from specified index.\n * \n * @param options - Array with start index and optional end index\n * @returns Filter function that returns sliced string\n */\nconst slice = (options?:string[]): FilterFn<string> => {\n const numberedOpts: number[] = [requiredNumberOption(options, 0, 'slice')];\n const opt2 = options?.[1];\n if (typeof opt2 !== 'undefined') {\n numberedOpts.push(numberOption(opt2, 'slice'));\n }\n return (value: unknown): string => {\n return String(value).slice(...numberedOpts);\n }\n}\n\n/**\n * Substring filter - extracts substring from specified position and length.\n * \n * @param options - Array with start index and length\n * @returns Filter function that returns substring\n */\nconst substr = (options?:string[]): FilterFn<string> => {\n // 4.0 removes `substr` in favour of `slice` (3.5 notice, D39). The registry caches the resolved\n // function per argument list, so this factory runs once per distinct use\n v4Migration?.removed('substr');\n const opt1 = requiredNumberOption(options, 0, 'substr');\n const opt2 = requiredNumberOption(options, 1, 'substr');\n return (value: unknown): string => {\n return String(value).substr(opt1, opt2);\n }\n}\n\n/**\n * Pad filter - pads string to specified length from start.\n * \n * @param options - Array with target length and pad string (default: '0')\n * @returns Filter function that returns padded string\n */\nconst pad = (options?:string[]): FilterFn<string> => {\n const opt1 = requiredNumberOption(options, 0, 'padStart');\n const opt2 = options?.[1] ?? '0';\n return (value: unknown): string => {\n return String(value).padStart(opt1, opt2);\n }\n}\n\n/**\n * padEnd filter - pads string to specified length from the end (the pair of `padStart`, requirement B12).\n *\n * @param options - Array with target length and pad string (default: ' ')\n * @returns Filter function that returns padded string\n */\nconst padEnd = (options?:string[]): FilterFn<string> => {\n const opt1 = requiredNumberOption(options, 0, 'padEnd');\n const opt2 = options?.[1] ?? ' ';\n return (value: unknown): string => {\n return String(value).padEnd(opt1, opt2);\n }\n}\n\n/**\n * Repeat filter - repeats string specified number of times.\n * \n * @param options - Array with repeat count as first element\n * @returns Filter function that returns repeated string\n */\nconst rep = (options?:string[]): FilterFn<string> => {\n const opt = requiredNumberOption(options, 0, 'repeat');\n return (value: unknown): string => {\n return String(value).repeat(opt);\n }\n}\n\n/**\n * Reverse filter - reverses character order in string.\n * \n * @param options - Unused\n * @returns Filter function that returns reversed string\n */\nconst rev = (_options?:string[]): FilterFn<string> => {\n return (value: unknown): string => {\n return String(value).split('').reverse().join('');\n }\n}\n\n/**\n * Integer filter - parses value to integer.\n * \n * @param options - Unused\n * @returns Filter function that returns integer\n */\nconst int = (_options?:string[]): FilterFn<number> => {\n return (value: unknown): number => {\n return parseInt(String(value), 10);\n }\n}\n\n/**\n * Float filter - parses value to floating point number.\n * \n * @param options - Unused\n * @returns Filter function that returns float\n */\nconst float = (_options?:string[]): FilterFn<number> => {\n return (value: unknown): number => {\n return parseFloat(String(value));\n }\n}\n\n/**\n * Round filter - rounds number to specified decimal places.\n * \n * @param options - Array with decimal places as first element (default: 0)\n * @returns Filter function that returns rounded number\n */\nconst round = (options?:string[]): FilterFn<number> => {\n const optValue = Math.pow(10, numberOption(options?.[0] ?? '0', 'round'));\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('round');}\n return Math.round(value * optValue) / optValue;\n }\n}\n\n/**\n * Floor filter - rounds number down to specified decimal places.\n * \n * @param options - Array with decimal places as first element (default: 0)\n * @returns Filter function that returns floored number\n */\nconst floor = (options?:string[]): FilterFn<number> => {\n const optValue = Math.pow(10, numberOption(options?.[0] ?? '0', 'floor'));\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('floor');}\n return Math.floor(value * optValue) / optValue;\n }\n}\n\n/**\n * Ceiling filter - rounds number up to specified decimal places.\n * \n * @param options - Array with decimal places as first element (default: 0)\n * @returns Filter function that returns ceiled number\n */\nconst ceil = (options?:string[]): FilterFn<number> => {\n const optValue = Math.pow(10, numberOption(options?.[0] ?? '0', 'ceil'));\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('ceil');}\n return Math.ceil(value * optValue) / optValue;\n }\n}\n\n/**\n * Percent filter - formats number as percentage string.\n * \n * @param options - Array with decimal places as first element (default: 0)\n * @returns Filter function that returns percentage string with '%'\n */\nconst percent = (options?:string[]): FilterFn<string> => {\n const opt = numberOption(options?.[0] ?? '0', 'percent');\n return (value: unknown): string => {\n if (typeof value !== 'number') {valueMustBeNumber('percent');}\n return `${(value * 100).toFixed(opt)}%`;\n }\n}\n\n/**\n * Unit filter - appends a CSS unit (or any suffix) to the value.\n *\n * A number alone does nothing in CSS, so without this the unit has to be built in\n * state — which drags presentation into the source of truth, and in the worst case\n * forces a whole derived array just to carry `\"42%\"` strings.\n * `style.height: samples.*.cpu|clamp(0,100)|fix(0)|unit(%)` keeps it on the wire.\n *\n * Accepts strings as well as numbers **on purpose**: the useful chains run through\n * `fix` / `percent`, which already return strings. Rejecting non-numbers here would\n * break exactly the combination this filter exists for.\n *\n * `null` / `undefined` pass through untouched rather than becoming `\"undefinedpx\"`, so the\n * binding layer's \"undefined skips the write, null clears\" semantics survive. That guard is no\n * longer written here: it is `nullishPassthrough`, shared with the rest of the `String(value)`\n * family, which used to paint `\"undefined\"` into the page for exactly the same reason.\n *\n * @param options - Array with the unit/suffix as first element (required)\n * @returns Filter function that returns the value with the unit appended\n */\nconst unit = (options?:string[]): FilterFn<string> => {\n const opt = options?.[0] ?? optionsRequired('unit');\n return (value: unknown): string => {\n return String(value) + opt;\n }\n}\n\n/**\n * Join filter - joins array elements into a string.\n *\n * The default separator is `\", \"` rather than `\",\"`: a bare comma is what `String()`\n * already produces without any filter, so defaulting to it would make `|join` a no-op.\n *\n * @param options - Array with separator as first element (default: ', ')\n * @returns Filter function that returns the joined string\n */\nconst join = (options?:string[]): FilterFn<string> => {\n const opt = options?.[0] ?? ', ';\n return (value: unknown): string => {\n if (!Array.isArray(value)) {valueMustBeArray('join');}\n return value.join(opt);\n }\n}\n\n/**\n * Truncate filter - shortens a string and appends an ellipsis.\n *\n * The length option counts **kept characters**, not the total including the suffix,\n * matching the existing `slice(0, n)` reading. A string at or below the limit is\n * returned untouched (no suffix).\n *\n * @param options - Array with max kept length as first element and suffix as second (default: '…')\n * @returns Filter function that returns the truncated string\n */\nconst truncate = (options?:string[]): FilterFn<string> => {\n const maxLength = requiredNumberOption(options, 0, 'truncate');\n const suffix = options?.[1] ?? '…';\n return (value: unknown): string => {\n const v = String(value);\n if (v.length <= maxLength) {return v;}\n return v.slice(0, maxLength) + suffix;\n }\n}\n\n/**\n * Date filter - formats Date object as localized date string.\n *\n * @param options - Array with locale string as first element (default: config.locale)\n * @returns Filter function that returns date string\n */\nconst date = (options?:string[]): FilterFn<string> => {\n // 既定ロケールは適用のたびに読む(`locale` フィルタの注記を参照)\n const explicit = options?.[0];\n return (value: unknown): string => {\n if (!(value instanceof Date)) {valueMustBeDate('date');}\n return value.toLocaleDateString(explicit ?? config.locale);\n }\n}\n\n/**\n * Time filter - formats Date object as localized time string.\n * \n * @param options - Array with locale string as first element (default: config.locale)\n * @returns Filter function that returns time string\n */\nconst time = (options?:string[]): FilterFn<string> => {\n // 既定ロケールは適用のたびに読む(`locale` フィルタの注記を参照)\n const explicit = options?.[0];\n return (value: unknown): string => {\n if (!(value instanceof Date)) {valueMustBeDate('time');}\n return value.toLocaleTimeString(explicit ?? config.locale);\n }\n}\n\n/**\n * DateTime filter - formats Date object as localized date and time string.\n * \n * @param options - Array with locale string as first element (default: config.locale)\n * @returns Filter function that returns datetime string\n */\nconst datetime = (options?:string[]): FilterFn<string> => {\n // 既定ロケールは適用のたびに読む(`locale` フィルタの注記を参照)\n const explicit = options?.[0];\n return (value: unknown): string => {\n if (!(value instanceof Date)) {valueMustBeDate('datetime');}\n return value.toLocaleString(explicit ?? config.locale);\n }\n}\n\n/**\n * Year-Month-Day filter - formats Date object as YYYY-MM-DD string.\n * \n * @param options - Array with separator string as first element (default: '-')\n * @returns Filter function that returns formatted date string\n */\nconst ymd = (options?:string[]): FilterFn<string> => {\n const opt = options?.[0] ?? '-';\n return (value: unknown): string => {\n if (!(value instanceof Date)) {valueMustBeDate('ymd');}\n const year = value.getFullYear().toString();\n const month = (value.getMonth() + 1).toString().padStart(2, '0');\n const day = value.getDate().toString().padStart(2, '0');\n return `${year}${opt}${month}${opt}${day}`;\n }\n}\n\n/**\n * Hour-Minute-Second filter - formats Date object as HH:MM:SS string.\n *\n * The counterpart of `ymd`: a fixed, zero-padded, locale-independent rendering with a\n * configurable separator, for when `time` (locale-formatted) is not stable enough.\n *\n * @param options - Array with separator string as first element (default: ':')\n * @returns Filter function that returns formatted time string\n */\nconst hms = (options?:string[]): FilterFn<string> => {\n const opt = options?.[0] ?? ':';\n return (value: unknown): string => {\n if (!(value instanceof Date)) {valueMustBeDate('hms');}\n const hours = value.getHours().toString().padStart(2, '0');\n const minutes = value.getMinutes().toString().padStart(2, '0');\n const seconds = value.getSeconds().toString().padStart(2, '0');\n return `${hours}${opt}${minutes}${opt}${seconds}`;\n }\n}\n\n/**\n * Falsy filter - checks if value is falsy, by JavaScript's own truthiness (`!value`: false, null,\n * undefined, 0, -0, 0n, '' and NaN). Before 3.0 the list was spelled out and missed 0n (B10).\n *\n * @param options - Unused\n * @returns Filter function that returns true for falsy values\n */\nconst falsy = (_options?:string[]): FilterFn<boolean> => {\n return (value: unknown): boolean => !value;\n}\n\n/**\n * Truthy filter - checks if value is truthy.\n * \n * @param options - Unused\n * @returns Filter function that returns true for non-falsy values\n */\nconst truthy = (_options?:string[]): FilterFn<boolean> => {\n // JavaScript's truthiness, the same as the `boolean` filter (B10)\n return (value: unknown): boolean => !!value;\n}\n\n/**\n * Default filter - returns default value if input is falsy (JavaScript's truthiness, as `falsy`).\n * \n * @param options - Array with default value as first element\n * @returns Filter function that returns value or default\n */\nconst defaults = (options?:string[], literals?: readonly unknown[]): FilterFn<unknown> => {\n const opt = options?.[0] ?? optionsRequired('defaults');\n // The fallback is the typed literal (B9): defaults(0) gives 0, defaults(null) gives null, defaults('0') gives \"0\"\n const fallback = literals !== undefined && literals.length > 0 ? literals[0] : opt;\n return (value: unknown): unknown => {\n if (!value) {return fallback;}\n return value;\n }\n}\n\n/**\n * coalesce filter - returns the default only for null / undefined (`defaults` also replaces 0, false and \"\").\n * Requirement B12: the nullish counterpart of `defaults`, read like SQL COALESCE.\n *\n * @param options - Array with default value as first element\n * @returns Filter function that returns value or default\n */\nconst coalesce = (options?:string[], literals?: readonly unknown[]): FilterFn<unknown> => {\n const opt = options?.[0] ?? optionsRequired('coalesce');\n const fallback = literals !== undefined && literals.length > 0 ? literals[0] : opt;\n return (value: unknown): unknown => value ?? fallback;\n}\n\n/**\n * Boolean filter - converts value to boolean.\n * \n * @param options - Unused\n * @returns Filter function that returns boolean\n */\nconst boolean = (_options?:string[]): FilterFn<boolean> => {\n return (value: unknown): boolean => {\n return Boolean(value);\n }\n}\n\n/**\n * Number filter - converts value to number.\n * \n * @param options - Unused\n * @returns Filter function that returns number\n */\nconst number = (_options?:string[]): FilterFn<number> => {\n return (value: unknown): number => {\n return Number(value);\n }\n}\n\n/**\n * String filter - converts value to string.\n * \n * @param options - Unused\n * @returns Filter function that returns string\n */\nconst string = (_options?:string[]): FilterFn<string> => {\n return (value: unknown): string => {\n return String(value);\n }\n}\n\n/**\n * Null filter - converts empty string to null.\n * \n * @param options - Unused\n * @returns Filter function that returns null for empty string, otherwise original value\n */\nconst _null = (_options?:string[]): FilterFn<unknown> => {\n return (value: unknown): unknown => {\n return (value === \"\") ? null : value;\n } \n}\n\nconst builtinFilters: FilterWithOptions = {\n \"eq\": eq,\n \"ne\": ne,\n \"not\": not,\n\n \"lt\": lt,\n \"le\": le,\n \"gt\": gt,\n \"ge\": ge,\n\n \"add\": inc,\n \"sub\": dec,\n \"mul\": mul,\n \"div\": div,\n \"mod\": mod,\n \"abs\": abs,\n \"clamp\": clamp,\n\n \"toFixed\": fix,\n \"locale\": locale,\n // `String(value)` で組み立てる族は、値が無いときに素通しする(要件 B8 — nullishPassthrough を参照)\n \"upper\": nullishPassthrough(uc),\n \"lower\": nullishPassthrough(lc),\n \"capitalize\": nullishPassthrough(cap),\n \"trim\": nullishPassthrough(trim),\n \"slice\": nullishPassthrough(slice),\n \"substr\": nullishPassthrough(substr),\n \"padStart\": nullishPassthrough(pad),\n \"padEnd\": nullishPassthrough(padEnd),\n \"repeat\": nullishPassthrough(rep),\n \"reverse\": nullishPassthrough(rev),\n \"truncate\": nullishPassthrough(truncate),\n \"join\": join,\n\n \"int\": int,\n \"float\": float,\n \"round\": round,\n \"floor\": floor,\n \"ceil\": ceil,\n \"percent\": percent,\n \"unit\": nullishPassthrough(unit),\n\n \"date\": date,\n \"time\": time,\n \"datetime\": datetime,\n \"ymd\": ymd,\n \"hms\": hms,\n\n \"falsy\": falsy,\n \"truthy\": truthy,\n \"defaults\": defaults,\n \"coalesce\": coalesce,\n\n \"boolean\": boolean,\n \"number\": number,\n \"string\": string,\n \"nullIfEmpty\": _null,\n};\n\n/**\n * The argument count each built-in accepts, [min, max] — checked when the bindings are planned\n * (`[wcs/filter-arity]`, requirement B3), with the same bounds lint uses. It is the same data as\n * `builtinFilterMeta` (filters/filterMeta.ts) without the descriptions, so that installing the formats\n * does not pull the metadata into the page; a test keeps the two equal.\n */\nexport const builtinFilterArity: Readonly<Record<string, readonly [number, number]>> = {\n eq: [1, 1],\n not: [0, 0],\n ne: [1, 1],\n lt: [1, 1],\n le: [1, 1],\n gt: [1, 1],\n ge: [1, 1],\n add: [1, 1],\n sub: [1, 1],\n mul: [1, 1],\n div: [1, 1],\n mod: [1, 1],\n abs: [0, 0],\n clamp: [2, 2],\n toFixed: [0, 1],\n locale: [0, 1],\n upper: [0, 0],\n lower: [0, 0],\n capitalize: [0, 0],\n trim: [0, 0],\n slice: [1, 2],\n // `substr` は長さも必須(実装が両方読む・README も `substr(start, length)`)。\n // [1, 2] だったころは `substr(0)` が引数の個数の検査を素通りし、工場の\n // 「requires at least one option」という的外れな文言で落ちていた\n substr: [2, 2],\n padStart: [1, 2],\n padEnd: [1, 2],\n repeat: [1, 1],\n reverse: [0, 0],\n truncate: [1, 2],\n join: [0, 1],\n int: [0, 0],\n float: [0, 0],\n round: [0, 1],\n floor: [0, 1],\n ceil: [0, 1],\n percent: [0, 1],\n unit: [1, 1],\n // ロケール依存の 3 つは `locale` と同じく引数 1 つ(`date(ja-JP)`)を受ける。\n // [0, 0] だったころは、README が規範として書いている `timestamp|date(ja-JP)` が\n // 束縛計画の段で必ず `[wcs/filter-arity]` になっていた(2.x には検査自体が無かった)\n date: [0, 1],\n time: [0, 1],\n datetime: [0, 1],\n ymd: [0, 1],\n hms: [0, 1],\n falsy: [0, 0],\n truthy: [0, 0],\n defaults: [1, 1],\n coalesce: [1, 1],\n boolean: [0, 0],\n number: [0, 0],\n string: [0, 0],\n nullIfEmpty: [0, 0],\n};\n\nexport const outputBuiltinFilters = builtinFilters;\nexport const inputBuiltinFilters = builtinFilters;\n\nexport const builtinFiltersByFilterIOType = {\n \"input\": inputBuiltinFilters,\n \"output\": outputBuiltinFilters,\n} as const;\n\n/**\n * Retrieves built-in filter function by name and options.\n *\n * **Test / tooling only.** The binding pipeline never goes through here: it resolves\n * filters from the registry with `core/filterRegistry.ts#resolveFilterFn`, which also\n * checks `builtinFilterArity` and passes the **typed literals** (requirement B9).\n * This helper takes raw option strings only, so `builtinFilterFn(\"coalesce\", [\"0\"])`\n * yields the string `\"0\"` where the runtime yields the number `0`. Prefer\n * `resolveFilterFn` in any new code, and treat a difference between the two as a\n * limitation of this helper rather than of the runtime.\n *\n * @param name - Filter name (a 3.x alias such as `uc` resolves to its canonical name)\n * @param options - Array of option strings\n * @returns Function that takes FilterWithOptions and returns filter function\n */\nexport const builtinFilterFn = (name:string, options: string[]) => (filters: FilterWithOptions) => {\n // 自前のキーだけを引く。素のオブジェクトへのブラケット参照だと `Object.prototype` のメンバが\n // フィルタとして通り(`toString` / `constructor` / `valueOf`)、`[wcs/filter-unknown]` の代わりに\n // `\"[object Undefined]\"` や素の TypeError が出ていた。登録簿(core/filterRegistry.ts)が\n // まさにこの穴のために `Map` を採っているのと同じ規準\n const own = Object.prototype.hasOwnProperty;\n const canonical = own.call(builtinFilterAliases, name) ? builtinFilterAliases[name] : name;\n const filter = own.call(filters, canonical) ? filters[canonical] : undefined;\n if (!filter) {\n // lint の wcs/filter-unknown と同じ語彙・同じ did-you-mean 規準(三面同語彙)。\n raiseError(`[wcs/filter-unknown] filter not found: ${name}.${didYouMean(name, Object.keys(filters))}${LINT_HINT}`);\n }\n return filter(options);\n}\n\n","/**\n * formats/install.ts — 書式フィルタ群の install(設計案 §4、要件 D16)。\n *\n * `uc` / `date` / `round` / `truncate` … の実装を core の登録簿へ置く。core 自身が持つのは\n * エンジンが差し込む `not` だけなので、この機能を入れないページでは、宣言されたフィルタが\n * 束縛計画の段で `[wcs/filter-unknown]` として名指しで落ちる(黙って素通ししない)。\n */\nimport { registerFilters } from \"../core/filterRegistry\";\nimport { builtinFilterArity, inputBuiltinFilters, outputBuiltinFilters } from \"./builtinFilters\";\nimport { builtinFilterAliases } from \"../filters/filterAliases\";\n\nlet installed = false;\n/** 冪等。full / auto では `bootstrapState()` が呼ぶ */\nexport function installFormats(): void {\n if (installed) return;\n installed = true;\n registerFilters(\"input\", inputBuiltinFilters, builtinFilterArity, builtinFilterAliases);\n registerFilters(\"output\", outputBuiltinFilters, builtinFilterArity, builtinFilterAliases);\n}\n","/**\n * features/formats.ts — 書式フィルタ群(@wcstack/state/features/formats)。\n * `|uc` `|date(…)` `|round(…)` のような宣言が要求する実関数を core の登録簿へ置く。\n */\nimport type { IStateFeature } from \"../core/features\";\nimport { installFormats } from \"../formats/install\";\n\nexport const formats: IStateFeature = {\n name: \"formats\",\n install(): void {\n installFormats();\n },\n};\nexport default formats;\n"],"names":["optionsRequired","fnName","raiseError","optionMustBeNumber","valueMustBeNumber","valueMustBeDate","builtinFilterAliases","inc","dec","fix","uc","lc","cap","rep","rev","pad","null","validateNumberString","value","isNaN","Number","numberOption","requiredNumberOption","options","index","nullishPassthrough","factory","filterFn","builtinFilters","eq","literals","opt","literal","undefined","length","ne","not","_options","lt","le","gt","ge","add","sub","mul","div","mod","abs","Math","clamp","min","max","toFixed","locale","explicit","toLocaleString","config","upper","String","toUpperCase","lower","toLowerCase","capitalize","v","charAt","slice","trim","numberedOpts","opt2","push","substr","opt1","padStart","padEnd","repeat","reverse","split","join","truncate","maxLength","suffix","Array","isArray","int","parseInt","float","parseFloat","round","optValue","pow","floor","ceil","percent","unit","date","Date","toLocaleDateString","time","toLocaleTimeString","datetime","ymd","year","getFullYear","toString","month","getMonth","day","getDate","hms","hours","getHours","minutes","getMinutes","seconds","getSeconds","falsy","truthy","defaults","fallback","coalesce","boolean","Boolean","number","string","nullIfEmpty","builtinFilterArity","outputBuiltinFilters","inputBuiltinFilters","installed","formats","name","install","registerFilters"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{r as t,l as e,a as n,C as o}from"../chunks/lifecycleHooks.js";import{k as r,l as s,a,m as i,D as c,V as l,n as u,W as d,g as f,o as h,R as p,p as m,i as g,q as y,r as w}from"../chunks/pathDiagnostics.js";import{r as $,d as b}from"../chunks/errorGuidance.js";import{r as v,g as k,N as P}from"../chunks/getAllPropertyDescriptors.js";import{c as S}from"../chunks/filterRegistry.js";import{n as x}from"../chunks/declarationAliases.js";import{q as I,u as j,t as C,v as N,w as M,j as A,i as O,x as R,y as E,z as W,A as K,B as L,C as D,D as B,E as z,o as T,F,G as V,H as q,I as _,J as G,K as H,L as U}from"../chunks/binder.js";import{a as X,r as J}from"../chunks/featureBridge.js";import{p as Q}from"../chunks/diagnosticsHooks.js";import{g as Y,a as Z,c as tt}from"../chunks/checkDependency.js";const et={written:function(t,e,n){const o=t.bindableEventMap,r=o[e.path],s="string"==typeof r,a=s?r:e.segments.length>1&&-1===e.path.indexOf("#")?o[e.segments[0]]:void 0;if("string"!=typeof a)return;const i=t.rootNode;i instanceof ShadowRoot&&i.host.dispatchEvent(new CustomEvent(a,{detail:s&&void 0!==n?n.value:void 0,bubbles:!0}))}};let nt=!1;function ot(t){return function(){const e=this.stateElement;if(!e)return;if(!0!==e.initialized)return;let n;try{e.createState("readonly",e=>{n=e[t]})}catch(e){return void console.warn(`[@wcstack/state] DCC getter "${t}" failed:`,e)}return n}}function rt(t){return function(e){const n=this.stateElement;n&&(!0!==n.initialized?n.initializePromise.then(()=>{n.createState("writable",n=>{n[t]=e})}):n.createState("writable",n=>{n[t]=e}))}}function st(t,e){return e?function(...e){const n=this.stateElement;if(n)return n.initializePromise.then(()=>{let o;return n.createStateAsync("writable",async n=>{o=await n[t](...e)}).then(()=>o)})}:function(...e){const n=this.stateElement;if(n)return n.initializePromise.then(()=>{let o;return n.createState("writable",n=>{o=n[t](...e)}),o})}}function at(t){return t.startsWith("$")}function it(t,e){return Object.keys(t).filter(n=>{if(n.startsWith("$")||"constructor"===n)return!1;const o="function"==typeof t[n].value;return"method"===e?o:!o})}function ct(t,e){const n=t[e];if(void 0===n)return null;Array.isArray(n)||$(`${e} must be an array of strings.`);const o=[],r=new Set;for(const t of n)"string"==typeof t&&0!==t.length||$(`${e} entries must be non-empty strings.`),t.startsWith("$")&&$(`${e} entry "${t}" must not start with "$" (internal properties are not exposed on the component).`),r.has(t)&&$(`${e} entry "${t}" is duplicated.`),r.add(t),o.push(t);return o}function lt(t){x(t);const e=ct(t,r)??[],n=ct(t,s)??[],o=k(t),i=function(t){const e=t[a];return"object"!=typeof e||null===e?new Set:new Set(Object.keys(e))}(t),c=[];for(const t of e){const e=o[t];if(void 0===e){if(i.has(t)){c.push(t);continue}$(`${r} entry "${t}" is not declared on the state.${b(t,it(o,"value"))}`)}"function"==typeof e.value&&$(`${r} entry "${t}" is a method. Declare it in ${s} instead.`)}for(const t of n){const e=o[t];void 0===e&&$(`${s} entry "${t}" is not declared on the state.${b(t,it(o,"method"))}`),"function"!=typeof e.value&&$(`${s} entry "${t}" is not a method. Declare it in ${r} instead.`)}return{bindables:e,commands:n,streamBackedBindables:c}}function ut(t,e,n){const o=t.tagName.toLowerCase();o.includes("-")||$(`DCC: "${o}" is not a valid custom element name (must contain a hyphen).`);const s=I(t);null!==s&&"function"==typeof s.define||$(`DCC: CustomElementRegistry is unavailable for "${o}".`),s.get(o)&&$(`DCC: "${o}" is already registered. A custom element name can only be defined once.`);const a=document.createElement("template"),c=a.content.ownerDocument;for(const t of Array.from(e.childNodes))a.content.appendChild(c.importNode(t,!0));const l=e.mode,{bindables:u,commands:d,streamBackedBindables:f}=lt(n),h=u.length>0||d.length>0?function(t,e,n=[]){const o={protocol:"wc-bindable",version:1,properties:e.map(e=>({name:e,event:`${t}:${e}-changed`,getter:t=>t.target[e]})),inputs:e.map(t=>({name:t}))};if(0===n.length)return o;const r=n.map(t=>({name:t,async:!0}));return{...o,commands:r}}(o,u,d):null,p=u.length>0?function(t,e){const n={};for(const o of e)n[o]=`${t}:${o}-changed`;return n}(o,u):{},m=S.tagNames.state,g=class extends HTMLElement{static template=a;static shadowRootMode=l;static wcBindable=h;static bindableEventMap=p;_shadow=null;_ensureShadow(){if(null!==this._shadow)return this._shadow;if(this.hasAttribute(i))return null;this._shadow=this.attachShadow({mode:g.shadowRootMode}),this._shadow.appendChild(g.template.content.cloneNode(!0));const t=I(this._shadow);return null!==t&&j(t,this._shadow),this._shadow}connectedCallback(){const t=this._ensureShadow();if(null!==t&&Object.keys(g.bindableEventMap).length>0){const e=t.querySelector(m);e?(nt||(nt=!0,v("dcc",et)),e.setBindableEventMap(g.bindableEventMap)):console.warn(`[@wcstack/state] DCC: "${o}" declares ${r} but its template has no <${S.tagNames.state}>. Change events will not be dispatched.`)}}get stateElement(){return this._ensureShadow()?.querySelector(m)??null}},y=k(n);for(const[t,e]of Object.entries(y)){if(at(t))continue;const n={configurable:!0,enumerable:!0};if("function"==typeof e.value){const o="AsyncFunction"===e.value.constructor?.name;n.value=st(t,o)}else n.get=ot(t),n.set=rt(t);Object.defineProperty(g.prototype,t,n)}for(const t of f)Object.defineProperty(g.prototype,t,{configurable:!0,enumerable:!0,get:ot(t),set:rt(t)});s.define(o,g)}async function dt(t,o,r){const s=t;try{s.hasAttribute("bind-component")&&$(`"bind-component" cannot be used inside a [${i}] host. DCC state comes from the template, not from a component property.`);const a=await async function(t,o){try{if(t.hasAttribute("src")){const n=t.getAttribute("src");if(n.endsWith(".js"))return await e(n);$(`DCC: Unsupported src type: ${n}`)}const r=t.querySelector('script[type="module"]');if(r)return await n(r,o.tagName.toLowerCase());$(`DCC: No state source found for "${o.tagName.toLowerCase()}".`)}catch(t){$(`DCC: Failed to load state: ${t}`)}}(s,o);ut(o,r,a),t.markTreeless(),t.markInitialized(),t.clearConnectedRootNode(),t.settleInitialization()}catch(e){t.failInitializeLoudly(e)}}const ft={order:10,connecting(t){const e=t.parentNode;return e instanceof ShadowRoot&&e.host.hasAttribute(i)?dt(t,e.host,e):null}};let ht=!1;function pt(t,e){if(e.length>t.length)return!1;for(let n=0;n<e.length;n++)if(t[n]!==e[n])return!1;return!0}function mt(t,e){for(const n of t)if(pt(e,n.innerSegments))return n;return null}function gt(t,e){const n=e.slice(t.innerSegments.length);return 0===n.length?t.outerPathInfo.path:t.outerPathInfo.path+c+n.join(c)}const yt=new Map([["$eq",[0]],["$eqPath",[0,1]],["$eqIndex",[0]],["$dependOn",[0]],["$trackDependency",[0]]]);function wt(t,e,n){const o=yt.get(t);return void 0===o?null:(...t)=>{const r=t.slice();for(let t=0;t<o.length;t++){const n=o[t];"string"==typeof r[n]&&(r[n]=e(r[n]))}return n(r)}}const $t=new WeakMap;function bt(t,e,n){let o=$t.get(t);void 0===o&&(o=new Map,$t.set(t,o));const r=o.get(e);null!=r&&$(`Volume slot "${e}" is already mounted on this tree.`),o.set(e,n)}function vt(t,e){if(null===t)return!1;const n=$t.get(t);if(void 0===n||0===n.size)return!1;for(const t of n.keys())if(e===t||e.startsWith(t+c)||t.startsWith(e+c))return!0;return!1}const kt=new WeakMap;const Pt=[];function St(t,e,n,o){if(e.length>0){const r=n.split(c),s=mt(e,r);if(null!==s)return o&&s.readonly&&$(`[wcs/mount-readonly] volume "${t}" cannot write "${n}": it is injected read-only ("${l}.${s.innerSegments.join(c)}#${u}: ${s.outerPathInfo.path}"). Write "${s.outerPathInfo.path}" on the root, or drop #${u} from the injection.`),gt(s,r)}return t+c+n}function xt(t,e,n){let o=-1,r=null;for(const t of e){const e=t.outerPathInfo.path;e.length<=o||(n===e?(o=e.length,r=t.innerSegments.join(c)):n.startsWith(e+c)&&(o=e.length,r=t.innerSegments.join(c)+n.slice(e.length)))}if(t.length>o){if(n===t)return"";if(n.startsWith(t+c))return n.slice(t.length+1)}return r}function It(t,e,n=Pt){return new Proxy({},{get(o,r){if("string"==typeof r&&"then"!==r){if("$"===r[0]){if("$postUpdate"===r||"$getAll"===r){const o=r;return(r,...s)=>e[o](St(t,n,r,!1),...s)}if("$setAll"===r)return(o,...r)=>e.$setAll(St(t,n,o,!0),...r);if("$resolve"===r)return(o,...r)=>e.$resolve(St(t,n,o,r.length>1),...r);const o=wt(r,e=>St(t,n,e,!1),t=>e[r](...t));return null!==o?o:e[r]}return e[St(t,n,r,!1)]}},set:(o,r,s)=>"string"!=typeof r||("$"===r[0]?(e[r]=s,!0):(e[St(t,n,r,!0)]=s,!0)),has:(t,e)=>"string"==typeof e&&"$"!==e[0]&&"#"!==e[0]})}const jt=new WeakMap,Ct=[];const Nt=new WeakMap,Mt=new WeakSet;function At(t){console.error(`[@wcstack/state] volume "${t.mountPath}" was not grafted — the root state element on this root node failed to initialize (its own diagnostic is reported separately). The volume is not at fault: fix the root <wcs-state>.`),t.onGrafted(null)}let Ot=null;let Rt=0;const Et=["$watch",a,"$scan","$listKeys",h,"$commandTokens","$eventTokens","$on","$recursion","$errorCallback"],Wt=new Set;function Kt(t,e,n){const o=t.stateObject[e];if("function"==typeof o)try{const r=o.call(n());r instanceof Promise&&r.catch(n=>{console.error(`[@wcstack/state] mounted <${t.component.tagName.toLowerCase()}> ${e} failed.`,n)})}catch(n){console.error(`[@wcstack/state] mounted <${t.component.tagName.toLowerCase()}> ${e} failed.`,n)}}function Lt(t,e,n,o,r,s=new Set){0===n.length&&$(`Cannot build a mount record without host bindings for "${e}".`),x(r);const a=[],i=new Set;let l=null;for(const t of n){const e=t.propSegments.slice(1),n=e.join(c);i.has(n)&&$("Duplicate mapping rule for web component."),i.add(n);const o={innerSegments:e,outerPathInfo:t.statePathInfo,readonly:!0===t.propModifiers?.includes(u)};a.push(o),0===e.length&&(l=o)}a.sort((t,e)=>e.innerSegments.length-t.innerSegments.length);const d=++Rt,f=`#m${d}`,{getterKeys:h,setterKeys:p}=function(t){const e=new Set,n=new Set,o=k(t);for(const[t,r]of Object.entries(o))"function"==typeof r.get&&e.add(t),"function"==typeof r.set&&n.add(t);return{getterKeys:e,setterKeys:n}}(r),m=new Set;for(const t of a)1===t.innerSegments.length&&m.add(t.innerSegments[0]);const g={};for(const t of Object.keys(r))t.startsWith("$")||h.has(t)||p.has(t)||"function"!=typeof r[t]&&(s.has(t)||m.has(t)||(g[t]=r[t]));return{id:d,marker:f,component:t,stateProp:e,parentStateElement:o,entries:a,rootEntry:l,delta:null===l?0:l.outerPathInfo.wildcardCount,markerBasePath:null===l?f:l.outerPathInfo.path+c+f,stateObject:r,getterKeys:h,setterKeys:p,injectedKeys:s,mappedKeys:m,hasReadonlyEntries:a.some(t=>t.readonly),privateSnapshot:g,accessorBySuffixByMarkerParent:new Map,indexShiftByLoopElementPath:new Map,addedGetterPaths:new Set,exports:new Map}}function Dt(t){const e=t.indexOf(c);return-1===e?t:t.slice(0,e)}function Bt(t,e){const n=mt(t.entries,e);return null===n?null:gt(n,e)}function zt(t,e){return t.markerBasePath+c+e}function Tt(t,e,n,o){let r=t.accessorBySuffixByMarkerParent.get(e);void 0===r&&(r=new Map,t.accessorBySuffixByMarkerParent.set(e,r));const s=e+c+n;r.set(n,{accessorName:o,indexShift:f(s).wildcardCount-f(o).wildcardCount}),t.getterKeys.has(o)&&(t.parentStateElement.getterPaths?.add(s),t.addedGetterPaths.add(s))}function Ft(t,e){return!t.injectedKeys.has(e)&&(!t.getterKeys.has(e)&&"function"==typeof t.stateObject[e]||!t.mappedKeys.has(e)&&(Object.prototype.hasOwnProperty.call(t.stateObject,e)&&!t.getterKeys.has(e)&&!t.setterKeys.has(e)))}function Vt(t,e){return`Path "${e}" in <${t.component.tagName.toLowerCase()}> does not resolve: it is not an own key of the component state and no mount entry covers it (mounted prefixes: ${t.entries.filter(t=>t.innerSegments.length>0).map(t=>t.innerSegments.join(c)).join(", ")}). Mount it from the host ("${t.stateProp}: path" / "${t.stateProp}.${Dt(e)}: path") or declare the key on the component state.`}const qt=/^\$(\d+)$/;function _t(t,e){if(!t.hasReadonlyEntries)return null;const n=e[0];if("$"===n||"#"===n)return null;if(t.getterKeys.has(e)||t.setterKeys.has(e))return null;const o=Dt(e);if(t.getterKeys.has(o)||t.setterKeys.has(o)||Ft(t,o))return null;const r=function(t,e){return mt(t.entries,e)}(t,e.split(c));return null!==r&&r.readonly?r:null}function Gt(t,e){const n=_t(t,e);if(null!==n){const o=0===n.innerSegments.length?"":c+n.innerSegments.join(c);$(`[wcs/mount-readonly] <${t.component.tagName.toLowerCase()}> cannot write "${e}": it is mounted read-only ("${t.stateProp}${o}#${u}: ${n.outerPathInfo.path}"). Write it on the host, or drop #${u} from the mount.`)}return Ht(t,e)}function Ht(t,e){const n=e[0];if("$"===n||"#"===n)return e;if(t.getterKeys.has(e)||t.setterKeys.has(e))return function(t,e){const n=e.split(c);let o=-1;for(let t=n.length-1;t>=0;t--)if(n[t]===d){o=t;break}if(-1===o)return Tt(t,t.markerBasePath,e,e),zt(t,e);if(Ft(t,n[0]))return Tt(t,t.markerBasePath,e,e),zt(t,e);const r=n.slice(0,o+1),s=n.slice(o+1),a=Bt(t,r);null===a&&$(Vt(t,e)),0===s.length&&$(`Wildcard-terminal accessor "${e}" on mounted <${t.component.tagName.toLowerCase()}> is not supported: it translates to a marker-terminal path where the mount overlay would shadow the accessor. Declare the row value as a getter on the host tree, or back it with a component-own array (a private key makes the whole path private).`);const i=a+c+t.marker;return Tt(t,i,s.join(c),e),i+c+s.join(c)}(t,e);const o=Dt(e);if(t.getterKeys.has(o)||t.setterKeys.has(o))return zt(t,e);if(Ft(t,o))return zt(t,e);const r=Bt(t,e.split(c));if(null!==r)return r;$(Vt(t,e))}const Ut=new Set(["prop","radio","checkbox"]);function Xt(t,e,n){let o;const r=qt.exec(e.statePathName);if(null!==r){const s=function(t,e){if(void 0===e)return t.delta;const n=Ht(t,e);return f(n).wildcardCount-f(e).wildcardCount}(t,n);o=0===s?e.statePathName:`$${Number(r[1])+s}`}else if(o=Ht(t,e.statePathName),"for"===e.bindingType){const n=f(o).wildcardCount-e.statePathInfo.wildcardCount;t.indexShiftByLoopElementPath.set(o+c+d,n)}const s=e.propModifiers,a=null===r&&Array.isArray(s)&&Ut.has(e.bindingType??"")&&!s.includes(u)&&null!==_t(t,e.statePathName);return o!==e.statePathName||a?{...e,statePathName:o,statePathInfo:f(o),...a?{propModifiers:[...s,u]}:{}}:e}function Jt(t,e,n,o,r){if(void 0===o)return;const s=f(n).wildcardCount-f(e).wildcardCount;return 0===s?o:(r.length<s&&$(`Cannot resolve "${e}" from this mount: the mounted prefix has ${s} wildcard(s) but the host context provides only ${r.length} index(es).`),[...r.slice(0,s),...o])}function Qt(t,e,n){if(-1!==t.indexOf(d))return e;const o=e.split(c);let r=0;for(let t=0;t<o.length&&r<n.length;t++)o[t]===d&&(o[t]=String(n[r++]));return o.join(c)}const Yt=new WeakMap,Zt=new WeakMap;const te=new WeakMap;const ee=new FinalizationRegistry(function(t){const e=t.byMarker.get(t.marker);if(void 0!==e&&void 0===e.deref()&&t.byMarker.delete(t.marker),void 0!==t.getterPaths)for(const e of t.addedGetterPaths)t.getterPaths.delete(e)}),ne=new WeakMap;function oe(t){return ne.get(t)??null}let re=!1;function se(t,e){re||(re=!0,C(t=>Yt.has(t)?t.host:null)),Yt.set(t,e),ne.set(e,t);let n=te.get(e.parentStateElement);void 0===n&&(n=new Map,te.set(e.parentStateElement,n)),n.set(e.marker,new WeakRef(e));let o=Zt.get(e.component);void 0===o&&(o=new Map,Zt.set(e.component,o));const r=o.get(e.stateProp)!==e;o.set(e.stateProp,e),r&&ee.register(e,{byMarker:n,marker:e.marker,getterPaths:e.parentStateElement.getterPaths,addedGetterPaths:e.addedGetterPaths}),e.parentStateElement.markHasMounts?.()}function ae(t){return Yt.get(t)??null}function ie(t){return ce(t).map(t=>({marker:t.marker,componentTag:t.component.tagName.toLowerCase(),stateProp:t.stateProp,mountTable:t.entries.map(t=>({inner:t.innerSegments.join(c),outer:t.outerPathInfo.path})),delta:t.delta,privateKeys:Object.keys(t.privateSnapshot),getterKeys:[...t.getterKeys],exports:[...t.exports.keys()]}))}function ce(t){const e=te.get(t);if(void 0===e)return[];const n=[];for(const t of e.values()){const e=t.deref();void 0!==e&&n.push(e)}return n}function le(t,e){const n=e.lastIndexOf("#");if(-1===n)return null;const o=te.get(t);if(void 0===o)return null;const r=e.indexOf(c,n),s=-1===r?e.slice(n):e.slice(n,r),a=o.get(s);if(void 0===a)return null;const i=a.deref();return void 0===i?(o.delete(s),null):i}const ue=new WeakMap,de=new Set;function fe(t,e,n,o){let r=ue.get(t);if(void 0===r){if(!o)return null;r=new Map,ue.set(t,r)}let s=r.get(e);if(void 0===s){if(!o)return null;s=new Map,r.set(e,s)}let a=s.get(n);if(void 0===a){if(!o)return null;a={holders:new Set,byListIndex:new WeakMap,noIndex:null},s.set(n,a)}return a}function he(t,e){if(!t.component.isConnected)return!1;const n=N(t.component)?.listIndex??null;if(null===e)return null===n;let o=n;for(;null!==o;){if(o===e)return!0;o=o.parentListIndex}return!1}function pe(t,e,n,o){const r=fe(t,e,n,!1);if(null===r)return null;const s=null===o?r.noIndex:r.byListIndex.get(o)??null;if(null!==s){const t=function(t,e){const n=t.ref.deref();return void 0!==n&&he(n,e)?n:null}(s,o);if(null!==t)return{record:t,entry:s.entry}}let a=null,i=null;for(const t of r.holders){const s=t.ref.deref();void 0!==s?he(s,o)&&(null!==i&&$(`[wcs/mount-export-ambiguous] "${e}${c}${n}" is exported by two mounted components on the same instance: <${i.component.tagName.toLowerCase()}> and <${s.component.tagName.toLowerCase()}>. Mount only one of them there, or rename one accessor. See docs/state-overlay-export-design.md X4.`),a=t,i=s):r.holders.delete(t)}return null===a||null===i?null:(null===o?r.noIndex=a:r.byListIndex.set(o,a),{record:i,entry:a.entry})}function me(t){const e=t.parentStateElement,n=N(t.component);if(!(!1===e.isConnected||t.delta>0&&null===n))for(const o of t.exports.values())e.createState("readonly",t=>{t[M](n,()=>{t.$postUpdate(o.exportedPath)})})}const ge=new WeakMap,ye=new WeakMap,we=new WeakMap,$e=new WeakMap;function be(t,e){ye.set(t,e);const n=[];for(let t=e?.listIndex.parentListIndex??null;null!==t;t=t.parentListIndex)n.push(t);$e.set(t,n)}function ve(t){return N(t.component)??ye.get(t)??null}function ke(t){return ve(t)?.listIndex??null}function Pe(t){$(`The host row of <${t.component.tagName.toLowerCase()}> was removed.`)}function Se(t){for(;null!==t;t=t.parentListIndex)if(O(t))return!0;return!1}function xe(t,e){return!t.component.isConnected&&(Se(e)||!0===$e.get(t)?.some(t=>O(t)))}class Ie{record;markerParentPath;listIndex;hostRow;isBase;receiver;handler;authorFacing;constructor(t,e,n,o,r,s,a,i=!1){this.record=t,this.markerParentPath=e,this.listIndex=n,this.hostRow=o,this.isBase=r,this.receiver=s,this.handler=a,this.authorFacing=i}authorThis(t,e){return this.authorFacing?e:new Proxy(t,new Ie(this.record,this.markerParentPath,this.listIndex,this.hostRow,this.isBase,this.receiver,this.handler,!0))}accessorNameFor(t){return this.record.accessorBySuffixByMarkerParent.get(this.markerParentPath)?.get(t)?.accessorName}accessorAddress(t){return A(f(this.markerParentPath+c+t),this.listIndex)}hostIndexes(){const t=this.listIndex??ke(this.record),e=this.hostRow??t;return(null===this.listIndex?e!==t||xe(this.record,e):Se(e))&&Pe(this.record),e?.indexes??[]}resolveTreePath(t,e){return-1===e.indexOf(d)||null!==this.listIndex&&0!==this.handler.addressStackLength&&"partial"!==Y(e).wildcardType&&!xe(this.record,this.listIndex)?e:Qt(t,e,this.hostIndexes())}get(t,e,n){if("string"!=typeof e)return Reflect.get(t,e);if("then"===e)return;if("$"===e[0]){if("$postUpdate"===e)return t=>{this.receiver.$postUpdate(this.resolveTreePath(t,Ht(this.record,t)))};if("$getAll"===e||"$setAll"===e||"$resolve"===e){const t=this.record,n=this.hostIndexes(),o=this.receiver,r=this.handler,s=this.listIndex;if("$resolve"===e)return(e,r,...s)=>{const a=s.length>0?Gt(t,e):Ht(t,e),i=Jt(0,e,a,r??[],n);return o.$resolve(a,i,...s)};const a=e;return(e,i,...c)=>{const l="$setAll"===a?Gt(t,e):Ht(t,e),u=Jt(0,e,l,void 0===i&&"$getAll"===a&&null===s&&null===Z(r,f(l).wildcardPaths[0])?[]:i,n);return o[a](l,u,...c)}}const t=this.record,n=this.receiver,o=wt(e,e=>this.resolveTreePath(e,Ht(t,e)),t=>n[e](...t));return null!==o?o:this.receiver[e]}const o=this.accessorNameFor(e);if(void 0!==o){this.handler.pushAddress(this.accessorAddress(e));try{return Reflect.get(this.record.stateObject,o,n)}finally{this.handler.popAddress()}}if(this.isBase){if(Object.prototype.hasOwnProperty.call(t,e))return tt(this.handler,this.accessorAddress(e)),t[e];const o=this.record.stateObject[e];if("function"==typeof o)return o.bind(this.authorThis(t,n))}return this.receiver[this.resolveTreePath(e,Ht(this.record,e))]}set(t,e,n,o){if("string"!=typeof e)return Reflect.set(t,e,n);const r=this.accessorNameFor(e);if(void 0!==r){this.record.setterKeys.has(r)||$(`Cannot write to "${r}" on mounted <${this.record.component.tagName.toLowerCase()}>: the accessor has no setter. Add a setter or write to the underlying state paths instead.`),this.handler.pushAddress(this.accessorAddress(e)),this.handler.beginUntrack();try{return Reflect.set(this.record.stateObject,r,n,this.authorThis(t,o))}finally{this.handler.endUntrack(),this.handler.popAddress()}}if(this.isBase&&Object.prototype.hasOwnProperty.call(t,e)){if(this.authorFacing&&"readonly"!==this.handler.mutability){null===this.listIndex&&this.hostIndexes(),this.handler.pushAddress(A(f(this.markerParentPath),this.listIndex));try{this.receiver[this.markerParentPath+c+e]=n}finally{this.handler.popAddress()}return!0}return t[e]=n,!0}return this.receiver[this.resolveTreePath(e,Gt(this.record,e))]=n,!0}has(t,e){if("string"!=typeof e)return Reflect.has(t,e);if("$"===e[0]||"#"===e[0])return!1;if(void 0!==this.accessorNameFor(e))return!0;if(this.isBase){if(Object.prototype.hasOwnProperty.call(t,e))return!0;if("function"==typeof this.record.stateObject[e])return!0}try{return Ht(this.record,e),!0}catch{return!1}}}function je(t,e,n,o){const r=e.pathInfo.path,s=r===t.markerBasePath,a=s?function(t,e){let n=ge.get(t);if(void 0===n&&(n={byListIndex:new WeakMap,noIndex:null},ge.set(t,n)),null===e)return n.noIndex??={...t.privateSnapshot};let o=n.byListIndex.get(e);return void 0===o&&(o={...t.privateSnapshot},n.byListIndex.set(e,o)),o}(t,e.listIndex):{};return new Proxy(a,new Ie(t,r,e.listIndex,e.listIndex??ke(t),s,n,o))}function Ce(t){if(null===ke(t))return t.component[t.stateProp];let e=we.get(t);if(void 0===e){const n={row:null};we.set(t,e=[Ne(t,n),n])}return e[0]}function Ne(t,e){const n=()=>{const n=ve(t);return void 0!==e&&we.get(t)?.[0]!==a&&n.listIndex!==e.row&&Pe(t),n},o=()=>{const e=n();return xe(t,e?.listIndex??null)&&Pe(t),e?.listIndex.indexes??[]},r=(e,n)=>-1===n.indexOf(d)?n:"partial"===Y(n).wildcardType?Qt(e,n,o()):-1===n.indexOf("#")&&xe(t,ke(t))?Pe(t):n,s=(e,o)=>{let r;const s=n();return t.parentStateElement.createState(e,t=>{r=t[M](s,()=>o(t))}),r},a=new Proxy({},{get(e,n){if("string"!=typeof n||"then"===n)return;if("$getAll"===n||"$setAll"===n||"$resolve"===n||"$postUpdate"===n)return function(t,e,n,o,r){return"$postUpdate"===e?e=>n("readonly",n=>n.$postUpdate(r(e,Ht(t,e)))):(r,s,...a)=>{const i="$setAll"===e||"$resolve"===e&&a.length>0,c=i?Gt(t,r):Ht(t,r),l=Jt(0,r,c,"$resolve"===e?s??[]:s,o());return n(i?"writable":"readonly",t=>t[e](c,l,...a))}}(t,n,s,o,r);const a=wt(n,e=>r(e,Ht(t,e)),t=>s("readonly",e=>e[n](...t)));if(null!==a)return a;const i=e=>e["$"===n[0]?n:r(n,Ht(t,n))],c=s("readonly",i);return"$"===n[0]||t.getterKeys.has(n)||"function"!=typeof t.stateObject[n]?c:function(...t){return s("writable",e=>i(e).apply(this,t))}},set:(e,n,o)=>("string"==typeof n&&s("writable",e=>{e["$"===n[0]?n:r(n,Gt(t,n))]=o}),!0),has(e,n){if("string"!=typeof n||"$"===n[0]||"#"===n[0])return!1;if(Object.prototype.hasOwnProperty.call(t.stateObject,n))return!0;try{return Ht(t,n),!0}catch{return!1}}});return a}function Me(t,e){const n=ae(e);null!==n&&n.stateProp!==t.stateProp&&$(`A mount scope is already initialized on this component for "${n.stateProp}" — one <wcs-state bind-component> per component (v2). Merge the "${t.stateProp}" wiring into "${n.stateProp}" or split the component.`),null!==n&&E(e).dispose(),se(e,t),e instanceof ShadowRoot&&K(e,t.parentStateElement),function(t,e){const n=(e,n)=>Xt(t,e,n);D(e);const o=N(t.component);be(t,o);const r=e instanceof ShadowRoot?e:e.getRootNode();B(r,e,void 0,n),z(e,o,n)}(t,e),function(t){if(t.exports.size>0||null===t.rootEntry)return;const e=new Set([...t.getterKeys,...t.setterKeys]);for(const n of e){let e;try{e=Ht(t,n)}catch{continue}const o=e.indexOf(c+t.marker);if(-1===o)continue;const r=e.slice(0,o+1+t.marker.length),s=e.slice(r.length+1),a=e.slice(0,o)+c+s,i=f(a);if(i.wildcardCount!==t.delta)continue;const l={markerTerminalPath:r,suffix:s,markerPath:e,exportedPath:a};t.exports.set(a,l),fe(t.parentStateElement,i.parentPath,i.lastSegment,!0).holders.add({ref:new WeakRef(t),entry:l}),t.parentStateElement.addDynamicDependency(e,a),Q?.markExported(t.parentStateElement,a)}t.parentStateElement.markHasMounts?.()}(t),function(t){const e=N(t.component);if(t.delta>0&&null===e)return;const n=t.component.tagName.toLowerCase();for(const o of t.exports.values()){const r=`${n}|${o.exportedPath}`;if(de.has(r))continue;const s=f(o.exportedPath);let a;t.parentStateElement.createState("readonly",t=>{t[M](e,()=>{a=t[s.parentPath]})}),null!=a&&s.lastSegment in Object(a)&&(de.add(r),console.warn(`[@wcstack/state] [wcs/mount-export-shadowed] <${n}>.${t.stateProp}.${o.suffix} is exported at "${o.exportedPath}" but the tree already has that key, so readers outside the component get the tree value. Remove the tree key or rename the accessor. See docs/state-overlay-export-design.md X1.`))}}(t),me(t),L(e,Promise.resolve())}function Ae(t,e){const n=Oe(t,e).rebindAddresses();R(n),me(t)}function Oe(t,e){const n=E(e),o=N(t.component);return be(t,o),n.forEachActiveBindingNode(t=>W(t,o)),n}function Re(t){for(let e=t.parentNode;null!==e;e=e.parentNode){const t=ae(e);if(null!==t)return Re(t.component),void Oe(t,e)}}function Ee(t,e){if(function(t){const e=te.get(t);return void 0!==e&&e.size>0}(e))for(const n of ce(e)){if(!We(n.component,t))continue;const e=oe(n);null!==e&&Ae(n,e)}}function We(t,e){for(let n=e.firstNode;null!==n;n=n.nextSibling){if(n===t||n.contains(t))return!0;if(n===e.lastNode)break}return!1}const Ke={read(t,e,n,o){if(!0===t.hasMounts&&35===e.pathInfo.lastSegment.charCodeAt(0)){const r=le(t,e.pathInfo.path);if(null!==r)return je(r,e,n,o)}return P},readMissing(t,e,n,o,r){if(null===n){if(vt(t.rootNode??null,e.pathInfo.path))return;return P}if(!0===t.hasMounts){const n=pe(t,e.parentAddress.pathInfo.path,e.pathInfo.lastSegment,e.listIndex);if(null!==n)return function(t,e,n,o,r){const s=je(t,A(f(e.markerTerminalPath),n),o,r);return Reflect.get(s,e.suffix)}(n.record,n.entry,e.listIndex,o,r)}return P},write(t,e){if(!0===t.hasGraftedVolumes){const n=e.pathInfo.path,o=function(t,e){const n=kt.get(t);if(void 0===n||0===n.size)return null;const o=e+c;for(const t of n)if(t.startsWith(o))return t;return null}(t,n);null!==o&&$(`Cannot replace "${n}" wholesale: a volume is mounted at "${o}" under it (D22). Replacing an ancestor of a mount point silently discards the grafted data while its accessors remain. Write "${o}" itself, or individual fields inside "${n}", instead.`)}return P},writeMissing(t,e,n,o,r,s,a){if(!0===t.hasMounts){const n=pe(t,e.parentAddress.pathInfo.path,e.pathInfo.lastSegment,e.listIndex);if(null!==n)return function(t,e,n,o,r,s){const a=je(t,A(f(e.markerTerminalPath),n),r,s);return Reflect.set(a,e.suffix,o)}(n.record,n.entry,e.listIndex,r,s,a)}return P},indexShift(t,e){const n=t.stateElement,o=e.pathInfo.path;if(!0===n.hasMounts&&-1!==o.indexOf("#")){const t=le(n,o);if(null!==t)return function(t,e){const n=e.lastIndexOf("#");if(-1===n)return t.delta;const o=e.indexOf(c,n);if((-1===o?e.slice(n):e.slice(n,o))!==t.marker)return t.delta;const r=-1===o?e:e.slice(0,o),s=-1===o?"":e.slice(o+1),a=t.accessorBySuffixByMarkerParent.get(r)?.get(s);return void 0!==a?a.indexShift:t.delta}(t,o)}return 0},handlerScope(t,e,n,o,r){if(!0!==t.hasMounts)return r;const s=function(t,e){let n=t;for(;null!==n&&n!==e;){const t=Yt.get(n);if(void 0!==t)return t;n=n.parentNode}return Yt.get(e)??null}(e,n);if(null===s)return r;const a=s.indexShiftByLoopElementPath.get(o.pathInfo.path);return void 0!==a?r-a:0},updated(t,e,n){const o=function(t){return jt.get(t)??Ct}(t);for(const r of o){const o=new Set,s={};for(const n of e){if(n.absolutePathInfo.stateElement!==t)continue;const e=n.absolutePathInfo.pathInfo.path;if(-1!==e.indexOf("#"))continue;const a=xt(r.mountPath,r.injections,e);if(null===a||""===a)continue;o.add(a);const i=n.absolutePathInfo.pathInfo.wildcardCount;if(i>0&&null!==n.listIndex){const t=T(n.listIndex,i);(s[a]??=[]).push(t)}}if(o.size>0)try{r.callback.call(It(r.mountPath,n,r.injections),Array.from(o),s)}catch(t){console.error(`[@wcstack/state] volume "${r.mountPath}" $updatedCallback threw.`,t)}}},suppressPathDiagnostic:(t,e)=>vt(!1===t.isConnected?null:t.rootNode??null,e),rowReused(t,e){Ee(e,t)}};let Le=!1;const De=new WeakMap;function Be(t){let e=De.get(t);return void 0===e&&(e={graftInfo:null,initializing:!1,mountPath:null,slotRootNode:null,detachedFrom:null},De.set(t,e)),e}function ze(t,e){null!==e.slotRootNode&&(!function(t,e,n){const o=$t.get(t);o?.get(e)===n&&o.set(e,null)}(e.slotRootNode,e.mountPath,t),e.slotRootNode=null)}function Te(t,e,n){if(e.slotRootNode===n)return!0;const o=e.mountPath;try{bt(n,o,t)}catch{return console.error(`[@wcstack/state] <${S.tagNames.state} mount="${o}"> will not graft: another volume already holds the "${o}" slot on this root. Keep one volume per mount path.`),!1}return F(n)?.markHasVolume?.(),e.slotRootNode=n,!0}async function Fe(t,e){const n=t,o=t.connectedRootNode,r=n.getAttribute("mount");let s;try{!function(t){0===t.length&&$('"mount" requires a non-empty tree path.');const e=f(t);for(const n of e.segments)0===n.length&&$(`"mount" path "${t}" has an empty segment.`),n===d&&$(`"mount" path "${t}" must be static (wildcards are not allowed).`),(n.includes("$")||n.includes("#")||n.includes("@"))&&$(`"mount" path "${t}" must not use reserved characters ($, #, @).`)}(r),s=function(t,e){const n=[],o=new Set;let r;try{r=H(t)}catch(t){$(`[wcs/mount-path-invalid] <${S.tagNames.state} mount="${e}"> has an invalid ${S.bindAttributeName}: ${t instanceof Error?t.message:String(t)}`)}for(const t of r){if(t.propSegments[0]!==l)continue;const r=t.propSegments.slice(1),s=t.statePathInfo,a=n=>$(`[wcs/mount-path-invalid] <${S.tagNames.state} mount="${e}"> "${t.propName}: ${t.statePathName}": ${n}`);1===r.length&&r[0]&&r[0]!==d&&"$"!==r[0][0]&&"#"!==r[0][0]||a(`inject one key at a time ("${l}.<key>: path"); change "mount" to move the whole volume.`),(s.wildcardCount>0||"$"===s.path[0]||"#"===s.path[0])&&a("the injected path must be a static path on the root tree (a volume has no loop context)."),(t.inFilters.length>0||t.outFilters.length>0)&&a("an injection takes no filters."),t.propModifiers.some(t=>t!==u)&&a(`an injection accepts only #${u}.`),o.has(r[0])&&a(`"${r[0]}" is injected twice.`),o.add(r[0]),n.push({innerSegments:r,outerPathInfo:s,readonly:t.propModifiers.includes(u)})}return n.sort((t,e)=>e.innerSegments.length-t.innerSegments.length),n}(n.getAttribute(S.bindAttributeName)??"",r),n.hasAttribute("bind-component")&&$('"mount" cannot be combined with "bind-component".'),n.hasAttribute("enable-ssr")&&console.warn(`[@wcstack/state] <${S.tagNames.state} mount="${r}"> ignores "enable-ssr" — snapshots are per root tree (the root state element aggregates volume data).`),bt(o,r,t),F(o)?.markHasVolume?.(),e.mountPath=r,e.slotRootNode=o}catch(e){throw t.settleInitialization(),e}e.initializing=!0,null===F(o)&&function(t,e){const n=()=>{if(null!==F(t))return;const n=t.querySelectorAll(S.tagNames.state);for(const t of n)if(!t.hasAttribute("mount")&&!t.hasAttribute("bind-component"))return;console.error(`[@wcstack/state] <${S.tagNames.state} mount="${e}"> has no root state tree to graft onto (D11). A volume mounts onto the root tree — add a root <${S.tagNames.state}> to this root node (an empty <${S.tagNames.state}></${S.tagNames.state}> is enough). If the root is added dynamically later, the graft will still complete and this report can be ignored.`)},o=t.ownerDocument??t;"loading"===o.readyState?o.addEventListener("DOMContentLoaded",()=>queueMicrotask(n),{once:!0}):setTimeout(n,0)}(o,r);const a=n=>{e.graftInfo=n,t.markInitialized(),null===n&&ze(t,e),t.settleInitialization()};let i;try{await Promise.resolve(),i=await t.loadStateFromSource()}catch(t){return console.error(`[@wcstack/state] volume "${r}" failed to load.`,t),void a(null)}const c=t.connectedRootNode??null;null!==c&&Te(t,e,c)?function(t,e,n,o,r,s,a=[]){const i={mountPath:n,volumeState:o,injections:a,onGrafted:r,acquireSlot:s};if(null!==e)return void yn(e,i);$n(),function(t,e){if(Mt.has(t))return void At(e);let n=Nt.get(t);void 0===n&&(n=[],Nt.set(t,n)),n.push(e)}(t,i)}(c,F(c),r,i,a,()=>Te(t,e,c),s):a(null)}const Ve={order:20,connecting(t){if(!t.hasAttribute("mount"))return null;const e=Be(t);if(e.initializing){const n=t.connectedRootNode;if(null!=n&&e.detachedFrom===n)try{bt(n,e.mountPath,t),F(n)?.markHasVolume?.(),e.slotRootNode=n}catch{}return e.detachedFrom=null,o}return Fe(t,e)},reconnecting(t){if(!t.hasAttribute("mount"))return!1;const e=Be(t),n=t.connectedRootNode??null;return null!==e.graftInfo&&null!==n&&F(n)===e.graftInfo.rootStateElement&&pn(e.graftInfo,"$connectedCallback"),!0},replacingState(t){if(!0!==De.get(t)?.initializing)return;const e=t.getAttribute("mount");$(`Cannot replace the state of <${S.tagNames.state} mount="${e}"> after it has loaded: a volume's data is copied into the root tree when it grafts, so a new state would never reach the page. Write the paths under "${e}" on the root state instead.`)},initializeFailed(t,e){!function(t){Mt.add(t);const e=Nt.get(t);if(void 0!==e){Nt.delete(t);for(const t of e)At(t)}}(e)},initializeFailureCleared(t,e){!function(t){Mt.delete(t)}(e)},disconnecting(t){if(!t.hasAttribute("mount"))return!1;const e=Be(t);return null!==e.graftInfo&&pn(e.graftInfo,"$disconnectedCallback"),!0!==t.initialized&&(e.detachedFrom=e.slotRootNode,ze(t,e)),t.clearConnectedRootNode(),!0}};let qe=!1;const _e=new WeakMap;function Ge(t,e){let n=_e.get(t);n||(n=new Set,_e.set(t,n)),n.add(e)}const He=new WeakMap;const Ue=new WeakMap,Xe=new WeakMap;const Je=new WeakMap;const Qe={isComplete:function(t,e){return!0===_e.get(t)?.has(e)},isDeclared:function(t,e){return!0===He.get(t)?.has(e)},rememberOverwrittenObject:function(t,e,n){let o=Ue.get(t);o||(o=new Map,Ue.set(t,o)),o.has(e)||o.set(e,n)},recordInjectedKey:function(t,e,n){let o=Xe.get(t);o||(o=new Map,Xe.set(t,o));let r=o.get(e);r||(r=new Set,o.set(e,r)),r.add(n)},rememberOverwrittenValue:function(t,e,n,o){let r=Je.get(t);r||(r=new Map,Je.set(t,r));let s=r.get(e);s||(s=new Map,r.set(e,s)),s.has(n)||s.set(n,o)}};function Ye(t){return function(t){const e=Object.getPrototypeOf(t),n=Object.create(e),o=Object.getOwnPropertyDescriptors(t);for(const t in o){const e=o[t];!1===e.writable&&(e.writable=!0)}return Object.defineProperties(n,o),n}(t)}const Ze=new WeakMap;class tn{_innerStateElement;constructor(t,e){this._innerStateElement=function(t,e){const n=Ze.get(t);return n?n.get(e)??null:null}(t,e)??$("State element not found for web component.")}get(t,e,n){if("string"==typeof e){let t;return this._innerStateElement.createState("readonly",n=>{t=n[e]}),t}return Reflect.get(t,e,n)}set(t,e,n,o){return"string"==typeof e?(this._innerStateElement.createState("writable",t=>{t[e]=n}),!0):Reflect.set(t,e,n,o)}}const en=t=>()=>t;function nn(t,e,n,o){!function(t,e,n){let o=Ze.get(t);o||(o=new Map,Ze.set(t,o)),o.set(e,n)}(e,n,t),t.setInitialState(Ye(o));const r=function(t,e){const n=new tn(t,e);return new Proxy({},n)}(e,n);Object.defineProperty(e,n,{get:en(r),enumerable:!0,configurable:!0}),Ge(e,n),on(e,n)}function on(t,e){if(m in t){const n=t[m];"function"==typeof n?n.call(t,e).catch(t=>{$(`Error in ${m}: ${t instanceof Error?t.message:String(t)}`)}):$(`${m} is not a function.`)}}const rn=new Set;function sn(t,e){rn.has(t)||(rn.add(t),console.warn(`[@wcstack/state] [wcs/mount-own-key-shadow] ${e} See docs/state-mount-design.md §4-3.`))}function an(t){!function(t){const e=t.component.tagName.toLowerCase(),n=t.stateProp;let o=null;for(const r of t.entries){if(0===r.innerSegments.length)continue;const s=r.innerSegments[0];o??=k(t.stateObject);const a=o[s];let i;if(t.getterKeys.has(s)||t.setterKeys.has(s)||"function"==typeof a?.get||"function"==typeof a?.set)i="an accessor";else if("function"==typeof a?.value)i="a method";else{if(t.mappedKeys.has(s)||t.injectedKeys.has(s)||!Object.prototype.hasOwnProperty.call(t.stateObject,s))continue;i="an own data key"}const l=r.innerSegments.join(c);sn(`${e}|${n}|${l}|entry`,`<${e}>.${n} declares "${s}" as ${i}, which hides the mounted entry "${n}.${l}: ${r.outerPathInfo.path}" (the host value never reaches it). Rename one of them.`)}}(t);const e=Object.keys(t.privateSnapshot);if(0===e.length)return;const n=t.component.tagName.toLowerCase(),o=t.stateProp;let r,s=!1;for(const a of e){if(null===t.rootEntry)continue;if(s||(r=cn(t),s=!0),"object"!=typeof r||null===r||!(a in r))continue;const e=t.rootEntry.outerPathInfo.path;sn(`${n}|${o}|${a}|root`,`<${n}>.${o}.${a} is private and hides the mounted tree key "${e}.${a}" (${o}: ${e}). Remove the default to read the tree, or rename it to keep it private.`)}}function cn(t){const e=t.rootEntry,n=N(t.component);if(e.outerPathInfo.wildcardCount>0&&null===n)return;let o;return t.parentStateElement.createState("readonly",t=>{t[M](n,()=>{o=t[e.outerPathInfo.path]})}),o}const ln=new WeakMap;function un(t,e){t.landInitialization(),$(e)}async function dn(t,e){const n=t;if(n.hasAttribute("bind-component")){const s=n.parentNode,a=s instanceof ShadowRoot?s.host:s instanceof Element?s:null,i=a?_(a):null;null!==a&&null!==i||$(`"bind-component" requires <${S.tagNames.state}> to be a direct child of a custom element.`),s instanceof ShadowRoot||a.hasAttribute(S.bindAttributeName)||un(t,`A plain (unwired) Light DOM "bind-component" is not supported. Attach a shadow root to <${i}>, or mount it from the host (data-wcs="${n.getAttribute("bind-component")}: path").`);const c=["state","src","json"].filter(t=>n.hasAttribute(t));null!==n.querySelector('script[type="module"]')&&c.push('<script type="module">'),c.length>0&&$(`"bind-component" cannot be combined with ${c.join(", ")}. The component's "${n.getAttribute("bind-component")}" property is the only state source.`);const l=n.getAttribute("bind-component");!function(t,e){let n=He.get(t);n||(n=new Set,He.set(t,n)),n.add(e)}(a,l);const u=I(a);null===u&&$(`CustomElementRegistry is unavailable for <${i}>.`),await u.whenDefined(i.toLowerCase()),a.hasAttribute(S.bindAttributeName)&&await G(a),l in a||$(`Component does not have property "${l}" for state binding.`);let d=a[l];"object"==typeof d&&null!==d||$(`Component property "${l}" is not an object for state binding.`);const f=function(t,e){const n=Ue.get(t);if(!n)return;const o=n.get(e);return n.delete(e),o}(a,l);if(void 0!==f&&function(t,e){if(!t.hasAttribute(S.bindAttributeName))return!1;const n=V(t);if(null===n)return!1;for(const t of n)if(1===t.propSegments.length&&t.propSegments[0]===e)return!0;return!1}(a,l)&&(a[l]=f,d=f),e.boundComponent=a,e.boundComponentStateProp=l,t.setBoundComponent(a,l),s instanceof ShadowRoot||(V(a)??[]).some(t=>t.propSegments[0]===l)||un(t,`A plain (unwired) Light DOM "bind-component" is not supported. Attach a shadow root to <${i}>, or mount it from the host (data-wcs="${l}: path").`),a.hasAttribute(S.bindAttributeName)){const c=(V(a)??[]).filter(t=>t.propSegments[0]===l);if(c.length>0){const u=F(a.getRootNode())??un(t,`No state tree found on this root for mount host <${i}>.`);let f=(o=a,r=l,Zt.get(o)?.get(r)??null);const h=null!==f;if(null===f&&(!function(t,e,n){const o=Je.get(t)?.get(e);if(void 0!==o){for(const[t,e]of o)n[t]=e;Je.get(t).delete(e)}}(a,l,d),f=Lt(a,l,c,u,d,function(t,e){return Xe.get(t)?.get(e)}(a,l)),an(f)),e.mountRecord=f,n.parentNode!==s)return;try{Me(f,s instanceof ShadowRoot?s:a)}catch(e){throw t.landInitialization(),e}if(!h){const t=Ne(f);Object.defineProperty(a,l,{get:()=>t,enumerable:!0,configurable:!0}),Ge(a,l)}return on(a,l),function(t){const e=Et.filter(e=>void 0!==t.stateObject[e]);for(const n of t.getterKeys)-1!==n.indexOf(p)&&e.push(`"${n}"`);if(0===e.length)return;const n=`${t.component.tagName.toLowerCase()}|${t.stateProp}`;Wt.has(n)||(Wt.add(n),console.warn(`[@wcstack/state] [wcs/mount-dollar-declaration] <${n.split("|")[0]}>.${t.stateProp} declares ${e.join(", ")}, which mounted components do not run. Declare them on the root state instead (a volume <wcs-state mount="..."> can host $watch / $listKeys / $updatedCallback; $recursion and "**" getters expand against the root tree). See docs/state-mount-design.md §4-6.`))}(f),void Kt(f,"$connectedCallback",()=>Ce(f))}}nn(t,e.boundComponent,e.boundComponentStateProp,d)}var o,r}const fn={order:30,preparing(t){if(!t.hasAttribute("bind-component"))return null;const e=function(t){let e=ln.get(t);return void 0===e&&(e={boundComponent:null,boundComponentStateProp:null,mountRecord:null},ln.set(t,e)),e}(t);return dn(t,e).then(()=>null!==e.mountRecord&&(t.markInitialized(),t.settleInitialization(),!0))},reconnecting(t){const e=ln.get(t);if(void 0===e||null===e.mountRecord)return!1;const n=e.mountRecord,o=t.parentNode;return queueMicrotask(()=>{null!=t.connectedRootNode&&Ae(n,o)}),t.isConnected&&(Re(n.component),Oe(n,o)),Kt(n,"$connectedCallback",()=>Ce(n)),!0},disconnecting(t){const e=ln.get(t);if(void 0===e||null===e.mountRecord)return!1;const n=e.mountRecord;return Kt(n,"$disconnectedCallback",()=>Ce(n)),function(t){const e=we.get(t);void 0!==e&&(e[1].row=ke(t),we.delete(t))}(n),me(e.mountRecord),t.clearConnectedRootNode(),!0}};let hn=!1;function pn(t,e){const n=t.volumeState[e];"function"==typeof n&&t.rootStateElement.createState("writable",o=>{const r=n.call(It(t.mountPath,o,t.injections));r instanceof Promise&&r.catch(n=>{console.error(`[@wcstack/state] volume "${t.mountPath}" ${e} failed.`,n)})})}function mn(t,e,n,o){const r=n[g];if(void 0!==r){const n=J(e),s=[],a=new Set;let i=0;for(const[n,c]of Object.entries(r)){const r=St(e,o,n,!1),l=function(t,n,...r){c.call(It(e,this,o),t,n,...r)};s.push({path:r,pathInfo:f(r),handler:l,order:1e6+i++}),a.add(r),t.setPathInfo(r,"prop","watch")}s.length>0&&(n.addEntries(t,s),t.addVolumeWatchPaths?.(a),n.start(t))}const s=n[y];if(void 0!==s){const n=new Map;for(const[t,r]of Object.entries(s))n.set(St(e,o,t,!1),r);t.mergeVolumeListKeys?.(n)}const a=n[h];"function"==typeof a&&(!function(t,e){let n=jt.get(t);void 0===n&&(n=[],jt.set(t,n)),n.push(e),t.markHasVolume?.()}(t,{mountPath:e,injections:o,callback:a}),t.enableUpdatedCallback?.());for(const t of["$commandTokens","$eventTokens","$on","$errorCallback"])void 0!==n[t]&&console.warn(`[@wcstack/state] volume "${e}" declares ${t}, which volumes do not support. Declare it on the root state instead.`)}function gn(t,e,n,o=[]){x(n),function(t,e,n,o){const r=0===o.length?null:k(n);for(const t of o){const n=t.innerSegments[0],o=r[n];void 0===o||"function"!=typeof o.get&&"function"!=typeof o.set&&"function"!=typeof o.value||$(`[wcs/mount-path-invalid] Volume "${e}" declares "${n}" as an accessor or a method and also injects it ("${l}.${n}: ${t.outerPathInfo.path}"). Rename one of them.`)}const s=n[g];if(void 0!==s){"object"==typeof s&&null!==s||$(`${g} must be an object mapping state paths to handler functions.`);const t=J(e);for(const[e,n]of Object.entries(s))"function"!=typeof n&&$(`${g} entry "${e}" must be a function.`),t.assertValidPath(e)}const i=n[y];if(void 0!==i){"object"==typeof i&&null!==i||$(`${y} must be an object mapping list paths to key specs.`);for(const[n,r]of Object.entries(i)){(0===n.length||"string"!=typeof r&&"function"!=typeof r)&&$(`${y} entry "${n}" must map a list path to a field name or a key function.`);const s=St(e,o,n,!1);t.listKeys?.has(s)&&$(`${y} entry "${s}" is declared by both the root and a volume (or two volumes). Keep exactly one.`)}}void 0!==n[a]&&$(`Volume "${e}" declares ${a}, which volumes do not support yet. Declare the stream on the root state.`),void 0!==n.$scan&&$(`Volume "${e}" declares $scan, which volumes do not support yet. Declare the scan on the root state.`),void 0!==n[w]&&$(`Volume "${e}" declares ${w}, which volumes do not support yet. Declare the recursion anchor on the root state — the anchor path is resolved against the root tree.`);for(const t of Object.keys(k(n)))-1!==t.indexOf(p)&&$(`Volume "${e}" declares "${t}", which uses "${p}". Volumes do not support recursive getters yet — declare them on the root state.`)}(t,e,n,o);const{data:r,accessors:s}=function(t,e){const n={},o=new Map;for(const[r,s]of Object.entries(k(t)))r.startsWith("$")||e.has(r)||("function"!=typeof s.get&&"function"!=typeof s.set?"function"!=typeof s.value&&(n[r]=s.value):o.set(r,s));return{data:n,accessors:o}}(n,new Set(o.map(t=>t.innerSegments[0]))),i=f(e),u=!0===t.hydratedFromSsr;t.createState("writable",t=>{if(1===i.segments.length&&e in t){if(u)return;$(`Volume mount "${e}" collides with an existing key on the root tree. Remove the root key or mount the volume elsewhere.`)}let n="";for(let e=0;e<i.segments.length-1;e++){const o=i.segments[e],r=""===n?o in t:void 0!==t[n+c+o];n=""===n?o:n+c+o,r||(t[n]={})}if(i.segments.length>1&&void 0!==t[e]){if(u)return;$(`Volume mount "${e}" collides with an existing key on the root tree. Remove the root key or mount the volume elsewhere.`)}t[e]=r}),function(t,e){let n=kt.get(t);void 0===n&&(n=new Set,kt.set(t,n)),n.add(e)}(t,e),t.markHasGraftedVolumes?.();for(const[n,r]of s){const s=e+c+n,a=r.get,i=r.set,l={enumerable:!1,configurable:!0};"function"==typeof a&&(l.get=function(){return a.call(It(e,this,o))}),"function"==typeof i&&(l.set=function(t){i.call(It(e,this,o),t)}),t.defineTreeAccessor(s,l)}mn(t,e,n,o);const d=n.$connectedCallback;return"function"==typeof d&&t.createState("writable",t=>{let n;try{n=d.call(It(e,t,o))}catch(t){return void console.error(`[@wcstack/state] volume "${e}" $connectedCallback failed.`,t)}n instanceof Promise&&n.catch(t=>{console.error(`[@wcstack/state] volume "${e}" $connectedCallback failed.`,t)})}),{rootStateElement:t,mountPath:e,volumeState:n,injections:o}}function yn(t,e){if(!e.acquireSlot())return void e.onGrafted(null);let n=null;try{n=gn(t,e.mountPath,e.volumeState,e.injections)}catch(t){console.error(`[@wcstack/state] volume "${e.mountPath}" failed to graft.`,t)}finally{e.onGrafted(n)}}let wn=!1;function $n(){wn||(wn=!0,Le||(Le=!0,v("scopes",Ke),X(ie)),qe||(qe=!0,t("scopes",Ve)),hn||(hn=!0,t("bindComponent",fn),q(Qe)),Ot=yn,U(bn))}function bn(t,e){(function(t){const e=$t.get(t);return void 0!==e&&e.size>0})(t)&&e.markHasVolume?.(),function(t,e){Mt.delete(t);const n=Nt.get(t);if(void 0===n||0===n.length||null===Ot)return;Nt.delete(t);const o=Ot;queueMicrotask(()=>{for(const t of n)o(e,t)})}(t,e)}const vn={name:"scopes",install(){$n(),ht||(ht=!0,t("dcc",ft))}};export{vn as default,vn as scopes};
1
+ import{r as t,l as e,a as n,C as o}from"../chunks/lifecycleHooks.js";import{k as r,l as s,a,m as i,D as c,V as l,n as u,W as d,g as f,o as h,R as p,p as m,i as g,q as y,r as w}from"../chunks/pathDiagnostics.js";import{r as $,d as b}from"../chunks/errorGuidance.js";import{r as v,g as k,N as P}from"../chunks/getAllPropertyDescriptors.js";import{c as S}from"../chunks/filterRegistry.js";import{n as x}from"../chunks/declarationAliases.js";import{q as I,u as j,t as C,v as N,w as M,j as A,i as O,x as R,y as E,z as W,A as K,B as L,C as D,D as B,E as z,o as T,F,G as V,H as q,I as _,J as G,K as H,L as U}from"../chunks/binder.js";import{a as X,r as J}from"../chunks/featureBridge.js";import{p as Q}from"../chunks/diagnosticsHooks.js";import{g as Y,a as Z,c as tt}from"../chunks/checkDependency.js";const et={written:function(t,e,n){const o=t.bindableEventMap,r=o[e.path],s="string"==typeof r,a=s?r:e.segments.length>1&&-1===e.path.indexOf("#")?o[e.segments[0]]:void 0;if("string"!=typeof a)return;const i=t.rootNode;i instanceof ShadowRoot&&i.host.dispatchEvent(new CustomEvent(a,{detail:s&&void 0!==n?n.value:void 0,bubbles:!0}))}};let nt=!1;function ot(t){return function(){const e=this.stateElement;if(!e)return;if(!0!==e.initialized)return;let n;try{e.createState("readonly",e=>{n=e[t]})}catch(e){return void console.warn(`[@wcstack/state] DCC getter "${t}" failed:`,e)}return n}}function rt(t){return function(e){const n=this.stateElement;n&&(!0!==n.initialized?n.initializePromise.then(()=>{n.createState("writable",n=>{n[t]=e})}):n.createState("writable",n=>{n[t]=e}))}}function st(t,e){return e?function(...e){const n=this.stateElement;if(n)return n.initializePromise.then(()=>{let o;return n.createStateAsync("writable",async n=>{o=await n[t](...e)}).then(()=>o)})}:function(...e){const n=this.stateElement;if(n)return n.initializePromise.then(()=>{let o;return n.createState("writable",n=>{o=n[t](...e)}),o})}}function at(t){return t.startsWith("$")}function it(t,e){return Object.keys(t).filter(n=>{if(n.startsWith("$")||"constructor"===n)return!1;const o="function"==typeof t[n].value;return"method"===e?o:!o})}function ct(t,e){const n=t[e];if(void 0===n)return null;Array.isArray(n)||$(`${e} must be an array of strings.`);const o=[],r=new Set;for(const t of n)"string"==typeof t&&0!==t.length||$(`${e} entries must be non-empty strings.`),t.startsWith("$")&&$(`${e} entry "${t}" must not start with "$" (internal properties are not exposed on the component).`),r.has(t)&&$(`${e} entry "${t}" is duplicated.`),r.add(t),o.push(t);return o}function lt(t){x(t);const e=ct(t,r)??[],n=ct(t,s)??[],o=k(t),i=function(t){const e=t[a];return"object"!=typeof e||null===e?new Set:new Set(Object.keys(e))}(t),c=[];for(const t of e){const e=o[t];if(void 0===e){if(i.has(t)){c.push(t);continue}$(`${r} entry "${t}" is not declared on the state.${b(t,it(o,"value"))}`)}"function"==typeof e.value&&$(`${r} entry "${t}" is a method. Declare it in ${s} instead.`)}for(const t of n){const e=o[t];void 0===e&&$(`${s} entry "${t}" is not declared on the state.${b(t,it(o,"method"))}`),"function"!=typeof e.value&&$(`${s} entry "${t}" is not a method. Declare it in ${r} instead.`)}return{bindables:e,commands:n,streamBackedBindables:c}}function ut(t,e,n){const o=t.tagName.toLowerCase();o.includes("-")||$(`DCC: "${o}" is not a valid custom element name (must contain a hyphen).`);const s=I(t);null!==s&&"function"==typeof s.define||$(`DCC: CustomElementRegistry is unavailable for "${o}".`),s.get(o)&&$(`DCC: "${o}" is already registered. A custom element name can only be defined once.`);const a=document.createElement("template"),c=a.content.ownerDocument;for(const t of Array.from(e.childNodes))a.content.appendChild(c.importNode(t,!0));const l=e.mode,{bindables:u,commands:d,streamBackedBindables:f}=lt(n),h=u.length>0||d.length>0?function(t,e,n=[]){const o={protocol:"wc-bindable",version:1,properties:e.map(e=>({name:e,event:`${t}:${e}-changed`,getter:t=>t.target[e]})),inputs:e.map(t=>({name:t}))};if(0===n.length)return o;const r=n.map(t=>({name:t,async:!0}));return{...o,commands:r}}(o,u,d):null,p=u.length>0?function(t,e){const n={};for(const o of e)n[o]=`${t}:${o}-changed`;return n}(o,u):{},m=S.tagNames.state,g=class extends HTMLElement{static template=a;static shadowRootMode=l;static wcBindable=h;static bindableEventMap=p;_shadow=null;_ensureShadow(){if(null!==this._shadow)return this._shadow;if(this.hasAttribute(i))return null;this._shadow=this.attachShadow({mode:g.shadowRootMode}),this._shadow.appendChild(g.template.content.cloneNode(!0));const t=I(this._shadow);return null!==t&&j(t,this._shadow),this._shadow}connectedCallback(){const t=this._ensureShadow();if(null!==t&&Object.keys(g.bindableEventMap).length>0){const e=t.querySelector(m);e?(nt||(nt=!0,v("dcc",et)),e.setBindableEventMap(g.bindableEventMap)):console.warn(`[@wcstack/state] DCC: "${o}" declares ${r} but its template has no <${S.tagNames.state}>. Change events will not be dispatched.`)}}get stateElement(){return this._ensureShadow()?.querySelector(m)??null}},y=k(n);for(const[t,e]of Object.entries(y)){if(at(t))continue;const n={configurable:!0,enumerable:!0};if("function"==typeof e.value){const o="AsyncFunction"===e.value.constructor?.name;n.value=st(t,o)}else n.get=ot(t),n.set=rt(t);Object.defineProperty(g.prototype,t,n)}for(const t of f)Object.defineProperty(g.prototype,t,{configurable:!0,enumerable:!0,get:ot(t),set:rt(t)});s.define(o,g)}async function dt(t,o,r){const s=t;try{s.hasAttribute("bind-component")&&$(`"bind-component" cannot be used inside a [${i}] host. DCC state comes from the template, not from a component property.`);const a=await async function(t,o){if(t.hasAttribute("src")){const n=t.getAttribute("src");if(n.endsWith(".js"))return await e(n);$(`DCC: Unsupported src type: ${n}`)}const r=t.querySelector('script[type="module"]');if(r)return await n(r,o.tagName.toLowerCase());$(`DCC: No state source found for "${o.tagName.toLowerCase()}".`)}(s,o);ut(o,r,a),t.markTreeless(),t.markInitialized(),t.clearConnectedRootNode(),t.settleInitialization()}catch(e){t.failInitializeLoudly(e)}}const ft={order:10,connecting(t){const e=t.parentNode;return e instanceof ShadowRoot&&e.host.hasAttribute(i)?dt(t,e.host,e):null}};let ht=!1;function pt(t,e){if(e.length>t.length)return!1;for(let n=0;n<e.length;n++)if(t[n]!==e[n])return!1;return!0}function mt(t,e){for(const n of t)if(pt(e,n.innerSegments))return n;return null}function gt(t,e){const n=e.slice(t.innerSegments.length);return 0===n.length?t.outerPathInfo.path:t.outerPathInfo.path+c+n.join(c)}const yt=new Map([["$eq",[0]],["$eqPath",[0,1]],["$eqIndex",[0]],["$dependOn",[0]],["$trackDependency",[0]]]);function wt(t,e,n){const o=yt.get(t);return void 0===o?null:(...t)=>{const r=t.slice();for(let t=0;t<o.length;t++){const n=o[t];"string"==typeof r[n]&&(r[n]=e(r[n]))}return n(r)}}const $t=new WeakMap;function bt(t,e,n){let o=$t.get(t);void 0===o&&(o=new Map,$t.set(t,o));const r=o.get(e);null!=r&&$(`Volume slot "${e}" is already mounted on this tree.`),o.set(e,n)}function vt(t,e){if(null===t)return!1;const n=$t.get(t);if(void 0===n||0===n.size)return!1;for(const t of n.keys())if(e===t||e.startsWith(t+c)||t.startsWith(e+c))return!0;return!1}const kt=new WeakMap;const Pt=[];function St(t,e,n,o){if(e.length>0){const r=n.split(c),s=mt(e,r);if(null!==s)return o&&s.readonly&&$(`[wcs/mount-readonly] volume "${t}" cannot write "${n}": it is injected read-only ("${l}.${s.innerSegments.join(c)}#${u}: ${s.outerPathInfo.path}"). Write "${s.outerPathInfo.path}" on the root, or drop #${u} from the injection.`),gt(s,r)}return t+c+n}function xt(t,e,n){let o=-1,r=null;for(const t of e){const e=t.outerPathInfo.path;e.length<=o||(n===e?(o=e.length,r=t.innerSegments.join(c)):n.startsWith(e+c)&&(o=e.length,r=t.innerSegments.join(c)+n.slice(e.length)))}if(t.length>o){if(n===t)return"";if(n.startsWith(t+c))return n.slice(t.length+1)}return r}function It(t,e,n=Pt){return new Proxy({},{get(o,r){if("string"==typeof r&&"then"!==r){if("$"===r[0]){if("$postUpdate"===r||"$getAll"===r){const o=r;return(r,...s)=>e[o](St(t,n,r,!1),...s)}if("$setAll"===r)return(o,...r)=>e.$setAll(St(t,n,o,!0),...r);if("$resolve"===r)return(o,...r)=>e.$resolve(St(t,n,o,r.length>1),...r);const o=wt(r,e=>St(t,n,e,!1),t=>e[r](...t));return null!==o?o:e[r]}return e[St(t,n,r,!1)]}},set:(o,r,s)=>"string"!=typeof r||("$"===r[0]?(e[r]=s,!0):(e[St(t,n,r,!0)]=s,!0)),has:(t,e)=>"string"==typeof e&&"$"!==e[0]&&"#"!==e[0]})}const jt=new WeakMap,Ct=[];const Nt=new WeakMap,Mt=new WeakSet;function At(t){console.error(`[@wcstack/state] volume "${t.mountPath}" was not grafted — the root state element on this root node failed to initialize (its own diagnostic is reported separately). The volume is not at fault: fix the root <wcs-state>.`),t.onGrafted(null)}let Ot=null;let Rt=0;const Et=["$watch",a,"$scan","$listKeys",h,"$commandTokens","$eventTokens","$on","$recursion","$errorCallback"],Wt=new Set;function Kt(t,e,n){const o=t.stateObject[e];if("function"==typeof o)try{const r=o.call(n());r instanceof Promise&&r.catch(n=>{console.error(`[@wcstack/state] mounted <${t.component.tagName.toLowerCase()}> ${e} failed.`,n)})}catch(n){console.error(`[@wcstack/state] mounted <${t.component.tagName.toLowerCase()}> ${e} failed.`,n)}}function Lt(t,e,n,o,r,s=new Set){0===n.length&&$(`Cannot build a mount record without host bindings for "${e}".`),x(r);const a=[],i=new Set;let l=null;for(const t of n){const e=t.propSegments.slice(1),n=e.join(c);i.has(n)&&$("Duplicate mapping rule for web component."),i.add(n);const o={innerSegments:e,outerPathInfo:t.statePathInfo,readonly:!0===t.propModifiers?.includes(u)};a.push(o),0===e.length&&(l=o)}a.sort((t,e)=>e.innerSegments.length-t.innerSegments.length);const d=++Rt,f=`#m${d}`,{getterKeys:h,setterKeys:p}=function(t){const e=new Set,n=new Set,o=k(t);for(const[t,r]of Object.entries(o))"function"==typeof r.get&&e.add(t),"function"==typeof r.set&&n.add(t);return{getterKeys:e,setterKeys:n}}(r),m=new Set;for(const t of a)1===t.innerSegments.length&&m.add(t.innerSegments[0]);const g={};for(const t of Object.keys(r))t.startsWith("$")||h.has(t)||p.has(t)||"function"!=typeof r[t]&&(s.has(t)||m.has(t)||(g[t]=r[t]));return{id:d,marker:f,component:t,stateProp:e,parentStateElement:o,entries:a,rootEntry:l,delta:null===l?0:l.outerPathInfo.wildcardCount,markerBasePath:null===l?f:l.outerPathInfo.path+c+f,stateObject:r,getterKeys:h,setterKeys:p,injectedKeys:s,mappedKeys:m,hasReadonlyEntries:a.some(t=>t.readonly),privateSnapshot:g,accessorBySuffixByMarkerParent:new Map,indexShiftByLoopElementPath:new Map,addedGetterPaths:new Set,exports:new Map}}function Dt(t){const e=t.indexOf(c);return-1===e?t:t.slice(0,e)}function Bt(t,e){const n=mt(t.entries,e);return null===n?null:gt(n,e)}function zt(t,e){return t.markerBasePath+c+e}function Tt(t,e,n,o){let r=t.accessorBySuffixByMarkerParent.get(e);void 0===r&&(r=new Map,t.accessorBySuffixByMarkerParent.set(e,r));const s=e+c+n;r.set(n,{accessorName:o,indexShift:f(s).wildcardCount-f(o).wildcardCount}),t.getterKeys.has(o)&&(t.parentStateElement.getterPaths?.add(s),t.addedGetterPaths.add(s))}function Ft(t,e){return!t.injectedKeys.has(e)&&(!t.getterKeys.has(e)&&"function"==typeof t.stateObject[e]||!t.mappedKeys.has(e)&&(Object.prototype.hasOwnProperty.call(t.stateObject,e)&&!t.getterKeys.has(e)&&!t.setterKeys.has(e)))}function Vt(t,e){return`Path "${e}" in <${t.component.tagName.toLowerCase()}> does not resolve: it is not an own key of the component state and no mount entry covers it (mounted prefixes: ${t.entries.filter(t=>t.innerSegments.length>0).map(t=>t.innerSegments.join(c)).join(", ")}). Mount it from the host ("${t.stateProp}: path" / "${t.stateProp}.${Dt(e)}: path") or declare the key on the component state.`}const qt=/^\$(\d+)$/;function _t(t,e){if(!t.hasReadonlyEntries)return null;const n=e[0];if("$"===n||"#"===n)return null;if(t.getterKeys.has(e)||t.setterKeys.has(e))return null;const o=Dt(e);if(t.getterKeys.has(o)||t.setterKeys.has(o)||Ft(t,o))return null;const r=function(t,e){return mt(t.entries,e)}(t,e.split(c));return null!==r&&r.readonly?r:null}function Gt(t,e){const n=_t(t,e);if(null!==n){const o=0===n.innerSegments.length?"":c+n.innerSegments.join(c);$(`[wcs/mount-readonly] <${t.component.tagName.toLowerCase()}> cannot write "${e}": it is mounted read-only ("${t.stateProp}${o}#${u}: ${n.outerPathInfo.path}"). Write it on the host, or drop #${u} from the mount.`)}return Ht(t,e)}function Ht(t,e){const n=e[0];if("$"===n||"#"===n)return e;if(t.getterKeys.has(e)||t.setterKeys.has(e))return function(t,e){const n=e.split(c);let o=-1;for(let t=n.length-1;t>=0;t--)if(n[t]===d){o=t;break}if(-1===o)return Tt(t,t.markerBasePath,e,e),zt(t,e);if(Ft(t,n[0]))return Tt(t,t.markerBasePath,e,e),zt(t,e);const r=n.slice(0,o+1),s=n.slice(o+1),a=Bt(t,r);null===a&&$(Vt(t,e)),0===s.length&&$(`Wildcard-terminal accessor "${e}" on mounted <${t.component.tagName.toLowerCase()}> is not supported: it translates to a marker-terminal path where the mount overlay would shadow the accessor. Declare the row value as a getter on the host tree, or back it with a component-own array (a private key makes the whole path private).`);const i=a+c+t.marker;return Tt(t,i,s.join(c),e),i+c+s.join(c)}(t,e);const o=Dt(e);if(t.getterKeys.has(o)||t.setterKeys.has(o))return zt(t,e);if(Ft(t,o))return zt(t,e);const r=Bt(t,e.split(c));if(null!==r)return r;$(Vt(t,e))}const Ut=new Set(["prop","radio","checkbox"]);function Xt(t,e,n){let o;const r=qt.exec(e.statePathName);if(null!==r){const s=function(t,e){if(void 0===e)return t.delta;const n=Ht(t,e);return f(n).wildcardCount-f(e).wildcardCount}(t,n);o=0===s?e.statePathName:`$${Number(r[1])+s}`}else if(o=Ht(t,e.statePathName),"for"===e.bindingType){const n=f(o).wildcardCount-e.statePathInfo.wildcardCount;t.indexShiftByLoopElementPath.set(o+c+d,n)}const s=e.propModifiers,a=null===r&&Array.isArray(s)&&Ut.has(e.bindingType??"")&&!s.includes(u)&&null!==_t(t,e.statePathName);return o!==e.statePathName||a?{...e,statePathName:o,statePathInfo:f(o),...a?{propModifiers:[...s,u]}:{}}:e}function Jt(t,e,n,o,r){if(void 0===o)return;const s=f(n).wildcardCount-f(e).wildcardCount;return 0===s?o:(r.length<s&&$(`Cannot resolve "${e}" from this mount: the mounted prefix has ${s} wildcard(s) but the host context provides only ${r.length} index(es).`),[...r.slice(0,s),...o])}function Qt(t,e,n){if(-1!==t.indexOf(d))return e;const o=e.split(c);let r=0;for(let t=0;t<o.length&&r<n.length;t++)o[t]===d&&(o[t]=String(n[r++]));return o.join(c)}const Yt=new WeakMap,Zt=new WeakMap;const te=new WeakMap;const ee=new FinalizationRegistry(function(t){const e=t.byMarker.get(t.marker);if(void 0!==e&&void 0===e.deref()&&t.byMarker.delete(t.marker),void 0!==t.getterPaths)for(const e of t.addedGetterPaths)t.getterPaths.delete(e)}),ne=new WeakMap;function oe(t){return ne.get(t)??null}let re=!1;function se(t,e){re||(re=!0,C(t=>Yt.has(t)?t.host:null)),Yt.set(t,e),ne.set(e,t);let n=te.get(e.parentStateElement);void 0===n&&(n=new Map,te.set(e.parentStateElement,n)),n.set(e.marker,new WeakRef(e));let o=Zt.get(e.component);void 0===o&&(o=new Map,Zt.set(e.component,o));const r=o.get(e.stateProp)!==e;o.set(e.stateProp,e),r&&ee.register(e,{byMarker:n,marker:e.marker,getterPaths:e.parentStateElement.getterPaths,addedGetterPaths:e.addedGetterPaths}),e.parentStateElement.markHasMounts?.()}function ae(t){return Yt.get(t)??null}function ie(t){return ce(t).map(t=>({marker:t.marker,componentTag:t.component.tagName.toLowerCase(),stateProp:t.stateProp,mountTable:t.entries.map(t=>({inner:t.innerSegments.join(c),outer:t.outerPathInfo.path})),delta:t.delta,privateKeys:Object.keys(t.privateSnapshot),getterKeys:[...t.getterKeys],exports:[...t.exports.keys()]}))}function ce(t){const e=te.get(t);if(void 0===e)return[];const n=[];for(const t of e.values()){const e=t.deref();void 0!==e&&n.push(e)}return n}function le(t,e){const n=e.lastIndexOf("#");if(-1===n)return null;const o=te.get(t);if(void 0===o)return null;const r=e.indexOf(c,n),s=-1===r?e.slice(n):e.slice(n,r),a=o.get(s);if(void 0===a)return null;const i=a.deref();return void 0===i?(o.delete(s),null):i}const ue=new WeakMap,de=new Set;function fe(t,e,n,o){let r=ue.get(t);if(void 0===r){if(!o)return null;r=new Map,ue.set(t,r)}let s=r.get(e);if(void 0===s){if(!o)return null;s=new Map,r.set(e,s)}let a=s.get(n);if(void 0===a){if(!o)return null;a={holders:new Set,byListIndex:new WeakMap,noIndex:null},s.set(n,a)}return a}function he(t,e){if(!t.component.isConnected)return!1;const n=N(t.component)?.listIndex??null;if(null===e)return null===n;let o=n;for(;null!==o;){if(o===e)return!0;o=o.parentListIndex}return!1}function pe(t,e,n,o){const r=fe(t,e,n,!1);if(null===r)return null;const s=null===o?r.noIndex:r.byListIndex.get(o)??null;if(null!==s){const t=function(t,e){const n=t.ref.deref();return void 0!==n&&he(n,e)?n:null}(s,o);if(null!==t)return{record:t,entry:s.entry}}let a=null,i=null;for(const t of r.holders){const s=t.ref.deref();void 0!==s?he(s,o)&&(null!==i&&$(`[wcs/mount-export-ambiguous] "${e}${c}${n}" is exported by two mounted components on the same instance: <${i.component.tagName.toLowerCase()}> and <${s.component.tagName.toLowerCase()}>. Mount only one of them there, or rename one accessor. See docs/state-overlay-export-design.md X4.`),a=t,i=s):r.holders.delete(t)}return null===a||null===i?null:(null===o?r.noIndex=a:r.byListIndex.set(o,a),{record:i,entry:a.entry})}function me(t){const e=t.parentStateElement,n=N(t.component);if(!(!1===e.isConnected||t.delta>0&&null===n))for(const o of t.exports.values())e.createState("readonly",t=>{t[M](n,()=>{t.$postUpdate(o.exportedPath)})})}const ge=new WeakMap,ye=new WeakMap,we=new WeakMap,$e=new WeakMap;function be(t,e){ye.set(t,e);const n=[];for(let t=e?.listIndex.parentListIndex??null;null!==t;t=t.parentListIndex)n.push(t);$e.set(t,n)}function ve(t){return N(t.component)??ye.get(t)??null}function ke(t){return ve(t)?.listIndex??null}function Pe(t){$(`The host row of <${t.component.tagName.toLowerCase()}> was removed.`)}function Se(t){for(;null!==t;t=t.parentListIndex)if(O(t))return!0;return!1}function xe(t,e){return!t.component.isConnected&&(Se(e)||!0===$e.get(t)?.some(t=>O(t)))}class Ie{record;markerParentPath;listIndex;hostRow;isBase;receiver;handler;authorFacing;constructor(t,e,n,o,r,s,a,i=!1){this.record=t,this.markerParentPath=e,this.listIndex=n,this.hostRow=o,this.isBase=r,this.receiver=s,this.handler=a,this.authorFacing=i}authorThis(t,e){return this.authorFacing?e:new Proxy(t,new Ie(this.record,this.markerParentPath,this.listIndex,this.hostRow,this.isBase,this.receiver,this.handler,!0))}accessorNameFor(t){return this.record.accessorBySuffixByMarkerParent.get(this.markerParentPath)?.get(t)?.accessorName}accessorAddress(t){return A(f(this.markerParentPath+c+t),this.listIndex)}hostIndexes(){const t=this.listIndex??ke(this.record),e=this.hostRow??t;return(null===this.listIndex?e!==t||xe(this.record,e):Se(e))&&Pe(this.record),e?.indexes??[]}resolveTreePath(t,e){return-1===e.indexOf(d)||null!==this.listIndex&&0!==this.handler.addressStackLength&&"partial"!==Y(e).wildcardType&&!xe(this.record,this.listIndex)?e:Qt(t,e,this.hostIndexes())}get(t,e,n){if("string"!=typeof e)return Reflect.get(t,e);if("then"===e)return;if("$"===e[0]){if("$postUpdate"===e)return t=>{this.receiver.$postUpdate(this.resolveTreePath(t,Ht(this.record,t)))};if("$getAll"===e||"$setAll"===e||"$resolve"===e){const t=this.record,n=this.hostIndexes(),o=this.receiver,r=this.handler,s=this.listIndex;if("$resolve"===e)return(e,r,...s)=>{const a=s.length>0?Gt(t,e):Ht(t,e),i=Jt(0,e,a,r??[],n);return o.$resolve(a,i,...s)};const a=e;return(e,i,...c)=>{const l="$setAll"===a?Gt(t,e):Ht(t,e),u=Jt(0,e,l,void 0===i&&"$getAll"===a&&null===s&&null===Z(r,f(l).wildcardPaths[0])?[]:i,n);return o[a](l,u,...c)}}const t=this.record,n=this.receiver,o=wt(e,e=>this.resolveTreePath(e,Ht(t,e)),t=>n[e](...t));return null!==o?o:this.receiver[e]}const o=this.accessorNameFor(e);if(void 0!==o){this.handler.pushAddress(this.accessorAddress(e));try{return Reflect.get(this.record.stateObject,o,n)}finally{this.handler.popAddress()}}if(this.isBase){if(Object.prototype.hasOwnProperty.call(t,e))return tt(this.handler,this.accessorAddress(e)),t[e];const o=this.record.stateObject[e];if("function"==typeof o)return o.bind(this.authorThis(t,n))}return this.receiver[this.resolveTreePath(e,Ht(this.record,e))]}set(t,e,n,o){if("string"!=typeof e)return Reflect.set(t,e,n);const r=this.accessorNameFor(e);if(void 0!==r){this.record.setterKeys.has(r)||$(`Cannot write to "${r}" on mounted <${this.record.component.tagName.toLowerCase()}>: the accessor has no setter. Add a setter or write to the underlying state paths instead.`),this.handler.pushAddress(this.accessorAddress(e)),this.handler.beginUntrack();try{return Reflect.set(this.record.stateObject,r,n,this.authorThis(t,o))}finally{this.handler.endUntrack(),this.handler.popAddress()}}if(this.isBase&&Object.prototype.hasOwnProperty.call(t,e)){if(this.authorFacing&&"readonly"!==this.handler.mutability){null===this.listIndex&&this.hostIndexes(),this.handler.pushAddress(A(f(this.markerParentPath),this.listIndex));try{this.receiver[this.markerParentPath+c+e]=n}finally{this.handler.popAddress()}return!0}return t[e]=n,!0}return this.receiver[this.resolveTreePath(e,Gt(this.record,e))]=n,!0}has(t,e){if("string"!=typeof e)return Reflect.has(t,e);if("$"===e[0]||"#"===e[0])return!1;if(void 0!==this.accessorNameFor(e))return!0;if(this.isBase){if(Object.prototype.hasOwnProperty.call(t,e))return!0;if("function"==typeof this.record.stateObject[e])return!0}try{return Ht(this.record,e),!0}catch{return!1}}}function je(t,e,n,o){const r=e.pathInfo.path,s=r===t.markerBasePath,a=s?function(t,e){let n=ge.get(t);if(void 0===n&&(n={byListIndex:new WeakMap,noIndex:null},ge.set(t,n)),null===e)return n.noIndex??={...t.privateSnapshot};let o=n.byListIndex.get(e);return void 0===o&&(o={...t.privateSnapshot},n.byListIndex.set(e,o)),o}(t,e.listIndex):{};return new Proxy(a,new Ie(t,r,e.listIndex,e.listIndex??ke(t),s,n,o))}function Ce(t){if(null===ke(t))return t.component[t.stateProp];let e=we.get(t);if(void 0===e){const n={row:null};we.set(t,e=[Ne(t,n),n])}return e[0]}function Ne(t,e){const n=()=>{const n=ve(t);return void 0!==e&&we.get(t)?.[0]!==a&&n.listIndex!==e.row&&Pe(t),n},o=()=>{const e=n();return xe(t,e?.listIndex??null)&&Pe(t),e?.listIndex.indexes??[]},r=(e,n)=>-1===n.indexOf(d)?n:"partial"===Y(n).wildcardType?Qt(e,n,o()):-1===n.indexOf("#")&&xe(t,ke(t))?Pe(t):n,s=(e,o)=>{let r;const s=n();return t.parentStateElement.createState(e,t=>{r=t[M](s,()=>o(t))}),r},a=new Proxy({},{get(e,n){if("string"!=typeof n||"then"===n)return;if("$getAll"===n||"$setAll"===n||"$resolve"===n||"$postUpdate"===n)return function(t,e,n,o,r){return"$postUpdate"===e?e=>n("readonly",n=>n.$postUpdate(r(e,Ht(t,e)))):(r,s,...a)=>{const i="$setAll"===e||"$resolve"===e&&a.length>0,c=i?Gt(t,r):Ht(t,r),l=Jt(0,r,c,"$resolve"===e?s??[]:s,o());return n(i?"writable":"readonly",t=>t[e](c,l,...a))}}(t,n,s,o,r);const a=wt(n,e=>r(e,Ht(t,e)),t=>s("readonly",e=>e[n](...t)));if(null!==a)return a;const i=e=>e["$"===n[0]?n:r(n,Ht(t,n))],c=s("readonly",i);return"$"===n[0]||t.getterKeys.has(n)||"function"!=typeof t.stateObject[n]?c:function(...t){return s("writable",e=>i(e).apply(this,t))}},set:(e,n,o)=>("string"==typeof n&&s("writable",e=>{e["$"===n[0]?n:r(n,Gt(t,n))]=o}),!0),has(e,n){if("string"!=typeof n||"$"===n[0]||"#"===n[0])return!1;if(Object.prototype.hasOwnProperty.call(t.stateObject,n))return!0;try{return Ht(t,n),!0}catch{return!1}}});return a}function Me(t,e){const n=ae(e);null!==n&&n.stateProp!==t.stateProp&&$(`A mount scope is already initialized on this component for "${n.stateProp}" — one <wcs-state bind-component> per component (v2). Merge the "${t.stateProp}" wiring into "${n.stateProp}" or split the component.`),null!==n&&E(e).dispose(),se(e,t),e instanceof ShadowRoot&&K(e,t.parentStateElement),function(t,e){const n=(e,n)=>Xt(t,e,n);D(e);const o=N(t.component);be(t,o);const r=e instanceof ShadowRoot?e:e.getRootNode();B(r,e,void 0,n),z(e,o,n)}(t,e),function(t){if(t.exports.size>0||null===t.rootEntry)return;const e=new Set([...t.getterKeys,...t.setterKeys]);for(const n of e){let e;try{e=Ht(t,n)}catch{continue}const o=e.indexOf(c+t.marker);if(-1===o)continue;const r=e.slice(0,o+1+t.marker.length),s=e.slice(r.length+1),a=e.slice(0,o)+c+s,i=f(a);if(i.wildcardCount!==t.delta)continue;const l={markerTerminalPath:r,suffix:s,markerPath:e,exportedPath:a};t.exports.set(a,l),fe(t.parentStateElement,i.parentPath,i.lastSegment,!0).holders.add({ref:new WeakRef(t),entry:l}),t.parentStateElement.addDynamicDependency(e,a),Q?.markExported(t.parentStateElement,a)}t.parentStateElement.markHasMounts?.()}(t),function(t){const e=N(t.component);if(t.delta>0&&null===e)return;const n=t.component.tagName.toLowerCase();for(const o of t.exports.values()){const r=`${n}|${o.exportedPath}`;if(de.has(r))continue;const s=f(o.exportedPath);let a;t.parentStateElement.createState("readonly",t=>{t[M](e,()=>{a=t[s.parentPath]})}),null!=a&&s.lastSegment in Object(a)&&(de.add(r),console.warn(`[@wcstack/state] [wcs/mount-export-shadowed] <${n}>.${t.stateProp}.${o.suffix} is exported at "${o.exportedPath}" but the tree already has that key, so readers outside the component get the tree value. Remove the tree key or rename the accessor. See docs/state-overlay-export-design.md X1.`))}}(t),me(t),L(e,Promise.resolve())}function Ae(t,e){const n=Oe(t,e).rebindAddresses();R(n),me(t)}function Oe(t,e){const n=E(e),o=N(t.component);return be(t,o),n.forEachActiveBindingNode(t=>W(t,o)),n}function Re(t){for(let e=t.parentNode;null!==e;e=e.parentNode){const t=ae(e);if(null!==t)return Re(t.component),void Oe(t,e)}}function Ee(t,e){if(function(t){const e=te.get(t);return void 0!==e&&e.size>0}(e))for(const n of ce(e)){if(!We(n.component,t))continue;const e=oe(n);null!==e&&Ae(n,e)}}function We(t,e){for(let n=e.firstNode;null!==n;n=n.nextSibling){if(n===t||n.contains(t))return!0;if(n===e.lastNode)break}return!1}const Ke={read(t,e,n,o){if(!0===t.hasMounts&&35===e.pathInfo.lastSegment.charCodeAt(0)){const r=le(t,e.pathInfo.path);if(null!==r)return je(r,e,n,o)}return P},readMissing(t,e,n,o,r){if(null===n){if(vt(t.rootNode??null,e.pathInfo.path))return;return P}if(!0===t.hasMounts){const n=pe(t,e.parentAddress.pathInfo.path,e.pathInfo.lastSegment,e.listIndex);if(null!==n)return function(t,e,n,o,r){const s=je(t,A(f(e.markerTerminalPath),n),o,r);return Reflect.get(s,e.suffix)}(n.record,n.entry,e.listIndex,o,r)}return P},write(t,e){if(!0===t.hasGraftedVolumes){const n=e.pathInfo.path,o=function(t,e){const n=kt.get(t);if(void 0===n||0===n.size)return null;const o=e+c;for(const t of n)if(t.startsWith(o))return t;return null}(t,n);null!==o&&$(`Cannot replace "${n}" wholesale: a volume is mounted at "${o}" under it (D22). Replacing an ancestor of a mount point silently discards the grafted data while its accessors remain. Write "${o}" itself, or individual fields inside "${n}", instead.`)}return P},writeMissing(t,e,n,o,r,s,a){if(!0===t.hasMounts){const n=pe(t,e.parentAddress.pathInfo.path,e.pathInfo.lastSegment,e.listIndex);if(null!==n)return function(t,e,n,o,r,s){const a=je(t,A(f(e.markerTerminalPath),n),r,s);return Reflect.set(a,e.suffix,o)}(n.record,n.entry,e.listIndex,r,s,a)}return P},indexShift(t,e){const n=t.stateElement,o=e.pathInfo.path;if(!0===n.hasMounts&&-1!==o.indexOf("#")){const t=le(n,o);if(null!==t)return function(t,e){const n=e.lastIndexOf("#");if(-1===n)return t.delta;const o=e.indexOf(c,n);if((-1===o?e.slice(n):e.slice(n,o))!==t.marker)return t.delta;const r=-1===o?e:e.slice(0,o),s=-1===o?"":e.slice(o+1),a=t.accessorBySuffixByMarkerParent.get(r)?.get(s);return void 0!==a?a.indexShift:t.delta}(t,o)}return 0},handlerScope(t,e,n,o,r){if(!0!==t.hasMounts)return r;const s=function(t,e){let n=t;for(;null!==n&&n!==e;){const t=Yt.get(n);if(void 0!==t)return t;n=n.parentNode}return Yt.get(e)??null}(e,n);if(null===s)return r;const a=s.indexShiftByLoopElementPath.get(o.pathInfo.path);return void 0!==a?r-a:0},updated(t,e,n){const o=function(t){return jt.get(t)??Ct}(t);for(const r of o){const o=new Set,s={};for(const n of e){if(n.absolutePathInfo.stateElement!==t)continue;const e=n.absolutePathInfo.pathInfo.path;if(-1!==e.indexOf("#"))continue;const a=xt(r.mountPath,r.injections,e);if(null===a||""===a)continue;o.add(a);const i=n.absolutePathInfo.pathInfo.wildcardCount;if(i>0&&null!==n.listIndex){const t=T(n.listIndex,i);(s[a]??=[]).push(t)}}if(o.size>0)try{r.callback.call(It(r.mountPath,n,r.injections),Array.from(o),s)}catch(t){console.error(`[@wcstack/state] volume "${r.mountPath}" $updatedCallback threw.`,t)}}},suppressPathDiagnostic:(t,e)=>vt(!1===t.isConnected?null:t.rootNode??null,e),rowReused(t,e){Ee(e,t)}};let Le=!1;const De=new WeakMap;function Be(t){let e=De.get(t);return void 0===e&&(e={graftInfo:null,initializing:!1,mountPath:null,slotRootNode:null,detachedFrom:null},De.set(t,e)),e}function ze(t,e){null!==e.slotRootNode&&(!function(t,e,n){const o=$t.get(t);o?.get(e)===n&&o.set(e,null)}(e.slotRootNode,e.mountPath,t),e.slotRootNode=null)}function Te(t,e,n){if(e.slotRootNode===n)return!0;const o=e.mountPath;try{bt(n,o,t)}catch{return console.error(`[@wcstack/state] <${S.tagNames.state} mount="${o}"> will not graft: another volume already holds the "${o}" slot on this root. Keep one volume per mount path.`),!1}return F(n)?.markHasVolume?.(),e.slotRootNode=n,!0}async function Fe(t,e){const n=t,o=t.connectedRootNode,r=n.getAttribute("mount");let s;try{!function(t){0===t.length&&$('"mount" requires a non-empty tree path.');const e=f(t);for(const n of e.segments)0===n.length&&$(`"mount" path "${t}" has an empty segment.`),n===d&&$(`"mount" path "${t}" must be static (wildcards are not allowed).`),(n.includes("$")||n.includes("#")||n.includes("@"))&&$(`"mount" path "${t}" must not use reserved characters ($, #, @).`)}(r),s=function(t,e){const n=[],o=new Set;let r;try{r=H(t)}catch(t){$(`[wcs/mount-path-invalid] <${S.tagNames.state} mount="${e}"> has an invalid ${S.bindAttributeName}: ${t instanceof Error?t.message:String(t)}`)}for(const t of r){if(t.propSegments[0]!==l)continue;const r=t.propSegments.slice(1),s=t.statePathInfo,a=n=>$(`[wcs/mount-path-invalid] <${S.tagNames.state} mount="${e}"> "${t.propName}: ${t.statePathName}": ${n}`);1===r.length&&r[0]&&r[0]!==d&&"$"!==r[0][0]&&"#"!==r[0][0]||a(`inject one key at a time ("${l}.<key>: path"); change "mount" to move the whole volume.`),(s.wildcardCount>0||"$"===s.path[0]||"#"===s.path[0])&&a("the injected path must be a static path on the root tree (a volume has no loop context)."),(t.inFilters.length>0||t.outFilters.length>0)&&a("an injection takes no filters."),t.propModifiers.some(t=>t!==u)&&a(`an injection accepts only #${u}.`),o.has(r[0])&&a(`"${r[0]}" is injected twice.`),o.add(r[0]),n.push({innerSegments:r,outerPathInfo:s,readonly:t.propModifiers.includes(u)})}return n.sort((t,e)=>e.innerSegments.length-t.innerSegments.length),n}(n.getAttribute(S.bindAttributeName)??"",r),n.hasAttribute("bind-component")&&$('"mount" cannot be combined with "bind-component".'),n.hasAttribute("enable-ssr")&&console.warn(`[@wcstack/state] <${S.tagNames.state} mount="${r}"> ignores "enable-ssr" — snapshots are per root tree (the root state element aggregates volume data).`),bt(o,r,t),F(o)?.markHasVolume?.(),e.mountPath=r,e.slotRootNode=o}catch(e){throw t.settleInitialization(),e}e.initializing=!0,null===F(o)&&function(t,e){const n=()=>{if(null!==F(t))return;const n=t.querySelectorAll(S.tagNames.state);for(const t of n)if(!t.hasAttribute("mount")&&!t.hasAttribute("bind-component"))return;console.error(`[@wcstack/state] <${S.tagNames.state} mount="${e}"> has no root state tree to graft onto (D11). A volume mounts onto the root tree — add a root <${S.tagNames.state}> to this root node (an empty <${S.tagNames.state}></${S.tagNames.state}> is enough). If the root is added dynamically later, the graft will still complete and this report can be ignored.`)},o=t.ownerDocument??t;"loading"===o.readyState?o.addEventListener("DOMContentLoaded",()=>queueMicrotask(n),{once:!0}):setTimeout(n,0)}(o,r);const a=n=>{e.graftInfo=n,t.markInitialized(),null===n&&ze(t,e),t.settleInitialization()};let i;try{await Promise.resolve(),i=await t.loadStateFromSource()}catch(t){return console.error(`[@wcstack/state] volume "${r}" failed to load.`,t),void a(null)}const c=t.connectedRootNode??null;null!==c&&Te(t,e,c)?function(t,e,n,o,r,s,a=[]){const i={mountPath:n,volumeState:o,injections:a,onGrafted:r,acquireSlot:s};if(null!==e)return void yn(e,i);$n(),function(t,e){if(Mt.has(t))return void At(e);let n=Nt.get(t);void 0===n&&(n=[],Nt.set(t,n)),n.push(e)}(t,i)}(c,F(c),r,i,a,()=>Te(t,e,c),s):a(null)}const Ve={order:20,connecting(t){if(!t.hasAttribute("mount"))return null;const e=Be(t);if(e.initializing){const n=t.connectedRootNode;if(null!=n&&e.detachedFrom===n)try{bt(n,e.mountPath,t),F(n)?.markHasVolume?.(),e.slotRootNode=n}catch{}return e.detachedFrom=null,o}return Fe(t,e)},reconnecting(t){if(!t.hasAttribute("mount"))return!1;const e=Be(t),n=t.connectedRootNode??null;return null!==e.graftInfo&&null!==n&&F(n)===e.graftInfo.rootStateElement&&pn(e.graftInfo,"$connectedCallback"),!0},replacingState(t){if(!0!==De.get(t)?.initializing)return;const e=t.getAttribute("mount");$(`Cannot replace the state of <${S.tagNames.state} mount="${e}"> after it has loaded: a volume's data is copied into the root tree when it grafts, so a new state would never reach the page. Write the paths under "${e}" on the root state instead.`)},initializeFailed(t,e){!function(t){Mt.add(t);const e=Nt.get(t);if(void 0!==e){Nt.delete(t);for(const t of e)At(t)}}(e)},initializeFailureCleared(t,e){!function(t){Mt.delete(t)}(e)},disconnecting(t){if(!t.hasAttribute("mount"))return!1;const e=Be(t);return null!==e.graftInfo&&pn(e.graftInfo,"$disconnectedCallback"),!0!==t.initialized&&(e.detachedFrom=e.slotRootNode,ze(t,e)),t.clearConnectedRootNode(),!0}};let qe=!1;const _e=new WeakMap;function Ge(t,e){let n=_e.get(t);n||(n=new Set,_e.set(t,n)),n.add(e)}const He=new WeakMap;const Ue=new WeakMap,Xe=new WeakMap;const Je=new WeakMap;const Qe={isComplete:function(t,e){return!0===_e.get(t)?.has(e)},isDeclared:function(t,e){return!0===He.get(t)?.has(e)},rememberOverwrittenObject:function(t,e,n){let o=Ue.get(t);o||(o=new Map,Ue.set(t,o)),o.has(e)||o.set(e,n)},recordInjectedKey:function(t,e,n){let o=Xe.get(t);o||(o=new Map,Xe.set(t,o));let r=o.get(e);r||(r=new Set,o.set(e,r)),r.add(n)},rememberOverwrittenValue:function(t,e,n,o){let r=Je.get(t);r||(r=new Map,Je.set(t,r));let s=r.get(e);s||(s=new Map,r.set(e,s)),s.has(n)||s.set(n,o)}};function Ye(t){return function(t){const e=Object.getPrototypeOf(t),n=Object.create(e),o=Object.getOwnPropertyDescriptors(t);for(const t in o){const e=o[t];!1===e.writable&&(e.writable=!0)}return Object.defineProperties(n,o),n}(t)}const Ze=new WeakMap;class tn{_innerStateElement;constructor(t,e){this._innerStateElement=function(t,e){const n=Ze.get(t);return n?n.get(e)??null:null}(t,e)??$("State element not found for web component.")}get(t,e,n){if("string"==typeof e){let t;return this._innerStateElement.createState("readonly",n=>{t=n[e]}),t}return Reflect.get(t,e,n)}set(t,e,n,o){return"string"==typeof e?(this._innerStateElement.createState("writable",t=>{t[e]=n}),!0):Reflect.set(t,e,n,o)}}const en=t=>()=>t;function nn(t,e,n,o){!function(t,e,n){let o=Ze.get(t);o||(o=new Map,Ze.set(t,o)),o.set(e,n)}(e,n,t),t.setInitialState(Ye(o));const r=function(t,e){const n=new tn(t,e);return new Proxy({},n)}(e,n);Object.defineProperty(e,n,{get:en(r),enumerable:!0,configurable:!0}),Ge(e,n),on(e,n)}function on(t,e){if(m in t){const n=t[m];"function"==typeof n?n.call(t,e).catch(t=>{$(`Error in ${m}: ${t instanceof Error?t.message:String(t)}`)}):$(`${m} is not a function.`)}}const rn=new Set;function sn(t,e){rn.has(t)||(rn.add(t),console.warn(`[@wcstack/state] [wcs/mount-own-key-shadow] ${e} See docs/state-mount-design.md §4-3.`))}function an(t){!function(t){const e=t.component.tagName.toLowerCase(),n=t.stateProp;let o=null;for(const r of t.entries){if(0===r.innerSegments.length)continue;const s=r.innerSegments[0];o??=k(t.stateObject);const a=o[s];let i;if(t.getterKeys.has(s)||t.setterKeys.has(s)||"function"==typeof a?.get||"function"==typeof a?.set)i="an accessor";else if("function"==typeof a?.value)i="a method";else{if(t.mappedKeys.has(s)||t.injectedKeys.has(s)||!Object.prototype.hasOwnProperty.call(t.stateObject,s))continue;i="an own data key"}const l=r.innerSegments.join(c);sn(`${e}|${n}|${l}|entry`,`<${e}>.${n} declares "${s}" as ${i}, which hides the mounted entry "${n}.${l}: ${r.outerPathInfo.path}" (the host value never reaches it). Rename one of them.`)}}(t);const e=Object.keys(t.privateSnapshot);if(0===e.length)return;const n=t.component.tagName.toLowerCase(),o=t.stateProp;let r,s=!1;for(const a of e){if(null===t.rootEntry)continue;if(s||(r=cn(t),s=!0),"object"!=typeof r||null===r||!(a in r))continue;const e=t.rootEntry.outerPathInfo.path;sn(`${n}|${o}|${a}|root`,`<${n}>.${o}.${a} is private and hides the mounted tree key "${e}.${a}" (${o}: ${e}). Remove the default to read the tree, or rename it to keep it private.`)}}function cn(t){const e=t.rootEntry,n=N(t.component);if(e.outerPathInfo.wildcardCount>0&&null===n)return;let o;return t.parentStateElement.createState("readonly",t=>{t[M](n,()=>{o=t[e.outerPathInfo.path]})}),o}const ln=new WeakMap;function un(t,e){t.landInitialization(),$(e)}async function dn(t,e){const n=t;if(n.hasAttribute("bind-component")){const s=n.parentNode,a=s instanceof ShadowRoot?s.host:s instanceof Element?s:null,i=a?_(a):null;null!==a&&null!==i||$(`"bind-component" requires <${S.tagNames.state}> to be a direct child of a custom element.`),s instanceof ShadowRoot||a.hasAttribute(S.bindAttributeName)||un(t,`A plain (unwired) Light DOM "bind-component" is not supported. Attach a shadow root to <${i}>, or mount it from the host (data-wcs="${n.getAttribute("bind-component")}: path").`);const c=["state","src","json"].filter(t=>n.hasAttribute(t));null!==n.querySelector('script[type="module"]')&&c.push('<script type="module">'),c.length>0&&$(`"bind-component" cannot be combined with ${c.join(", ")}. The component's "${n.getAttribute("bind-component")}" property is the only state source.`);const l=n.getAttribute("bind-component");!function(t,e){let n=He.get(t);n||(n=new Set,He.set(t,n)),n.add(e)}(a,l);const u=I(a);null===u&&$(`CustomElementRegistry is unavailable for <${i}>.`),await u.whenDefined(i.toLowerCase()),a.hasAttribute(S.bindAttributeName)&&await G(a),l in a||$(`Component does not have property "${l}" for state binding.`);let d=a[l];"object"==typeof d&&null!==d||$(`Component property "${l}" is not an object for state binding.`);const f=function(t,e){const n=Ue.get(t);if(!n)return;const o=n.get(e);return n.delete(e),o}(a,l);if(void 0!==f&&function(t,e){if(!t.hasAttribute(S.bindAttributeName))return!1;const n=V(t);if(null===n)return!1;for(const t of n)if(1===t.propSegments.length&&t.propSegments[0]===e)return!0;return!1}(a,l)&&(a[l]=f,d=f),e.boundComponent=a,e.boundComponentStateProp=l,t.setBoundComponent(a,l),s instanceof ShadowRoot||(V(a)??[]).some(t=>t.propSegments[0]===l)||un(t,`A plain (unwired) Light DOM "bind-component" is not supported. Attach a shadow root to <${i}>, or mount it from the host (data-wcs="${l}: path").`),a.hasAttribute(S.bindAttributeName)){const c=(V(a)??[]).filter(t=>t.propSegments[0]===l);if(c.length>0){const u=F(a.getRootNode())??un(t,`No state tree found on this root for mount host <${i}>.`);let f=(o=a,r=l,Zt.get(o)?.get(r)??null);const h=null!==f;if(null===f&&(!function(t,e,n){const o=Je.get(t)?.get(e);if(void 0!==o){for(const[t,e]of o)n[t]=e;Je.get(t).delete(e)}}(a,l,d),f=Lt(a,l,c,u,d,function(t,e){return Xe.get(t)?.get(e)}(a,l)),an(f)),e.mountRecord=f,n.parentNode!==s)return;try{Me(f,s instanceof ShadowRoot?s:a)}catch(e){throw t.landInitialization(),e}if(!h){const t=Ne(f);Object.defineProperty(a,l,{get:()=>t,enumerable:!0,configurable:!0}),Ge(a,l)}return on(a,l),function(t){const e=Et.filter(e=>void 0!==t.stateObject[e]);for(const n of t.getterKeys)-1!==n.indexOf(p)&&e.push(`"${n}"`);if(0===e.length)return;const n=`${t.component.tagName.toLowerCase()}|${t.stateProp}`;Wt.has(n)||(Wt.add(n),console.warn(`[@wcstack/state] [wcs/mount-dollar-declaration] <${n.split("|")[0]}>.${t.stateProp} declares ${e.join(", ")}, which mounted components do not run. Declare them on the root state instead (a volume <wcs-state mount="..."> can host $watch / $listKeys / $updatedCallback; $recursion and "**" getters expand against the root tree). See docs/state-mount-design.md §4-6.`))}(f),void Kt(f,"$connectedCallback",()=>Ce(f))}}nn(t,e.boundComponent,e.boundComponentStateProp,d)}var o,r}const fn={order:30,preparing(t){if(!t.hasAttribute("bind-component"))return null;const e=function(t){let e=ln.get(t);return void 0===e&&(e={boundComponent:null,boundComponentStateProp:null,mountRecord:null},ln.set(t,e)),e}(t);return dn(t,e).then(()=>null!==e.mountRecord&&(t.markInitialized(),t.settleInitialization(),!0))},reconnecting(t){const e=ln.get(t);if(void 0===e||null===e.mountRecord)return!1;const n=e.mountRecord,o=t.parentNode;return queueMicrotask(()=>{null!=t.connectedRootNode&&Ae(n,o)}),t.isConnected&&(Re(n.component),Oe(n,o)),Kt(n,"$connectedCallback",()=>Ce(n)),!0},disconnecting(t){const e=ln.get(t);if(void 0===e||null===e.mountRecord)return!1;const n=e.mountRecord;return Kt(n,"$disconnectedCallback",()=>Ce(n)),function(t){const e=we.get(t);void 0!==e&&(e[1].row=ke(t),we.delete(t))}(n),me(e.mountRecord),t.clearConnectedRootNode(),!0}};let hn=!1;function pn(t,e){const n=t.volumeState[e];"function"==typeof n&&t.rootStateElement.createState("writable",o=>{const r=n.call(It(t.mountPath,o,t.injections));r instanceof Promise&&r.catch(n=>{console.error(`[@wcstack/state] volume "${t.mountPath}" ${e} failed.`,n)})})}function mn(t,e,n,o){const r=n[g];if(void 0!==r){const n=J(e),s=[],a=new Set;let i=0;for(const[n,c]of Object.entries(r)){const r=St(e,o,n,!1),l=function(t,n,...r){c.call(It(e,this,o),t,n,...r)};s.push({path:r,pathInfo:f(r),handler:l,order:1e6+i++}),a.add(r),t.setPathInfo(r,"prop","watch")}s.length>0&&(n.addEntries(t,s),t.addVolumeWatchPaths?.(a),n.start(t))}const s=n[y];if(void 0!==s){const n=new Map;for(const[t,r]of Object.entries(s))n.set(St(e,o,t,!1),r);t.mergeVolumeListKeys?.(n)}const a=n[h];"function"==typeof a&&(!function(t,e){let n=jt.get(t);void 0===n&&(n=[],jt.set(t,n)),n.push(e),t.markHasVolume?.()}(t,{mountPath:e,injections:o,callback:a}),t.enableUpdatedCallback?.());for(const t of["$commandTokens","$eventTokens","$on","$errorCallback"])void 0!==n[t]&&console.warn(`[@wcstack/state] volume "${e}" declares ${t}, which volumes do not support. Declare it on the root state instead.`)}function gn(t,e,n,o=[]){x(n),function(t,e,n,o){const r=0===o.length?null:k(n);for(const t of o){const n=t.innerSegments[0],o=r[n];void 0===o||"function"!=typeof o.get&&"function"!=typeof o.set&&"function"!=typeof o.value||$(`[wcs/mount-path-invalid] Volume "${e}" declares "${n}" as an accessor or a method and also injects it ("${l}.${n}: ${t.outerPathInfo.path}"). Rename one of them.`)}const s=n[g];if(void 0!==s){"object"==typeof s&&null!==s||$(`${g} must be an object mapping state paths to handler functions.`);const t=J(e);for(const[e,n]of Object.entries(s))"function"!=typeof n&&$(`${g} entry "${e}" must be a function.`),t.assertValidPath(e)}const i=n[y];if(void 0!==i){"object"==typeof i&&null!==i||$(`${y} must be an object mapping list paths to key specs.`);for(const[n,r]of Object.entries(i)){(0===n.length||"string"!=typeof r&&"function"!=typeof r)&&$(`${y} entry "${n}" must map a list path to a field name or a key function.`);const s=St(e,o,n,!1);t.listKeys?.has(s)&&$(`${y} entry "${s}" is declared by both the root and a volume (or two volumes). Keep exactly one.`)}}void 0!==n[a]&&$(`Volume "${e}" declares ${a}, which volumes do not support yet. Declare the stream on the root state.`),void 0!==n.$scan&&$(`Volume "${e}" declares $scan, which volumes do not support yet. Declare the scan on the root state.`),void 0!==n[w]&&$(`Volume "${e}" declares ${w}, which volumes do not support yet. Declare the recursion anchor on the root state — the anchor path is resolved against the root tree.`);for(const t of Object.keys(k(n)))-1!==t.indexOf(p)&&$(`Volume "${e}" declares "${t}", which uses "${p}". Volumes do not support recursive getters yet — declare them on the root state.`)}(t,e,n,o);const{data:r,accessors:s}=function(t,e){const n={},o=new Map;for(const[r,s]of Object.entries(k(t)))r.startsWith("$")||e.has(r)||("function"!=typeof s.get&&"function"!=typeof s.set?"function"!=typeof s.value&&(n[r]=s.value):o.set(r,s));return{data:n,accessors:o}}(n,new Set(o.map(t=>t.innerSegments[0]))),i=f(e),u=!0===t.hydratedFromSsr;t.createState("writable",t=>{if(1===i.segments.length&&e in t){if(u)return;$(`Volume mount "${e}" collides with an existing key on the root tree. Remove the root key or mount the volume elsewhere.`)}let n="";for(let e=0;e<i.segments.length-1;e++){const o=i.segments[e],r=""===n?o in t:void 0!==t[n+c+o];n=""===n?o:n+c+o,r||(t[n]={})}if(i.segments.length>1&&void 0!==t[e]){if(u)return;$(`Volume mount "${e}" collides with an existing key on the root tree. Remove the root key or mount the volume elsewhere.`)}t[e]=r}),function(t,e){let n=kt.get(t);void 0===n&&(n=new Set,kt.set(t,n)),n.add(e)}(t,e),t.markHasGraftedVolumes?.();for(const[n,r]of s){const s=e+c+n,a=r.get,i=r.set,l={enumerable:!1,configurable:!0};"function"==typeof a&&(l.get=function(){return a.call(It(e,this,o))}),"function"==typeof i&&(l.set=function(t){i.call(It(e,this,o),t)}),t.defineTreeAccessor(s,l)}mn(t,e,n,o);const d=n.$connectedCallback;return"function"==typeof d&&t.createState("writable",t=>{let n;try{n=d.call(It(e,t,o))}catch(t){return void console.error(`[@wcstack/state] volume "${e}" $connectedCallback failed.`,t)}n instanceof Promise&&n.catch(t=>{console.error(`[@wcstack/state] volume "${e}" $connectedCallback failed.`,t)})}),{rootStateElement:t,mountPath:e,volumeState:n,injections:o}}function yn(t,e){if(!e.acquireSlot())return void e.onGrafted(null);let n=null;try{n=gn(t,e.mountPath,e.volumeState,e.injections)}catch(t){console.error(`[@wcstack/state] volume "${e.mountPath}" failed to graft.`,t)}finally{e.onGrafted(n)}}let wn=!1;function $n(){wn||(wn=!0,Le||(Le=!0,v("scopes",Ke),X(ie)),qe||(qe=!0,t("scopes",Ve)),hn||(hn=!0,t("bindComponent",fn),q(Qe)),Ot=yn,U(bn))}function bn(t,e){(function(t){const e=$t.get(t);return void 0!==e&&e.size>0})(t)&&e.markHasVolume?.(),function(t,e){Mt.delete(t);const n=Nt.get(t);if(void 0===n||0===n.length||null===Ot)return;Nt.delete(t);const o=Ot;queueMicrotask(()=>{for(const t of n)o(e,t)})}(t,e)}const vn={name:"scopes",install(){$n(),ht||(ht=!0,t("dcc",ft))}};export{vn as default,vn as scopes};
2
2
  //# sourceMappingURL=scopes.js.map