@wcstack/state 4.6.2 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +40 -13
- package/README.md +42 -13
- package/dist/auto.min.js +1 -1
- package/dist/auto.min.js.map +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/manifest.esm.js +5 -5
- package/dist/split/auto.js +1 -1
- package/dist/split/chunks/chunk-BCL75PFH.js +2 -0
- package/dist/split/chunks/chunk-BCL75PFH.js.map +1 -0
- package/dist/split/chunks/{chunk-JWRQLKOQ.js → chunk-DRSAQE4E.js} +2 -2
- package/dist/split/chunks/{chunk-GBBBRPZR.js → chunk-GQTEYSRZ.js} +2 -2
- package/dist/split/chunks/{chunk-FBBHQU7S.js → chunk-IBGHHABS.js} +2 -2
- package/dist/split/chunks/chunk-M3BJN6SQ.js +2 -0
- package/dist/split/chunks/{chunk-AAEFSJ6G.js.map → chunk-M3BJN6SQ.js.map} +1 -1
- package/dist/split/chunks/{chunk-T3FN37DU.js → chunk-P3EXTBXC.js} +2 -2
- package/dist/split/chunks/{chunk-CBMAVRYG.js → chunk-PKEAYPFR.js} +2 -2
- package/dist/split/chunks/chunk-QMOIMPIJ.js +2 -0
- package/dist/split/chunks/chunk-QMOIMPIJ.js.map +1 -0
- package/dist/split/chunks/chunk-T3KW5DZD.js +2 -0
- package/dist/split/chunks/chunk-T3KW5DZD.js.map +1 -0
- package/dist/split/chunks/chunk-XXVJ6J2N.js +2 -0
- package/dist/split/chunks/chunk-XXVJ6J2N.js.map +1 -0
- package/dist/split/core.d.ts +2 -0
- package/dist/split/core.js +1 -1
- package/dist/split/features/devtools.d.ts +2 -0
- package/dist/split/features/devtools.js +1 -1
- package/dist/split/features/devtools.js.map +1 -1
- package/dist/split/features/diagnostics.d.ts +2 -0
- package/dist/split/features/diagnostics.js +1 -1
- package/dist/split/features/diagnostics.js.map +1 -1
- package/dist/split/features/formats.d.ts +2 -0
- package/dist/split/features/formats.js +1 -1
- package/dist/split/features/formats.js.map +1 -1
- package/dist/split/features/list-keys.d.ts +2 -0
- package/dist/split/features/list-keys.js +1 -1
- package/dist/split/features/list-keys.js.map +1 -1
- package/dist/split/features/native-commands.d.ts +2 -0
- package/dist/split/features/native-commands.js +1 -1
- package/dist/split/features/native-commands.js.map +1 -1
- package/dist/split/features/recursion.d.ts +2 -0
- package/dist/split/features/recursion.js +1 -1
- package/dist/split/features/recursion.js.map +1 -1
- package/dist/split/features/scopes.d.ts +2 -0
- package/dist/split/features/scopes.js +1 -1
- package/dist/split/features/scopes.js.map +1 -1
- package/dist/split/features/ssr.d.ts +2 -0
- package/dist/split/features/ssr.js +1 -1
- package/dist/split/features/ssr.js.map +1 -1
- package/dist/split/features/temporal.d.ts +2 -0
- package/dist/split/features/temporal.js +1 -1
- package/dist/split/features/temporal.js.map +1 -1
- package/package.json +1 -1
- package/dist/split/chunks/chunk-467LYA2V.js +0 -2
- package/dist/split/chunks/chunk-467LYA2V.js.map +0 -1
- package/dist/split/chunks/chunk-AAEFSJ6G.js +0 -2
- package/dist/split/chunks/chunk-TNYNJXEC.js +0 -2
- package/dist/split/chunks/chunk-TNYNJXEC.js.map +0 -1
- package/dist/split/chunks/chunk-ULMHOGJ2.js +0 -2
- package/dist/split/chunks/chunk-ULMHOGJ2.js.map +0 -1
- package/dist/split/chunks/chunk-ZJYPRSTO.js +0 -2
- package/dist/split/chunks/chunk-ZJYPRSTO.js.map +0 -1
- /package/dist/split/chunks/{chunk-JWRQLKOQ.js.map → chunk-DRSAQE4E.js.map} +0 -0
- /package/dist/split/chunks/{chunk-GBBBRPZR.js.map → chunk-GQTEYSRZ.js.map} +0 -0
- /package/dist/split/chunks/{chunk-FBBHQU7S.js.map → chunk-IBGHHABS.js.map} +0 -0
- /package/dist/split/chunks/{chunk-T3FN37DU.js.map → chunk-P3EXTBXC.js.map} +0 -0
- /package/dist/split/chunks/{chunk-CBMAVRYG.js.map → chunk-PKEAYPFR.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["seen","nullishPassthrough","factory","options","filterFn","value","valid","defaultLocale","config","locale","Intl","getCanonicalLocales","console","warn","text","STYLES","dateOptions","fn","loc","style","includes","styleInvalid","eq","ne","not","lt","le","gt","ge","falsy","truthy","boolean","coreFilters","registered","toFixed","opt","numberOption","valueMustBeNumber","arity","explicit","toLocaleString","upper","String","toUpperCase","lower","toLowerCase","capitalize","v","length","charAt","slice","trim","numberedOpts","requiredNumberOption","opt2","push","padStart","opt1","padEnd","repeat","reverse","split","join","truncate","maxLength","suffix","Array","isArray","valueMustBeArray","round","optValue","Math","pow","floor","ceil","percent","unit","optionsRequired","date","format","dateStyle","Date","valueMustBeDate","toLocaleDateString","time","timeStyle","toLocaleTimeString","datetime","ymd","year","getFullYear","toString","month","getMonth","day","getDate","hms","hours","getHours","minutes","getMinutes","seconds","getSeconds","add","numeric","sub","mul","div","mod","abs","clamp","min","max","int","parseInt","float","parseFloat","defaults","literals","fallback","firstLiteral","coalesce","number","Number","string","nullIfEmpty","currency","code","NumberFormat","known","supportedValuesOf","currencyInvalid","installed","formats","name","install","registerFilters","formats_default"],"sources":["../../../src/filters/formats.ts","../../../src/features/formats.ts"],"sourcesContent":["/**\n * filters/formats.ts — the formats add-on (38 filters): the values a binding computes and shows, as\n * opposed to the conditions the core set (`./core`) tests. Ported from `@wcstack/state`\n * (`formats/builtinFilters.ts`) with the semantics unchanged.\n *\n * - number display: `toFixed round floor ceil percent unit locale currency`\n * - string shaping: `upper lower capitalize trim slice padStart padEnd repeat reverse truncate join`\n * (`substr` was removed in 4.0: `slice(start, start + length)`)\n * - date and time: `date time datetime ymd hms`\n * - arithmetic: `add sub mul div mod abs clamp`\n * - conversions: `number string int float`\n * - missing values: `defaults coalesce nullIfEmpty`\n *\n * (The last three groups were the core's up to 4.0.0-rc.3.)\n *\n * `installFormats()` puts them in the registry. Without it, one of these filters fails when the\n * bindings are planned with `[wcs/filter-unknown]` naming this add-on (never passes silently).\n * The locale-dependent five (`locale currency date time datetime`) read `config.locale` as their default.\n */\nimport { config } from \"../config\";\nimport { currencyInvalid, optionsRequired, styleInvalid, valueMustBeArray, valueMustBeDate, valueMustBeNumber } from \"./errorMessages\";\nimport { firstLiteral, numberOption, requiredNumberOption } from \"./options\";\nimport { registerFilters, type FilterDefinition, type FilterFactory, type FilterFn } from \"./registry\";\nimport { coreFilters, numeric } from \"./core\";\nimport { M, text } from \"../messages\";\n\n/**\n * Extends the display-side empty-value contract (requirement B8) to the filters that build their\n * result with `String(value)`: those turn `undefined` / `null` into the *characters* \"undefined\" /\n * \"null\", so `attr.title: x|trim` wrote `title=\"undefined\"` where `attr.title: x` removes the\n * attribute. This family passes an absent value straight through and leaves the decision to the\n * apply side (attribute removed, class cleared, style cleared, text emptied).\n *\n * Deliberately **not** wrapped: the filters that reject a value of the wrong type (the number, date\n * and array families) — their throw is confined to the one binding and reported, a different\n * quality of failure from painting the word \"undefined\" into the page.\n */\nconst nullishPassthrough = (factory: (options: string[]) => FilterFn): FilterFactory =>\n (options: string[]): FilterFn => {\n const filterFn = factory(options);\n // `== null` matches both null and undefined (deliberately loose)\n return (value: unknown): unknown => (value == null ? value : filterFn(value));\n };\n\n/** Fixed decimals (default 0). */\nconst toFixed = (options: string[]): FilterFn => {\n const opt = numberOption(options?.[0] ?? \"0\", 'toFixed');\n return (value: unknown): string => {\n if (typeof value !== 'number') {valueMustBeNumber('toFixed', value);}\n return value.toFixed(opt);\n };\n};\n\n/** Rounds to the given decimals (default 0). */\nconst round = (options: string[]): FilterFn => {\n const optValue = Math.pow(10, numberOption(options?.[0] ?? '0', 'round'));\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('round', value);}\n return Math.round(value * optValue) / optValue;\n };\n};\n\n/** Rounds down to the given decimals (default 0). */\nconst floor = (options: string[]): FilterFn => {\n const optValue = Math.pow(10, numberOption(options?.[0] ?? '0', 'floor'));\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('floor', value);}\n return Math.floor(value * optValue) / optValue;\n };\n};\n\n/** Rounds up to the given decimals (default 0). */\nconst ceil = (options: string[]): FilterFn => {\n const optValue = Math.pow(10, numberOption(options?.[0] ?? '0', 'ceil'));\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('ceil', value);}\n return Math.ceil(value * optValue) / optValue;\n };\n};\n\n/** `0.123` → `\"12%\"` with the given decimals (default 0). */\nconst percent = (options: string[]): FilterFn => {\n const opt = numberOption(options?.[0] ?? '0', 'percent');\n return (value: unknown): string => {\n if (typeof value !== 'number') {valueMustBeNumber('percent', value);}\n return `${(value * 100).toFixed(opt)}%`;\n };\n};\n\n/**\n * Appends a CSS unit (or any suffix). Accepts strings as well as numbers **on purpose**: the useful\n * chains run through `toFixed` / `percent`, which already return strings\n * (`style.height: cpu|clamp(0,100)|toFixed(0)|unit(%)`). null / undefined pass through\n * (`nullishPassthrough`) rather than becoming \"undefinedpx\".\n */\nconst unit = (options: string[]): FilterFn => {\n const opt = options?.[0] ?? optionsRequired('unit');\n return (value: unknown): string => String(value) + opt;\n};\n\nlet seen: string | undefined;\nlet valid = \"en\";\n\n/**\n * The default locale (`config.locale`) as Intl takes it, checked when it changes (an identity\n * compare per apply): one it does not (`<html lang=\"en_US\">`) is \"en\" (as 3.x), with a warning.\n */\nfunction defaultLocale(): string {\n if (config.locale !== seen) {\n seen = config.locale;\n try {\n valid = Intl.getCanonicalLocales(seen)[0];\n } catch {\n console.warn(`[@wcstack/state] ${text(M.LocaleInvalid, [seen])}`);\n valid = \"en\";\n }\n }\n return valid;\n}\n\n/**\n * Locale-formatted number. The locale-dependent filters (`locale date time datetime`) fix an\n * **explicit** locale at construction but read the default `config.locale` **on every apply**: a\n * default baked into the closure at binding time would make an ordering accident (locale settled\n * after the bindings) permanent, since `config.locale` is not in the dependency graph. Read per\n * apply, a re-applied binding at least recovers.\n */\nconst locale = (options: string[]): FilterFn => {\n const explicit = options?.[0];\n return (value: unknown): string => {\n if (typeof value !== 'number') {valueMustBeNumber('locale', value);}\n return value.toLocaleString(explicit ?? defaultLocale());\n };\n};\n\n/**\n * A number as money: `currency(code[, locale])`, the code ISO 4217 (`price|currency(JPY)` → \"¥1,800\",\n * `currency(EUR,de-DE)` → \"1.800,00 €\"). A code Intl does not take fails when the bindings are planned.\n * (docs/seam-apps.md, router-admin: the page built an `Intl.NumberFormat` per currency in getters.)\n */\nconst currency = (options: string[]): FilterFn => {\n const code = options?.[0] ?? optionsRequired('currency');\n const explicit = options?.[1];\n const format = { style: \"currency\", currency: code } as const;\n try {\n new Intl.NumberFormat(\"en\", format);\n // (Intl takes any three letters: the list of the ones it knows, where there is one)\n const known = (Intl as { supportedValuesOf?: (key: string) => string[] }).supportedValuesOf?.(\"currency\");\n if (known && !known.includes(code.toUpperCase())) throw 0;\n } catch {\n currencyInvalid(code);\n }\n return (value: unknown): string => {\n if (typeof value !== 'number') {valueMustBeNumber('currency', value);}\n return value.toLocaleString(explicit ?? defaultLocale(), format);\n };\n};\n\nconst upper = (): FilterFn => (value: unknown): string => String(value).toUpperCase();\n\nconst lower = (): FilterFn => (value: unknown): string => String(value).toLowerCase();\n\nconst capitalize = (): FilterFn => (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\nconst trim = (): FilterFn => (value: unknown): string => String(value).trim();\n\n/** `slice(start[, end])`. */\nconst slice = (options: string[]): FilterFn => {\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 => String(value).slice(...numberedOpts);\n};\n\n/** Pads the start to a length; the pad string defaults to '0' (JavaScript's default is a space). */\nconst padStart = (options: string[]): FilterFn => {\n const opt1 = requiredNumberOption(options, 0, 'padStart');\n const opt2 = options?.[1] ?? '0';\n return (value: unknown): string => String(value).padStart(opt1, opt2);\n};\n\n/** Pads the end to a length; the pad string defaults to ' ' (as in JavaScript). */\nconst padEnd = (options: string[]): FilterFn => {\n const opt1 = requiredNumberOption(options, 0, 'padEnd');\n const opt2 = options?.[1] ?? ' ';\n return (value: unknown): string => String(value).padEnd(opt1, opt2);\n};\n\nconst repeat = (options: string[]): FilterFn => {\n const opt = requiredNumberOption(options, 0, 'repeat');\n return (value: unknown): string => String(value).repeat(opt);\n};\n\nconst reverse = (): FilterFn => (value: unknown): string => String(value).split('').reverse().join('');\n\n/**\n * Shortens a string and appends a suffix (default '…', U+2026). The length counts **kept\n * characters**; a string at or below it is returned untouched (no suffix).\n */\nconst truncate = (options: string[]): FilterFn => {\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 * Joins an array. The default separator is \", \" rather than \",\": a bare comma is what `String()`\n * already produces, so defaulting to it would make `|join` a no-op.\n */\nconst join = (options: string[]): FilterFn => {\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\nconst STYLES = [\"full\", \"long\", \"medium\", \"short\"];\n\n/**\n * The options of `date time datetime`: `(locale?, style?)`, the style Intl's `dateStyle` / `timeStyle`\n * (`date(en-US,medium)` → \"Oct 13, 2026\"). A style alone keeps the default locale (`date(long)`).\n * Without a style the format is the locale's numeric one, as before.\n */\nfunction dateOptions(options: string[], fn: string): [string | undefined, Intl.DateTimeFormatOptions[\"dateStyle\"]] {\n let [loc, style]: (string | undefined)[] = options ?? [];\n if (style === undefined && loc !== undefined && STYLES.includes(loc)) [loc, style] = [undefined, loc];\n if (style !== undefined && !STYLES.includes(style)) styleInvalid(fn, style);\n return [loc, style as Intl.DateTimeFormatOptions[\"dateStyle\"]];\n}\n\n/** Locale-formatted date (the default locale is read per apply — see `locale`). */\nconst date = (options: string[]): FilterFn => {\n const [explicit, style] = dateOptions(options, 'date');\n const format: Intl.DateTimeFormatOptions | undefined = style && { dateStyle: style };\n return (value: unknown): string => {\n if (!(value instanceof Date)) {valueMustBeDate('date', value);}\n return value.toLocaleDateString(explicit ?? defaultLocale(), format);\n };\n};\n\n/** Locale-formatted time (the default locale is read per apply — see `locale`). */\nconst time = (options: string[]): FilterFn => {\n const [explicit, style] = dateOptions(options, 'time');\n const format: Intl.DateTimeFormatOptions | undefined = style && { timeStyle: style };\n return (value: unknown): string => {\n if (!(value instanceof Date)) {valueMustBeDate('time', value);}\n return value.toLocaleTimeString(explicit ?? defaultLocale(), format);\n };\n};\n\n/** Locale-formatted date and time (the default locale is read per apply — see `locale`). */\nconst datetime = (options: string[]): FilterFn => {\n const [explicit, style] = dateOptions(options, 'datetime');\n const format: Intl.DateTimeFormatOptions | undefined = style && { dateStyle: style, timeStyle: style };\n return (value: unknown): string => {\n if (!(value instanceof Date)) {valueMustBeDate('datetime', value);}\n return value.toLocaleString(explicit ?? defaultLocale(), format);\n };\n};\n\n/** YYYY-MM-DD with a configurable separator (default '-'), locale-independent. */\nconst ymd = (options: string[]): FilterFn => {\n const opt = options?.[0] ?? '-';\n return (value: unknown): string => {\n if (!(value instanceof Date)) {valueMustBeDate('ymd', value);}\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/** HH:MM:SS with a configurable separator (default ':'), zero-padded and locale-independent. */\nconst hms = (options: string[]): FilterFn => {\n const opt = options?.[0] ?? ':';\n return (value: unknown): string => {\n if (!(value instanceof Date)) {valueMustBeDate('hms', value);}\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\nconst abs = (): FilterFn => (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('abs', value);}\n return Math.abs(value);\n};\n\n/** Constrains a number to the inclusive range [min, max] (`style.width: ratio|clamp(0,1)|percent(0)`). */\nconst clamp = (options: string[]): FilterFn => {\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', value);}\n return Math.min(Math.max(value, min), max);\n };\n};\n\n// The conversions convert — an absent value is converted too (`string` gives \"undefined\");\n// put `coalesce` in front when a missing value should not be converted.\nconst number = (): FilterFn => (value: unknown): number => Number(value);\n\nconst string = (): FilterFn => (value: unknown): string => String(value);\n\nconst int = (): FilterFn => (value: unknown): number => parseInt(String(value), 10);\n\nconst float = (): FilterFn => (value: unknown): number => parseFloat(String(value));\n\n/** Replaces a falsy value (JavaScript's truthiness) with the typed literal: defaults(0) gives 0, defaults('0') \"0\" (B9). */\nconst defaults = (options: string[], literals?: readonly unknown[]): FilterFn => {\n const opt = options?.[0] ?? optionsRequired('defaults');\n const fallback = firstLiteral(opt, literals);\n return (value: unknown): unknown => {\n if (!value) {return fallback;}\n return value;\n };\n};\n\n/** Replaces only null / undefined (`defaults` also replaces 0, false and \"\") — SQL's COALESCE. */\nconst coalesce = (options: string[], literals?: readonly unknown[]): FilterFn => {\n const opt = options?.[0] ?? optionsRequired('coalesce');\n const fallback = firstLiteral(opt, literals);\n return (value: unknown): unknown => value ?? fallback;\n};\n\n/** \"\" → null, anything else unchanged. */\nconst nullIfEmpty = (): FilterFn => (value: unknown): unknown => (value === \"\") ? null : value;\n\nconst { eq, ne, not, lt, le, gt, ge, falsy, truthy, boolean } = coreFilters;\n\n/**\n * What `installFormats()` registers: factory and [min, max] argument count (B3 — the same bounds\n * lint uses), in the order the registry keeps them. The did-you-mean suggestion gives a tie to the\n * first registered, so the order is the one the full build registered up to 4.0.0-rc.3, when this\n * add-on had the 23 display filters and the core 24: the display filters, then that core set, each\n * in the source's (lint's) relative order. The core's 10 are registered here too, in their place\n * (the core registers them again when it first plans a binding, and a name registered again keeps\n * its place).\n */\nconst registered: Readonly<Record<string, FilterDefinition>> = {\n toFixed: { factory: toFixed, arity: [0, 1] },\n locale: { factory: locale, arity: [0, 1] },\n\n // The `String(value)` family passes an absent value through (B8 — see nullishPassthrough)\n upper: { factory: nullishPassthrough(upper), arity: [0, 0] },\n lower: { factory: nullishPassthrough(lower), arity: [0, 0] },\n capitalize: { factory: nullishPassthrough(capitalize), arity: [0, 0] },\n trim: { factory: nullishPassthrough(trim), arity: [0, 0] },\n slice: { factory: nullishPassthrough(slice), arity: [1, 2] },\n // The length is required too (the implementation reads both)\n padStart: { factory: nullishPassthrough(padStart), arity: [1, 2] },\n padEnd: { factory: nullishPassthrough(padEnd), arity: [1, 2] },\n repeat: { factory: nullishPassthrough(repeat), arity: [1, 1] },\n reverse: { factory: nullishPassthrough(reverse), arity: [0, 0] },\n truncate: { factory: nullishPassthrough(truncate), arity: [1, 2] },\n join: { factory: join, arity: [0, 1] },\n\n round: { factory: round, arity: [0, 1] },\n floor: { factory: floor, arity: [0, 1] },\n ceil: { factory: ceil, arity: [0, 1] },\n percent: { factory: percent, arity: [0, 1] },\n unit: { factory: nullishPassthrough(unit), arity: [1, 1] },\n\n // The locale-dependent three take a locale like `locale` does (`date(ja-JP)`), and a style (`date(ja-JP,long)`)\n date: { factory: date, arity: [0, 2] },\n time: { factory: time, arity: [0, 2] },\n datetime: { factory: datetime, arity: [0, 2] },\n ymd: { factory: ymd, arity: [0, 1] },\n hms: { factory: hms, arity: [0, 1] },\n\n // the core set of 4.0.0-rc.3 (the core's own: eq ne not lt le gt ge falsy truthy boolean)\n eq, ne, not, lt, le, gt, ge,\n add: numeric('add', (value, opt) => value + opt),\n sub: numeric('sub', (value, opt) => value - opt),\n mul: numeric('mul', (value, opt) => value * opt),\n div: numeric('div', (value, opt) => value / opt),\n mod: numeric('mod', (value, opt) => value % opt),\n abs: { factory: abs, arity: [0, 0] },\n clamp: { factory: clamp, arity: [2, 2] },\n int: { factory: int, arity: [0, 0] },\n float: { factory: float, arity: [0, 0] },\n falsy, truthy,\n defaults: { factory: defaults, arity: [1, 1] },\n coalesce: { factory: coalesce, arity: [1, 1] },\n boolean,\n number: { factory: number, arity: [0, 0] },\n string: { factory: string, arity: [0, 0] },\n nullIfEmpty: { factory: nullIfEmpty, arity: [0, 0] },\n // (added in 4.2: last, so the order of the others is unchanged)\n currency: { factory: currency, arity: [1, 2] },\n};\n\n/** The formats add-on's own filters (what `registered` holds beyond the core set), in that order. */\nexport const formatFilters: Readonly<Record<string, FilterDefinition>> = /*#__PURE__*/ Object.fromEntries(\n /*#__PURE__*/ Object.entries(registered).filter(([name]) => !(name in coreFilters)),\n);\n\nlet installed = false;\n\n/** Puts the formats add-on in the registry. Idempotent. */\nexport function installFormats(): void {\n if (installed) return;\n installed = true;\n registerFilters(registered);\n}\n","/**\n * The formats add-on (@wcstack/state/features/formats): the 38 filters that compute and show a value\n * (display, string shaping, dates — locale-aware —, arithmetic, conversions, missing values).\n */\nimport type { Feature } from \"../hooks\";\nimport { installFormats } from \"../filters/formats\";\n\nexport const formats: Feature = { name: \"formats\", install: installFormats };\nexport default formats;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["seen","nullishPassthrough","factory","options","filterFn","value","valid","defaultLocale","config","locale","Intl","getCanonicalLocales","console","warn","text","STYLES","dateOptions","fn","loc","style","includes","styleInvalid","eq","ne","not","lt","le","gt","ge","falsy","truthy","boolean","coreFilters","registered","toFixed","opt","numberOption","valueMustBeNumber","arity","explicit","toLocaleString","upper","String","toUpperCase","lower","toLowerCase","capitalize","v","length","charAt","slice","trim","numberedOpts","requiredNumberOption","opt2","push","padStart","opt1","padEnd","repeat","reverse","split","join","truncate","maxLength","suffix","Array","isArray","valueMustBeArray","round","optValue","Math","pow","floor","ceil","percent","unit","optionsRequired","date","format","dateStyle","Date","valueMustBeDate","toLocaleDateString","time","timeStyle","toLocaleTimeString","datetime","ymd","year","getFullYear","toString","month","getMonth","day","getDate","hms","hours","getHours","minutes","getMinutes","seconds","getSeconds","add","numeric","sub","mul","div","mod","abs","clamp","min","max","int","parseInt","float","parseFloat","defaults","literals","fallback","firstLiteral","coalesce","number","Number","string","nullIfEmpty","currency","code","NumberFormat","known","supportedValuesOf","currencyInvalid","installed","formats","name","hooks","install","registerFilters","formats_default"],"sources":["../../../src/filters/formats.ts","../../../src/features/formats.ts"],"sourcesContent":["/**\n * filters/formats.ts — the formats add-on (38 filters): the values a binding computes and shows, as\n * opposed to the conditions the core set (`./core`) tests. Ported from `@wcstack/state`\n * (`formats/builtinFilters.ts`) with the semantics unchanged.\n *\n * - number display: `toFixed round floor ceil percent unit locale currency`\n * - string shaping: `upper lower capitalize trim slice padStart padEnd repeat reverse truncate join`\n * (`substr` was removed in 4.0: `slice(start, start + length)`)\n * - date and time: `date time datetime ymd hms`\n * - arithmetic: `add sub mul div mod abs clamp`\n * - conversions: `number string int float`\n * - missing values: `defaults coalesce nullIfEmpty`\n *\n * (The last three groups were the core's up to 4.0.0-rc.3.)\n *\n * `installFormats()` puts them in the registry. Without it, one of these filters fails when the\n * bindings are planned with `[wcs/filter-unknown]` naming this add-on (never passes silently).\n * The locale-dependent five (`locale currency date time datetime`) read `config.locale` as their default.\n */\nimport { config } from \"../config\";\nimport { currencyInvalid, optionsRequired, styleInvalid, valueMustBeArray, valueMustBeDate, valueMustBeNumber } from \"./errorMessages\";\nimport { firstLiteral, numberOption, requiredNumberOption } from \"./options\";\nimport { registerFilters, type FilterDefinition, type FilterFactory, type FilterFn } from \"./registry\";\nimport { coreFilters, numeric } from \"./core\";\nimport { M, text } from \"../messages\";\n\n/**\n * Extends the display-side empty-value contract (requirement B8) to the filters that build their\n * result with `String(value)`: those turn `undefined` / `null` into the *characters* \"undefined\" /\n * \"null\", so `attr.title: x|trim` wrote `title=\"undefined\"` where `attr.title: x` removes the\n * attribute. This family passes an absent value straight through and leaves the decision to the\n * apply side (attribute removed, class cleared, style cleared, text emptied).\n *\n * Deliberately **not** wrapped: the filters that reject a value of the wrong type (the number and\n * array families) — their throw is confined to the one binding and reported, a different quality of\n * failure from painting the word \"undefined\" into the page. The date family is wrapped (since 4.7):\n * a date usually arrives later (a fetch, a route) and is absent until then, and no value put in\n * front (`coalesce`) could stand for a missing date — every load reported a failure\n * (docs/seam-apps.md, prod-booking). A value of another type still throws.\n */\nconst nullishPassthrough = (factory: (options: string[]) => FilterFn): FilterFactory =>\n (options: string[]): FilterFn => {\n const filterFn = factory(options);\n // `== null` matches both null and undefined (deliberately loose)\n return (value: unknown): unknown => (value == null ? value : filterFn(value));\n };\n\n/** Fixed decimals (default 0). */\nconst toFixed = (options: string[]): FilterFn => {\n const opt = numberOption(options?.[0] ?? \"0\", 'toFixed');\n return (value: unknown): string => {\n if (typeof value !== 'number') {valueMustBeNumber('toFixed', value);}\n return value.toFixed(opt);\n };\n};\n\n/** Rounds to the given decimals (default 0). */\nconst round = (options: string[]): FilterFn => {\n const optValue = Math.pow(10, numberOption(options?.[0] ?? '0', 'round'));\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('round', value);}\n return Math.round(value * optValue) / optValue;\n };\n};\n\n/** Rounds down to the given decimals (default 0). */\nconst floor = (options: string[]): FilterFn => {\n const optValue = Math.pow(10, numberOption(options?.[0] ?? '0', 'floor'));\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('floor', value);}\n return Math.floor(value * optValue) / optValue;\n };\n};\n\n/** Rounds up to the given decimals (default 0). */\nconst ceil = (options: string[]): FilterFn => {\n const optValue = Math.pow(10, numberOption(options?.[0] ?? '0', 'ceil'));\n return (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('ceil', value);}\n return Math.ceil(value * optValue) / optValue;\n };\n};\n\n/** `0.123` → `\"12%\"` with the given decimals (default 0). */\nconst percent = (options: string[]): FilterFn => {\n const opt = numberOption(options?.[0] ?? '0', 'percent');\n return (value: unknown): string => {\n if (typeof value !== 'number') {valueMustBeNumber('percent', value);}\n return `${(value * 100).toFixed(opt)}%`;\n };\n};\n\n/**\n * Appends a CSS unit (or any suffix). Accepts strings as well as numbers **on purpose**: the useful\n * chains run through `toFixed` / `percent`, which already return strings\n * (`style.height: cpu|clamp(0,100)|toFixed(0)|unit(%)`). null / undefined pass through\n * (`nullishPassthrough`) rather than becoming \"undefinedpx\".\n */\nconst unit = (options: string[]): FilterFn => {\n const opt = options?.[0] ?? optionsRequired('unit');\n return (value: unknown): string => String(value) + opt;\n};\n\nlet seen: string | undefined;\nlet valid = \"en\";\n\n/**\n * The default locale (`config.locale`) as Intl takes it, checked when it changes (an identity\n * compare per apply): one it does not (`<html lang=\"en_US\">`) is \"en\" (as 3.x), with a warning.\n */\nfunction defaultLocale(): string {\n if (config.locale !== seen) {\n seen = config.locale;\n try {\n valid = Intl.getCanonicalLocales(seen)[0];\n } catch {\n console.warn(`[@wcstack/state] ${text(M.LocaleInvalid, [seen])}`);\n valid = \"en\";\n }\n }\n return valid;\n}\n\n/**\n * Locale-formatted number. The locale-dependent filters (`locale date time datetime`) fix an\n * **explicit** locale at construction but read the default `config.locale` **on every apply**: a\n * default baked into the closure at binding time would make an ordering accident (locale settled\n * after the bindings) permanent, since `config.locale` is not in the dependency graph. Read per\n * apply, a re-applied binding at least recovers.\n */\nconst locale = (options: string[]): FilterFn => {\n const explicit = options?.[0];\n return (value: unknown): string => {\n if (typeof value !== 'number') {valueMustBeNumber('locale', value);}\n return value.toLocaleString(explicit ?? defaultLocale());\n };\n};\n\n/**\n * A number as money: `currency(code[, locale])`, the code ISO 4217 (`price|currency(JPY)` → \"¥1,800\",\n * `currency(EUR,de-DE)` → \"1.800,00 €\"). A code Intl does not take fails when the bindings are planned.\n * (docs/seam-apps.md, router-admin: the page built an `Intl.NumberFormat` per currency in getters.)\n */\nconst currency = (options: string[]): FilterFn => {\n const code = options?.[0] ?? optionsRequired('currency');\n const explicit = options?.[1];\n const format = { style: \"currency\", currency: code } as const;\n try {\n new Intl.NumberFormat(\"en\", format);\n // (Intl takes any three letters: the list of the ones it knows, where there is one)\n const known = (Intl as { supportedValuesOf?: (key: string) => string[] }).supportedValuesOf?.(\"currency\");\n if (known && !known.includes(code.toUpperCase())) throw 0;\n } catch {\n currencyInvalid(code);\n }\n return (value: unknown): string => {\n if (typeof value !== 'number') {valueMustBeNumber('currency', value);}\n return value.toLocaleString(explicit ?? defaultLocale(), format);\n };\n};\n\nconst upper = (): FilterFn => (value: unknown): string => String(value).toUpperCase();\n\nconst lower = (): FilterFn => (value: unknown): string => String(value).toLowerCase();\n\nconst capitalize = (): FilterFn => (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\nconst trim = (): FilterFn => (value: unknown): string => String(value).trim();\n\n/** `slice(start[, end])`. */\nconst slice = (options: string[]): FilterFn => {\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 => String(value).slice(...numberedOpts);\n};\n\n/** Pads the start to a length; the pad string defaults to '0' (JavaScript's default is a space). */\nconst padStart = (options: string[]): FilterFn => {\n const opt1 = requiredNumberOption(options, 0, 'padStart');\n const opt2 = options?.[1] ?? '0';\n return (value: unknown): string => String(value).padStart(opt1, opt2);\n};\n\n/** Pads the end to a length; the pad string defaults to ' ' (as in JavaScript). */\nconst padEnd = (options: string[]): FilterFn => {\n const opt1 = requiredNumberOption(options, 0, 'padEnd');\n const opt2 = options?.[1] ?? ' ';\n return (value: unknown): string => String(value).padEnd(opt1, opt2);\n};\n\nconst repeat = (options: string[]): FilterFn => {\n const opt = requiredNumberOption(options, 0, 'repeat');\n return (value: unknown): string => String(value).repeat(opt);\n};\n\nconst reverse = (): FilterFn => (value: unknown): string => String(value).split('').reverse().join('');\n\n/**\n * Shortens a string and appends a suffix (default '…', U+2026). The length counts **kept\n * characters**; a string at or below it is returned untouched (no suffix).\n */\nconst truncate = (options: string[]): FilterFn => {\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 * Joins an array. The default separator is \", \" rather than \",\": a bare comma is what `String()`\n * already produces, so defaulting to it would make `|join` a no-op.\n */\nconst join = (options: string[]): FilterFn => {\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\nconst STYLES = [\"full\", \"long\", \"medium\", \"short\"];\n\n/**\n * The options of `date time datetime`: `(locale?, style?)`, the style Intl's `dateStyle` / `timeStyle`\n * (`date(en-US,medium)` → \"Oct 13, 2026\"). A style alone keeps the default locale (`date(long)`).\n * Without a style the format is the locale's numeric one, as before.\n */\nfunction dateOptions(options: string[], fn: string): [string | undefined, Intl.DateTimeFormatOptions[\"dateStyle\"]] {\n let [loc, style]: (string | undefined)[] = options ?? [];\n if (style === undefined && loc !== undefined && STYLES.includes(loc)) [loc, style] = [undefined, loc];\n if (style !== undefined && !STYLES.includes(style)) styleInvalid(fn, style);\n return [loc, style as Intl.DateTimeFormatOptions[\"dateStyle\"]];\n}\n\n/** Locale-formatted date (the default locale is read per apply — see `locale`). */\nconst date = (options: string[]): FilterFn => {\n const [explicit, style] = dateOptions(options, 'date');\n const format: Intl.DateTimeFormatOptions | undefined = style && { dateStyle: style };\n return (value: unknown): string => {\n if (!(value instanceof Date)) {valueMustBeDate('date', value);}\n return value.toLocaleDateString(explicit ?? defaultLocale(), format);\n };\n};\n\n/** Locale-formatted time (the default locale is read per apply — see `locale`). */\nconst time = (options: string[]): FilterFn => {\n const [explicit, style] = dateOptions(options, 'time');\n const format: Intl.DateTimeFormatOptions | undefined = style && { timeStyle: style };\n return (value: unknown): string => {\n if (!(value instanceof Date)) {valueMustBeDate('time', value);}\n return value.toLocaleTimeString(explicit ?? defaultLocale(), format);\n };\n};\n\n/** Locale-formatted date and time (the default locale is read per apply — see `locale`). */\nconst datetime = (options: string[]): FilterFn => {\n const [explicit, style] = dateOptions(options, 'datetime');\n const format: Intl.DateTimeFormatOptions | undefined = style && { dateStyle: style, timeStyle: style };\n return (value: unknown): string => {\n if (!(value instanceof Date)) {valueMustBeDate('datetime', value);}\n return value.toLocaleString(explicit ?? defaultLocale(), format);\n };\n};\n\n/** YYYY-MM-DD with a configurable separator (default '-'), locale-independent. */\nconst ymd = (options: string[]): FilterFn => {\n const opt = options?.[0] ?? '-';\n return (value: unknown): string => {\n if (!(value instanceof Date)) {valueMustBeDate('ymd', value);}\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/** HH:MM:SS with a configurable separator (default ':'), zero-padded and locale-independent. */\nconst hms = (options: string[]): FilterFn => {\n const opt = options?.[0] ?? ':';\n return (value: unknown): string => {\n if (!(value instanceof Date)) {valueMustBeDate('hms', value);}\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\nconst abs = (): FilterFn => (value: unknown): number => {\n if (typeof value !== 'number') {valueMustBeNumber('abs', value);}\n return Math.abs(value);\n};\n\n/** Constrains a number to the inclusive range [min, max] (`style.width: ratio|clamp(0,1)|percent(0)`). */\nconst clamp = (options: string[]): FilterFn => {\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', value);}\n return Math.min(Math.max(value, min), max);\n };\n};\n\n// The conversions convert — an absent value is converted too (`string` gives \"undefined\");\n// put `coalesce` in front when a missing value should not be converted.\nconst number = (): FilterFn => (value: unknown): number => Number(value);\n\nconst string = (): FilterFn => (value: unknown): string => String(value);\n\nconst int = (): FilterFn => (value: unknown): number => parseInt(String(value), 10);\n\nconst float = (): FilterFn => (value: unknown): number => parseFloat(String(value));\n\n/** Replaces a falsy value (JavaScript's truthiness) with the typed literal: defaults(0) gives 0, defaults('0') \"0\" (B9). */\nconst defaults = (options: string[], literals?: readonly unknown[]): FilterFn => {\n const opt = options?.[0] ?? optionsRequired('defaults');\n const fallback = firstLiteral(opt, literals);\n return (value: unknown): unknown => {\n if (!value) {return fallback;}\n return value;\n };\n};\n\n/** Replaces only null / undefined (`defaults` also replaces 0, false and \"\") — SQL's COALESCE. */\nconst coalesce = (options: string[], literals?: readonly unknown[]): FilterFn => {\n const opt = options?.[0] ?? optionsRequired('coalesce');\n const fallback = firstLiteral(opt, literals);\n return (value: unknown): unknown => value ?? fallback;\n};\n\n/** \"\" → null, anything else unchanged. */\nconst nullIfEmpty = (): FilterFn => (value: unknown): unknown => (value === \"\") ? null : value;\n\nconst { eq, ne, not, lt, le, gt, ge, falsy, truthy, boolean } = coreFilters;\n\n/**\n * What `installFormats()` registers: factory and [min, max] argument count (B3 — the same bounds\n * lint uses), in the order the registry keeps them. The did-you-mean suggestion gives a tie to the\n * first registered, so the order is the one the full build registered up to 4.0.0-rc.3, when this\n * add-on had the 23 display filters and the core 24: the display filters, then that core set, each\n * in the source's (lint's) relative order. The core's 10 are registered here too, in their place\n * (the core registers them again when it first plans a binding, and a name registered again keeps\n * its place).\n */\nconst registered: Readonly<Record<string, FilterDefinition>> = {\n toFixed: { factory: toFixed, arity: [0, 1] },\n locale: { factory: locale, arity: [0, 1] },\n\n // The `String(value)` family passes an absent value through (B8 — see nullishPassthrough)\n upper: { factory: nullishPassthrough(upper), arity: [0, 0] },\n lower: { factory: nullishPassthrough(lower), arity: [0, 0] },\n capitalize: { factory: nullishPassthrough(capitalize), arity: [0, 0] },\n trim: { factory: nullishPassthrough(trim), arity: [0, 0] },\n slice: { factory: nullishPassthrough(slice), arity: [1, 2] },\n // The length is required too (the implementation reads both)\n padStart: { factory: nullishPassthrough(padStart), arity: [1, 2] },\n padEnd: { factory: nullishPassthrough(padEnd), arity: [1, 2] },\n repeat: { factory: nullishPassthrough(repeat), arity: [1, 1] },\n reverse: { factory: nullishPassthrough(reverse), arity: [0, 0] },\n truncate: { factory: nullishPassthrough(truncate), arity: [1, 2] },\n join: { factory: join, arity: [0, 1] },\n\n round: { factory: round, arity: [0, 1] },\n floor: { factory: floor, arity: [0, 1] },\n ceil: { factory: ceil, arity: [0, 1] },\n percent: { factory: percent, arity: [0, 1] },\n unit: { factory: nullishPassthrough(unit), arity: [1, 1] },\n\n // The locale-dependent three take a locale like `locale` does (`date(ja-JP)`), and a style (`date(ja-JP,long)`)\n date: { factory: nullishPassthrough(date), arity: [0, 2] },\n time: { factory: nullishPassthrough(time), arity: [0, 2] },\n datetime: { factory: nullishPassthrough(datetime), arity: [0, 2] },\n ymd: { factory: nullishPassthrough(ymd), arity: [0, 1] },\n hms: { factory: nullishPassthrough(hms), arity: [0, 1] },\n\n // the core set of 4.0.0-rc.3 (the core's own: eq ne not lt le gt ge falsy truthy boolean)\n eq, ne, not, lt, le, gt, ge,\n add: numeric('add', (value, opt) => value + opt),\n sub: numeric('sub', (value, opt) => value - opt),\n mul: numeric('mul', (value, opt) => value * opt),\n div: numeric('div', (value, opt) => value / opt),\n mod: numeric('mod', (value, opt) => value % opt),\n abs: { factory: abs, arity: [0, 0] },\n clamp: { factory: clamp, arity: [2, 2] },\n int: { factory: int, arity: [0, 0] },\n float: { factory: float, arity: [0, 0] },\n falsy, truthy,\n defaults: { factory: defaults, arity: [1, 1] },\n coalesce: { factory: coalesce, arity: [1, 1] },\n boolean,\n number: { factory: number, arity: [0, 0] },\n string: { factory: string, arity: [0, 0] },\n nullIfEmpty: { factory: nullIfEmpty, arity: [0, 0] },\n // (added in 4.2: last, so the order of the others is unchanged)\n currency: { factory: currency, arity: [1, 2] },\n};\n\n/** The formats add-on's own filters (what `registered` holds beyond the core set), in that order. */\nexport const formatFilters: Readonly<Record<string, FilterDefinition>> = /*#__PURE__*/ Object.fromEntries(\n /*#__PURE__*/ Object.entries(registered).filter(([name]) => !(name in coreFilters)),\n);\n\nlet installed = false;\n\n/** Puts the formats add-on in the registry. Idempotent. */\nexport function installFormats(): void {\n if (installed) return;\n installed = true;\n registerFilters(registered);\n}\n","/**\n * The formats add-on (@wcstack/state/features/formats): the 38 filters that compute and show a value\n * (display, string shaping, dates — locale-aware —, arithmetic, conversions, missing values).\n */\nimport { hooks, type Feature } from \"../hooks\";\nimport { installFormats } from \"../filters/formats\";\n\nexport const formats: Feature = { name: \"formats\", hooks, install: installFormats };\nexport default formats;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
/** An add-on entry: `installFeatures([temporal, diagnostics])` before the state is defined. */
|
|
17
17
|
interface Feature {
|
|
18
18
|
readonly name: string;
|
|
19
|
+
/** The slots of the build it comes from: it fills only those (the core checks they are its own). */
|
|
20
|
+
readonly hooks: object;
|
|
19
21
|
install(): void;
|
|
20
22
|
}
|
|
21
23
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as t,b as e,c as l,d as n,j as o}from"../chunks/chunk-
|
|
1
|
+
import{a as t,b as e,c as l,d as n,j as o}from"../chunks/chunk-BCL75PFH.js";var s=new WeakMap,r=!1,i=/^(?!prototype$)[^\d.*$][^.*]*$/;function f(t,e){let l=e.$listKeys,n=new Map;if(void 0!==l){(null===l||"object"!=typeof l)&&o("$listKeys must be an object mapping list paths to a key field or function.");for(let e of Object.keys(l)){let s=l[e];"string"==typeof s?n.set(t.o(e),t=>t[s]):"function"==typeof s?n.set(t.o(e),s):o(`$listKeys "${e}" must be a field name or a function.`)}}s.set(e,n)}function u(t){if(null===t||"object"!=typeof t)return!1;let e=Object.getPrototypeOf(t);return e===Object.prototype||null===e}function a(t,e,l){let n=new Map;for(let s of e){u(s)||o(`$listKeys "${t}": rows must be plain objects.`);let e=l(s);null==e&&o(`$listKeys "${t}": a row has no key.`),n.has(e)&&o(`$listKeys "${t}": duplicate key ${JSON.stringify(e)}.`),n.set(e,s)}return n}function y(t,e,l,n){if(r||!Array.isArray(n))return!1;let o=s.get(t.target)?.get(e);if(void 0===o)return!1;let f=t.it(e,l);if(!Array.isArray(f)||f===n)return!1;let u=a(e.t,f,o);a(e.t,n,o);let y=[],p=[],c=f.length===n.length;for(let t=0;t<n.length;t++){let e=n[t],l=u.get(o(e));y.push(l??e),void 0!==l&&p.push([t,l,e]),y[t]!==f[t]&&(c=!1)}let $=[];for(let[t,e,l]of p){for(let n of Object.keys(l))Object.is(e[n],l[n])||$.push([t,n,l[n]]);for(let n of Object.keys(e))!(n in l)&&null!==e[n]&&$.push([t,n,null])}if(c&&0===$.length)return!0;if(!c){r=!0;try{t.A(e,l,y)}finally{r=!1}}if($.length>0){let n=t.Ke(0===e.n?null:l,e);for(let[l,o,s]of $){if("__proto__"===o)continue;let r=n.f[l],f=i.test(o)?t.o(`${e.t}.*.${o}`):null;null===f?.getter?t.A(f,r,s):(r.E[o]=s,t.A(t.o(`${e.t}.*`),r,r.E,!0))}}return!0}var p={name:"list-keys",hooks:t,install(){t.fe=e(t.fe,f),t.Ie=l(n,t.Ie,y)}},c=p;export{c as default,p as listKeys};
|
|
2
2
|
//# sourceMappingURL=list-keys.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["keysByTarget","WeakMap","merging","SEGMENT","declare","engine","target","decl","$listKeys","keys","Map","raiseError","path","Object","key","set","pattern","row","isPlain","v","proto","getPrototypeOf","prototype","keyed","rows","keyOf","out","r","k","has","JSON","stringify","beforeWrite","p","value","Array","isArray","get","old","readData","before","merged","updates","same","length","i","next","kept","push","changes","f","is","write","list","childList","depth","fp","test","getter","item","listKeys","name","
|
|
1
|
+
{"version":3,"names":["keysByTarget","WeakMap","merging","SEGMENT","declare","engine","target","decl","$listKeys","keys","Map","raiseError","path","Object","key","set","pattern","row","isPlain","v","proto","getPrototypeOf","prototype","keyed","rows","keyOf","out","r","k","has","JSON","stringify","beforeWrite","p","value","Array","isArray","get","old","readData","before","merged","updates","same","length","i","next","kept","push","changes","f","is","write","list","childList","depth","fp","test","getter","item","listKeys","name","hooks","install","chain","first","handled","list_keys_default"],"sources":["../../../src/features/list-keys.ts"],"sourcesContent":["/**\n * The list-keys add-on (@wcstack/state/features/list-keys): `$listKeys` — identity for refetched\n * rows (README \"$listKeys\"). Assigning an array to a declared list path keeps the row objects whose\n * key matches and writes into them only the fields that changed (a dropped field is cleared with\n * null); the stored array is rebuilt from the kept objects, so rows, their DOM and focus survive a\n * refresh, and a refresh that changes nothing does nothing.\n */\nimport type { Engine } from \"../engine\";\nimport type { Pattern } from \"../pattern\";\nimport type { StateRow } from \"../list\";\nimport { chain, first, handled, hooks, type Feature } from \"../hooks\";\nimport { raiseError } from \"../parser/raiseError\";\n\ntype KeyOf = (row: Record<string, unknown>) => unknown;\n\n/** By state object: a re-set refused after the declaration (recursion) leaves the old state's keys in force. */\nconst keysByTarget = new WeakMap<object, Map<Pattern, KeyOf>>();\n/** The merged array is being written: the write goes through as a plain one. */\nlet merging = false;\nconst PROTO = \"__proto__\";\n/** A field name that is one path segment (no `.` / `*`, not an index, not a `$` name, not `prototype`: a path refuses it). */\nconst SEGMENT = /^(?!prototype$)[^\\d.*$][^.*]*$/;\n\nfunction declare(engine: Engine, target: Record<string, any>): void {\n const decl = target.$listKeys;\n const keys = new Map<Pattern, KeyOf>();\n if (decl !== undefined) {\n if (decl === null || typeof decl !== \"object\") raiseError(\"$listKeys must be an object mapping list paths to a key field or function.\");\n for (const path of Object.keys(decl)) {\n const key = decl[path];\n if (typeof key === \"string\") keys.set(engine.pattern(path), (row) => row[key]);\n else if (typeof key === \"function\") keys.set(engine.pattern(path), key as KeyOf);\n else raiseError(`$listKeys \"${path}\" must be a field name or a function.`);\n }\n }\n keysByTarget.set(target, keys);\n}\n\nfunction isPlain(v: unknown): v is Record<string, unknown> {\n if (v === null || typeof v !== \"object\") return false;\n const proto = Object.getPrototypeOf(v);\n return proto === Object.prototype || proto === null;\n}\n\nfunction keyed(path: string, rows: readonly unknown[], keyOf: KeyOf): Map<unknown, Record<string, unknown>> {\n const out = new Map<unknown, Record<string, unknown>>();\n for (const r of rows) {\n if (!isPlain(r)) raiseError(`$listKeys \"${path}\": rows must be plain objects.`);\n const k = keyOf(r);\n if (k === undefined || k === null) raiseError(`$listKeys \"${path}\": a row has no key.`);\n if (out.has(k)) raiseError(`$listKeys \"${path}\": duplicate key ${JSON.stringify(k)}.`);\n out.set(k, r);\n }\n return out;\n}\n\nfunction beforeWrite(engine: Engine, p: Pattern, row: StateRow | null, value: unknown): boolean {\n if (merging || !Array.isArray(value)) return false;\n const keyOf = keysByTarget.get(engine.target)?.get(p);\n if (keyOf === undefined) return false;\n const old = engine.readData(p, row);\n if (!Array.isArray(old) || old === value) return false;\n const before = keyed(p.path, old, keyOf);\n keyed(p.path, value, keyOf);\n // the stored array: the kept objects where keys match, the new ones elsewhere\n const merged: unknown[] = [];\n const updates: [number, Record<string, unknown>, Record<string, unknown>][] = [];\n let same = old.length === value.length;\n for (let i = 0; i < value.length; i++) {\n const next = value[i] as Record<string, unknown>;\n const kept = before.get(keyOf(next));\n merged.push(kept ?? next);\n if (kept !== undefined) updates.push([i, kept, next]);\n if (merged[i] !== old[i]) same = false;\n }\n const changes: [number, string, unknown][] = [];\n for (const [i, kept, next] of updates) {\n for (const f of Object.keys(next)) if (!Object.is(kept[f], next[f])) changes.push([i, f, next[f]]);\n for (const f of Object.keys(kept)) if (!(f in next) && kept[f] !== null) changes.push([i, f, null]);\n }\n if (same && changes.length === 0) return true; // a no-op refresh does nothing\n if (!same) {\n merging = true;\n try {\n engine.write(p, row, merged);\n } finally {\n merging = false;\n }\n }\n if (changes.length > 0) {\n const list = engine.childList(p.depth === 0 ? null : row, p);\n for (const [i, f, v] of changes) {\n // a field name is the server's. `__proto__` (an own key from JSON) is not a field: copied, it\n // would replace the row's prototype. A name that is not one path segment (`@odata.etag`,\n // `2fa`) or is a row getter's goes into the row as it is, the row told as a whole.\n if (f === PROTO) continue;\n const r = list.rows[i];\n const fp = SEGMENT.test(f) ? engine.pattern(`${p.path}.*.${f}`) : null;\n if (fp?.getter === null) engine.write(fp, r, v);\n else {\n (r.item as Record<string, unknown>)[f] = v;\n engine.write(engine.pattern(`${p.path}.*`), r, r.item, true);\n }\n }\n }\n return true;\n}\n\nexport const listKeys: Feature = {\n name: \"list-keys\",\n hooks,\n install(): void {\n hooks.declare = chain(hooks.declare, declare);\n hooks.beforeWrite = first(handled, hooks.beforeWrite, beforeWrite);\n },\n};\nexport default listKeys;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
/** An add-on entry: `installFeatures([temporal, diagnostics])` before the state is defined. */
|
|
17
17
|
interface Feature {
|
|
18
18
|
readonly name: string;
|
|
19
|
+
/** The slots of the build it comes from: it fills only those (the core checks they are its own). */
|
|
20
|
+
readonly hooks: object;
|
|
19
21
|
install(): void;
|
|
20
22
|
}
|
|
21
23
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{b as e}from"../chunks/chunk-
|
|
1
|
+
import{b as e}from"../chunks/chunk-DRSAQE4E.js";import{a as t}from"../chunks/chunk-BCL75PFH.js";var o={"*":["focus","blur","click","scrollIntoView","showPopover","hidePopover","togglePopover"],dialog:["show","showModal","close","requestClose"],form:["requestSubmit","checkValidity","reportValidity"],input:["select","setSelectionRange","showPicker","setCustomValidity","checkValidity","reportValidity"],textarea:["select","setSelectionRange","setCustomValidity","checkValidity","reportValidity"],select:["showPicker","setCustomValidity","checkValidity","reportValidity"],audio:["play","pause","load"],video:["play","pause","load"]};function i(t,i){let a=t.localName;if(a.includes("-"))return null;let l=(e=>[...o["*"],...Object.hasOwn(o,e)?o[e]:[]])(a);return l.includes(i)||e(1205,[a,i,l.join(", ")],i,l),(e,t)=>e[i](...t[0]instanceof Event?[]:t)}var a={name:"native-commands",hooks:t,install(){t.or=i}},l=a;export{l as default,a as nativeCommands};
|
|
2
2
|
//# sourceMappingURL=native-commands.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NATIVE_COMMANDS","dialog","form","input","textarea","select","audio","video","nativeCommand","el","method","tag","localName","includes","allowed","Object","hasOwn","nativeCommandsOf","raise","join","target","args","Event","nativeCommands","name","
|
|
1
|
+
{"version":3,"names":["NATIVE_COMMANDS","dialog","form","input","textarea","select","audio","video","nativeCommand","el","method","tag","localName","includes","allowed","Object","hasOwn","nativeCommandsOf","raise","join","target","args","Event","nativeCommands","name","hooks","install","native_commands_default"],"sources":["../../../src/native/commands.ts","../../../src/features/native-commands.ts"],"sourcesContent":["/**\n * Native element commands (the native-commands add-on): `command.<method>:` on an element with no\n * wc-bindable declaration — `<dialog data-wcs=\"command.showModal: $command.open\">` — so a state\n * opens a dialog, focuses an input or plays a video by emitting a token, never by reaching the\n * element (docs/state-engine-rewrite/native-commands.ja.md).\n */\nimport type { NativeCall } from \"../hooks\";\nimport { raise, M } from \"../messages\";\n\n/**\n * The methods a native element's `command.<method>:` may call, by tag (`*`: every element). None\n * writes HTML, an attribute or the tree, or changes a control's value without its `input` event\n * (the state would not see it). Decided by this table alone, not by what the element has: a\n * binding binds in every browser (and on the server) alike, and a method a browser lacks fails\n * when it is called. The tooling manifest publishes a copy as `nativeCommands`.\n */\nexport const NATIVE_COMMANDS: Readonly<Record<string, readonly string[]>> = {\n \"*\": [\"focus\", \"blur\", \"click\", \"scrollIntoView\", \"showPopover\", \"hidePopover\", \"togglePopover\"],\n \"dialog\": [\"show\", \"showModal\", \"close\", \"requestClose\"],\n \"form\": [\"requestSubmit\", \"checkValidity\", \"reportValidity\"],\n \"input\": [\"select\", \"setSelectionRange\", \"showPicker\", \"setCustomValidity\", \"checkValidity\", \"reportValidity\"],\n \"textarea\": [\"select\", \"setSelectionRange\", \"setCustomValidity\", \"checkValidity\", \"reportValidity\"],\n \"select\": [\"showPicker\", \"setCustomValidity\", \"checkValidity\", \"reportValidity\"],\n \"audio\": [\"play\", \"pause\", \"load\"],\n \"video\": [\"play\", \"pause\", \"load\"],\n};\n\n/** What a native `tag` may be commanded to run (its own row only: `<constructor>` reads no prototype). */\nexport const nativeCommandsOf = (tag: string): readonly string[] =>\n [...NATIVE_COMMANDS[\"*\"], ...(Object.hasOwn(NATIVE_COMMANDS, tag) ? NATIVE_COMMANDS[tag] : [])];\n\n/** `hooks.nativeCommand`: null for a custom element (it declares its commands); throws for a method outside the table. */\nexport function nativeCommand(el: Element, method: string): NativeCall | null {\n const tag = el.localName;\n if (tag.includes(\"-\")) return null;\n const allowed = nativeCommandsOf(tag);\n if (!allowed.includes(method)) raise(M.NativeNoCommand, [tag, method, allowed.join(\", \")], method, allowed);\n // an event's emit (`onclick: $command.x`: the event, then the list indexes) is no argument of a\n // native method — `close(event)` would set the dialog's returnValue to \"[object PointerEvent]\"\n return (target, args) => (target as any)[method](...(args[0] instanceof Event ? [] : args));\n}\n","/**\n * The native-commands add-on (@wcstack/state/features/native-commands): `command.<method>:` on a\n * native element (README \"Native element commands\") — `showModal` / `close` on a `<dialog>`,\n * `focus` on an `<input>`, `play` / `pause` on a `<video>`, from the table in native/commands.ts.\n * Without it a native element's `command.` fails as before (`[wcs/token-misconfigured]`).\n */\nimport { hooks, type Feature } from \"../hooks\";\nimport { nativeCommand } from \"../native/commands\";\n\nexport const nativeCommands: Feature = {\n name: \"native-commands\",\n hooks,\n install(): void {\n hooks.nativeCommand = nativeCommand;\n },\n};\nexport default nativeCommands;\n"],"mappings":"gGAgBO,IAAMA,EAA+D,CAC1E,IAAK,CAAC,QAAS,OAAQ,QAAS,iBAAkB,cAAe,cAAe,iBAChFC,OAAU,CAAC,OAAQ,YAAa,QAAS,gBACzCC,KAAQ,CAAC,gBAAiB,gBAAiB,kBAC3CC,MAAS,CAAC,SAAU,oBAAqB,aAAc,oBAAqB,gBAAiB,kBAC7FC,SAAY,CAAC,SAAU,oBAAqB,oBAAqB,gBAAiB,kBAClFC,OAAU,CAAC,aAAc,oBAAqB,gBAAiB,kBAC/DC,MAAS,CAAC,OAAQ,QAAS,QAC3BC,MAAS,CAAC,OAAQ,QAAS,SAQtB,SAASC,EAAcC,EAAaC,GACzC,IAAMC,EAAMF,EAAGG,UACf,GAAID,EAAIE,SAAS,KAAM,OAAO,KAC9B,IAAMC,EAPyBH,IAC/B,IAAIX,EAAgB,QAAUe,OAAOC,OAAOhB,EAAiBW,GAAOX,EAAgBW,GAAO,IAM3EM,CAAiBN,GACjC,OAAKG,EAAQD,SAASH,IAASQ,OAAyB,CAACP,EAAKD,EAAQI,EAAQK,KAAK,OAAQT,EAAQI,GAG5F,CAACM,EAAQC,IAAUD,EAAeV,MAAYW,EAAK,aAAcC,MAAQ,GAAKD,EACvF,CC/BO,IAAME,EAA0B,CACrCC,KAAM,kBACNC,QACA,OAAAC,GACED,EAAMjB,GAAgBA,CACxB,GAEKmB,EAAQJ","ignoreList":[]}
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
/** An add-on entry: `installFeatures([temporal, diagnostics])` before the state is defined. */
|
|
17
17
|
interface Feature {
|
|
18
18
|
readonly name: string;
|
|
19
|
+
/** The slots of the build it comes from: it fills only those (the core checks they are its own). */
|
|
20
|
+
readonly hooks: object;
|
|
19
21
|
install(): void;
|
|
20
22
|
}
|
|
21
23
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{m as e}from"../chunks/chunk-
|
|
1
|
+
import{m as e}from"../chunks/chunk-PKEAYPFR.js";import{b as t}from"../chunks/chunk-DRSAQE4E.js";import{a as r,b as l,c as n,d as s,j as a}from"../chunks/chunk-BCL75PFH.js";var i="$recursion",o=new WeakMap,c=new WeakSet,u=new WeakSet,h=0,d=e=>e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),$=e=>`[wcs/recursion-${e}]`;function f(e,t){let r=r=>a(`${$("declaration-invalid")} ${i} ${e} "${String(t)}" ${r}`);("string"!=typeof t||""===t)&&a(`${$("declaration-invalid")} ${i} ${e} must be a non-empty string.`);let l=t.split(".");(l.length<2||"*"!==l[l.length-1])&&r('must end with ".*" (a list element).');for(let e=0;e<l.length-1;e++){let t=l[e];""===t&&r("must not contain empty path segments."),("*"===t||"**"===t||/^\d/.test(t))&&r('must have exactly one "*", at the end.'),t.includes("#")&&r('must not contain "#".')}return"$"===t[0]&&r('must not start with "$".'),t}var p=(e,t)=>`${e.l}.*${e.step.repeat(t)}`;function g(e,t){let r=`${e.l}.**`,l=t.slice(r.length);return(!t.startsWith(r)||""!==l&&"."!==l[0]||l.includes("**"))&&a(`[wcs/recursion-anchor] "${t}" does not start at the recursion anchor "${e.l}.*".`),l}function m(e,t,r){let l=g(e,t),n=function(e,t){for(let r=t;null!==r;r=r.l.ce){let t=e.nodeList.exec(r.l.o.t);if(null!==t)return{k:t[1].length/(e.key.length+3),r}}return null}(e,r);return null===n&&a(`[wcs/recursion-context] "${t}" uses "**", which is bound to the depth of the row it is evaluated in; there is none here — use $getAll("${t}", []) for every depth.`),p(e,n.k)+l}function w(e,t,r){let l=new Set,n=new Set,s=(e,r,s)=>!(!Array.isArray(e)||0===e.length||(l.has(e)&&a(`${$("cycle")} "${r}" is reachable from itself: the data under "${t.l}" must be a tree.`),n.has(e)&&a(`${$("shared-list")} "${r}" is the same array instance as a list reached before: the data under "${t.l}" must be a tree.`),s+1>128&&a(`${$("depth-exceeded")} Recursion on "${t.l}.*" reached depth ${s+1} (the limit is 128).`),n.add(e),0)),i=(n,a)=>{for(let o of n){r(a,o);let n=e.o(`${p(t,a)}.${t.key}`),c=e.read(n,o);s(c,n.t,a+1)&&(l.add(c),i(e.Ke(o,n).f,a+1),l.delete(c))}},o=e.o(t.l),c=e.read(o,null);s(c,t.l,0)&&(l.add(c),i(e.Ke(null,o).f,0))}function y(r,l){let n=function(t){let r=t[i],l=[],n=new Set;for(let e=t;null!==e&&e!==Object.prototype;e=Object.getPrototypeOf(e))for(let t of Object.getOwnPropertyNames(e))!n.has(t)&&t.includes("**")&&l.push([t,Object.getOwnPropertyDescriptor(e,t)]),n.add(t);if(void 0===r)return l.length>0&&e(l[0][0]),null;(null===r||"object"!=typeof r||Array.isArray(r))&&a(`${$("declaration-invalid")} ${i} must be an object mapping one anchor path to its repeating sub-path.`);let s=Object.entries(r);1!==s.length&&a(`${$("declaration-invalid")} ${i} must declare exactly one anchor (it declares ${s.length}).`);let o=f("anchor",s[0][0]),c=f("repeat",s[0][1]),u=o.slice(0,-2),h=c.slice(0,-2),p=`.${c}`,g=new Map,m=[],w=`${u}.**`;for(let[e,t]of l){let r=e.slice(w.length);(!e.startsWith(w)||""!==r&&"."!==r[0]||r.includes("**"))&&a(`[wcs/recursion-anchor] "${e}": a recursive key is "${w}" followed by a path (the anchor is "${o}").`),(""===r||r.split(".").slice(1).some(e=>""===e))&&a(`[wcs/recursion-anchor] "${e}" needs a path after "**".`),(void 0===t.get||void 0!==t.set)&&a(`${$("declaration-invalid")} "${e}": a recursive key is a getter without a setter.`),g.set(r,t.get),m.push([new RegExp(`^${d(o)}((?:${d(p)})*)${d(r)}$`),r])}return{l:u,step:p,key:h,families:g,matchers:m,owners:new Map,nodeList:new RegExp(`^${d(u)}((?:${d(`.*.${h}`)})*)$`)}}(l),s=o.has(r);null!==n?(s||h++,o.set(r,n),u.add(r),c.has(r)||function(r){c.add(r);let l=r,n=l.ot;l.ot=t=>{let s=o.get(r);if(t.t.includes("**")){let l=r.O.wt(t.t)===t;return void(u.has(r)||void 0===s&&l?t.getter=()=>e(t.t):l||n.call(r,t))}if(void 0!==s&&null===t.getter)for(let[e,r]of s.matchers)if(e.test(t.t)){t.getter=s.families.get(r),t.n>0&&(t.F=l.Le++),s.owners.set(t,s.l+".**"+r);break}n.call(r,t)};let s=l.resolve;l.resolve=(e,t)=>{let l=o.get(r);return s.call(r,void 0!==l&&e.includes("**")?m(l,e,t):e,t)};let i=l.getAll;l.getAll=(e,t)=>{let n=o.get(r);if(void 0===n||!e.includes("**"))return i.call(r,e,t);if(void 0===t)return i.call(r,m(n,e,l.d));(!Array.isArray(t)||t.length>0)&&a(`${$("getall-form")} $getAll("${e}", indexes) with "**" takes either no indexes (this depth) or [] (every depth).`);let s=g(n,e),c=[];return w(r,n,(e,t)=>{for(let l of i.call(r,p(n,e)+s,r.H(t)))c.push(l)}),c};let h=l.wn;l.wn=(e,n,s,i)=>{let c=o.get(r);if(void 0===c||!e.includes("**"))return h.call(r,e,n,s,i);Array.isArray(n)||t(9,[e]),n.length>0&&a(`${$("setall-form")} $setAll("${e}", indexes, …) with "**" takes no partial prefix: pass [] to write every node.`),("function"==typeof s||!0===i?.spread)&&a(`${$("setall-form")} $setAll("${e}", [], value) with "**" takes a plain value (no mapper, no spread).`),l.Be>0&&t(8);let u=g(c,e),d=u.replace(/\.\d+(?=\.|$)/g,".*");for(;d.startsWith(c.step);)d=d.slice(c.step.length);let f=c.key.split(".");(""===d||d===`.${c.key}.length`||f.some((e,t)=>d===`.${f.slice(0,t+1).join(".")}`))&&a(`${$("structural-write")} "${e}" writes the recursion structure itself (a node, its "${c.key}" list or that list's length, or an object on the way to it).`);for(let t of c.families.keys()){let r=t;for(;r.startsWith(c.step);)r=r.slice(c.step.length);(d===r||d.startsWith(`${r}.`))&&a(`${$("readonly")} "${e}" writes into the recursive getter "${c.l}.**${t}".`)}let m=[];w(r,c,(e,t)=>m.push([e,t]));let y=0;for(let[e,t]of m)y+=h.call(r,p(c,e)+u,r.H(t),s);return y}}(r)):s&&(o.delete(r),h--)}function v(e,t){if(0===h)return!1;let r=o.get(e);if(void 0===r)return!1;for(let e=t;null!==e;e=e.c){let l=r.owners.get(e);void 0!==l&&a(`${$("readonly")} "${t.t}" writes into the recursive getter "${l}".`)}return!1}var k={name:"recursion",hooks:r,install(){r.fe=l(r.fe,y),r.element=l(r.element,(e,t)=>{("mounting"===t||"reset"===t)&&function(e){u.delete(e)}(e)}),r.Ie=n(s,r.Ie,v)}},b=k;export{b as default,k as recursion};
|
|
2
2
|
//# sourceMappingURL=recursion.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NAME","specs","WeakMap","wrapped","WeakSet","registering","engines","esc","s","replace","code","c","checkPath","kind","path","bad","why","raiseError","String","segs","split","length","i","test","includes","nodePath","spec","k","list","step","repeat","suffixOf","head","rest","slice","startsWith","bind","ctx","at","row","r","parentRow","m","nodeList","exec","pattern","key","depthOf","walk","engine","visit","ancestors","Set","seen","enter","arr","listPath","Array","isArray","has","add","down","rows","listP","read","childList","delete","rootP","declareRecursion","target","decl","keys","o","Object","prototype","getPrototypeOf","getOwnPropertyNames","push","getOwnPropertyDescriptor","recursionUnsupported","entries","anchor","families","Map","matchers","d","suffix","some","get","set","RegExp","owners","had","e","created","onPatternCreated","p","known","patterns","peek","getter","call","re","depth","slot","slotCount","resolve","getAll","indexes","out","v","indexesOf","setAll","value","options","raise","spread","readonlyDepth","_","join","f","nodes","written","wrap","guardExpansion","q","parent","owner","recursion","name","install","hooks","declare","chain","element","phase","recursionSettled","beforeWrite","first","handled","recursion_default"],"sources":["../../../src/recursion/recursion.ts","../../../src/features/recursion.ts"],"sourcesContent":["/**\n * Recursive paths (README \"Recursive paths\"): one self-recursive anchor per state,\n * `$recursion: { \"nodes.*\": \"children.*\" }`, and `**` as a depth variable — `nodes.**.x` stands\n * for `nodes.*.x`, `nodes.*.children.*.x`, … The engine only ever sees the concrete depths:\n *\n * - a getter `get \"nodes.**.total\"()` is a family, materialized as an ordinary getter on each\n * concrete depth's pattern when that pattern is made (so `$1`, caching and dependencies are the\n * ordinary per-depth ones, and a deep change reaches every ancestor through ordinary edges);\n * - `**` in a path read or `$getAll(path)` without indexes is bound to the depth of the row the\n * evaluation runs in (a family getter's row, a row getter's, an event handler's);\n * - `$getAll(path, [])` collects every depth (depth first, pre-order), `$setAll(path, [], v)`\n * writes every node; the expansions of a family are read-only.\n *\n * The engines with a `$recursion` get their `onPatternCreated`, `resolve`, `getAll` and `setAll`\n * wrapped; an engine without one pays nothing. The static checks of 3.3 (colliding families,\n * structural suffixes on getters) are the diagnostics add-on's (approved simplification).\n */\nimport type { Engine } from \"../engine\";\nimport type { Pattern } from \"../pattern\";\nimport type { StateRow } from \"../list\";\nimport { raiseError } from \"../parser/raiseError\";\nimport { raise, M } from \"../messages\";\nimport { recursionUnsupported } from \"../parser/parseStatePart\";\n\nconst NAME = \"$recursion\";\nconst MAX_DEPTH = 128;\n\ninterface Spec {\n /** `nodes` (the anchor without its trailing `.*`). */\n readonly list: string;\n /** `.children.*` */\n readonly step: string;\n /** `children` */\n readonly key: string;\n /** Families by suffix (`.total`): the author's getter. */\n readonly families: Map<string, (this: unknown) => unknown>;\n readonly matchers: [RegExp, string][];\n /** Node list patterns: `nodes`, `nodes.*.children`, `nodes.*.children.*.children`, … */\n readonly nodeList: RegExp;\n /** The family key each materialized expansion belongs to. */\n readonly owners: Map<Pattern, string>;\n}\n\nconst specs = new WeakMap<Engine, Spec>();\nconst wrapped = new WeakSet<Engine>();\n/** Patterns created while the state's accessors are registered (the `**` keys among them are templates). */\nconst registering = new WeakSet<Engine>();\nlet engines = 0;\n\nconst esc = (s: string): string => s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\nconst code = (c: string) => `[wcs/recursion-${c}]`;\n\nfunction checkPath(kind: string, path: unknown): string {\n const bad = (why: string): never => raiseError(`${code(\"declaration-invalid\")} ${NAME} ${kind} \"${String(path)}\" ${why}`);\n if (typeof path !== \"string\" || path === \"\") raiseError(`${code(\"declaration-invalid\")} ${NAME} ${kind} must be a non-empty string.`);\n const segs = path.split(\".\");\n if (segs.length < 2 || segs[segs.length - 1] !== \"*\") bad('must end with \".*\" (a list element).');\n for (let i = 0; i < segs.length - 1; i++) {\n const s = segs[i];\n if (s === \"\") bad(\"must not contain empty path segments.\");\n if (s === \"*\" || s === \"**\" || /^\\d/.test(s)) bad('must have exactly one \"*\", at the end.');\n if (s.includes(\"#\")) bad('must not contain \"#\".');\n }\n if (path[0] === \"$\") bad('must not start with \"$\".');\n return path;\n}\n\n/** Reads and checks the declaration; null when the state has none. */\nfunction read(target: Record<string, any>): Spec | null {\n const decl = target[NAME];\n const keys: [string, PropertyDescriptor][] = [];\n const seen = new Set<string>();\n for (let o: object | null = target; o !== null && o !== Object.prototype; o = Object.getPrototypeOf(o)) {\n for (const k of Object.getOwnPropertyNames(o)) {\n if (!seen.has(k) && k.includes(\"**\")) keys.push([k, Object.getOwnPropertyDescriptor(o, k)!]);\n seen.add(k);\n }\n }\n if (decl === undefined) {\n if (keys.length > 0) recursionUnsupported(keys[0][0]);\n return null;\n }\n if (decl === null || typeof decl !== \"object\" || Array.isArray(decl)) {\n raiseError(`${code(\"declaration-invalid\")} ${NAME} must be an object mapping one anchor path to its repeating sub-path.`);\n }\n const entries = Object.entries(decl);\n if (entries.length !== 1) raiseError(`${code(\"declaration-invalid\")} ${NAME} must declare exactly one anchor (it declares ${entries.length}).`);\n const anchor = checkPath(\"anchor\", entries[0][0]);\n const repeat = checkPath(\"repeat\", entries[0][1]);\n const list = anchor.slice(0, -2);\n const key = repeat.slice(0, -2);\n const step = `.${repeat}`;\n const families = new Map<string, (this: unknown) => unknown>();\n const matchers: [RegExp, string][] = [];\n const head = `${list}.**`;\n for (const [k, d] of keys) {\n const suffix = k.slice(head.length);\n if (!k.startsWith(head) || (suffix !== \"\" && suffix[0] !== \".\") || suffix.includes(\"**\")) {\n raiseError(`[wcs/recursion-anchor] \"${k}\": a recursive key is \"${head}\" followed by a path (the anchor is \"${anchor}\").`);\n }\n if (suffix === \"\" || suffix.split(\".\").slice(1).some((s) => s === \"\")) raiseError(`[wcs/recursion-anchor] \"${k}\" needs a path after \"**\".`);\n if (d.get === undefined || d.set !== undefined) raiseError(`${code(\"declaration-invalid\")} \"${k}\": a recursive key is a getter without a setter.`);\n families.set(suffix, d.get);\n matchers.push([new RegExp(`^${esc(anchor)}((?:${esc(step)})*)${esc(suffix)}$`), suffix]);\n }\n return { list, step, key, families, matchers, owners: new Map(), nodeList: new RegExp(`^${esc(list)}((?:${esc(`.*.${key}`)})*)$`) };\n}\n\n/** `nodes.*` + `.children.*` × k */\nconst nodePath = (spec: Spec, k: number): string => `${spec.list}.*${spec.step.repeat(k)}`;\n\n/** The depth of the node row `row` is in or under (null: not under the anchor). */\nfunction depthOf(spec: Spec, row: StateRow | null): { k: number; row: StateRow } | null {\n for (let r = row; r !== null; r = r.list.parentRow) {\n const m = spec.nodeList.exec(r.list.pattern.path);\n if (m !== null) return { k: m[1].length / (spec.key.length + 3), row: r };\n }\n return null;\n}\n\n/** What follows `nodes.**` in a path (`.x`, or \"\" for the nodes themselves). */\nfunction suffixOf(spec: Spec, path: string): string {\n const head = `${spec.list}.**`;\n const rest = path.slice(head.length);\n if (!path.startsWith(head) || (rest !== \"\" && rest[0] !== \".\") || rest.includes(\"**\")) {\n raiseError(`[wcs/recursion-anchor] \"${path}\" does not start at the recursion anchor \"${spec.list}.*\".`);\n }\n return rest;\n}\n\n/** `nodes.**.x` → the concrete depth of the evaluation's row. */\nfunction bind(spec: Spec, path: string, ctx: StateRow | null): string {\n const rest = suffixOf(spec, path);\n const at = depthOf(spec, ctx);\n if (at === null) {\n raiseError(`[wcs/recursion-context] \"${path}\" uses \"**\", which is bound to the depth of the row it is evaluated in; there is none here — use $getAll(\"${path}\", []) for every depth.`);\n }\n return nodePath(spec, at.k) + rest;\n}\n\n/** Every node row, depth first and pre-order: (depth, row). Reads (and so tracks) each list. */\nfunction walk(engine: Engine, spec: Spec, visit: (k: number, row: StateRow) => void): void {\n const ancestors = new Set<unknown>();\n const seen = new Set<unknown>();\n const enter = (arr: unknown, listPath: string, k: number): boolean => {\n if (!Array.isArray(arr) || arr.length === 0) return false;\n if (ancestors.has(arr)) raiseError(`${code(\"cycle\")} \"${listPath}\" is reachable from itself: the data under \"${spec.list}\" must be a tree.`);\n if (seen.has(arr)) raiseError(`${code(\"shared-list\")} \"${listPath}\" is the same array instance as a list reached before: the data under \"${spec.list}\" must be a tree.`);\n if (k + 1 > MAX_DEPTH) raiseError(`${code(\"depth-exceeded\")} Recursion on \"${spec.list}.*\" reached depth ${k + 1} (the limit is ${MAX_DEPTH}).`);\n seen.add(arr);\n return true;\n };\n const down = (rows: StateRow[], k: number): void => {\n for (const row of rows) {\n visit(k, row);\n const listP = engine.pattern(`${nodePath(spec, k)}.${spec.key}`);\n const arr = engine.read(listP, row);\n if (!enter(arr, listP.path, k + 1)) continue;\n ancestors.add(arr);\n down(engine.childList(row, listP).rows, k + 1);\n ancestors.delete(arr);\n }\n };\n const rootP = engine.pattern(spec.list);\n const arr = engine.read(rootP, null);\n if (!enter(arr, spec.list, 0)) return;\n ancestors.add(arr);\n down(engine.childList(null, rootP).rows, 0);\n}\n\nfunction wrap(engine: Engine): void {\n wrapped.add(engine);\n const e = engine as any;\n const created = e.onPatternCreated;\n e.onPatternCreated = (p: Pattern) => {\n const spec = specs.get(engine);\n if (p.path.includes(\"**\")) {\n // a recursive key's own pattern while the accessors are registered: an inert template that\n // refuses to be read, and stays one when every pattern is looked at again (a volume grafting\n // its accessors, a re-set — one that drops `$recursion` forgets it: refused again); a new one\n // later is refused by the core (made patterns are interned after this runs)\n const known = engine.patterns.peek(p.path) === p;\n if (registering.has(engine) || (spec === undefined && known)) p.getter = () => recursionUnsupported(p.path);\n else if (!known) created.call(engine, p);\n return;\n }\n if (spec !== undefined && p.getter === null) {\n for (const [re, suffix] of spec.matchers) {\n if (!re.test(p.path)) continue;\n p.getter = spec.families.get(suffix)!;\n if (p.depth > 0) p.slot = e.slotCount++;\n spec.owners.set(p, spec.list + \".**\" + suffix);\n break;\n }\n }\n created.call(engine, p);\n };\n const resolve = e.resolve;\n e.resolve = (path: string, ctx: StateRow | null) => {\n const spec = specs.get(engine);\n return resolve.call(engine, spec !== undefined && path.includes(\"**\") ? bind(spec, path, ctx) : path, ctx);\n };\n const getAll = e.getAll;\n e.getAll = (path: string, indexes?: number[]) => {\n const spec = specs.get(engine);\n if (spec === undefined || !path.includes(\"**\")) return getAll.call(engine, path, indexes);\n if (indexes === undefined) return getAll.call(engine, bind(spec, path, e.ctx));\n if (!Array.isArray(indexes) || indexes.length > 0) {\n raiseError(`${code(\"getall-form\")} $getAll(\"${path}\", indexes) with \"**\" takes either no indexes (this depth) or [] (every depth).`);\n }\n const suffix = suffixOf(spec, path);\n const out: unknown[] = [];\n walk(engine, spec, (k, row) => {\n for (const v of getAll.call(engine, nodePath(spec, k) + suffix, engine.indexesOf(row))) out.push(v);\n });\n return out;\n };\n const setAll = e.setAll;\n e.setAll = (path: string, indexes: number[], value: unknown, options?: { spread?: boolean }) => {\n const spec = specs.get(engine);\n if (spec === undefined || !path.includes(\"**\")) return setAll.call(engine, path, indexes, value, options);\n // (the core's own messages where the core's $setAll has one)\n if (!Array.isArray(indexes)) raise(M.SetAllNeedsIndexes, [path]);\n if (indexes.length > 0) raiseError(`${code(\"setall-form\")} $setAll(\"${path}\", indexes, …) with \"**\" takes no partial prefix: pass [] to write every node.`);\n if (typeof value === \"function\" || options?.spread === true) raiseError(`${code(\"setall-form\")} $setAll(\"${path}\", [], value) with \"**\" takes a plain value (no mapper, no spread).`);\n if (e.readonlyDepth > 0) raise(M.Readonly);\n const suffix = suffixOf(spec, path);\n // the checks (3.x's): an index spelling is a `*` (`.children.0` is a child node), and a child\n // node's path is a node's (`.children.*.total` is the family `.total` one level down)\n let rest = suffix.replace(/\\.\\d+(?=\\.|$)/g, \".*\");\n while (rest.startsWith(spec.step)) rest = rest.slice(spec.step.length);\n // the structure: a node, the objects on the way to its child list and the list, the list's length\n const segs = spec.key.split(\".\");\n if (rest === \"\" || rest === `.${spec.key}.length` || segs.some((_, i) => rest === `.${segs.slice(0, i + 1).join(\".\")}`)) {\n raiseError(`${code(\"structural-write\")} \"${path}\" writes the recursion structure itself (a node, its \"${spec.key}\" list or that list's length, or an object on the way to it).`);\n }\n for (const s of spec.families.keys()) {\n // (a family under a child node, `.children.*.x`, is `.x` at every depth below the first: refused\n // before anything is written, not part-way through)\n let f = s;\n while (f.startsWith(spec.step)) f = f.slice(spec.step.length);\n if (rest === f || rest.startsWith(`${f}.`)) raiseError(`${code(\"readonly\")} \"${path}\" writes into the recursive getter \"${spec.list}.**${s}\".`);\n }\n // every node first: a tree that fails the walk writes nothing\n const nodes: [number, StateRow][] = [];\n walk(engine, spec, (k, row) => nodes.push([k, row]));\n let written = 0;\n for (const [k, row] of nodes) written += setAll.call(engine, nodePath(spec, k) + suffix, engine.indexesOf(row), value);\n return written;\n };\n}\n\n/** The `declare` hook: a state received (construction, or a re-set before it replaces the old one). */\nexport function declareRecursion(engine: Engine, target: Record<string, any>): void {\n const spec = read(target);\n const had = specs.has(engine);\n if (spec === null) {\n if (had) {\n specs.delete(engine);\n engines--;\n }\n return;\n }\n if (!had) engines++;\n specs.set(engine, spec);\n registering.add(engine);\n if (!wrapped.has(engine)) wrap(engine);\n}\n\n/** The `element` hook: the state's accessors are registered — a new `**` pattern is refused again. */\nexport function recursionSettled(engine: Engine): void {\n registering.delete(engine);\n}\n\n/** The `beforeWrite` hook: an expansion of a recursive getter is read-only. */\nexport function guardExpansion(engine: Engine, p: Pattern): boolean {\n if (engines === 0) return false;\n const spec = specs.get(engine);\n if (spec === undefined) return false;\n for (let q: Pattern | null = p; q !== null; q = q.parent) {\n const owner = spec.owners.get(q);\n if (owner !== undefined) raiseError(`${code(\"readonly\")} \"${p.path}\" writes into the recursive getter \"${owner}\".`);\n }\n return false;\n}\n","/**\n * The recursion add-on (@wcstack/state/features/recursion): `$recursion` and `**` — see\n * src/recursion/recursion.ts.\n */\nimport { chain, first, handled, hooks, type Feature } from \"../hooks\";\nimport { declareRecursion, guardExpansion, recursionSettled } from \"../recursion/recursion\";\n\nexport const recursion: Feature = {\n name: \"recursion\",\n install(): void {\n hooks.declare = chain(hooks.declare, declareRecursion);\n hooks.element = chain(hooks.element, (engine, phase) => {\n if (phase === \"mounting\" || phase === \"reset\") recursionSettled(engine);\n });\n hooks.beforeWrite = first(handled, hooks.beforeWrite, guardExpansion);\n },\n};\nexport default recursion;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["NAME","specs","WeakMap","wrapped","WeakSet","registering","engines","esc","s","replace","code","c","checkPath","kind","path","bad","why","raiseError","String","segs","split","length","i","test","includes","nodePath","spec","k","list","step","repeat","suffixOf","head","rest","slice","startsWith","bind","ctx","at","row","r","parentRow","m","nodeList","exec","pattern","key","depthOf","walk","engine","visit","ancestors","Set","seen","enter","arr","listPath","Array","isArray","has","add","down","rows","listP","read","childList","delete","rootP","declareRecursion","target","decl","keys","o","Object","prototype","getPrototypeOf","getOwnPropertyNames","push","getOwnPropertyDescriptor","recursionUnsupported","entries","anchor","families","Map","matchers","d","suffix","some","get","set","RegExp","owners","had","e","created","onPatternCreated","p","known","patterns","peek","getter","call","re","depth","slot","slotCount","resolve","getAll","indexes","out","v","indexesOf","setAll","value","options","raise","spread","readonlyDepth","_","join","f","nodes","written","wrap","guardExpansion","q","parent","owner","recursion","name","hooks","install","declare","chain","element","phase","recursionSettled","beforeWrite","first","handled","recursion_default"],"sources":["../../../src/recursion/recursion.ts","../../../src/features/recursion.ts"],"sourcesContent":["/**\n * Recursive paths (README \"Recursive paths\"): one self-recursive anchor per state,\n * `$recursion: { \"nodes.*\": \"children.*\" }`, and `**` as a depth variable — `nodes.**.x` stands\n * for `nodes.*.x`, `nodes.*.children.*.x`, … The engine only ever sees the concrete depths:\n *\n * - a getter `get \"nodes.**.total\"()` is a family, materialized as an ordinary getter on each\n * concrete depth's pattern when that pattern is made (so `$1`, caching and dependencies are the\n * ordinary per-depth ones, and a deep change reaches every ancestor through ordinary edges);\n * - `**` in a path read or `$getAll(path)` without indexes is bound to the depth of the row the\n * evaluation runs in (a family getter's row, a row getter's, an event handler's);\n * - `$getAll(path, [])` collects every depth (depth first, pre-order), `$setAll(path, [], v)`\n * writes every node; the expansions of a family are read-only.\n *\n * The engines with a `$recursion` get their `onPatternCreated`, `resolve`, `getAll` and `setAll`\n * wrapped; an engine without one pays nothing. The static checks of 3.3 (colliding families,\n * structural suffixes on getters) are the diagnostics add-on's (approved simplification).\n */\nimport type { Engine } from \"../engine\";\nimport type { Pattern } from \"../pattern\";\nimport type { StateRow } from \"../list\";\nimport { raiseError } from \"../parser/raiseError\";\nimport { raise, M } from \"../messages\";\nimport { recursionUnsupported } from \"../parser/parseStatePart\";\n\nconst NAME = \"$recursion\";\nconst MAX_DEPTH = 128;\n\ninterface Spec {\n /** `nodes` (the anchor without its trailing `.*`). */\n readonly list: string;\n /** `.children.*` */\n readonly step: string;\n /** `children` */\n readonly key: string;\n /** Families by suffix (`.total`): the author's getter. */\n readonly families: Map<string, (this: unknown) => unknown>;\n readonly matchers: [RegExp, string][];\n /** Node list patterns: `nodes`, `nodes.*.children`, `nodes.*.children.*.children`, … */\n readonly nodeList: RegExp;\n /** The family key each materialized expansion belongs to. */\n readonly owners: Map<Pattern, string>;\n}\n\nconst specs = new WeakMap<Engine, Spec>();\nconst wrapped = new WeakSet<Engine>();\n/** Patterns created while the state's accessors are registered (the `**` keys among them are templates). */\nconst registering = new WeakSet<Engine>();\nlet engines = 0;\n\nconst esc = (s: string): string => s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\nconst code = (c: string) => `[wcs/recursion-${c}]`;\n\nfunction checkPath(kind: string, path: unknown): string {\n const bad = (why: string): never => raiseError(`${code(\"declaration-invalid\")} ${NAME} ${kind} \"${String(path)}\" ${why}`);\n if (typeof path !== \"string\" || path === \"\") raiseError(`${code(\"declaration-invalid\")} ${NAME} ${kind} must be a non-empty string.`);\n const segs = path.split(\".\");\n if (segs.length < 2 || segs[segs.length - 1] !== \"*\") bad('must end with \".*\" (a list element).');\n for (let i = 0; i < segs.length - 1; i++) {\n const s = segs[i];\n if (s === \"\") bad(\"must not contain empty path segments.\");\n if (s === \"*\" || s === \"**\" || /^\\d/.test(s)) bad('must have exactly one \"*\", at the end.');\n if (s.includes(\"#\")) bad('must not contain \"#\".');\n }\n if (path[0] === \"$\") bad('must not start with \"$\".');\n return path;\n}\n\n/** Reads and checks the declaration; null when the state has none. */\nfunction read(target: Record<string, any>): Spec | null {\n const decl = target[NAME];\n const keys: [string, PropertyDescriptor][] = [];\n const seen = new Set<string>();\n for (let o: object | null = target; o !== null && o !== Object.prototype; o = Object.getPrototypeOf(o)) {\n for (const k of Object.getOwnPropertyNames(o)) {\n if (!seen.has(k) && k.includes(\"**\")) keys.push([k, Object.getOwnPropertyDescriptor(o, k)!]);\n seen.add(k);\n }\n }\n if (decl === undefined) {\n if (keys.length > 0) recursionUnsupported(keys[0][0]);\n return null;\n }\n if (decl === null || typeof decl !== \"object\" || Array.isArray(decl)) {\n raiseError(`${code(\"declaration-invalid\")} ${NAME} must be an object mapping one anchor path to its repeating sub-path.`);\n }\n const entries = Object.entries(decl);\n if (entries.length !== 1) raiseError(`${code(\"declaration-invalid\")} ${NAME} must declare exactly one anchor (it declares ${entries.length}).`);\n const anchor = checkPath(\"anchor\", entries[0][0]);\n const repeat = checkPath(\"repeat\", entries[0][1]);\n const list = anchor.slice(0, -2);\n const key = repeat.slice(0, -2);\n const step = `.${repeat}`;\n const families = new Map<string, (this: unknown) => unknown>();\n const matchers: [RegExp, string][] = [];\n const head = `${list}.**`;\n for (const [k, d] of keys) {\n const suffix = k.slice(head.length);\n if (!k.startsWith(head) || (suffix !== \"\" && suffix[0] !== \".\") || suffix.includes(\"**\")) {\n raiseError(`[wcs/recursion-anchor] \"${k}\": a recursive key is \"${head}\" followed by a path (the anchor is \"${anchor}\").`);\n }\n if (suffix === \"\" || suffix.split(\".\").slice(1).some((s) => s === \"\")) raiseError(`[wcs/recursion-anchor] \"${k}\" needs a path after \"**\".`);\n if (d.get === undefined || d.set !== undefined) raiseError(`${code(\"declaration-invalid\")} \"${k}\": a recursive key is a getter without a setter.`);\n families.set(suffix, d.get);\n matchers.push([new RegExp(`^${esc(anchor)}((?:${esc(step)})*)${esc(suffix)}$`), suffix]);\n }\n return { list, step, key, families, matchers, owners: new Map(), nodeList: new RegExp(`^${esc(list)}((?:${esc(`.*.${key}`)})*)$`) };\n}\n\n/** `nodes.*` + `.children.*` × k */\nconst nodePath = (spec: Spec, k: number): string => `${spec.list}.*${spec.step.repeat(k)}`;\n\n/** The depth of the node row `row` is in or under (null: not under the anchor). */\nfunction depthOf(spec: Spec, row: StateRow | null): { k: number; row: StateRow } | null {\n for (let r = row; r !== null; r = r.list.parentRow) {\n const m = spec.nodeList.exec(r.list.pattern.path);\n if (m !== null) return { k: m[1].length / (spec.key.length + 3), row: r };\n }\n return null;\n}\n\n/** What follows `nodes.**` in a path (`.x`, or \"\" for the nodes themselves). */\nfunction suffixOf(spec: Spec, path: string): string {\n const head = `${spec.list}.**`;\n const rest = path.slice(head.length);\n if (!path.startsWith(head) || (rest !== \"\" && rest[0] !== \".\") || rest.includes(\"**\")) {\n raiseError(`[wcs/recursion-anchor] \"${path}\" does not start at the recursion anchor \"${spec.list}.*\".`);\n }\n return rest;\n}\n\n/** `nodes.**.x` → the concrete depth of the evaluation's row. */\nfunction bind(spec: Spec, path: string, ctx: StateRow | null): string {\n const rest = suffixOf(spec, path);\n const at = depthOf(spec, ctx);\n if (at === null) {\n raiseError(`[wcs/recursion-context] \"${path}\" uses \"**\", which is bound to the depth of the row it is evaluated in; there is none here — use $getAll(\"${path}\", []) for every depth.`);\n }\n return nodePath(spec, at.k) + rest;\n}\n\n/** Every node row, depth first and pre-order: (depth, row). Reads (and so tracks) each list. */\nfunction walk(engine: Engine, spec: Spec, visit: (k: number, row: StateRow) => void): void {\n const ancestors = new Set<unknown>();\n const seen = new Set<unknown>();\n const enter = (arr: unknown, listPath: string, k: number): boolean => {\n if (!Array.isArray(arr) || arr.length === 0) return false;\n if (ancestors.has(arr)) raiseError(`${code(\"cycle\")} \"${listPath}\" is reachable from itself: the data under \"${spec.list}\" must be a tree.`);\n if (seen.has(arr)) raiseError(`${code(\"shared-list\")} \"${listPath}\" is the same array instance as a list reached before: the data under \"${spec.list}\" must be a tree.`);\n if (k + 1 > MAX_DEPTH) raiseError(`${code(\"depth-exceeded\")} Recursion on \"${spec.list}.*\" reached depth ${k + 1} (the limit is ${MAX_DEPTH}).`);\n seen.add(arr);\n return true;\n };\n const down = (rows: StateRow[], k: number): void => {\n for (const row of rows) {\n visit(k, row);\n const listP = engine.pattern(`${nodePath(spec, k)}.${spec.key}`);\n const arr = engine.read(listP, row);\n if (!enter(arr, listP.path, k + 1)) continue;\n ancestors.add(arr);\n down(engine.childList(row, listP).rows, k + 1);\n ancestors.delete(arr);\n }\n };\n const rootP = engine.pattern(spec.list);\n const arr = engine.read(rootP, null);\n if (!enter(arr, spec.list, 0)) return;\n ancestors.add(arr);\n down(engine.childList(null, rootP).rows, 0);\n}\n\nfunction wrap(engine: Engine): void {\n wrapped.add(engine);\n const e = engine as any;\n const created = e.onPatternCreated;\n e.onPatternCreated = (p: Pattern) => {\n const spec = specs.get(engine);\n if (p.path.includes(\"**\")) {\n // a recursive key's own pattern while the accessors are registered: an inert template that\n // refuses to be read, and stays one when every pattern is looked at again (a volume grafting\n // its accessors, a re-set — one that drops `$recursion` forgets it: refused again); a new one\n // later is refused by the core (made patterns are interned after this runs)\n const known = engine.patterns.peek(p.path) === p;\n if (registering.has(engine) || (spec === undefined && known)) p.getter = () => recursionUnsupported(p.path);\n else if (!known) created.call(engine, p);\n return;\n }\n if (spec !== undefined && p.getter === null) {\n for (const [re, suffix] of spec.matchers) {\n if (!re.test(p.path)) continue;\n p.getter = spec.families.get(suffix)!;\n if (p.depth > 0) p.slot = e.slotCount++;\n spec.owners.set(p, spec.list + \".**\" + suffix);\n break;\n }\n }\n created.call(engine, p);\n };\n const resolve = e.resolve;\n e.resolve = (path: string, ctx: StateRow | null) => {\n const spec = specs.get(engine);\n return resolve.call(engine, spec !== undefined && path.includes(\"**\") ? bind(spec, path, ctx) : path, ctx);\n };\n const getAll = e.getAll;\n e.getAll = (path: string, indexes?: number[]) => {\n const spec = specs.get(engine);\n if (spec === undefined || !path.includes(\"**\")) return getAll.call(engine, path, indexes);\n if (indexes === undefined) return getAll.call(engine, bind(spec, path, e.ctx));\n if (!Array.isArray(indexes) || indexes.length > 0) {\n raiseError(`${code(\"getall-form\")} $getAll(\"${path}\", indexes) with \"**\" takes either no indexes (this depth) or [] (every depth).`);\n }\n const suffix = suffixOf(spec, path);\n const out: unknown[] = [];\n walk(engine, spec, (k, row) => {\n for (const v of getAll.call(engine, nodePath(spec, k) + suffix, engine.indexesOf(row))) out.push(v);\n });\n return out;\n };\n const setAll = e.setAll;\n e.setAll = (path: string, indexes: number[], value: unknown, options?: { spread?: boolean }) => {\n const spec = specs.get(engine);\n if (spec === undefined || !path.includes(\"**\")) return setAll.call(engine, path, indexes, value, options);\n // (the core's own messages where the core's $setAll has one)\n if (!Array.isArray(indexes)) raise(M.SetAllNeedsIndexes, [path]);\n if (indexes.length > 0) raiseError(`${code(\"setall-form\")} $setAll(\"${path}\", indexes, …) with \"**\" takes no partial prefix: pass [] to write every node.`);\n if (typeof value === \"function\" || options?.spread === true) raiseError(`${code(\"setall-form\")} $setAll(\"${path}\", [], value) with \"**\" takes a plain value (no mapper, no spread).`);\n if (e.readonlyDepth > 0) raise(M.Readonly);\n const suffix = suffixOf(spec, path);\n // the checks (3.x's): an index spelling is a `*` (`.children.0` is a child node), and a child\n // node's path is a node's (`.children.*.total` is the family `.total` one level down)\n let rest = suffix.replace(/\\.\\d+(?=\\.|$)/g, \".*\");\n while (rest.startsWith(spec.step)) rest = rest.slice(spec.step.length);\n // the structure: a node, the objects on the way to its child list and the list, the list's length\n const segs = spec.key.split(\".\");\n if (rest === \"\" || rest === `.${spec.key}.length` || segs.some((_, i) => rest === `.${segs.slice(0, i + 1).join(\".\")}`)) {\n raiseError(`${code(\"structural-write\")} \"${path}\" writes the recursion structure itself (a node, its \"${spec.key}\" list or that list's length, or an object on the way to it).`);\n }\n for (const s of spec.families.keys()) {\n // (a family under a child node, `.children.*.x`, is `.x` at every depth below the first: refused\n // before anything is written, not part-way through)\n let f = s;\n while (f.startsWith(spec.step)) f = f.slice(spec.step.length);\n if (rest === f || rest.startsWith(`${f}.`)) raiseError(`${code(\"readonly\")} \"${path}\" writes into the recursive getter \"${spec.list}.**${s}\".`);\n }\n // every node first: a tree that fails the walk writes nothing\n const nodes: [number, StateRow][] = [];\n walk(engine, spec, (k, row) => nodes.push([k, row]));\n let written = 0;\n for (const [k, row] of nodes) written += setAll.call(engine, nodePath(spec, k) + suffix, engine.indexesOf(row), value);\n return written;\n };\n}\n\n/** The `declare` hook: a state received (construction, or a re-set before it replaces the old one). */\nexport function declareRecursion(engine: Engine, target: Record<string, any>): void {\n const spec = read(target);\n const had = specs.has(engine);\n if (spec === null) {\n if (had) {\n specs.delete(engine);\n engines--;\n }\n return;\n }\n if (!had) engines++;\n specs.set(engine, spec);\n registering.add(engine);\n if (!wrapped.has(engine)) wrap(engine);\n}\n\n/** The `element` hook: the state's accessors are registered — a new `**` pattern is refused again. */\nexport function recursionSettled(engine: Engine): void {\n registering.delete(engine);\n}\n\n/** The `beforeWrite` hook: an expansion of a recursive getter is read-only. */\nexport function guardExpansion(engine: Engine, p: Pattern): boolean {\n if (engines === 0) return false;\n const spec = specs.get(engine);\n if (spec === undefined) return false;\n for (let q: Pattern | null = p; q !== null; q = q.parent) {\n const owner = spec.owners.get(q);\n if (owner !== undefined) raiseError(`${code(\"readonly\")} \"${p.path}\" writes into the recursive getter \"${owner}\".`);\n }\n return false;\n}\n","/**\n * The recursion add-on (@wcstack/state/features/recursion): `$recursion` and `**` — see\n * src/recursion/recursion.ts.\n */\nimport { chain, first, handled, hooks, type Feature } from \"../hooks\";\nimport { declareRecursion, guardExpansion, recursionSettled } from \"../recursion/recursion\";\n\nexport const recursion: Feature = {\n name: \"recursion\",\n hooks,\n install(): void {\n hooks.declare = chain(hooks.declare, declareRecursion);\n hooks.element = chain(hooks.element, (engine, phase) => {\n if (phase === \"mounting\" || phase === \"reset\") recursionSettled(engine);\n });\n hooks.beforeWrite = first(handled, hooks.beforeWrite, guardExpansion);\n },\n};\nexport default recursion;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
/** An add-on entry: `installFeatures([temporal, diagnostics])` before the state is defined. */
|
|
17
17
|
interface Feature {
|
|
18
18
|
readonly name: string;
|
|
19
|
+
/** The slots of the build it comes from: it fills only those (the core checks they are its own). */
|
|
20
|
+
readonly hooks: object;
|
|
19
21
|
install(): void;
|
|
20
22
|
}
|
|
21
23
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as e,b as t,d as n}from"../chunks/chunk-GBBBRPZR.js";import{b as o,p as l,q as r,r as i}from"../chunks/chunk-467LYA2V.js";import"../chunks/chunk-FBBHQU7S.js";import{e as a,f as s}from"../chunks/chunk-ZJYPRSTO.js";import{a as u}from"../chunks/chunk-T3FN37DU.js";import"../chunks/chunk-NITPUCPA.js";import"../chunks/chunk-CBMAVRYG.js";import"../chunks/chunk-JWRQLKOQ.js";import{a as c,b as d,c as f,d as h,f as p,h as m,j as g}from"../chunks/chunk-TNYNJXEC.js";var $=new WeakMap,y=new WeakMap,b="will not graft: the root state failed to initialize.",w=new WeakSet,v=new WeakMap,k=["$stream","$streams","$scan","$recursion","$watch","$listKeys","$renderedCallback","$updatedCallback","$behavior","$features"],j=["$commandTokens","$eventTokens","$on","$errorCallback"],P=e=>`[@wcstack/state] <${u.tagNames.state} mount="${e}">`,N=new Set(["$getAll","$setAll","$resolve","$postUpdate","$dependOn","$eq","$eqIndex"]),O=e=>e?.element?.isConnected?e:void 0;function A(e){let t=y.get(e);return void 0!==t&&!Array.isArray(t)&&t.isConnected}function C(e,t){let n=y.get(t);if(y.delete(t),Array.isArray(n))for(let t of n)W(t,e)}function x(e){let t=$.get(e.root);t?.get(e.t)===e&&t.delete(e.t)}function M(e,t){console.error(`${P(e.t)} ${t}`),x(e),e.Qe?.(),e.Qe=null}function S(e,t){let n=e.state?.[t];if("function"==typeof n)try{let t=n.call(e.chroot);null!==t&&"object"==typeof t&&"function"==typeof t.then&&t.then(void 0,e=>console.error(e))}catch(e){console.error(e)}}function W(e,t){if(w.has(t))return M(e,"will not graft: its component is wired to its host.");let n=e.state,o=t.target,l=e.t.split("."),r=o;for(let e of l)r=r?.[e];if(void 0!==r&&!0!==t.hydrated)return M(e,`will not graft: the root state already has "${e.t}".`);let i=function(e,t){let n=e=>`${t}.${e}`;return new Proxy({},{get(t,o){if("symbol"==typeof o)return;if(36!==o.charCodeAt(0))return e.proxy[n(o)];let l=e.proxy[o];return"$eqPath"===o?(e,t)=>l(n(e),n(t)):N.has(o)&&"function"==typeof l?(e,...t)=>l(n(e),...t):l},set:(t,o,l)=>"symbol"!=typeof o&&(e.proxy[n(o)]=l,!0)})}(t,e.t);e.chroot=i;let a={},s={},u=new Set;for(let t=n;null!==t&&t!==Object.prototype;t=Object.getPrototypeOf(t))for(let n of Object.getOwnPropertyNames(t)){if(u.has(n)||"constructor"===n)continue;u.add(n);let{get:o,set:l,value:r}=Object.getOwnPropertyDescriptor(t,n);if(void 0!==o||void 0!==l)s[`${e.t}.${n}`]={get:o&&function(){return o.call(i)},set:l&&function(e){l.call(i,e)}};else{if("$"===n[0])continue;if("function"==typeof r){let t=r.bind(i);s[`${e.t}.${n}`]={get:()=>t}}else a[n]=r}}if(void 0===r){for(let e=1;e<l.length;e++){let n=t.o(l.slice(0,e).join("."));null==t.it(n,null)&&t.A(n,null,{})}t.A(t.o(e.t),null,a)}t.no(Object.defineProperties({},s));for(let e in s)t.Ue(t.o(e),null);e.engine=t;let c=v.get(t);void 0===c&&v.set(t,c=[]),c.push(e),e.el.isConnected&&S(e,"$connectedCallback"),e.Qe?.(),e.Qe=null}function D(e,t){let n=y.get(e);if(Array.isArray(n))for(let e of n)M(e,b);y.set(e,t)}var E=new WeakMap;function T(e,t){let n=e.getAttribute("mount");if(null===n)return null;let o={el:e,root:t,t:n,state:null,engine:null,chroot:null,Qe:null},r=null;if(function(e){return""!==e&&e.split(".").every(e=>""!==e&&!/[*$#@\s]/.test(e))}(n))if(e.hasAttribute(u.bindAttributeName))r='injections (data-wcs="state.<key>: …") are not supported — read the root path in a root getter.';else{let e=$.get(t);void 0===e&&$.set(t,e=new Map);let l=e.get(n);if(void 0!==l&&l!==o&&(null===l.engine?l.el.isConnected:O(l.engine)))r=`will not graft: another volume already holds "${n}".`;else{if(null===l?.engine){let e=y.get(t);Array.isArray(e)&&y.set(t,e.filter(e=>e!==l)),l.Qe?.(),l.Qe=null}e.set(n,o)}}else r='has an invalid mount path: it must be a static path (no "*", "$", "#", "@").';return{Po:!0,start(e){if(null!==r)return M(o,r);if($.get(t).get(n)===o){for(let t of k)if(void 0!==e[t])return M(o,`${t} is not run in a volume — declare it on the root state.`);for(let t of j)void 0!==e[t]&&console.warn(`${P(n)} ${t} is not run in a volume (it belongs to the root).`);return o.state=e,new Promise(e=>{o.Qe=e;let n=O(l.get(t)),r=y.get(t);void 0!==n?W(o,n):A(t)?M(o,b):y.set(t,[...Array.isArray(r)?r:[],o])})}},Je(){null!==o.engine&&S(o,"$connectedCallback")},Bn(){null!==o.engine&&S(o,"$disconnectedCallback")},reset(){g(`re-setting a volume is not supported: its data was copied into the root tree at "${n}" — write the paths under it on the root instead.`)}}}var R=new WeakMap,L=new WeakMap;function q(e,t){let n=e[t];if(void 0===n)return[];Array.isArray(n)||g(`${t} must be an array of state member names.`);let o=new Set;for(let e of n)("string"!=typeof e||""===e)&&g(`${t} entries must be non-empty strings.`),"$"===e[0]&&g(`${t} entry "${e}": internal ($) members are never exposed.`),o.has(e)&&g(`${t} entry "${e}" is duplicated.`),o.add(e);return n}function Q(e,t){let n=t.host;if(void 0===n||!n.hasAttribute("data-wc-definition"))return null;let o=document.createDocumentFragment();for(let e of[...t.childNodes])o.appendChild(e.cloneNode(!0));let l=t.mode;return{start(t){e.hasAttribute("bind-component")&&g("DCC: a <wcs-state bind-component> cannot define a component (use one mechanism)."),function(e,t,n,o){e.includes("-")||g(`DCC: <${e} data-wc-definition> is not a valid custom element name.`),void 0!==customElements.get(e)&&g(`DCC: <${e}> is already defined.`);let l=function(e){let t=new Map;for(let n=e;null!==n&&n!==Object.prototype;n=Object.getPrototypeOf(n))for(let e of Object.getOwnPropertyNames(n))"constructor"===e||"$"===e[0]||t.has(e)||t.set(e,Object.getOwnPropertyDescriptor(n,e));let n=e.$stream;if(null!==n&&"object"==typeof n)for(let e of Object.keys(n))t.has(e)||t.set(e,{value:void 0});return t}(o),r=q(o,"$bindables"),i=q(o,"$commands");for(let e of r){let t=l.get(e);void 0===t&&g(`$bindables entry "${e}" does not exist on the state.`),"function"==typeof t.value&&g(`$bindables entry "${e}" is a method: list it in $commands.`)}for(let e of i){let t=l.get(e);void 0===t&&g(`$commands entry "${e}" does not exist on the state.`),"function"!=typeof t.value&&g(`$commands entry "${e}" is not a method: list it in $bindables.`)}let a={tag:e,bindables:r},s=new WeakMap,c=new WeakMap,d=o=>{if(s.has(o))return s.get(o);if(o.hasAttribute("data-wc-definition"))return null;let l=o.attachShadow({mode:n});l.appendChild(t.cloneNode(!0));let i=l.querySelector(u.tagNames.state);return s.set(o,i),R.set(o,a),null===i&&r.length>0&&console.warn(`[@wcstack/state] DCC: <${e}> declares $bindables but its content has no <${u.tagNames.state}>: no change events.`),i},f=e=>d(e)?.engine??null,h=e=>Promise.resolve(d(e)?.initializePromise).then(()=>{let t=c.get(e);c.delete(e);let n=f(e);if(void 0!==t&&null!==n)for(let[e,o]of t)n.proxy[e]=o});class p extends HTMLElement{static{this.wcBindable=0===r.length&&0===i.length?null:{protocol:"wc-bindable",version:1,properties:r.map(t=>({name:t,event:`${e}:${t}-changed`,getter:e=>e.target[t]})),inputs:r.map(e=>({name:e})),...0===i.length?{}:{commands:i.map(e=>({name:e,async:!0}))}}}connectedCallback(){null!==d(this)&&h(this)}get stateElement(){return d(this)}}for(let[e,t]of l)"function"==typeof t.value?Object.defineProperty(p.prototype,e,{configurable:!0,value(...t){return h(this).then(()=>{let n=f(this);return null===n?void 0:n.proxy[e].apply(n.proxy,t)})}}):Object.defineProperty(p.prototype,e,{configurable:!0,get(){return f(this)?.proxy[e]},set(t){let n=f(this);if(null!==n)n.proxy[e]=t;else{let n=c.get(this);void 0===n&&c.set(this,n=[]),n.push([e,t])}}});customElements.define(e,p)}(n.localName,o,l,t)},Je(){},Bn(){},reset(){g("re-setting a DCC definition is not supported: each instance loads its own state.")}}}var B=new WeakMap,I=new WeakSet,z=new WeakMap,F=new WeakMap,H="data-wcs-wired",J=new WeakMap,U=new WeakMap,Y=new WeakMap,V=0,X=new Set,G={},K=["$watch","$stream","$renderedCallback"],Z=e=>e.split(".",1)[0];function _(e,t){let n=0;return e.split(".").map(e=>"*"===e?String(t[n++]):e).join(".")}function ee(e,t){let n=e.a,o=Z(e.name);if(!0!==document.documentElement?.hasAttribute("data-wcs-server"))n.removeAttribute(H);else if(!ne(n,o)){let e=n.getAttribute(H)?.split(" ")??[];e.includes(o)||n.setAttribute(H,[...e,o].join(" "))}J.get(n)?.he===o&&g(`<${n.localName}>.${o} has loaded its state: the wiring "${e.name}" added afterwards cannot reach it — bind the host's wiring before the component loads.`);let l=B.get(n);void 0===l&&B.set(n,l=[]),l.push(e),t&&I.add(e);let r=z.get(n);return void 0===r&&z.set(n,r=new Map),r.has(o)||r.set(o,n[o]),F.get(n)?.(),!1}function te(e){return e.localName.includes("-")&&null!==e.querySelector(`:scope > ${u.tagNames.state}[bind-component]`)}function ne(e,t){let n=e.getAttribute(u.bindAttributeName);return null!==n&&new RegExp(`(^|;)\\s*${t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}\\s*[.#:]`).test(n)}function oe(t){let n=t.parentElement;for(;null!==n&&!te(n);)n=n.parentElement;let o=l.get(n??t.getRootNode()),r=o?.element;(r?.isConnected?r.V:null===n)&&(null===n?e(t):i(o,t))}var le=new Set;function re(e,t){le.has(e)||(le.add(e),console.warn(`[@wcstack/state] ${t}`))}var ie=(e,t)=>t in e.state;function ae(e,t){let n=se(e.state,t);return void 0!==n&&(void 0!==n.get||void 0!==n.set||"function"==typeof n.value)}function se(e,t){for(let n=e;null!==n&&n!==Object.prototype;n=Object.getPrototypeOf(n)){let e=Object.getOwnPropertyDescriptor(n,t);if(void 0!==e)return e}}function ue(e,t,n){if(null!==n.getter)return;let o,l=e.host,r=l.engine,i=Z(n.t),s=l.entries.find(e=>e.$===n.t);if(void 0===s&&null!==n.c)return function(e,t){let n,o=t.c;for(;null!==o&&void 0===(n=e.pt.get(o));)o=o.c;if(null===o||void 0===n)return;let l=e.P,r=e.host.engine,i=r.o(n.p.t+t.t.slice(o.t.length));if(null===i.getter)return;let s=n,u=()=>{let n=ce(e,s.r);return 0===t.n?n:(r.resolve(_(i.t,[...r.H(n),...l.H(a(l.d,t.n))]),null),r.rr)};t.getter=()=>{let e=u();return i.n>0&&null===e?void 0:r.v(i,e)},null!==i.se&&(t.se=n=>{let o=u();de(e,s.e,()=>r.A(i,o,n)),e.dn=t}),t.n>0&&(t.F=l.Le++),e.pt.set(t,{e:s.e,p:i,r:s.r})}(e,n);if(0!==n.n)return;if(void 0!==s){if(s.$!==i?ie(l,i):ae(l,i))return;o=s.ye}else{if(null===t||null!==n.c||"$"===i[0]||ie(l,i))return;s=t,o=r.o(`${t.ye.t}.${i}`)}let u=s.r,c=s;n.getter=()=>r.v(o,ce(e,u)),n.se=t=>{de(e,c,()=>r.A(o,u,t)),e.dn=n},e.pt.set(n,{e:s,p:o,r:u})}function ce(e,t){return null!==t&&!t.w&&g(`The host row of <${e.host.el.localName}> was removed.`),t}function de(e,t,n){let o=X.has(e.P);X.add(e.P),e.from=t;try{n()}finally{o||X.delete(e.P),e.from=null}}var fe=(e,t)=>t||!X.has(e.m.P)||null!==e.m.from&&e.m.from!==e.e;function he(e,t){if(e.fn===t||null===e.host.engine)return;e.fn=t,V+=t?1:-1;let n=e.host.engine,o=Y.get(n);void 0===o&&Y.set(n,o=new Map);for(let n of e.pe){let e=o.get(n.e.ye);void 0===e&&o.set(n.e.ye,e=new Map);let l=e.get(n.e.r);void 0===l&&e.set(n.e.r,l=new Set),t?l.add(n):(l.delete(n),0===l.size&&e.delete(n.e.r))}let l=e.host.entries.find(e=>""===e.$);if(void 0!==l){null===e.ie&&function(e,t){let n=e.host,o=n.engine;e.ie=new Map;let l=new Set;for(let r=n.state;null!==r&&r!==Object.prototype;r=Object.getPrototypeOf(r))for(let i of Object.getOwnPropertyNames(r)){if(l.has(i))continue;l.add(i);let a=Object.getOwnPropertyDescriptor(r,i);if(void 0===a.get&&void 0===a.set||"$"===i[0]||i.includes("*"))continue;let s=Z(i);if(i!==s&&!ie(n,s))continue;let u=o.o(`${t.ye.t}.${i}`);if(null===u.getter)ge(o,u,t.ye);else if(!pe.has(u.getter))continue;e.ie.set(u,e.P.o(i))}}(e,l);for(let o of e.ie.keys())t&&null===o.getter&&ge(n,o,l.ye),n.T.ke(n,o,l.r);e.ie.size>0&&n.ve(),t&&function(e,t){let n=e.host.engine;for(let[o,l]of e.ie){let r=n.v(o.c,t.r);if(null===r||"object"!=typeof r||!(o.s in r))continue;let i=e.host.el.localName;re(`${i}|${o.t}`,`[wcs/mount-export-shadowed] <${i}>.${e.host.he}.${l.t} is exported at "${o.t}" 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.`)}}(e,l)}}var pe=new WeakSet;function me(e,t,n,o){let l=Y.get(e)?.get(t)?.get(n);if(void 0===l)return null;let r=null;for(let e of l)""!==e.e.$||!0!==e.m.ie?.has(o)||e.m===r||(null!==r&&g(`[wcs/mount-export-ambiguous] "${o.t}" is exported by two mounted components on the same instance: <${r.host.el.localName}> and <${e.m.host.el.localName}>. Mount only one of them there, or rename one accessor. See docs/state-overlay-export-design.md X4.`),r=e.m);return r}function ge(e,t,n){let o=t.c,l=t.s,r=()=>{let t=e.read(o,e.d);return null!==t&&"object"==typeof t&&l in t?t:null};t.getter=()=>{let o=r();if(null!==o)return o[l];let i=me(e,n,e.d,t);return null===i?void 0:i.P.read(i.ie.get(t),null)},pe.add(t.getter),t.se=i=>{let a=null===r()?me(e,n,e.d,t):null;if(null===a){let t=e.read(o,e.d);return void(null!==t&&"object"==typeof t&&(t[l]=i))}let s=a.ie.get(t);void 0===se(a.host.state,s.t)?.set&&g(`Cannot write to "${s.t}" on mounted <${a.host.el.localName}>: the accessor has no setter. Add a setter or write to the underlying state paths instead.`),a.P.A(s,null,i)},t.n>0&&(t.F=e.Le++)}function $e(e,t,n,o,l,r){if(null!==t.getter)return e.T.ke(e,t,n),void e.ve();if("*"===t.s){if(null===n)return;if(n.E=n.l.R[n.y],e.T.Xt(n),null!==n.u)for(let t of n.u.values())e.G(t)}else e.En(t,n);c.re?.(e,t,n,o,l,r),e.Ue(t,n)}function ye(e){let t=e.m.P;for(let[n,o]of e.m.pt)o.e===e.e&&(0===n.n?t.T.ke(t,n,null):t.nn(n.h[n.n],e=>t.T.ke(t,n,e)));t.ve()}function be(e,t,n,o,l,r,i){let s=n.t.slice(t.t.length);if(""===s)return ye(e);let u,c=e.m,d=c.P;if(""===e.e.$){u=s.slice(1);let e=Z(u);if("$"===e[0]||ie(c.host,e)||c.host.entries.some(e=>""!==e.$&&(u===e.$||u.startsWith(`${e.$}.`))))return}else u=e.e.$+s;let f=[];for(let e=t.n+1;e<=n.n;e++)f.push(a(o,e).y);d.resolve(_(u,f),null);let h=d.rp,p=d.rr;h.n>0&&null===p||$e(d,h,p,l,r,i)}function we(e,t,n,o,l,r,i){if(0===V)return;let s=X.has(e);X.add(e);try{let s=U.get(e);!i&&void 0!==s&&s.fn&&!X.has(s.host.engine)&&function(e,t,n,o,l,r){let i,a=t;for(;null!==a&&void 0===(i=e.pt.get(a));)a=a.c;if(null===a||void 0===i)return;let s=e.host.engine;if(a===t&&e.dn===t)return void(e.dn=null);if(null!==i.r&&!i.r.w)return;let u=[...s.H(i.r),...e.P.H(n)];s.resolve(_(i.p.t+t.t.slice(a.t.length),u),null);let c=s.rp,d=s.rr;c.n>0&&null===d||de(e,i.e,()=>$e(s,c,d,o,l,r))}(s,t,n,o,l,r),i&&void 0!==s&&s.fn&&null!==s.ie&&function(e,t){let n=e.host.entries.find(e=>""===e.$),o=e.host.engine;for(let[l,r]of e.ie)r===t&&(o.T.ke(o,l,n.r),o.ve())}(s,t);let u=Y.get(e);if(void 0===u)return;for(let[e,s]of u)if(t.ee(e)){let u=s.get(0===e.n?null:a(n,e.n));if(void 0!==u)for(let a of[...u])fe(a,i)&&be(a,e,t,n,o,l,r)}else if(e.ee(t))for(let[e,o]of[...s])if(0===t.n||a(e,t.n)===n)for(let e of[...o])fe(e,i)&&ye(e)}finally{s||X.delete(e)}}async function ve(e,o,l,i,a){if(i===G)return;let d=m(i);d&&await d;let f=J.get(o);f.engine&&i.$recursion&&g(`[wcs/mount-dollar-declaration] <${o.localName}>: $recursion is not run in a mounted component — declare it on the root state.`);let h=f.I;if(null!==h&&h.el!==e&&h.el.isConnected&&g(`<${o.localName}> already has a connected <${u.tagNames.state} bind-component="${f.he}">.`),null!==h&&he(h,!1),null!==h&&function(e,t,n){let o=e.P,l=`[${u.bindAttributeName}]`,r=e=>1===e.nodeType&&(e.matches(l)||null!==e.querySelector(l)),i=new Set,a=e=>{for(;null!==e&&e.parentNode!==n;)e=e.parentNode;null!==e&&i.add(e)},s=(e,t)=>{for(let n=e.In(t);null!==n&&n!==t;n=n.nextSibling)a(n);a(t)};for(let e of o.ue.values())for(let t of e)if(null===t.D)a(t.a);else for(let e of t.D.q)s(t.D,e.S);for(let e of o.oe.values())for(let t of[e.N,...e.M??[]])null!==t&&s(t,t.S);for(let t of e.L)t.parentNode===n&&r(t)&&i.add(t);if(0===i.size)return!1;let c=[...n.childNodes].filter(n=>n!==t&&!i.has(n)&&!e.L.includes(n)&&(r(n)||o.Wt&&n.textContent.includes("{{")));return c.length>0&&console.warn(`[@wcstack/state] <${e.host.el.localName}>: ${c.length} node(s) added beside the content taken over are not bound.`),!0}(h,e,l))return async function(e,t,n,o){e.el.engine=null,e.el=t,e.P.element=t,t.engine=e.P,e.L=e.L.filter(e=>e.parentNode===n),t.isConnected?await ke(e,o):o()}(h,e,l,a);let p=new s(i,new n);p.element=e,e.engine=p,function(e,t){let n=new Map;for(let e=t;null!==e&&e!==Object.prototype;e=Object.getPrototypeOf(e))for(let t of Object.getOwnPropertyNames(e)){let o=Object.getOwnPropertyDescriptor(e,t).value;"function"==typeof o&&"constructor"!==t&&n.set(o,null)}let o=(t,n,o)=>Reflect.apply(t,e.proxy,o);e.V=e=>{let t=n.get(e);return null===t&&n.set(e,t=new Proxy(e,{apply:o})),t}}(p,i);let $={el:e,L:[],P:p,host:f,pe:[],pt:new Map,fn:!1,dn:null,from:null,ie:null};for(let e of f.entries)$.pe.push({m:$,e});f.I=$,U.set(p,$);let y=null===f.engine;y?c.element?.(p,"mounting"):(function(e){let t=e.P,n=e.host,o=n.engine,l=n.el.localName,r=n.entries.find(e=>""===e.$)??null;for(let e of n.entries){if(""===e.$)continue;let t=Z(e.$);ie(n,t)&&(e.$!==t||ae(n,t))&&re(`${l}.${e.$}`,`[wcs/mount-own-key-shadow] <${l}>: "${n.he}.${e.$}" is hidden by the component's own "${t}"; rename one side.`)}if(null!==r){let e=o.v(r.ye,r.r);if(null!==e&&"object"==typeof e)for(let t of Object.keys(n.state))"$"!==t[0]&&t in e&&!n.entries.some(e=>e.$===t)&&re(`${l}.${t}`,`[wcs/mount-own-key-shadow] <${l}>: its own "${t}" hides "${r.ye.t}.${t}" — remove the default to read the tree, or rename it to keep it private.`)}let i=K.filter(e=>void 0!==n.state[e]);i.length>0&&re(`${l}.${n.he}$`,`[wcs/mount-dollar-declaration] <${l}>: ${i.join(", ")} ${1===i.length?"is":"are"} not run in a mounted component — declare it on the root state.`);let a=t.ot;t.ot=n=>{ue(e,r,n),a.call(t,n)};let s=[...t.O.all()];for(let t of s)ue(e,r,t);for(let e of s)a.call(t,e);let u=t.Yt;t.Yt=()=>{(function(e){for(;void 0!==e;e=U.get(e.host.engine))if(e.host.entries.some(e=>null!==e.r&&!e.r.w))return!1;return!0})(e)&&u.call(t)}}($),he($,!0),w.add(p),C(p,l));let b=c.hr?.(l,p);r(p,l),b?.(),$.L=[...l.childNodes],t(),y&&p.Nn(),Object.defineProperty(o,f.he,{configurable:!0,enumerable:!0,get:()=>p.proxy});let v=o.$stateReadyCallback;if("function"==typeof v)try{let e=v.call(o,f.he);null!==e&&"object"==typeof e&&"function"==typeof e.then&&e.then(void 0,e=>console.error(e))}catch(e){console.error(e)}a(),e.isConnected?(await p.$e("$connectedCallback"),y&&e.isConnected&&c.element?.(p,"connected")):he($,!1)}async function ke(e,t){he(e,!0);for(let t of e.pe)ye(t);t?.(),!e.broken&&(await e.P.$e("$connectedCallback"),null===e.host.engine&&e.el.isConnected&&c.element?.(e.P,"connected"))}function je(e,t){let n=e.getAttribute("bind-component");if(null===n)return function(e,t){return e.connectedCallbackPromise.catch(()=>{let n=l.get(t)?.element;if(!(e.V||void 0!==n&&n!==e&&n.isConnected)){D(t,e);for(let e of E.get(t)??[])e()}}),null}(e,t);let r=e.parentNode,i=r instanceof ShadowRoot,a=i?r.host:r instanceof Element?r:null,s=()=>{let t=null===a?void 0:J.get(a)?.I;return t?.el===e?t:null},d=t=>{throw i&&D(r,e),t},f=!1;return{kt:()=>(null!==a&&a.localName.includes("-")?async function(e,t,n,l){let r=n.localName;(["state","src","json"].some(t=>e.hasAttribute(t))||null!==e.querySelector('script[type="module"]'))&&g(`<${u.tagNames.state} bind-component> takes its state from <${r}>.${t}: it cannot also load one (state / src / json / an inline script).`),await o(n).whenDefined(r);let i=J.get(n);if(void 0!==i)return i.he!==t&&g(`<${r}> already has a <${u.tagNames.state} bind-component="${i.he}">.`),i.state;let a=()=>(B.get(n)??[]).filter(e=>Z(e.name)===t),s=ne(n,t);if(s&&0===a().length&&oe(n),0===a().length&&(s||((e,t)=>!0===e.getAttribute(H)?.split(" ").includes(t))(n,t))){let e;await new Promise((o,l)=>{F.set(n,o),e=function(e,t){A(e)&&t();let n=E.get(e)??new Set;return E.set(e,n.add(t)),()=>n.delete(t)}(n.getRootNode(),()=>l(new Error(`[@wcstack/state] <${r}>.${t} will not mount: the root state failed to initialize.`)))}).finally(()=>e())}F.delete(n);let c=a(),d=z.get(n),f=void 0!==d&&d.has(t)?d.get(t):n[t];if((null===f||"object"!=typeof f)&&g(`"bind-component": <${r}>.${t} must be an object (the component's state), got ${null===f?"null":typeof f}.`),0===c.length&&l){let e=new Error(`[@wcstack/state] A plain (unwired) Light DOM "bind-component" is not supported. Attach a shadow root to <${r}>, or mount it from the host (${u.bindAttributeName}="${t}: path").`);return queueMicrotask(()=>{throw e}),G}let h=[];for(let e of c){let o=e.name===t?"":e.name.slice(t.length+1);h.some(e=>e.$===o)&&g(`<${r}> maps "${e.name}" twice.`);let l=o.split(".").indexOf("*");if(l>=0){let n=o.split(".").slice(0,l).join(".");g(`<${r}> maps "${e.name}": the component-side path of a mount cannot contain "*"${""===n?"":` — map the list itself ("${t}.${n}: <the host's list>")`}.`)}h.push({$:o,ye:e.o,r:e.r,ro:I.has(e)}),e.engine.Pn(e),""!==o&&delete n[e.name]}let p=0===c.length?function(e){let t=Object.getOwnPropertyDescriptors(e),n=Object.isFrozen(e);for(let e of Object.values(t))"value"in e&&!1===e.writable&&(e.writable=!0,n=!0);return n?Object.create(Object.getPrototypeOf(e),t):e}(f):f;return J.set(n,i={el:n,he:t,state:p,engine:0===c.length?null:c[0].engine,entries:h,I:null}),p}(e,n,a,!i):Promise.reject(new Error(`[@wcstack/state] "bind-component" requires <${u.tagNames.state}> to be a direct child of a custom element.`))).catch(d),async start(t,n){await ve(e,a,i?r:a,t,()=>{f=!0,n()}).catch(e=>{let t=s();return!f&&null!==t&&(t.broken=!0),d(e)})},Je(){let t=s();null!==t?ke(t).catch(e=>console.error(e)):f?Promise.resolve().then(()=>{if(e.parentNode===r)return ve(e,a,i?r:a,J.get(a).state,()=>{})}).catch(e=>console.error(e)):F.has(a)&&oe(a)},Bn(){let e=s();null!==e&&(he(e,!1),!e.broken&&(e.P.$e("$disconnectedCallback"),null===e.host.engine&&c.element?.(e.P,"disconnected")))},reset(){g(`re-setting a component's state is not supported: write <${a?.localName}>.${n} instead.`)}}}var Pe={name:"scopes",install(){c.ut=f(p,c.ut,T),c.ut=f(p,c.ut,Q),c.ut=f(p,c.ut,je),c.ar=ee,c.Eo=te,c.element=d(c.element,(e,t)=>{if("mounting"!==t)return function(e,t){let n=v.get(e)??[];if("disconnected"===t)for(let e of n)x(e);else if("reset"!==t&&O(l.get(e.root))===e){C(e,e.root);for(let e of n)$.get(e.root).has(e.t)||$.get(e.root).set(e.t,e)}}(e,t);let n=e.element.getRootNode();C(e,n),function(e,t){let n=t.host,o=void 0===n?void 0:R.get(n);void 0!==o&&L.set(e,{host:n,def:o})}(e,n)}),c.re=d(c.re,(e,t,n,o,l,r)=>{(function(e,t,n,o){let l=L.get(e);if(void 0===l)return;let r=t.t.split(".",1)[0];if(!l.def.bindables.includes(r))return;let i=o&&t.t===r;l.host.dispatchEvent(new CustomEvent(`${l.def.tag}:${r}-changed`,{detail:i?n:void 0,bubbles:!0}))})(e,t,l,r),we(e,t,n,o,l,r,!1)}),c.Se=d(c.Se,(e,t,n)=>we(e,t,n,void 0,void 0,!1,!0)),c.Ie=f(h,c.Ie,(e,t,n,o,l)=>(function(e,t){let n=v.get(e);if(void 0!==n&&0===t.n)for(let{t:e}of n)e.startsWith(`${t.t}.`)&&g(`writing "${t.t}" would replace the volume grafted at "${e}"; write the paths under it instead.`)}(e,t),function(e,t,n){let o,l=U.get(e);if(void 0===l)return!1;for(let e=t;null!==e&&void 0===o;e=e.c)o=l.pt.get(e);if(void 0===o)return!1;let r=o.e;return!((null===r.r||r.r.w)&&!r.ro)&&(!!n||(ce(l,r.r),void g(`[wcs/mount-readonly] <${l.host.el.localName}> cannot write "${t.t}": it is mounted read-only ("${l.host.he}${""===r.$?"":`.${r.$}`}#ro: ${r.ye.t}"). Write it on the host, or drop #ro from the mount.`)))}(e,t,l)));let e=c.fe;c.fe=(t,n)=>{let o=v.get(t);void 0!==o&&o.length>0&&g(`re-setting a root state with grafted volumes (${o.map(e=>e.t).join(", ")}) is not supported: their data is part of the tree.`),function(e){let t=Y.get(e);if(void 0===t)return!1;for(let e of t.values())if(e.size>0)return!0;return!1}(t)&&g("re-setting a root state with mounted components is not supported: they read its data."),e?.(t,n)}}},Ne=Pe;export{Ne as default,Pe as scopes};
|
|
1
|
+
import{a as e,b as t,d as n}from"../chunks/chunk-GQTEYSRZ.js";import{b as o,p as l,q as r,r as i}from"../chunks/chunk-XXVJ6J2N.js";import"../chunks/chunk-IBGHHABS.js";import{e as a,f as s}from"../chunks/chunk-T3KW5DZD.js";import{a as u}from"../chunks/chunk-P3EXTBXC.js";import"../chunks/chunk-NITPUCPA.js";import"../chunks/chunk-PKEAYPFR.js";import"../chunks/chunk-DRSAQE4E.js";import{a as c,b as d,c as f,d as h,f as p,h as m,j as g,k as $}from"../chunks/chunk-BCL75PFH.js";var y=new WeakMap,b=new WeakMap,w="will not graft: the root state failed to initialize.",v=new WeakSet,k=new WeakMap,j=["$stream","$streams","$scan","$recursion","$watch","$listKeys","$renderedCallback","$updatedCallback","$behavior","$features"],P=["$commandTokens","$eventTokens","$on","$errorCallback"],N=e=>`[@wcstack/state] <${u.tagNames.state} mount="${e}">`,O=new Set(["$getAll","$setAll","$resolve","$postUpdate","$dependOn","$eq","$eqIndex"]),A=e=>e?.element?.isConnected?e:void 0;function C(e){let t=b.get(e);return void 0!==t&&!Array.isArray(t)&&t.isConnected}function S(e,t){let n=b.get(t);if(b.delete(t),Array.isArray(n))for(let t of n)W(t,e)}function x(e){let t=y.get(e.root);t?.get(e.t)===e&&t.delete(e.t)}function M(e,t){$(`${N(e.t)} ${t}`),x(e),e.Qe?.(),e.Qe=null}function E(e,t){let n=e.state?.[t];if("function"==typeof n)try{let t=n.call(e.chroot);null!==t&&"object"==typeof t&&"function"==typeof t.then&&t.then(void 0,$)}catch(e){$(e)}}function W(e,t){if(v.has(t))return M(e,"will not graft: its component is wired to its host.");let n=e.state,o=t.target,l=e.t.split("."),r=o;for(let e of l)r=r?.[e];if(void 0!==r&&!0!==t.hydrated)return M(e,`will not graft: the root state already has "${e.t}".`);let i=function(e,t){let n=e=>`${t}.${e}`;return new Proxy({},{get(t,o){if("symbol"==typeof o)return;if(36!==o.charCodeAt(0))return e.proxy[n(o)];let l=e.proxy[o];return"$eqPath"===o?(e,t)=>l(n(e),n(t)):O.has(o)&&"function"==typeof l?(e,...t)=>l(n(e),...t):l},set:(t,o,l)=>"symbol"!=typeof o&&(e.proxy[n(o)]=l,!0)})}(t,e.t);e.chroot=i;let a={},s={},u=new Set;for(let t=n;null!==t&&t!==Object.prototype;t=Object.getPrototypeOf(t))for(let n of Object.getOwnPropertyNames(t)){if(u.has(n)||"constructor"===n)continue;u.add(n);let{get:o,set:l,value:r}=Object.getOwnPropertyDescriptor(t,n);if(void 0!==o||void 0!==l)s[`${e.t}.${n}`]={get:o&&function(){return o.call(i)},set:l&&function(e){l.call(i,e)}};else{if("$"===n[0])continue;if("function"==typeof r){let t=r.bind(i);s[`${e.t}.${n}`]={get:()=>t}}else a[n]=r}}if(void 0===r){for(let e=1;e<l.length;e++){let n=t.o(l.slice(0,e).join("."));null==t.it(n,null)&&t.A(n,null,{})}t.A(t.o(e.t),null,a)}t.no(Object.defineProperties({},s));for(let e in s)t.Ue(t.o(e),null);e.engine=t;let c=k.get(t);void 0===c&&k.set(t,c=[]),c.push(e),e.el.isConnected&&E(e,"$connectedCallback"),e.Qe?.(),e.Qe=null}function D(e,t){let n=b.get(e);if(Array.isArray(n))for(let e of n)M(e,w);b.set(e,t)}var T=new WeakMap;function R(e,t){let n=e.getAttribute("mount");if(null===n)return null;let o={el:e,root:t,t:n,state:null,engine:null,chroot:null,Qe:null},r=null;if(function(e){return""!==e&&e.split(".").every(e=>""!==e&&!/[*$#@\s]/.test(e))}(n))if(e.hasAttribute(u.bindAttributeName))r='injections (data-wcs="state.<key>: …") are not supported — read the root path in a root getter.';else{let e=y.get(t);void 0===e&&y.set(t,e=new Map);let l=e.get(n);if(void 0!==l&&l!==o&&(null===l.engine?l.el.isConnected:A(l.engine)))r=`will not graft: another volume already holds "${n}".`;else{if(null===l?.engine){let e=b.get(t);Array.isArray(e)&&b.set(t,e.filter(e=>e!==l)),l.Qe?.(),l.Qe=null}e.set(n,o)}}else r='has an invalid mount path: it must be a static path (no "*", "$", "#", "@").';return{Po:!0,start(e){if(null!==r)return M(o,r);if(y.get(t).get(n)===o){for(let t of j)if(void 0!==e[t])return M(o,`${t} is not run in a volume — declare it on the root state.`);for(let t of P)void 0!==e[t]&&console.warn(`${N(n)} ${t} is not run in a volume (it belongs to the root).`);return o.state=e,new Promise(e=>{o.Qe=e;let n=A(l.get(t)),r=b.get(t);void 0!==n?W(o,n):C(t)?M(o,w):b.set(t,[...Array.isArray(r)?r:[],o])})}},Je(){null!==o.engine&&E(o,"$connectedCallback")},Bn(){null!==o.engine&&E(o,"$disconnectedCallback")},reset(){g(`re-setting a volume is not supported: its data was copied into the root tree at "${n}" — write the paths under it on the root instead.`)}}}var q=new WeakMap,L=new WeakMap;function I(e,t){let n=e[t];if(void 0===n)return[];Array.isArray(n)||g(`${t} must be an array of state member names.`);let o=new Set;for(let e of n)("string"!=typeof e||""===e)&&g(`${t} entries must be non-empty strings.`),"$"===e[0]&&g(`${t} entry "${e}": internal ($) members are never exposed.`),o.has(e)&&g(`${t} entry "${e}" is duplicated.`),o.add(e);return n}function Q(e,t){let n=t.host;if(void 0===n||!n.hasAttribute("data-wc-definition"))return null;let o=document.createDocumentFragment();for(let e of[...t.childNodes])o.appendChild(e.cloneNode(!0));let l=t.mode;return{start(t){e.hasAttribute("bind-component")&&g("DCC: a <wcs-state bind-component> cannot define a component (use one mechanism)."),function(e,t,n,o){e.includes("-")||g(`DCC: <${e} data-wc-definition> is not a valid custom element name.`),void 0!==customElements.get(e)&&g(`DCC: <${e}> is already defined.`);let l=function(e){let t=new Map;for(let n=e;null!==n&&n!==Object.prototype;n=Object.getPrototypeOf(n))for(let e of Object.getOwnPropertyNames(n))"constructor"===e||"$"===e[0]||t.has(e)||t.set(e,Object.getOwnPropertyDescriptor(n,e));let n=e.$stream;if(null!==n&&"object"==typeof n)for(let e of Object.keys(n))t.has(e)||t.set(e,{value:void 0});return t}(o),r=I(o,"$bindables"),i=I(o,"$commands");for(let e of r){let t=l.get(e);void 0===t&&g(`$bindables entry "${e}" does not exist on the state.`),"function"==typeof t.value&&g(`$bindables entry "${e}" is a method: list it in $commands.`)}for(let e of i){let t=l.get(e);void 0===t&&g(`$commands entry "${e}" does not exist on the state.`),"function"!=typeof t.value&&g(`$commands entry "${e}" is not a method: list it in $bindables.`)}let a={tag:e,bindables:r},s=new WeakMap,c=new WeakMap,d=o=>{if(s.has(o))return s.get(o);if(o.hasAttribute("data-wc-definition"))return null;let l=o.attachShadow({mode:n});l.appendChild(t.cloneNode(!0));let i=l.querySelector(u.tagNames.state);return s.set(o,i),q.set(o,a),null===i&&r.length>0&&console.warn(`[@wcstack/state] DCC: <${e}> declares $bindables but its content has no <${u.tagNames.state}>: no change events.`),i},f=e=>d(e)?.engine??null,h=e=>Promise.resolve(d(e)?.initializePromise).then(()=>{let t=c.get(e);c.delete(e);let n=f(e);if(void 0!==t&&null!==n)for(let[e,o]of t)n.proxy[e]=o});class p extends HTMLElement{static{this.wcBindable=0===r.length&&0===i.length?null:{protocol:"wc-bindable",version:1,properties:r.map(t=>({name:t,event:`${e}:${t}-changed`,getter:e=>e.target[t]})),inputs:r.map(e=>({name:e})),...0===i.length?{}:{commands:i.map(e=>({name:e,async:!0}))}}}connectedCallback(){null!==d(this)&&h(this)}get stateElement(){return d(this)}}for(let[e,t]of l)"function"==typeof t.value?Object.defineProperty(p.prototype,e,{configurable:!0,value(...t){return h(this).then(()=>{let n=f(this);return null===n?void 0:n.proxy[e].apply(n.proxy,t)})}}):Object.defineProperty(p.prototype,e,{configurable:!0,get(){return f(this)?.proxy[e]},set(t){let n=f(this);if(null!==n)n.proxy[e]=t;else{let n=c.get(this);void 0===n&&c.set(this,n=[]),n.push([e,t])}}});customElements.define(e,p)}(n.localName,o,l,t)},Je(){},Bn(){},reset(){g("re-setting a DCC definition is not supported: each instance loads its own state.")}}}var z=new WeakMap,B=new WeakSet,H=new WeakMap,X=new WeakMap,F="data-wcs-wired",J=new WeakMap,U=new WeakMap,V=new WeakMap,Y=0,G=new Set,K={},Z=["$watch","$stream","$renderedCallback"],_=e=>e.split(".",1)[0];function ee(e,t){let n=0;return e.split(".").map(e=>"*"===e?String(t[n++]):e).join(".")}function te(e,t){let n=e.a,o=_(e.name);if(!0!==document.documentElement?.hasAttribute("data-wcs-server"))n.removeAttribute(F);else if(!oe(n,o)){let e=n.getAttribute(F)?.split(" ")??[];e.includes(o)||n.setAttribute(F,[...e,o].join(" "))}J.get(n)?.he===o&&g(`<${n.localName}>.${o} has loaded its state: the wiring "${e.name}" added afterwards cannot reach it — bind the host's wiring before the component loads.`);let l=z.get(n);void 0===l&&z.set(n,l=[]),l.push(e),t&&B.add(e);let r=H.get(n);return void 0===r&&H.set(n,r=new Map),r.has(o)||r.set(o,n[o]),X.get(n)?.(),!1}function ne(e){return e.localName.includes("-")&&null!==e.querySelector(`:scope > ${u.tagNames.state}[bind-component]`)}function oe(e,t){let n=e.getAttribute(u.bindAttributeName);return null!==n&&new RegExp(`(^|;)\\s*${t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}\\s*[.#:]`).test(n)}function le(t){let n=t.parentElement;for(;null!==n&&!ne(n);)n=n.parentElement;let o=l.get(n??t.getRootNode()),r=o?.element;(r?.isConnected?r.V:null===n)&&(null===n?e(t):i(o,t))}var re=new Set;function ie(e,t){re.has(e)||(re.add(e),console.warn(`[@wcstack/state] ${t}`))}var ae=(e,t)=>t in e.state;function se(e,t){let n=ue(e.state,t);return void 0!==n&&(void 0!==n.get||void 0!==n.set||"function"==typeof n.value)}function ue(e,t){for(let n=e;null!==n&&n!==Object.prototype;n=Object.getPrototypeOf(n)){let e=Object.getOwnPropertyDescriptor(n,t);if(void 0!==e)return e}}function ce(e,t,n){if(null!==n.getter)return;let o,l=e.host,r=l.engine,i=_(n.t),s=l.entries.find(e=>e.$===n.t);if(void 0===s&&null!==n.c)return function(e,t){let n,o=t.c;for(;null!==o&&void 0===(n=e.pt.get(o));)o=o.c;if(null===o||void 0===n)return;let l=e.P,r=e.host.engine,i=r.o(n.p.t+t.t.slice(o.t.length));if(null===i.getter)return;let s=n,u=()=>{let n=de(e,s.r);return 0===t.n?n:(r.resolve(ee(i.t,[...r.H(n),...l.H(a(l.d,t.n))]),null),r.rr)};t.getter=()=>{let e=u();return i.n>0&&null===e?void 0:r.v(i,e)},null!==i.se&&(t.se=n=>{let o=u();fe(e,s.e,()=>r.A(i,o,n)),e.dn=t}),t.n>0&&(t.F=l.Le++),e.pt.set(t,{e:s.e,p:i,r:s.r})}(e,n);if(0!==n.n)return;if(void 0!==s){if(s.$!==i?ae(l,i):se(l,i))return;o=s.ye}else{if(null===t||null!==n.c||"$"===i[0]||ae(l,i))return;s=t,o=r.o(`${t.ye.t}.${i}`)}let u=s.r,c=s;n.getter=()=>r.v(o,de(e,u)),n.se=t=>{fe(e,c,()=>r.A(o,u,t)),e.dn=n},e.pt.set(n,{e:s,p:o,r:u})}function de(e,t){return null!==t&&!t.w&&g(`The host row of <${e.host.el.localName}> was removed.`),t}function fe(e,t,n){let o=G.has(e.P);G.add(e.P),e.from=t;try{n()}finally{o||G.delete(e.P),e.from=null}}var he=(e,t)=>t||!G.has(e.m.P)||null!==e.m.from&&e.m.from!==e.e;function pe(e,t){if(e.fn===t||null===e.host.engine)return;e.fn=t,Y+=t?1:-1;let n=e.host.engine,o=V.get(n);void 0===o&&V.set(n,o=new Map);for(let n of e.pe){let e=o.get(n.e.ye);void 0===e&&o.set(n.e.ye,e=new Map);let l=e.get(n.e.r);void 0===l&&e.set(n.e.r,l=new Set),t?l.add(n):(l.delete(n),0===l.size&&e.delete(n.e.r))}let l=e.host.entries.find(e=>""===e.$);if(void 0!==l){null===e.ie&&function(e,t){let n=e.host,o=n.engine;e.ie=new Map;let l=new Set;for(let r=n.state;null!==r&&r!==Object.prototype;r=Object.getPrototypeOf(r))for(let i of Object.getOwnPropertyNames(r)){if(l.has(i))continue;l.add(i);let a=Object.getOwnPropertyDescriptor(r,i);if(void 0===a.get&&void 0===a.set||"$"===i[0]||i.includes("*"))continue;let s=_(i);if(i!==s&&!ae(n,s))continue;let u=o.o(`${t.ye.t}.${i}`);if(null===u.getter)$e(o,u,t.ye);else if(!me.has(u.getter))continue;e.ie.set(u,e.P.o(i))}}(e,l);for(let o of e.ie.keys())t&&null===o.getter&&$e(n,o,l.ye),n.T.ke(n,o,l.r);e.ie.size>0&&n.ve(),t&&function(e,t){let n=e.host.engine;for(let[o,l]of e.ie){let r=n.v(o.c,t.r);if(null===r||"object"!=typeof r||!(o.s in r))continue;let i=e.host.el.localName;ie(`${i}|${o.t}`,`[wcs/mount-export-shadowed] <${i}>.${e.host.he}.${l.t} is exported at "${o.t}" 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.`)}}(e,l)}}var me=new WeakSet;function ge(e,t,n,o){let l=V.get(e)?.get(t)?.get(n);if(void 0===l)return null;let r=null;for(let e of l)""!==e.e.$||!0!==e.m.ie?.has(o)||e.m===r||(null!==r&&g(`[wcs/mount-export-ambiguous] "${o.t}" is exported by two mounted components on the same instance: <${r.host.el.localName}> and <${e.m.host.el.localName}>. Mount only one of them there, or rename one accessor. See docs/state-overlay-export-design.md X4.`),r=e.m);return r}function $e(e,t,n){let o=t.c,l=t.s,r=()=>{let t=e.read(o,e.d);return null!==t&&"object"==typeof t&&l in t?t:null};t.getter=()=>{let o=r();if(null!==o)return o[l];let i=ge(e,n,e.d,t);return null===i?void 0:i.P.read(i.ie.get(t),null)},me.add(t.getter),t.se=i=>{let a=null===r()?ge(e,n,e.d,t):null;if(null===a){let t=e.read(o,e.d);return void(null!==t&&"object"==typeof t&&(t[l]=i))}let s=a.ie.get(t);void 0===ue(a.host.state,s.t)?.set&&g(`Cannot write to "${s.t}" on mounted <${a.host.el.localName}>: the accessor has no setter. Add a setter or write to the underlying state paths instead.`),a.P.A(s,null,i)},t.n>0&&(t.F=e.Le++)}function ye(e,t,n,o,l,r){if(null!==t.getter)return e.T.ke(e,t,n),void e.ve();if("*"===t.s){if(null===n)return;if(n.E=n.l.R[n.y],e.T.Xt(n),null!==n.u)for(let t of n.u.values())e.G(t)}else e.En(t,n);c.re?.(e,t,n,o,l,r),e.Ue(t,n)}function be(e){let t=e.m.P;for(let[n,o]of e.m.pt)o.e===e.e&&(0===n.n?t.T.ke(t,n,null):t.nn(n.h[n.n],e=>t.T.ke(t,n,e)));t.ve()}function we(e,t,n,o,l,r,i){let s=n.t.slice(t.t.length);if(""===s)return be(e);let u,c=e.m,d=c.P;if(""===e.e.$){u=s.slice(1);let e=_(u);if("$"===e[0]||ae(c.host,e)||c.host.entries.some(e=>""!==e.$&&(u===e.$||u.startsWith(`${e.$}.`))))return}else u=e.e.$+s;let f=[];for(let e=t.n+1;e<=n.n;e++)f.push(a(o,e).y);d.resolve(ee(u,f),null);let h=d.rp,p=d.rr;h.n>0&&null===p||ye(d,h,p,l,r,i)}function ve(e,t,n,o,l,r,i){if(0===Y)return;let s=G.has(e);G.add(e);try{let s=U.get(e);!i&&void 0!==s&&s.fn&&!G.has(s.host.engine)&&function(e,t,n,o,l,r){let i,a=t;for(;null!==a&&void 0===(i=e.pt.get(a));)a=a.c;if(null===a||void 0===i)return;let s=e.host.engine;if(a===t&&e.dn===t)return void(e.dn=null);if(null!==i.r&&!i.r.w)return;let u=[...s.H(i.r),...e.P.H(n)];s.resolve(ee(i.p.t+t.t.slice(a.t.length),u),null);let c=s.rp,d=s.rr;c.n>0&&null===d||fe(e,i.e,()=>ye(s,c,d,o,l,r))}(s,t,n,o,l,r),i&&void 0!==s&&s.fn&&null!==s.ie&&function(e,t){let n=e.host.entries.find(e=>""===e.$),o=e.host.engine;for(let[l,r]of e.ie)r===t&&(o.T.ke(o,l,n.r),o.ve())}(s,t);let u=V.get(e);if(void 0===u)return;for(let[e,s]of u)if(t.ee(e)){let u=s.get(0===e.n?null:a(n,e.n));if(void 0!==u)for(let a of[...u])he(a,i)&&we(a,e,t,n,o,l,r)}else if(e.ee(t))for(let[e,o]of[...s])if(0===t.n||a(e,t.n)===n)for(let e of[...o])he(e,i)&&be(e)}finally{s||G.delete(e)}}async function ke(e,o,l,i,a){if(i===K)return;let d=m(i);d&&await d;let f=J.get(o);f.engine&&i.$recursion&&g(`[wcs/mount-dollar-declaration] <${o.localName}>: $recursion is not run in a mounted component — declare it on the root state.`);let h=f.I;if(null!==h&&h.el!==e&&h.el.isConnected&&g(`<${o.localName}> already has a connected <${u.tagNames.state} bind-component="${f.he}">.`),null!==h&&pe(h,!1),null!==h&&function(e,t,n){let o=e.P,l=`[${u.bindAttributeName}]`,r=e=>1===e.nodeType&&(e.matches(l)||null!==e.querySelector(l)),i=new Set,a=e=>{for(;null!==e&&e.parentNode!==n;)e=e.parentNode;null!==e&&i.add(e)},s=(e,t)=>{for(let n=e.In(t);null!==n&&n!==t;n=n.nextSibling)a(n);a(t)};for(let e of o.ue.values())for(let t of e)if(null===t.D)a(t.a);else for(let e of t.D.q)s(t.D,e.S);for(let e of o.oe.values())for(let t of[e.N,...e.M??[]])null!==t&&s(t,t.S);for(let t of e.L)t.parentNode===n&&r(t)&&i.add(t);if(0===i.size)return!1;let c=[...n.childNodes].filter(n=>n!==t&&!i.has(n)&&!e.L.includes(n)&&(r(n)||o.Wt&&n.textContent.includes("{{")));return c.length>0&&console.warn(`[@wcstack/state] <${e.host.el.localName}>: ${c.length} node(s) added beside the content taken over are not bound.`),!0}(h,e,l))return async function(e,t,n,o){e.el.engine=null,e.el=t,e.P.element=t,t.engine=e.P,e.L=e.L.filter(e=>e.parentNode===n),t.isConnected?await je(e,o):o()}(h,e,l,a);let p=new s(i,new n);p.element=e,e.engine=p,function(e,t){let n=new Map;for(let e=t;null!==e&&e!==Object.prototype;e=Object.getPrototypeOf(e))for(let t of Object.getOwnPropertyNames(e)){let o=Object.getOwnPropertyDescriptor(e,t).value;"function"==typeof o&&"constructor"!==t&&n.set(o,null)}let o=(t,n,o)=>Reflect.apply(t,e.proxy,o);e.V=e=>{let t=n.get(e);return null===t&&n.set(e,t=new Proxy(e,{apply:o})),t}}(p,i);let y={el:e,L:[],P:p,host:f,pe:[],pt:new Map,fn:!1,dn:null,from:null,ie:null};for(let e of f.entries)y.pe.push({m:y,e});f.I=y,U.set(p,y);let b=null===f.engine;b?c.element?.(p,"mounting"):(function(e){let t=e.P,n=e.host,o=n.engine,l=n.el.localName,r=n.entries.find(e=>""===e.$)??null;for(let e of n.entries){if(""===e.$)continue;let t=_(e.$);ae(n,t)&&(e.$!==t||se(n,t))&&ie(`${l}.${e.$}`,`[wcs/mount-own-key-shadow] <${l}>: "${n.he}.${e.$}" is hidden by the component's own "${t}"; rename one side.`)}if(null!==r){let e=o.v(r.ye,r.r);if(null!==e&&"object"==typeof e)for(let t of Object.keys(n.state))"$"!==t[0]&&t in e&&!n.entries.some(e=>e.$===t)&&ie(`${l}.${t}`,`[wcs/mount-own-key-shadow] <${l}>: its own "${t}" hides "${r.ye.t}.${t}" — remove the default to read the tree, or rename it to keep it private.`)}let i=Z.filter(e=>void 0!==n.state[e]);i.length>0&&ie(`${l}.${n.he}$`,`[wcs/mount-dollar-declaration] <${l}>: ${i.join(", ")} ${1===i.length?"is":"are"} not run in a mounted component — declare it on the root state.`);let a=t.ot;t.ot=n=>{ce(e,r,n),a.call(t,n)};let s=[...t.O.all()];for(let t of s)ce(e,r,t);for(let e of s)a.call(t,e);let u=t.Yt;t.Yt=()=>{(function(e){for(;void 0!==e;e=U.get(e.host.engine))if(e.host.entries.some(e=>null!==e.r&&!e.r.w))return!1;return!0})(e)&&u.call(t)}}(y),pe(y,!0),v.add(p),S(p,l));let w=c.hr?.(l,p);r(p,l),w?.(),y.L=[...l.childNodes],t(),b&&p.Nn(),Object.defineProperty(o,f.he,{configurable:!0,enumerable:!0,get:()=>p.proxy});let k=o.$stateReadyCallback;if("function"==typeof k)try{let e=k.call(o,f.he);null!==e&&"object"==typeof e&&"function"==typeof e.then&&e.then(void 0,$)}catch(e){$(e)}a(),e.isConnected?(await p.$e("$connectedCallback"),b&&e.isConnected&&c.element?.(p,"connected")):pe(y,!1)}async function je(e,t){pe(e,!0);for(let t of e.pe)be(t);t?.(),!e.broken&&(await e.P.$e("$connectedCallback"),null===e.host.engine&&e.el.isConnected&&c.element?.(e.P,"connected"))}function Pe(e,t){let n=e.getAttribute("bind-component");if(null===n)return function(e,t){return e.connectedCallbackPromise.catch(()=>{let n=l.get(t)?.element;if(!(e.V||void 0!==n&&n!==e&&n.isConnected)){D(t,e);for(let e of T.get(t)??[])e()}}),null}(e,t);let r=e.parentNode,i=r instanceof ShadowRoot,a=i?r.host:r instanceof Element?r:null,s=()=>{let t=null===a?void 0:J.get(a)?.I;return t?.el===e?t:null},d=t=>{throw i&&D(r,e),t},f=!1;return{kt:()=>(null!==a&&a.localName.includes("-")?async function(e,t,n,l){let r=n.localName;(["state","src","json"].some(t=>e.hasAttribute(t))||null!==e.querySelector('script[type="module"]'))&&g(`<${u.tagNames.state} bind-component> takes its state from <${r}>.${t}: it cannot also load one (state / src / json / an inline script).`),await o(n).whenDefined(r);let i=J.get(n);if(void 0!==i)return i.he!==t&&g(`<${r}> already has a <${u.tagNames.state} bind-component="${i.he}">.`),i.state;let a=()=>(z.get(n)??[]).filter(e=>_(e.name)===t),s=oe(n,t);if(s&&0===a().length&&le(n),0===a().length&&(s||((e,t)=>!0===e.getAttribute(F)?.split(" ").includes(t))(n,t))){let e;await new Promise((o,l)=>{X.set(n,o),e=function(e,t){C(e)&&t();let n=T.get(e)??new Set;return T.set(e,n.add(t)),()=>n.delete(t)}(n.getRootNode(),()=>l(new Error(`[@wcstack/state] <${r}>.${t} will not mount: the root state failed to initialize.`)))}).finally(()=>e())}X.delete(n);let c=a(),d=H.get(n),f=void 0!==d&&d.has(t)?d.get(t):n[t];if((null===f||"object"!=typeof f)&&g(`"bind-component": <${r}>.${t} must be an object (the component's state), got ${null===f?"null":typeof f}.`),0===c.length&&l){let e=new Error(`[@wcstack/state] A plain (unwired) Light DOM "bind-component" is not supported. Attach a shadow root to <${r}>, or mount it from the host (${u.bindAttributeName}="${t}: path").`);return queueMicrotask(()=>{throw e}),K}let h=[];for(let e of c){let o=e.name===t?"":e.name.slice(t.length+1);h.some(e=>e.$===o)&&g(`<${r}> maps "${e.name}" twice.`);let l=o.split(".").indexOf("*");if(l>=0){let n=o.split(".").slice(0,l).join(".");g(`<${r}> maps "${e.name}": the component-side path of a mount cannot contain "*"${""===n?"":` — map the list itself ("${t}.${n}: <the host's list>")`}.`)}h.push({$:o,ye:e.o,r:e.r,ro:B.has(e)}),e.engine.Pn(e),""!==o&&delete n[e.name]}let p=0===c.length?function(e){let t=Object.getOwnPropertyDescriptors(e),n=Object.isFrozen(e);for(let e of Object.values(t))"value"in e&&!1===e.writable&&(e.writable=!0,n=!0);return n?Object.create(Object.getPrototypeOf(e),t):e}(f):f;return J.set(n,i={el:n,he:t,state:p,engine:0===c.length?null:c[0].engine,entries:h,I:null}),p}(e,n,a,!i):Promise.reject(new Error(`[@wcstack/state] "bind-component" requires <${u.tagNames.state}> to be a direct child of a custom element.`))).catch(d),async start(t,n){await ke(e,a,i?r:a,t,()=>{f=!0,n()}).catch(e=>{let t=s();return!f&&null!==t&&(t.broken=!0),d(e)})},Je(){let t=s();null!==t?je(t).catch($):f?Promise.resolve().then(()=>{if(e.parentNode===r)return ke(e,a,i?r:a,J.get(a).state,()=>{})}).catch($):X.has(a)&&le(a)},Bn(){let e=s();null!==e&&(pe(e,!1),!e.broken&&(e.P.$e("$disconnectedCallback"),null===e.host.engine&&c.element?.(e.P,"disconnected")))},reset(){g(`re-setting a component's state is not supported: write <${a?.localName}>.${n} instead.`)}}}var Ne={name:"scopes",hooks:c,install(){c.ut=f(p,c.ut,R),c.ut=f(p,c.ut,Q),c.ut=f(p,c.ut,Pe),c.ar=te,c.Eo=ne,c.element=d(c.element,(e,t)=>{if("mounting"!==t)return function(e,t){let n=k.get(e)??[];if("disconnected"===t)for(let e of n)x(e);else if("reset"!==t&&A(l.get(e.root))===e){S(e,e.root);for(let e of n)y.get(e.root).has(e.t)||y.get(e.root).set(e.t,e)}}(e,t);let n=e.element.getRootNode();S(e,n),function(e,t){let n=t.host,o=void 0===n?void 0:q.get(n);void 0!==o&&L.set(e,{host:n,def:o})}(e,n)}),c.re=d(c.re,(e,t,n,o,l,r)=>{(function(e,t,n,o){let l=L.get(e);if(void 0===l)return;let r=t.t.split(".",1)[0];if(!l.def.bindables.includes(r))return;let i=o&&t.t===r;l.host.dispatchEvent(new CustomEvent(`${l.def.tag}:${r}-changed`,{detail:i?n:void 0,bubbles:!0}))})(e,t,l,r),ve(e,t,n,o,l,r,!1)}),c.Se=d(c.Se,(e,t,n)=>ve(e,t,n,void 0,void 0,!1,!0)),c.Ie=f(h,c.Ie,(e,t,n,o,l)=>(function(e,t){let n=k.get(e);if(void 0!==n&&0===t.n)for(let{t:e}of n)e.startsWith(`${t.t}.`)&&g(`writing "${t.t}" would replace the volume grafted at "${e}"; write the paths under it instead.`)}(e,t),function(e,t,n){let o,l=U.get(e);if(void 0===l)return!1;for(let e=t;null!==e&&void 0===o;e=e.c)o=l.pt.get(e);if(void 0===o)return!1;let r=o.e;return!((null===r.r||r.r.w)&&!r.ro)&&(!!n||(de(l,r.r),void g(`[wcs/mount-readonly] <${l.host.el.localName}> cannot write "${t.t}": it is mounted read-only ("${l.host.he}${""===r.$?"":`.${r.$}`}#ro: ${r.ye.t}"). Write it on the host, or drop #ro from the mount.`)))}(e,t,l)));let e=c.fe;c.fe=(t,n)=>{let o=k.get(t);void 0!==o&&o.length>0&&g(`re-setting a root state with grafted volumes (${o.map(e=>e.t).join(", ")}) is not supported: their data is part of the tree.`),function(e){let t=V.get(e);if(void 0===t)return!1;for(let e of t.values())if(e.size>0)return!0;return!1}(t)&&g("re-setting a root state with mounted components is not supported: they read its data."),e?.(t,n)}}},Oe=Ne;export{Oe as default,Ne as scopes};
|
|
2
2
|
//# sourceMappingURL=scopes.js.map
|