@wcstack/state 3.1.0 → 3.2.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 +25 -17
- package/README.md +25 -17
- package/dist/auto.min.js +1 -1
- package/dist/auto.min.js.map +1 -1
- package/dist/define.d.ts +11 -7
- package/dist/index.d.ts +13 -7
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/manifest.d.ts +12 -1
- package/dist/manifest.esm.js +90 -35
- package/dist/split/chunks/declarationAliases.js +2 -0
- package/dist/split/chunks/declarationAliases.js.map +1 -0
- package/dist/split/chunks/filterRegistry.js +1 -1
- package/dist/split/chunks/filterRegistry.js.map +1 -1
- package/dist/split/chunks/mount.js +1 -1
- package/dist/split/chunks/mount.js.map +1 -1
- package/dist/split/chunks/pathDiagnostics.js +1 -1
- package/dist/split/chunks/pathDiagnostics.js.map +1 -1
- package/dist/split/chunks/registerComponents.js +1 -1
- package/dist/split/chunks/registerComponents.js.map +1 -1
- package/dist/split/chunks/version.js +1 -1
- package/dist/split/core.d.ts +11 -7
- package/dist/split/core.js +1 -1
- package/dist/split/core.js.map +1 -1
- package/dist/split/features/devtools.js +1 -1
- package/dist/split/features/devtools.js.map +1 -1
- package/dist/split/features/formats.js +1 -1
- package/dist/split/features/formats.js.map +1 -1
- package/dist/split/features/scopes.js +1 -1
- package/dist/split/features/scopes.js.map +1 -1
- package/dist/split/features/ssr.js +1 -1
- package/dist/split/features/ssr.js.map +1 -1
- package/dist/split/features/temporal.js +1 -1
- package/dist/split/features/temporal.js.map +1 -1
- package/dist/wcs-manifest.json +64 -25
- package/package.json +1 -1
package/dist/manifest.d.ts
CHANGED
|
@@ -30,6 +30,15 @@ interface IFilterMeta {
|
|
|
30
30
|
/** 組み込みフィルタ名 → 構造化メタデータ。キー集合は builtinFilters と一致しなければならない。 */
|
|
31
31
|
declare const builtinFilterMeta: Record<string, IFilterMeta>;
|
|
32
32
|
|
|
33
|
+
/**
|
|
34
|
+
* filters/filterAliases.ts — 組み込みフィルタの旧名 → 正式名(要件 B12・docs/state-3x-naming.ja.md V1〜V9)。
|
|
35
|
+
*
|
|
36
|
+
* 旧名は 3.x の間エイリアスとして残り、4.0 で外す(D4)。解決は登録簿(core/filterRegistry)が行い、
|
|
37
|
+
* 実装・引数の個数・メタデータは正式名だけが持つ。formats の install と manifest(tooling)の両方が読むので、
|
|
38
|
+
* 実装にもメタデータにも依存しない小さな表として独立させている。
|
|
39
|
+
*/
|
|
40
|
+
declare const builtinFilterAliases: Readonly<Record<string, string>>;
|
|
41
|
+
|
|
33
42
|
type BindingType = 'text' | 'prop' | 'event' | 'for' | 'if' | 'elseif' | 'else' | 'radio' | 'checkbox' | 'spread';
|
|
34
43
|
|
|
35
44
|
declare const STRUCTURAL_BINDING_TYPE_SET: Set<BindingType>;
|
|
@@ -98,6 +107,8 @@ interface IWcsManifest {
|
|
|
98
107
|
filters: string[];
|
|
99
108
|
/** 組み込みフィルタの構造化メタデータ(説明・引数仕様・型)。vscode-wcs の手リスト撤去用。 */
|
|
100
109
|
filterMeta: Record<string, IFilterMeta>;
|
|
110
|
+
/** 組み込みフィルタの旧名 → 正式名(要件 B12)。旧名も解決するが、ツールは正式名を提案する */
|
|
111
|
+
filterAliases: Readonly<Record<string, string>>;
|
|
101
112
|
/** 予約ライフサイクルフック名 */
|
|
102
113
|
reservedLifecycle: readonly string[];
|
|
103
114
|
/** 予約 state API(プロトコル系の `$` 名前空間) */
|
|
@@ -106,5 +117,5 @@ interface IWcsManifest {
|
|
|
106
117
|
/** 機械可読な単一正本を返す。vscode-wcs はこれを消費する想定。 */
|
|
107
118
|
declare function getWcsManifest(): IWcsManifest;
|
|
108
119
|
|
|
109
|
-
export { STRUCTURAL_BINDING_TYPE_SET, WCS_MANIFEST_VERSION, builtinFilterMeta, getWcsManifest };
|
|
120
|
+
export { STRUCTURAL_BINDING_TYPE_SET, WCS_MANIFEST_VERSION, builtinFilterAliases, builtinFilterMeta, getWcsManifest };
|
|
110
121
|
export type { FilterArgType, FilterResultType, IFilterMeta, IWcsManifest };
|
package/dist/manifest.esm.js
CHANGED
|
@@ -81,6 +81,26 @@ function valueMustBeArray(fnName) {
|
|
|
81
81
|
raiseError(`filter ${fnName} requires an array value`);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
/**
|
|
85
|
+
* filters/filterAliases.ts — 組み込みフィルタの旧名 → 正式名(要件 B12・docs/state-3x-naming.ja.md V1〜V9)。
|
|
86
|
+
*
|
|
87
|
+
* 旧名は 3.x の間エイリアスとして残り、4.0 で外す(D4)。解決は登録簿(core/filterRegistry)が行い、
|
|
88
|
+
* 実装・引数の個数・メタデータは正式名だけが持つ。formats の install と manifest(tooling)の両方が読むので、
|
|
89
|
+
* 実装にもメタデータにも依存しない小さな表として独立させている。
|
|
90
|
+
*/
|
|
91
|
+
const builtinFilterAliases = {
|
|
92
|
+
inc: "add",
|
|
93
|
+
dec: "sub",
|
|
94
|
+
fix: "toFixed",
|
|
95
|
+
uc: "upper",
|
|
96
|
+
lc: "lower",
|
|
97
|
+
cap: "capitalize",
|
|
98
|
+
rep: "repeat",
|
|
99
|
+
rev: "reverse",
|
|
100
|
+
pad: "padStart",
|
|
101
|
+
null: "nullIfEmpty",
|
|
102
|
+
};
|
|
103
|
+
|
|
84
104
|
/**
|
|
85
105
|
* builtinFilters.ts
|
|
86
106
|
*
|
|
@@ -245,13 +265,13 @@ const ge = (options) => {
|
|
|
245
265
|
* @returns Filter function that returns incremented number
|
|
246
266
|
*/
|
|
247
267
|
const inc = (options) => {
|
|
248
|
-
const opt = options?.[0] ?? optionsRequired('
|
|
268
|
+
const opt = options?.[0] ?? optionsRequired('add');
|
|
249
269
|
if (!validateNumberString(opt)) {
|
|
250
|
-
optionMustBeNumber('
|
|
270
|
+
optionMustBeNumber('add');
|
|
251
271
|
}
|
|
252
272
|
return (value) => {
|
|
253
273
|
if (typeof value !== 'number') {
|
|
254
|
-
valueMustBeNumber('
|
|
274
|
+
valueMustBeNumber('add');
|
|
255
275
|
}
|
|
256
276
|
return value + Number(opt);
|
|
257
277
|
};
|
|
@@ -263,13 +283,13 @@ const inc = (options) => {
|
|
|
263
283
|
* @returns Filter function that returns decremented number
|
|
264
284
|
*/
|
|
265
285
|
const dec = (options) => {
|
|
266
|
-
const opt = options?.[0] ?? optionsRequired('
|
|
286
|
+
const opt = options?.[0] ?? optionsRequired('sub');
|
|
267
287
|
if (!validateNumberString(opt)) {
|
|
268
|
-
optionMustBeNumber('
|
|
288
|
+
optionMustBeNumber('sub');
|
|
269
289
|
}
|
|
270
290
|
return (value) => {
|
|
271
291
|
if (typeof value !== 'number') {
|
|
272
|
-
valueMustBeNumber('
|
|
292
|
+
valueMustBeNumber('sub');
|
|
273
293
|
}
|
|
274
294
|
return value - Number(opt);
|
|
275
295
|
};
|
|
@@ -379,11 +399,11 @@ const clamp = (options) => {
|
|
|
379
399
|
const fix = (options) => {
|
|
380
400
|
const opt = options?.[0] ?? "0";
|
|
381
401
|
if (!validateNumberString(opt)) {
|
|
382
|
-
optionMustBeNumber('
|
|
402
|
+
optionMustBeNumber('toFixed');
|
|
383
403
|
}
|
|
384
404
|
return (value) => {
|
|
385
405
|
if (typeof value !== 'number') {
|
|
386
|
-
valueMustBeNumber('
|
|
406
|
+
valueMustBeNumber('toFixed');
|
|
387
407
|
}
|
|
388
408
|
return value.toFixed(Number(opt));
|
|
389
409
|
};
|
|
@@ -521,15 +541,31 @@ const substr = (options) => {
|
|
|
521
541
|
* @returns Filter function that returns padded string
|
|
522
542
|
*/
|
|
523
543
|
const pad = (options) => {
|
|
524
|
-
const opt1 = options?.[0] ?? optionsRequired('
|
|
544
|
+
const opt1 = options?.[0] ?? optionsRequired('padStart');
|
|
525
545
|
if (!validateNumberString(opt1)) {
|
|
526
|
-
optionMustBeNumber('
|
|
546
|
+
optionMustBeNumber('padStart');
|
|
527
547
|
}
|
|
528
548
|
const opt2 = options?.[1] ?? '0';
|
|
529
549
|
return (value) => {
|
|
530
550
|
return String(value).padStart(Number(opt1), opt2);
|
|
531
551
|
};
|
|
532
552
|
};
|
|
553
|
+
/**
|
|
554
|
+
* padEnd filter - pads string to specified length from the end (the pair of `padStart`, requirement B12).
|
|
555
|
+
*
|
|
556
|
+
* @param options - Array with target length and pad string (default: ' ')
|
|
557
|
+
* @returns Filter function that returns padded string
|
|
558
|
+
*/
|
|
559
|
+
const padEnd = (options) => {
|
|
560
|
+
const opt1 = options?.[0] ?? optionsRequired('padEnd');
|
|
561
|
+
if (!validateNumberString(opt1)) {
|
|
562
|
+
optionMustBeNumber('padEnd');
|
|
563
|
+
}
|
|
564
|
+
const opt2 = options?.[1] ?? ' ';
|
|
565
|
+
return (value) => {
|
|
566
|
+
return String(value).padEnd(Number(opt1), opt2);
|
|
567
|
+
};
|
|
568
|
+
};
|
|
533
569
|
/**
|
|
534
570
|
* Repeat filter - repeats string specified number of times.
|
|
535
571
|
*
|
|
@@ -537,9 +573,9 @@ const pad = (options) => {
|
|
|
537
573
|
* @returns Filter function that returns repeated string
|
|
538
574
|
*/
|
|
539
575
|
const rep = (options) => {
|
|
540
|
-
const opt = options?.[0] ?? optionsRequired('
|
|
576
|
+
const opt = options?.[0] ?? optionsRequired('repeat');
|
|
541
577
|
if (!validateNumberString(opt)) {
|
|
542
|
-
optionMustBeNumber('
|
|
578
|
+
optionMustBeNumber('repeat');
|
|
543
579
|
}
|
|
544
580
|
return (value) => {
|
|
545
581
|
return String(value).repeat(Number(opt));
|
|
@@ -847,6 +883,18 @@ const defaults = (options, literals) => {
|
|
|
847
883
|
return value;
|
|
848
884
|
};
|
|
849
885
|
};
|
|
886
|
+
/**
|
|
887
|
+
* coalesce filter - returns the default only for null / undefined (`defaults` also replaces 0, false and "").
|
|
888
|
+
* Requirement B12: the nullish counterpart of `defaults`, read like SQL COALESCE.
|
|
889
|
+
*
|
|
890
|
+
* @param options - Array with default value as first element
|
|
891
|
+
* @returns Filter function that returns value or default
|
|
892
|
+
*/
|
|
893
|
+
const coalesce = (options, literals) => {
|
|
894
|
+
const opt = options?.[0] ?? optionsRequired('coalesce');
|
|
895
|
+
const fallback = literals !== undefined && literals.length > 0 ? literals[0] : opt;
|
|
896
|
+
return (value) => value ?? fallback;
|
|
897
|
+
};
|
|
850
898
|
/**
|
|
851
899
|
* Boolean filter - converts value to boolean.
|
|
852
900
|
*
|
|
@@ -899,24 +947,25 @@ const builtinFilters = {
|
|
|
899
947
|
"le": le,
|
|
900
948
|
"gt": gt,
|
|
901
949
|
"ge": ge,
|
|
902
|
-
"
|
|
903
|
-
"
|
|
950
|
+
"add": inc,
|
|
951
|
+
"sub": dec,
|
|
904
952
|
"mul": mul,
|
|
905
953
|
"div": div,
|
|
906
954
|
"mod": mod,
|
|
907
955
|
"abs": abs,
|
|
908
956
|
"clamp": clamp,
|
|
909
|
-
"
|
|
957
|
+
"toFixed": fix,
|
|
910
958
|
"locale": locale,
|
|
911
|
-
"
|
|
912
|
-
"
|
|
913
|
-
"
|
|
959
|
+
"upper": uc,
|
|
960
|
+
"lower": lc,
|
|
961
|
+
"capitalize": cap,
|
|
914
962
|
"trim": trim,
|
|
915
963
|
"slice": slice,
|
|
916
964
|
"substr": substr,
|
|
917
|
-
"
|
|
918
|
-
"
|
|
919
|
-
"
|
|
965
|
+
"padStart": pad,
|
|
966
|
+
"padEnd": padEnd,
|
|
967
|
+
"repeat": rep,
|
|
968
|
+
"reverse": rev,
|
|
920
969
|
"truncate": truncate,
|
|
921
970
|
"join": join,
|
|
922
971
|
"int": int,
|
|
@@ -934,10 +983,11 @@ const builtinFilters = {
|
|
|
934
983
|
"falsy": falsy,
|
|
935
984
|
"truthy": truthy,
|
|
936
985
|
"defaults": defaults,
|
|
986
|
+
"coalesce": coalesce,
|
|
937
987
|
"boolean": boolean,
|
|
938
988
|
"number": number,
|
|
939
989
|
"string": string,
|
|
940
|
-
"
|
|
990
|
+
"nullIfEmpty": _null,
|
|
941
991
|
};
|
|
942
992
|
const outputBuiltinFilters = builtinFilters;
|
|
943
993
|
|
|
@@ -963,26 +1013,27 @@ const builtinFilterMeta = {
|
|
|
963
1013
|
gt: { description: "より大きいか", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
|
|
964
1014
|
ge: { description: "以上か", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
|
|
965
1015
|
// 算術
|
|
966
|
-
|
|
967
|
-
|
|
1016
|
+
add: { description: "加算", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
|
|
1017
|
+
sub: { description: "減算", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
|
|
968
1018
|
mul: { description: "乗算", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
|
|
969
1019
|
div: { description: "除算", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
|
|
970
1020
|
mod: { description: "剰余", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
|
|
971
1021
|
abs: { description: "絶対値", hasArgs: false, resultType: "number", acceptTypes: ["number"], minArgs: 0, maxArgs: 0 },
|
|
972
1022
|
clamp: { description: "範囲内に丸める (min,max)", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 2, maxArgs: 2, argTypes: ["number", "number"] },
|
|
973
1023
|
// 数値フォーマット
|
|
974
|
-
|
|
1024
|
+
toFixed: { description: "固定小数点表記", hasArgs: true, resultType: "string", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
|
|
975
1025
|
locale: { description: "ロケール形式で数値フォーマット", hasArgs: true, resultType: "string", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["string"] },
|
|
976
1026
|
// 文字列
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
1027
|
+
upper: { description: "大文字に変換", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
|
|
1028
|
+
lower: { description: "小文字に変換", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
|
|
1029
|
+
capitalize: { description: "先頭文字を大文字に", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
|
|
980
1030
|
trim: { description: "前後の空白を削除", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
|
|
981
1031
|
slice: { description: "部分文字列 (start[,end])", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "number"] },
|
|
982
1032
|
substr: { description: "部分文字列 (pos,len)", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "number"] },
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1033
|
+
padStart: { description: "先頭を埋める (length[,char])", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "string"] },
|
|
1034
|
+
padEnd: { description: "末尾を埋める (length[,char])", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "string"] },
|
|
1035
|
+
repeat: { description: "繰り返し (count)", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
|
|
1036
|
+
reverse: { description: "文字順を反転", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
|
|
986
1037
|
truncate: { description: "切り詰めて省略記号 (length[,suffix])", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "string"] },
|
|
987
1038
|
join: { description: "配列を連結 ([separator])", hasArgs: true, resultType: "string", acceptTypes: ["array"], minArgs: 0, maxArgs: 1, argTypes: ["string"] },
|
|
988
1039
|
// 数値パース・丸め
|
|
@@ -1005,10 +1056,11 @@ const builtinFilterMeta = {
|
|
|
1005
1056
|
falsy: { description: "偽値か判定", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
|
|
1006
1057
|
truthy: { description: "真値か判定", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
|
|
1007
1058
|
defaults: { description: "偽値の場合デフォルト値", hasArgs: true, resultType: "passthrough", acceptTypes: "any", minArgs: 1, maxArgs: 1, argTypes: ["any"] },
|
|
1059
|
+
coalesce: { description: "null / undefined の場合デフォルト値", hasArgs: true, resultType: "passthrough", acceptTypes: "any", minArgs: 1, maxArgs: 1, argTypes: ["any"] },
|
|
1008
1060
|
boolean: { description: "ブール値に変換", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
|
|
1009
1061
|
number: { description: "数値に変換", hasArgs: false, resultType: "number", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
|
|
1010
1062
|
string: { description: "文字列に変換", hasArgs: false, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
|
|
1011
|
-
|
|
1063
|
+
nullIfEmpty: { description: "空文字列をnullに変換", hasArgs: false, resultType: "passthrough", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
|
|
1012
1064
|
};
|
|
1013
1065
|
|
|
1014
1066
|
const STRUCTURAL_BINDING_TYPE_SET = new Set([
|
|
@@ -1075,7 +1127,8 @@ for (let i = 0; i < MAX_WILDCARD_DEPTH; i++) {
|
|
|
1075
1127
|
Object.freeze(tmpIndexByIndexName);
|
|
1076
1128
|
const STATE_CONNECTED_CALLBACK_NAME = "$connectedCallback";
|
|
1077
1129
|
const STATE_DISCONNECTED_CALLBACK_NAME = "$disconnectedCallback";
|
|
1078
|
-
|
|
1130
|
+
/** 旧名 `$updatedCallback` は 3.x の間のエイリアス(要件 B12・declarationAliases.ts) */
|
|
1131
|
+
const STATE_UPDATED_CALLBACK_NAME = "$renderedCallback";
|
|
1079
1132
|
const STATE_ERROR_CALLBACK_NAME = "$errorCallback";
|
|
1080
1133
|
const WEBCOMPONENT_STATE_READY_CALLBACK_NAME = "$stateReadyCallback";
|
|
1081
1134
|
const STATE_BINDABLES_NAME = "$bindables";
|
|
@@ -1084,7 +1137,8 @@ const STATE_COMMAND_TOKENS_NAME = "$commandTokens";
|
|
|
1084
1137
|
const STATE_COMMAND_NAMESPACE_NAME = "$command";
|
|
1085
1138
|
const STATE_EVENT_TOKENS_NAME = "$eventTokens";
|
|
1086
1139
|
const STATE_ON_NAME = "$on";
|
|
1087
|
-
|
|
1140
|
+
/** 旧名 `$streams` は 3.x の間のエイリアス(要件 B12・declarationAliases.ts) */
|
|
1141
|
+
const STATE_STREAMS_NAME = "$stream";
|
|
1088
1142
|
const STATE_WATCH_NAME = "$watch";
|
|
1089
1143
|
const STATE_SCAN_NAME = "$scan";
|
|
1090
1144
|
const STATE_RECURSION_NAME = "$recursion";
|
|
@@ -1150,6 +1204,7 @@ function getWcsManifest() {
|
|
|
1150
1204
|
// 実装(Record のキー)から自動導出。手リストを持たない=ドリフトの構造的排除。
|
|
1151
1205
|
filters: Object.keys(outputBuiltinFilters),
|
|
1152
1206
|
filterMeta: builtinFilterMeta,
|
|
1207
|
+
filterAliases: builtinFilterAliases,
|
|
1153
1208
|
reservedLifecycle: [
|
|
1154
1209
|
STATE_CONNECTED_CALLBACK_NAME,
|
|
1155
1210
|
STATE_DISCONNECTED_CALLBACK_NAME,
|
|
@@ -1175,4 +1230,4 @@ function getWcsManifest() {
|
|
|
1175
1230
|
};
|
|
1176
1231
|
}
|
|
1177
1232
|
|
|
1178
|
-
export { STRUCTURAL_BINDING_TYPE_SET, WCS_MANIFEST_VERSION, builtinFilterMeta, getWcsManifest };
|
|
1233
|
+
export { STRUCTURAL_BINDING_TYPE_SET, WCS_MANIFEST_VERSION, builtinFilterAliases, builtinFilterMeta, getWcsManifest };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{a as e,o as t}from"./pathDiagnostics.js";import{r as o}from"./errorGuidance.js";const r={$updatedCallback:t,$streams:e},a=new WeakSet;function n(e,t){let o=e;for(;null!==o&&!Object.prototype.hasOwnProperty.call(o,t);)o=Object.getPrototypeOf(o);return o}function s(e){if(!a.has(e)){for(const t of Object.keys(r)){if(!(t in e))continue;const a=r[t];a in e&&o(`[wcs/declaration-alias] The state declares both "${t}" and "${a}". "${t}" is the old name of "${a}" (it works through 3.x) — keep "${a}".`);const s=n(e,t),c=Object.getOwnPropertyDescriptor(s,t);Object.defineProperty(e,a,{...c,configurable:!0}),s===e&&delete e[t]}a.add(e)}}export{s as n};
|
|
2
|
+
//# sourceMappingURL=declarationAliases.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"declarationAliases.js","sources":["../../../../../src/declarationAliases.ts"],"sourcesContent":["/**\n * declarationAliases.ts — 宣言キーの旧名 → 正式名(要件 B12・docs/state-3x-naming.ja.md V13 / V14)。\n *\n * `$updatedCallback` → `$renderedCallback`、`$streams` → `$stream`。旧名は 3.x の間は受け、4.0 で外す(D4)。\n * state オブジェクトがランタイムに入る入口(State の `_state` と `_loadStateFromSource`、マウント記録)で\n * 1 回だけ正規化し、以降のすべての読み手は正式名だけを見る。両方の綴りを宣言したらどちらが効くのか\n * 書き手に見えないので、名指しで落とす(D38)。\n */\nimport { STATE_STREAMS_NAME, STATE_UPDATED_CALLBACK_NAME } from \"./define\";\nimport { raiseError } from \"./raiseError\";\n\nexport const DECLARATION_ALIASES: Readonly<Record<string, string>> = {\n $updatedCallback: STATE_UPDATED_CALLBACK_NAME,\n $streams: STATE_STREAMS_NAME,\n};\n\n/** 正規化済みの state オブジェクト(同じオブジェクトの再セット・ボリュームの 2 つの入口で二重に処理しない) */\nconst normalizedStates = new WeakSet<object>();\n\nfunction findOwner(value: object, key: string): object {\n let owner: object | null = value;\n while (owner !== null && !Object.prototype.hasOwnProperty.call(owner, key)) {\n owner = Object.getPrototypeOf(owner);\n }\n return owner!;\n}\n\n/**\n * 旧名で宣言されたキーを正式名へ写す。自前のプロパティなら旧名は消す。class の state でメソッドが\n * プロトタイプにある形(`$updatedCallback() {}`)は、インスタンスに正式名の定義を足すだけにする。\n */\nexport function normalizeDeclarationAliases(state: object): void {\n if (normalizedStates.has(state)) {\n return;\n }\n for (const alias of Object.keys(DECLARATION_ALIASES)) {\n if (!(alias in state)) {\n continue;\n }\n const canonical = DECLARATION_ALIASES[alias];\n if (canonical in state) {\n raiseError(\n `[wcs/declaration-alias] The state declares both \"${alias}\" and \"${canonical}\". ` +\n `\"${alias}\" is the old name of \"${canonical}\" (it works through 3.x) — keep \"${canonical}\".`,\n );\n }\n const owner = findOwner(state, alias);\n const descriptor = Object.getOwnPropertyDescriptor(owner, alias)!;\n Object.defineProperty(state, canonical, { ...descriptor, configurable: true });\n if (owner === state) {\n delete (state as Record<string, unknown>)[alias];\n }\n }\n normalizedStates.add(state);\n}\n"],"names":["DECLARATION_ALIASES","$updatedCallback","STATE_UPDATED_CALLBACK_NAME","$streams","STATE_STREAMS_NAME","normalizedStates","WeakSet","findOwner","value","key","owner","Object","prototype","hasOwnProperty","call","getPrototypeOf","normalizeDeclarationAliases","state","has","alias","keys","canonical","raiseError","descriptor","getOwnPropertyDescriptor","defineProperty","configurable","add"],"mappings":"uFAWO,MAAMA,EAAwD,CACnEC,iBAAkBC,EAClBC,SAAUC,GAINC,EAAmB,IAAIC,QAE7B,SAASC,EAAUC,EAAeC,GAChC,IAAIC,EAAuBF,EAC3B,KAAiB,OAAVE,IAAmBC,OAAOC,UAAUC,eAAeC,KAAKJ,EAAOD,IACpEC,EAAQC,OAAOI,eAAeL,GAEhC,OAAOA,CACT,CAMM,SAAUM,EAA4BC,GAC1C,IAAIZ,EAAiBa,IAAID,GAAzB,CAGA,IAAK,MAAME,KAASR,OAAOS,KAAKpB,GAAsB,CACpD,KAAMmB,KAASF,GACb,SAEF,MAAMI,EAAYrB,EAAoBmB,GAClCE,KAAaJ,GACfK,EACE,oDAAoDH,WAAeE,QAC/DF,0BAA8BE,qCAA6CA,OAGnF,MAAMX,EAAQH,EAAUU,EAAOE,GACzBI,EAAaZ,OAAOa,yBAAyBd,EAAOS,GAC1DR,OAAOc,eAAeR,EAAOI,EAAW,IAAKE,EAAYG,cAAc,IACnEhB,IAAUO,UACJA,EAAkCE,EAE9C,CACAd,EAAiBsB,IAAIV,EAnBrB,CAoBF"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{r as e,L as t,d as n}from"./errorGuidance.js";const
|
|
1
|
+
import{r as e,L as t,d as n}from"./errorGuidance.js";const o=Symbol.for("wcstack.ssr.snapshotBuilder");function a(){const e=document.documentElement;return!!e&&"orchestrated"===e.getAttribute("data-wcs-server")}function r(){const e=document.documentElement;return!!e&&e.hasAttribute("data-wcs-server")}const s={bindAttributeName:"data-wcs",commentTextPrefix:"wcs-text",commentForPrefix:"wcs-for",commentIfPrefix:"wcs-if",commentElseIfPrefix:"wcs-elseif",commentElsePrefix:"wcs-else",tagNames:{state:"wcs-state",ssr:"wcs-ssr"},locale:"en",debug:!1,enableMustache:!0,enableDirectionalInitialSync:!0,enablePropagationContext:!0,enableContractAnalyzer:!1,sameValueGuard:!0},i=s;function c(){return i}function l(e){e.tagNames&&Object.assign(s.tagNames,e.tagNames),"string"==typeof e.bindAttributeName&&(s.bindAttributeName=e.bindAttributeName),"string"==typeof e.commentTextPrefix&&(s.commentTextPrefix=e.commentTextPrefix),"string"==typeof e.commentForPrefix&&(s.commentForPrefix=e.commentForPrefix),"string"==typeof e.commentIfPrefix&&(s.commentIfPrefix=e.commentIfPrefix),"string"==typeof e.commentElseIfPrefix&&(s.commentElseIfPrefix=e.commentElseIfPrefix),"string"==typeof e.commentElsePrefix&&(s.commentElsePrefix=e.commentElsePrefix),"string"==typeof e.locale&&(s.locale=e.locale),"boolean"==typeof e.debug&&(s.debug=e.debug),"boolean"==typeof e.enableMustache&&(s.enableMustache=e.enableMustache),"boolean"==typeof e.enableDirectionalInitialSync&&(s.enableDirectionalInitialSync=e.enableDirectionalInitialSync),"boolean"==typeof e.enablePropagationContext&&(s.enablePropagationContext=e.enablePropagationContext),"boolean"==typeof e.enableContractAnalyzer&&(s.enableContractAnalyzer=e.enableContractAnalyzer),"boolean"==typeof e.sameValueGuard&&(s.sameValueGuard=e.sameValueGuard)}const f={not:()=>e=>!e},m={input:new Map,output:new Map},u={input:new Map,output:new Map},b={input:new Map,output:new Map},g=new Map;function p(e,t,n,o){const a=m[e],r=u[e];for(const e of Object.keys(t)){a.set(e,t[e]);const o=n?.[e];void 0===o?r.delete(e):r.set(e,o)}for(const t of Object.keys(o??{}))b[e].set(t,o[t]);g.clear()}function x(o,a,r,s=a){const i=`${o}${JSON.stringify(s)}:${r}`,c=g.get(i);if(void 0!==c)return c;const l=b[r].get(o)??o,p=m[r].get(l)??f[l];void 0===p&&e(`[wcs/filter-unknown] filter not found: ${o}.${n(o,function(e){return[...new Set([...Object.keys(f),...m[e].keys()])]}(r))}${t}`);const x=u[r].get(l);void 0!==x&&(a.length<x[0]||a.length>x[1])&&e(a.length<x[0]?`[wcs/filter-arity] filter "${o}" requires at least ${x[0]} argument(s) (${a.length} given).${t}`:`[wcs/filter-arity] filter "${o}" accepts at most ${x[1]} argument(s) (${a.length} given).${t}`);const d=p(a,s);return g.set(i,d),d}export{o as S,a,p as b,i as c,c as g,r as i,x as r,l as s};
|
|
2
2
|
//# sourceMappingURL=filterRegistry.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filterRegistry.js","sources":["../../../../../src/protocol/ssrSnapshot.ts","../../../../../src/config.ts","../../../../../src/core/filterRegistry.ts"],"sourcesContent":["// ===========================================================================\n// AUTO-GENERATED FILE - DO NOT EDIT.\n// Generated from /protocol/ssr-snapshot.ts by scripts/sync-protocol-types.mjs.\n// Run `node scripts/sync-protocol-types.mjs` after editing the source.\n// ===========================================================================\n\n// ssr-snapshot protocol — how the SSR renderer asks whoever owns reactive\n// state to build hydration snapshots (<wcs-ssr>) as a final pass, after every\n// DOM inserter (router route content, late custom elements) has settled.\n//\n// Without this, the snapshot is built inside <wcs-state>'s connectedCallback\n// and races DOM inserted by other packages: whether a route's structural\n// templates make it into the snapshot depends on document order and state's\n// load mechanism (docs/ssr-router-design.md §5).\n//\n// The provider (@wcstack/state) installs itself on a well-known global symbol\n// at bootstrap. The renderer (@wcstack/server) looks the builder up after\n// running bootstraps: if present it announces orchestration by setting\n// `data-wcs-server=\"orchestrated\"` on the document element BEFORE parsing, and\n// calls build() right before serialization. The provider keeps its inline\n// per-element fallback whenever the attribute value is anything else, so:\n// - old renderer + new provider -> inline build, yesterday's behavior\n// - new renderer + old provider -> no builder found, attribute stays \"\",\n// the old provider builds inline as before\n// - new renderer + new provider -> orchestrated: snapshots are built last\n// and therefore always see settled DOM\n//\n// The symbol (rather than a package import) also pins the builder to the state\n// copy that actually runs on the page — its module-scoped fragment registries\n// are the ones the snapshot must read.\n//\n// SINGLE SOURCE OF TRUTH: edit only this file (/protocol/ssr-snapshot.ts), then\n// run `node scripts/sync-protocol-types.mjs` to regenerate the per-package\n// copies (packages/<pkg>/src/protocol/ssrSnapshot.ts). Those copies are\n// generated — do not edit them.\n\n/**\n * Global key the snapshot builder installs itself under. `Symbol.for` so\n * independently loaded copies of this file (state's and server's) still agree.\n */\nexport const SSR_SNAPSHOT_BUILDER_KEY = Symbol.for(\"wcstack.ssr.snapshotBuilder\");\n\n/**\n * `data-wcs-server` attribute value announcing that the renderer will call the\n * builder as a final pass. Providers must skip their inline per-element build\n * when they see this value, and keep it for any other value (including \"\").\n */\nexport const SSR_ORCHESTRATED_VALUE = \"orchestrated\";\n\nexport interface IWcsSsrSnapshotBuilder {\n readonly protocol: \"wcs-ssr-snapshot\";\n /** Integer protocol version. All versions >= 1 are participant-compatible. */\n readonly version: number;\n /**\n * Build a hydration snapshot for every enable-ssr state element in `root`\n * that does not already have one. Called once per render, after all\n * waiting-protocol elements have settled and bindings are ready. Must be\n * idempotent with respect to already-snapshotted elements.\n */\n build(root: Document): void;\n}\n\n/**\n * The installed builder, or null when there is none or it speaks a shape this\n * reader does not.\n */\nexport function getSsrSnapshotBuilder(): IWcsSsrSnapshotBuilder | null {\n const candidate = (globalThis as Record<symbol, unknown>)[\n SSR_SNAPSHOT_BUILDER_KEY\n ] as IWcsSsrSnapshotBuilder | undefined;\n if (candidate === undefined || candidate === null) return null;\n if (candidate.protocol !== \"wcs-ssr-snapshot\") return null;\n if (typeof candidate.version !== \"number\" || candidate.version < 1) return null;\n if (typeof candidate.build !== \"function\") return null;\n return candidate;\n}\n","import { IConfig, IWritableConfig } from \"./types.js\";\nimport { SSR_ORCHESTRATED_VALUE } from \"./protocol/ssrSnapshot.js\";\n\n/**\n * サーバー主導スナップショット(orchestrated)の判定\n * (docs/ssr-router-design.md §5)。renderToString が snapshot builder を\n * 見つけたときだけ `data-wcs-server=\"orchestrated\"` を宣言する — 値が他の\n * もの(旧 server の \"\" を含む)なら inline 生成が従来どおり働く。\n * inSsr と同じ理由でキャッシュしない。\n */\nexport function isOrchestratedSsr(): boolean {\n const html = document.documentElement;\n return html ? html.getAttribute('data-wcs-server') === SSR_ORCHESTRATED_VALUE : false;\n}\n\nexport function inSsr(): boolean {\n // キャッシュしない: SSR モードはプロセスの属性ではなく「現在の document」の\n // 属性。@wcstack/server はグローバル document を差し替えてサーバーレンダリング\n // した後、同一プロセスでクライアント側ハイドレーションが走る(SSR→hydrate の\n // e2e が該当)。サーバーフェーズの判定をキャッシュするとクライアントフェーズが\n // SSR モード扱いになり、hydrateBindings の代わりに buildBindings が選ばれて\n // connectedCallbackPromise が永久に未解決になる。\n const html = document.documentElement;\n return html ? html.hasAttribute('data-wcs-server') : false;\n}\n\ninterface IInternalConfig {\n bindAttributeName: string;\n commentTextPrefix: string;\n commentForPrefix: string;\n commentIfPrefix: string;\n commentElseIfPrefix: string;\n commentElsePrefix: string;\n tagNames: {\n state: string;\n ssr: string;\n };\n locale: string;\n debug: boolean;\n enableMustache: boolean;\n enableDirectionalInitialSync: boolean;\n enablePropagationContext: boolean;\n enableContractAnalyzer: boolean;\n sameValueGuard: boolean;\n}\n\nconst _config: IInternalConfig = {\n bindAttributeName: 'data-wcs',\n commentTextPrefix: 'wcs-text',\n commentForPrefix: 'wcs-for',\n commentIfPrefix: 'wcs-if',\n commentElseIfPrefix: 'wcs-elseif',\n commentElsePrefix: 'wcs-else',\n tagNames: {\n state: 'wcs-state',\n ssr: 'wcs-ssr',\n },\n locale: 'en',\n debug: false,\n enableMustache: true,\n enableDirectionalInitialSync: true,\n enablePropagationContext: true,\n // Phase 5b の dev-time contract analyzer は意図的に explicit opt-in(既定 off)。\n // wcstack は buildless / zero-config で NODE_ENV 相当の確実な dev/prod 判定が無く、\n // hostname や minification の heuristic で auto-ON すると誤検出で prod にコストを\n // 乗せうるため、dev 既定 ON は採らない。利用側が setConfig で明示有効化する\n // (docs/architecture-hardening/10-defaulting-rollout-status.md §C)。\n enableContractAnalyzer: false,\n sameValueGuard: true,\n};\n\n// backward compatible export (read-only usage)\nexport const config: IConfig = _config as IConfig;\n\nexport function getConfig(): IConfig {\n return config;\n}\n\nexport function setConfig(partialConfig: IWritableConfig): void {\n if (partialConfig.tagNames) {\n Object.assign(_config.tagNames, partialConfig.tagNames);\n }\n if (typeof partialConfig.bindAttributeName === \"string\") {\n _config.bindAttributeName = partialConfig.bindAttributeName;\n }\n if (typeof partialConfig.commentTextPrefix === \"string\") {\n _config.commentTextPrefix = partialConfig.commentTextPrefix;\n }\n if (typeof partialConfig.commentForPrefix === \"string\") {\n _config.commentForPrefix = partialConfig.commentForPrefix;\n }\n if (typeof partialConfig.commentIfPrefix === \"string\") {\n _config.commentIfPrefix = partialConfig.commentIfPrefix;\n }\n if (typeof partialConfig.commentElseIfPrefix === \"string\") {\n _config.commentElseIfPrefix = partialConfig.commentElseIfPrefix;\n }\n if (typeof partialConfig.commentElsePrefix === \"string\") {\n _config.commentElsePrefix = partialConfig.commentElsePrefix;\n }\n if (typeof partialConfig.locale === \"string\") {\n _config.locale = partialConfig.locale;\n }\n if (typeof partialConfig.debug === \"boolean\") {\n _config.debug = partialConfig.debug;\n }\n if (typeof partialConfig.enableMustache === \"boolean\") {\n _config.enableMustache = partialConfig.enableMustache;\n }\n if (typeof partialConfig.enableDirectionalInitialSync === \"boolean\") {\n _config.enableDirectionalInitialSync = partialConfig.enableDirectionalInitialSync;\n }\n if (typeof partialConfig.enablePropagationContext === \"boolean\") {\n _config.enablePropagationContext = partialConfig.enablePropagationContext;\n }\n if (typeof partialConfig.enableContractAnalyzer === \"boolean\") {\n _config.enableContractAnalyzer = partialConfig.enableContractAnalyzer;\n }\n if (typeof partialConfig.sameValueGuard === \"boolean\") {\n _config.sameValueGuard = partialConfig.sameValueGuard;\n }\n}\n","/**\n * core/filterRegistry.ts — フィルタ実関数の登録簿(設計案 §4、要件 D16)。\n *\n * 文法(`path|filter(args)` の解析)は core に残り、**実関数は登録簿から束縛計画の段で引く**。\n * 解析の段は名前と引数しか作らない(`bindTextParser/parseFilters.ts`)ので、パーサだけを使う\n * tooling(`@wcstack/state/parser`)はフィルタの実装を 1 バイトも引き込まない。\n *\n * 書式フィルタ群(`uc` / `date` / `round` …)は `features/formats` が install で登録する。\n * core が自前で持つのは、エンジン自身が差し込む `not` だけ(`if` / `else` の反転 —\n * structural/notFilter.ts)。未知のフィルタは束縛計画の段で名指しで落ちる(従来は解析時)。\n */\nimport { didYouMean, LINT_HINT } from \"../errorGuidance\";\nimport type { FilterFn, FilterIOType, FilterWithOptions } from \"../filters/types\";\nimport { raiseError } from \"../raiseError\";\n\n/** `options` を受け取って実関数を返す工場(`filters/types.ts` の `FilterWithOptions` の要素) */\nexport type FilterFactory = (options?: string[], literals?: readonly unknown[]) => FilterFn;\n\n/**\n * エンジン自身が差し込むフィルタ。`if` / `else` の分岐は `not` を付けた束縛として組み立てられる\n * ので、`features/formats` の無いページでも必ず要る。\n */\nconst CORE_FILTERS: Record<string, FilterFactory> = {\n not: () => (value: unknown): boolean => !value,\n};\n\nconst registries: Record<FilterIOType, Map<string, FilterFactory>> = {\n input: new Map<string, FilterFactory>(),\n output: new Map<string, FilterFactory>(),\n};\n\n/** 受け付ける引数の個数 [最少, 最多]。登録した機能が渡したものだけ(要件 B3) */\nconst aritiesByIOType: Record<FilterIOType, Map<string, readonly [number, number]>> = {\n input: new Map<string, readonly [number, number]>(),\n output: new Map<string, readonly [number, number]>(),\n};\n\n/** 名前 + 引数 + 入出力ごとに解決済みの実関数(解決は 1 回だけ) */\nconst resolvedByKey = new Map<string, FilterFn>();\n\n/** 機能の install が呼ぶ(冪等 — 同じ名前は置き換え)。hot path には触れない */\nexport function registerFilters(\n filterIOType: FilterIOType,\n filters: FilterWithOptions,\n arity?: Readonly<Record<string, readonly [number, number]>>,\n): void {\n const registry = registries[filterIOType];\n const arities = aritiesByIOType[filterIOType];\n for (const name of Object.keys(filters)) {\n registry.set(name, filters[name] as FilterFactory);\n const bounds = arity?.[name];\n if (typeof bounds === \"undefined\") {\n arities.delete(name);\n } else {\n arities.set(name, bounds);\n }\n }\n // 登録が変われば解決済みの答えも変わりうる(同じページで 2 回 install することは無いが、\n // テストと tooling は登録簿を入れ替える)\n resolvedByKey.clear();\n}\n\n/** 登録済みの名前(core のものを含む)。診断の did-you-mean が読む */\nexport function knownFilterNames(filterIOType: FilterIOType): string[] {\n return [...new Set([...Object.keys(CORE_FILTERS), ...registries[filterIOType].keys()])];\n}\n\n/** 解決済みの答えを捨てる(tooling: `@wcstack/state/parser` の clearParserCaches) */\nexport function clearFilterResolutionCache(): void {\n resolvedByKey.clear();\n}\n\n/**\n * 実関数を引く(束縛計画の段)。未知のフィルタはここで落ちる — 解析の段では落とさない。\n * 文言は lint の `wcs/filter-unknown` と同じ語彙・同じ did-you-mean 規準(三面同語彙)。\n */\nexport function resolveFilterFn(\n filterName: string,\n args: string[],\n filterIOType: FilterIOType,\n literals: readonly unknown[] = args,\n): FilterFn {\n // 引数は型付きの値の構造のまま鍵にする(`join('a,b')` と `join(a,b)` — 要件 B3、`eq(1)` と\n // `eq('1')` — 要件 B9 を取り違えない)\n const key = `${filterName}${JSON.stringify(literals)}:${filterIOType}`;\n const resolved = resolvedByKey.get(key);\n if (typeof resolved !== \"undefined\") {\n return resolved;\n }\n const factory = registries[filterIOType].get(filterName) ?? CORE_FILTERS[filterName];\n if (typeof factory === \"undefined\") {\n raiseError(`[wcs/filter-unknown] filter not found: ${filterName}.${didYouMean(filterName, knownFilterNames(filterIOType))}${LINT_HINT}`);\n }\n const bounds = aritiesByIOType[filterIOType].get(filterName);\n if (typeof bounds !== \"undefined\" && (args.length < bounds[0] || args.length > bounds[1])) {\n // lint の wcs/filter-arity と同じ語彙\n raiseError(args.length < bounds[0]\n ? `[wcs/filter-arity] filter \"${filterName}\" requires at least ${bounds[0]} argument(s) (${args.length} given).${LINT_HINT}`\n : `[wcs/filter-arity] filter \"${filterName}\" accepts at most ${bounds[1]} argument(s) (${args.length} given).${LINT_HINT}`);\n }\n const filterFn = factory(args, literals);\n resolvedByKey.set(key, filterFn);\n return filterFn;\n}\n"],"names":["SSR_SNAPSHOT_BUILDER_KEY","Symbol","for","isOrchestratedSsr","html","document","documentElement","getAttribute","inSsr","hasAttribute","_config","bindAttributeName","commentTextPrefix","commentForPrefix","commentIfPrefix","commentElseIfPrefix","commentElsePrefix","tagNames","state","ssr","locale","debug","enableMustache","enableDirectionalInitialSync","enablePropagationContext","enableContractAnalyzer","sameValueGuard","config","getConfig","setConfig","partialConfig","Object","assign","CORE_FILTERS","not","value","registries","input","Map","output","aritiesByIOType","resolvedByKey","registerFilters","filterIOType","filters","arity","registry","arities","name","keys","set","bounds","delete","clear","resolveFilterFn","filterName","args","literals","key","JSON","stringify","resolved","get","factory","raiseError","didYouMean","Set","knownFilterNames","LINT_HINT","length","filterFn"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"filterRegistry.js","sources":["../../../../../src/protocol/ssrSnapshot.ts","../../../../../src/config.ts","../../../../../src/core/filterRegistry.ts"],"sourcesContent":["// ===========================================================================\n// AUTO-GENERATED FILE - DO NOT EDIT.\n// Generated from /protocol/ssr-snapshot.ts by scripts/sync-protocol-types.mjs.\n// Run `node scripts/sync-protocol-types.mjs` after editing the source.\n// ===========================================================================\n\n// ssr-snapshot protocol — how the SSR renderer asks whoever owns reactive\n// state to build hydration snapshots (<wcs-ssr>) as a final pass, after every\n// DOM inserter (router route content, late custom elements) has settled.\n//\n// Without this, the snapshot is built inside <wcs-state>'s connectedCallback\n// and races DOM inserted by other packages: whether a route's structural\n// templates make it into the snapshot depends on document order and state's\n// load mechanism (docs/ssr-router-design.md §5).\n//\n// The provider (@wcstack/state) installs itself on a well-known global symbol\n// at bootstrap. The renderer (@wcstack/server) looks the builder up after\n// running bootstraps: if present it announces orchestration by setting\n// `data-wcs-server=\"orchestrated\"` on the document element BEFORE parsing, and\n// calls build() right before serialization. The provider keeps its inline\n// per-element fallback whenever the attribute value is anything else, so:\n// - old renderer + new provider -> inline build, yesterday's behavior\n// - new renderer + old provider -> no builder found, attribute stays \"\",\n// the old provider builds inline as before\n// - new renderer + new provider -> orchestrated: snapshots are built last\n// and therefore always see settled DOM\n//\n// The symbol (rather than a package import) also pins the builder to the state\n// copy that actually runs on the page — its module-scoped fragment registries\n// are the ones the snapshot must read.\n//\n// SINGLE SOURCE OF TRUTH: edit only this file (/protocol/ssr-snapshot.ts), then\n// run `node scripts/sync-protocol-types.mjs` to regenerate the per-package\n// copies (packages/<pkg>/src/protocol/ssrSnapshot.ts). Those copies are\n// generated — do not edit them.\n\n/**\n * Global key the snapshot builder installs itself under. `Symbol.for` so\n * independently loaded copies of this file (state's and server's) still agree.\n */\nexport const SSR_SNAPSHOT_BUILDER_KEY = Symbol.for(\"wcstack.ssr.snapshotBuilder\");\n\n/**\n * `data-wcs-server` attribute value announcing that the renderer will call the\n * builder as a final pass. Providers must skip their inline per-element build\n * when they see this value, and keep it for any other value (including \"\").\n */\nexport const SSR_ORCHESTRATED_VALUE = \"orchestrated\";\n\nexport interface IWcsSsrSnapshotBuilder {\n readonly protocol: \"wcs-ssr-snapshot\";\n /** Integer protocol version. All versions >= 1 are participant-compatible. */\n readonly version: number;\n /**\n * Build a hydration snapshot for every enable-ssr state element in `root`\n * that does not already have one. Called once per render, after all\n * waiting-protocol elements have settled and bindings are ready. Must be\n * idempotent with respect to already-snapshotted elements.\n */\n build(root: Document): void;\n}\n\n/**\n * The installed builder, or null when there is none or it speaks a shape this\n * reader does not.\n */\nexport function getSsrSnapshotBuilder(): IWcsSsrSnapshotBuilder | null {\n const candidate = (globalThis as Record<symbol, unknown>)[\n SSR_SNAPSHOT_BUILDER_KEY\n ] as IWcsSsrSnapshotBuilder | undefined;\n if (candidate === undefined || candidate === null) return null;\n if (candidate.protocol !== \"wcs-ssr-snapshot\") return null;\n if (typeof candidate.version !== \"number\" || candidate.version < 1) return null;\n if (typeof candidate.build !== \"function\") return null;\n return candidate;\n}\n","import { IConfig, IWritableConfig } from \"./types.js\";\nimport { SSR_ORCHESTRATED_VALUE } from \"./protocol/ssrSnapshot.js\";\n\n/**\n * サーバー主導スナップショット(orchestrated)の判定\n * (docs/ssr-router-design.md §5)。renderToString が snapshot builder を\n * 見つけたときだけ `data-wcs-server=\"orchestrated\"` を宣言する — 値が他の\n * もの(旧 server の \"\" を含む)なら inline 生成が従来どおり働く。\n * inSsr と同じ理由でキャッシュしない。\n */\nexport function isOrchestratedSsr(): boolean {\n const html = document.documentElement;\n return html ? html.getAttribute('data-wcs-server') === SSR_ORCHESTRATED_VALUE : false;\n}\n\nexport function inSsr(): boolean {\n // キャッシュしない: SSR モードはプロセスの属性ではなく「現在の document」の\n // 属性。@wcstack/server はグローバル document を差し替えてサーバーレンダリング\n // した後、同一プロセスでクライアント側ハイドレーションが走る(SSR→hydrate の\n // e2e が該当)。サーバーフェーズの判定をキャッシュするとクライアントフェーズが\n // SSR モード扱いになり、hydrateBindings の代わりに buildBindings が選ばれて\n // connectedCallbackPromise が永久に未解決になる。\n const html = document.documentElement;\n return html ? html.hasAttribute('data-wcs-server') : false;\n}\n\ninterface IInternalConfig {\n bindAttributeName: string;\n commentTextPrefix: string;\n commentForPrefix: string;\n commentIfPrefix: string;\n commentElseIfPrefix: string;\n commentElsePrefix: string;\n tagNames: {\n state: string;\n ssr: string;\n };\n locale: string;\n debug: boolean;\n enableMustache: boolean;\n enableDirectionalInitialSync: boolean;\n enablePropagationContext: boolean;\n enableContractAnalyzer: boolean;\n sameValueGuard: boolean;\n}\n\nconst _config: IInternalConfig = {\n bindAttributeName: 'data-wcs',\n commentTextPrefix: 'wcs-text',\n commentForPrefix: 'wcs-for',\n commentIfPrefix: 'wcs-if',\n commentElseIfPrefix: 'wcs-elseif',\n commentElsePrefix: 'wcs-else',\n tagNames: {\n state: 'wcs-state',\n ssr: 'wcs-ssr',\n },\n locale: 'en',\n debug: false,\n enableMustache: true,\n enableDirectionalInitialSync: true,\n enablePropagationContext: true,\n // Phase 5b の dev-time contract analyzer は意図的に explicit opt-in(既定 off)。\n // wcstack は buildless / zero-config で NODE_ENV 相当の確実な dev/prod 判定が無く、\n // hostname や minification の heuristic で auto-ON すると誤検出で prod にコストを\n // 乗せうるため、dev 既定 ON は採らない。利用側が setConfig で明示有効化する\n // (docs/architecture-hardening/10-defaulting-rollout-status.md §C)。\n enableContractAnalyzer: false,\n sameValueGuard: true,\n};\n\n// backward compatible export (read-only usage)\nexport const config: IConfig = _config as IConfig;\n\nexport function getConfig(): IConfig {\n return config;\n}\n\nexport function setConfig(partialConfig: IWritableConfig): void {\n if (partialConfig.tagNames) {\n Object.assign(_config.tagNames, partialConfig.tagNames);\n }\n if (typeof partialConfig.bindAttributeName === \"string\") {\n _config.bindAttributeName = partialConfig.bindAttributeName;\n }\n if (typeof partialConfig.commentTextPrefix === \"string\") {\n _config.commentTextPrefix = partialConfig.commentTextPrefix;\n }\n if (typeof partialConfig.commentForPrefix === \"string\") {\n _config.commentForPrefix = partialConfig.commentForPrefix;\n }\n if (typeof partialConfig.commentIfPrefix === \"string\") {\n _config.commentIfPrefix = partialConfig.commentIfPrefix;\n }\n if (typeof partialConfig.commentElseIfPrefix === \"string\") {\n _config.commentElseIfPrefix = partialConfig.commentElseIfPrefix;\n }\n if (typeof partialConfig.commentElsePrefix === \"string\") {\n _config.commentElsePrefix = partialConfig.commentElsePrefix;\n }\n if (typeof partialConfig.locale === \"string\") {\n _config.locale = partialConfig.locale;\n }\n if (typeof partialConfig.debug === \"boolean\") {\n _config.debug = partialConfig.debug;\n }\n if (typeof partialConfig.enableMustache === \"boolean\") {\n _config.enableMustache = partialConfig.enableMustache;\n }\n if (typeof partialConfig.enableDirectionalInitialSync === \"boolean\") {\n _config.enableDirectionalInitialSync = partialConfig.enableDirectionalInitialSync;\n }\n if (typeof partialConfig.enablePropagationContext === \"boolean\") {\n _config.enablePropagationContext = partialConfig.enablePropagationContext;\n }\n if (typeof partialConfig.enableContractAnalyzer === \"boolean\") {\n _config.enableContractAnalyzer = partialConfig.enableContractAnalyzer;\n }\n if (typeof partialConfig.sameValueGuard === \"boolean\") {\n _config.sameValueGuard = partialConfig.sameValueGuard;\n }\n}\n","/**\n * core/filterRegistry.ts — フィルタ実関数の登録簿(設計案 §4、要件 D16)。\n *\n * 文法(`path|filter(args)` の解析)は core に残り、**実関数は登録簿から束縛計画の段で引く**。\n * 解析の段は名前と引数しか作らない(`bindTextParser/parseFilters.ts`)ので、パーサだけを使う\n * tooling(`@wcstack/state/parser`)はフィルタの実装を 1 バイトも引き込まない。\n *\n * 書式フィルタ群(`uc` / `date` / `round` …)は `features/formats` が install で登録する。\n * core が自前で持つのは、エンジン自身が差し込む `not` だけ(`if` / `else` の反転 —\n * structural/notFilter.ts)。未知のフィルタは束縛計画の段で名指しで落ちる(従来は解析時)。\n */\nimport { didYouMean, LINT_HINT } from \"../errorGuidance\";\nimport type { FilterFn, FilterIOType, FilterWithOptions } from \"../filters/types\";\nimport { raiseError } from \"../raiseError\";\n\n/** `options` を受け取って実関数を返す工場(`filters/types.ts` の `FilterWithOptions` の要素) */\nexport type FilterFactory = (options?: string[], literals?: readonly unknown[]) => FilterFn;\n\n/**\n * エンジン自身が差し込むフィルタ。`if` / `else` の分岐は `not` を付けた束縛として組み立てられる\n * ので、`features/formats` の無いページでも必ず要る。\n */\nconst CORE_FILTERS: Record<string, FilterFactory> = {\n not: () => (value: unknown): boolean => !value,\n};\n\nconst registries: Record<FilterIOType, Map<string, FilterFactory>> = {\n input: new Map<string, FilterFactory>(),\n output: new Map<string, FilterFactory>(),\n};\n\n/** 受け付ける引数の個数 [最少, 最多]。登録した機能が渡したものだけ(要件 B3) */\nconst aritiesByIOType: Record<FilterIOType, Map<string, readonly [number, number]>> = {\n input: new Map<string, readonly [number, number]>(),\n output: new Map<string, readonly [number, number]>(),\n};\n\n/** 旧名 → 正式名(要件 B12)。解決・引数の個数は正式名で引く。登録した機能が渡したものだけ */\nconst aliasesByIOType: Record<FilterIOType, Map<string, string>> = {\n input: new Map<string, string>(),\n output: new Map<string, string>(),\n};\n\n/** 名前 + 引数 + 入出力ごとに解決済みの実関数(解決は 1 回だけ) */\nconst resolvedByKey = new Map<string, FilterFn>();\n\n/** 機能の install が呼ぶ(冪等 — 同じ名前は置き換え)。hot path には触れない */\nexport function registerFilters(\n filterIOType: FilterIOType,\n filters: FilterWithOptions,\n arity?: Readonly<Record<string, readonly [number, number]>>,\n aliases?: Readonly<Record<string, string>>,\n): void {\n const registry = registries[filterIOType];\n const arities = aritiesByIOType[filterIOType];\n for (const name of Object.keys(filters)) {\n registry.set(name, filters[name] as FilterFactory);\n const bounds = arity?.[name];\n if (typeof bounds === \"undefined\") {\n arities.delete(name);\n } else {\n arities.set(name, bounds);\n }\n }\n for (const alias of Object.keys(aliases ?? {})) {\n aliasesByIOType[filterIOType].set(alias, aliases![alias]);\n }\n // 登録が変われば解決済みの答えも変わりうる(同じページで 2 回 install することは無いが、\n // テストと tooling は登録簿を入れ替える)\n resolvedByKey.clear();\n}\n\n/** 登録済みの名前(core のものを含む)。診断の did-you-mean が読む */\nexport function knownFilterNames(filterIOType: FilterIOType): string[] {\n return [...new Set([...Object.keys(CORE_FILTERS), ...registries[filterIOType].keys()])];\n}\n\n/** 解決済みの答えを捨てる(tooling: `@wcstack/state/parser` の clearParserCaches) */\nexport function clearFilterResolutionCache(): void {\n resolvedByKey.clear();\n}\n\n/**\n * 実関数を引く(束縛計画の段)。未知のフィルタはここで落ちる — 解析の段では落とさない。\n * 文言は lint の `wcs/filter-unknown` と同じ語彙・同じ did-you-mean 規準(三面同語彙)。\n */\nexport function resolveFilterFn(\n filterName: string,\n args: string[],\n filterIOType: FilterIOType,\n literals: readonly unknown[] = args,\n): FilterFn {\n // 引数は型付きの値の構造のまま鍵にする(`join('a,b')` と `join(a,b)` — 要件 B3、`eq(1)` と\n // `eq('1')` — 要件 B9 を取り違えない)\n const key = `${filterName}${JSON.stringify(literals)}:${filterIOType}`;\n const resolved = resolvedByKey.get(key);\n if (typeof resolved !== \"undefined\") {\n return resolved;\n }\n // 旧名(`uc` / `fix` …)は正式名で引く — 3.x の間のエイリアス(要件 B12、4.0 で外す)\n const canonical = aliasesByIOType[filterIOType].get(filterName) ?? filterName;\n const factory = registries[filterIOType].get(canonical) ?? CORE_FILTERS[canonical];\n if (typeof factory === \"undefined\") {\n raiseError(`[wcs/filter-unknown] filter not found: ${filterName}.${didYouMean(filterName, knownFilterNames(filterIOType))}${LINT_HINT}`);\n }\n const bounds = aritiesByIOType[filterIOType].get(canonical);\n if (typeof bounds !== \"undefined\" && (args.length < bounds[0] || args.length > bounds[1])) {\n // lint の wcs/filter-arity と同じ語彙\n raiseError(args.length < bounds[0]\n ? `[wcs/filter-arity] filter \"${filterName}\" requires at least ${bounds[0]} argument(s) (${args.length} given).${LINT_HINT}`\n : `[wcs/filter-arity] filter \"${filterName}\" accepts at most ${bounds[1]} argument(s) (${args.length} given).${LINT_HINT}`);\n }\n const filterFn = factory(args, literals);\n resolvedByKey.set(key, filterFn);\n return filterFn;\n}\n"],"names":["SSR_SNAPSHOT_BUILDER_KEY","Symbol","for","isOrchestratedSsr","html","document","documentElement","getAttribute","inSsr","hasAttribute","_config","bindAttributeName","commentTextPrefix","commentForPrefix","commentIfPrefix","commentElseIfPrefix","commentElsePrefix","tagNames","state","ssr","locale","debug","enableMustache","enableDirectionalInitialSync","enablePropagationContext","enableContractAnalyzer","sameValueGuard","config","getConfig","setConfig","partialConfig","Object","assign","CORE_FILTERS","not","value","registries","input","Map","output","aritiesByIOType","aliasesByIOType","resolvedByKey","registerFilters","filterIOType","filters","arity","aliases","registry","arities","name","keys","set","bounds","delete","alias","clear","resolveFilterFn","filterName","args","literals","key","JSON","stringify","resolved","get","canonical","factory","raiseError","didYouMean","Set","knownFilterNames","LINT_HINT","length","filterFn"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{D as t,j as e,g as n,W as r,R as
|
|
1
|
+
import{D as t,j as e,g as n,W as r,a as o,o as s,R as a}from"./pathDiagnostics.js";import{aS as i}from"./binder.js";import{n as c}from"./declarationAliases.js";import{r as l}from"./errorGuidance.js";function u(t,e){if(e.length>t.length)return!1;for(let n=0;n<e.length;n++)if(t[n]!==e[n])return!1;return!0}function d(t,e){for(const n of t)if(u(e,n.innerSegments))return n;return null}function f(e,n){const r=n.slice(e.innerSegments.length);return 0===r.length?e.outerPathInfo.path:e.outerPathInfo.path+t+r.join(t)}let h=0;const m=["$watch",o,"$scan","$listKeys",s,"$commandTokens","$eventTokens","$on","$recursion","$errorCallback"],p=new Set;function g(t){const e=m.filter(e=>void 0!==t.stateObject[e]);for(const n of t.getterKeys)-1!==n.indexOf(a)&&e.push(`"${n}"`);if(0===e.length)return;const n=`${t.component.tagName.toLowerCase()}|${t.stateProp}`;p.has(n)||(p.add(n),console.warn(`[@wcstack/state] [wcs/mount-dollar-declaration] <${n.split("|")[0]}>.${t.stateProp} declares ${e.join(", ")}, which mounted components do not run. Declare them on the root state instead (a volume <wcs-state mount="..."> can host $watch / $listKeys / $updatedCallback; $recursion and "**" getters expand against the root tree). See docs/state-mount-design.md §4-6.`))}function y(t,e){const n=t.stateObject[e];if("function"==typeof n)try{const r=t.component[t.stateProp],o=n.call(r);o instanceof Promise&&o.catch(n=>{console.error(`[@wcstack/state] mounted <${t.component.tagName.toLowerCase()}> ${e} failed.`,n)})}catch(n){console.error(`[@wcstack/state] mounted <${t.component.tagName.toLowerCase()}> ${e} failed.`,n)}}function w(n,r,o,s,a,i=new Set){0===o.length&&l(`Cannot build a mount record without host bindings for "${r}".`),c(a);const u=[],d=new Set;let f=null;for(const n of o){const r=n.propSegments.slice(1),o=r.join(t);d.has(o)&&l("Duplicate mapping rule for web component."),d.add(o);const s={innerSegments:r,outerPathInfo:n.statePathInfo,readonly:!0===n.propModifiers?.includes(e)};u.push(s),0===r.length&&(f=s)}u.sort((t,e)=>e.innerSegments.length-t.innerSegments.length);const m=++h,p=`#m${m}`,{getterKeys:g,setterKeys:y}=function(t){const e=new Set,n=new Set,r=Object.getOwnPropertyDescriptors(t);for(const[t,o]of Object.entries(r))"function"==typeof o.get&&e.add(t),"function"==typeof o.set&&n.add(t);return{getterKeys:e,setterKeys:n}}(a),w=new Set;for(const t of u)t.innerSegments.length>0&&w.add(t.innerSegments[0]);const $={};for(const t of Object.keys(a))t.startsWith("$")||g.has(t)||y.has(t)||"function"!=typeof a[t]&&(i.has(t)||w.has(t)||($[t]=a[t]));return{id:m,marker:p,component:n,stateProp:r,parentStateElement:s,entries:u,rootEntry:f,delta:null===f?0:f.outerPathInfo.wildcardCount,markerBasePath:null===f?p:f.outerPathInfo.path+t+p,stateObject:a,getterKeys:g,setterKeys:y,injectedKeys:i,mappedKeys:w,privateSnapshot:$,accessorBySuffixByMarkerParent:new Map,indexShiftByLoopElementPath:new Map,addedGetterPaths:new Set,exports:new Map}}function $(e){const n=e.indexOf(t);return-1===n?e:e.slice(0,n)}function P(t,e){const n=d(t.entries,e);return null===n?null:f(n,e)}function k(e,n){return e.markerBasePath+t+n}function S(e,r,o,s){let a=e.accessorBySuffixByMarkerParent.get(r);void 0===a&&(a=new Map,e.accessorBySuffixByMarkerParent.set(r,a));const i=r+t+o;a.set(o,{accessorName:s,indexShift:n(i).wildcardCount-n(s).wildcardCount}),e.getterKeys.has(s)&&(e.parentStateElement.getterPaths?.add(i),e.addedGetterPaths.add(i))}function v(t,e){return!t.injectedKeys.has(e)&&!t.mappedKeys.has(e)&&("function"==typeof t.stateObject[e]&&!t.getterKeys.has(e)||Object.prototype.hasOwnProperty.call(t.stateObject,e)&&!t.getterKeys.has(e)&&!t.setterKeys.has(e))}function j(e,n){return`Path "${n}" in <${e.component.tagName.toLowerCase()}> does not resolve: it is not an own key of the component state and no mount entry covers it (mounted prefixes: ${e.entries.filter(t=>t.innerSegments.length>0).map(e=>e.innerSegments.join(t)).join(", ")}). Mount it from the host ("${e.stateProp}: path" / "${e.stateProp}.${$(n)}: path") or declare the key on the component state.`}const K=/^\$(\d+)$/;function b(e,n){const r=n[0];if("$"===r||"#"===r)return null;if(e.getterKeys.has(n)||e.setterKeys.has(n))return null;const o=$(n);if(e.getterKeys.has(o)||e.setterKeys.has(o)||v(e,o))return null;const s=function(t,e){return d(t.entries,e)}(e,n.split(t));return null!==s&&s.readonly?s:null}function x(n,r){const o=b(n,r);if(null!==o){const s=0===o.innerSegments.length?"":t+o.innerSegments.join(t);l(`[wcs/mount-readonly] <${n.component.tagName.toLowerCase()}> cannot write "${r}": it is mounted read-only ("${n.stateProp}${s}#${e}: ${o.outerPathInfo.path}"). Write it on the host, or drop #${e} from the mount.`)}return M(n,r)}function M(e,n){const o=n[0];if("$"===o||"#"===o)return n;if(e.getterKeys.has(n)||e.setterKeys.has(n))return function(e,n){const o=n.split(t);let s=-1;for(let t=o.length-1;t>=0;t--)if(o[t]===r){s=t;break}if(-1===s)return S(e,e.markerBasePath,n,n),k(e,n);if(v(e,o[0]))return S(e,e.markerBasePath,n,n),k(e,n);const a=o.slice(0,s+1),i=o.slice(s+1),c=P(e,a);null===c&&l(j(e,n)),0===i.length&&l(`Wildcard-terminal accessor "${n}" on mounted <${e.component.tagName.toLowerCase()}> is not supported: it translates to a marker-terminal path where the mount overlay would shadow the accessor. Declare the row value as a getter on the host tree, or back it with a component-own array (a private key makes the whole path private).`);const u=c+t+e.marker;return S(e,u,i.join(t),n),u+t+i.join(t)}(e,n);const s=$(n);if(e.getterKeys.has(s)||e.setterKeys.has(s))return k(e,n);if(v(e,s))return k(e,n);const a=P(e,n.split(t));if(null!==a)return a;l(j(e,n))}function C(o,s,a){let i;const c=K.exec(s.statePathName);if(null!==c){const t=function(t,e){if(void 0===e)return t.delta;const r=M(t,e);return n(r).wildcardCount-n(e).wildcardCount}(o,a);i=0===t?s.statePathName:`$${Number(c[1])+t}`}else if(i=M(o,s.statePathName),"for"===s.bindingType){const e=n(i).wildcardCount-s.statePathInfo.wildcardCount;o.indexShiftByLoopElementPath.set(i+t+r,e)}const l=s.propModifiers,u=null===c&&Array.isArray(l)&&!l.includes(e)&&null!==b(o,s.statePathName);return i!==s.statePathName||u?{...s,statePathName:i,statePathInfo:n(i),...u?{propModifiers:[...l,e]}:{}}:s}function O(e,n){const r=n.lastIndexOf("#");if(-1===r)return e.delta;const o=n.indexOf(t,r);if((-1===o?n.slice(r):n.slice(r,o))!==e.marker)return e.delta;const s=-1===o?n:n.slice(0,o),a=-1===o?"":n.slice(o+1),i=e.accessorBySuffixByMarkerParent.get(s)?.get(a);return void 0!==i?i.indexShift:e.delta}function N(t,e,r,o,s){if(void 0===o)return;const a=n(r).wildcardCount-n(e).wildcardCount;return 0===a?o:(s.length<a&&l(`Cannot resolve "${e}" from this mount: the mounted prefix has ${a} wildcard(s) but the host context provides only ${s.length} index(es).`),[...s.slice(0,a),...o])}const B=new WeakMap,I=new WeakMap;function E(t,e){return I.get(t)?.get(e)??null}const W=new WeakMap;const L=new FinalizationRegistry(function(t){const e=t.byMarker.get(t.marker);if(void 0!==e&&void 0===e.deref()&&t.byMarker.delete(t.marker),void 0!==t.getterPaths)for(const e of t.addedGetterPaths)t.getterPaths.delete(e)}),D=new WeakMap;function G(t){return D.get(t)??null}let A=!1;function R(t,e){A||(A=!0,i(t=>B.has(t)?t.host:null)),B.set(t,e),D.set(e,t);let n=W.get(e.parentStateElement);void 0===n&&(n=new Map,W.set(e.parentStateElement,n)),n.set(e.marker,new WeakRef(e));let r=I.get(e.component);void 0===r&&(r=new Map,I.set(e.component,r));const o=r.get(e.stateProp)!==e;r.set(e.stateProp,e),o&&L.register(e,{byMarker:n,marker:e.marker,getterPaths:e.parentStateElement.getterPaths,addedGetterPaths:e.addedGetterPaths}),e.parentStateElement.markHasMounts?.()}function T(t){return B.get(t)??null}function z(t,e){let n=t;for(;null!==n&&n!==e;){const t=B.get(n);if(void 0!==t)return t;n=n.parentNode}return B.get(e)??null}function F(t){const e=W.get(t);if(void 0===e)return[];const n=[];for(const t of e.values()){const e=t.deref();void 0!==e&&n.push(e)}return n}function H(t){const e=W.get(t);return void 0!==e&&e.size>0}function q(e,n){const r=n.lastIndexOf("#");if(-1===r)return null;const o=W.get(e);if(void 0===o)return null;const s=n.indexOf(t,r),a=-1===s?n.slice(r):n.slice(r,s),i=o.get(a);if(void 0===i)return null;const c=i.deref();return void 0===c?(o.delete(a),null):c}export{M as a,x as b,N as c,G as d,T as e,d as f,F as g,C as h,z as i,q as j,O as k,y as l,E as m,w as n,R as r,H as s,f as t,g as w};
|
|
2
2
|
//# sourceMappingURL=mount.js.map
|