@wcstack/state 1.27.0 → 1.29.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.
@@ -57,6 +57,41 @@ interface IWcsManifest {
57
57
  };
58
58
  /** 構造ディレクティブ(`<template data-wcs="for: ...">` 等) */
59
59
  structuralDirectives: readonly string[];
60
+ /**
61
+ * 修飾子(`#` 後)の語彙。flags は値を取らない形(`#prevent`)、keyValue は
62
+ * `=` で値を取る形(`#init=element`)、eventNamePrefix は `on` + イベント名の形
63
+ * (`#onchange` — two-way / radio / checkbox のイベント名上書き。README「Modifiers」)。
64
+ * define.ts の定数が単一正本で、ランタイムの消費箇所も同じ定数に分岐する。
65
+ */
66
+ modifiers: {
67
+ flags: readonly string[];
68
+ keyValue: readonly string[];
69
+ eventNamePrefix: string;
70
+ };
71
+ /** リストインデックス参照名(`$1`..`$N`)。prefix + 1 始まり連番、maxDepth まで。 */
72
+ indexParam: {
73
+ prefix: string;
74
+ maxDepth: number;
75
+ };
76
+ /**
77
+ * bindingType 判別の語彙(parseBindTextsForElement の分岐と同一の定数から導出)。
78
+ * 判別順: else → spread → 構造ディレクティブ/radio/checkbox → eventToken・`on*`
79
+ * (event)→ prop。propNamespaces は左辺先頭セグメントの特殊 namespace で、
80
+ * apply 層のディスパッチキー集合との一致はテストが強制する。
81
+ * 既知の未収載: `radio` / `checkbox`(BindingType union のみが正本)。
82
+ */
83
+ bindingTypes: {
84
+ elseKeyword: string;
85
+ spread: string;
86
+ eventPropertyPrefix: string;
87
+ propNamespaces: {
88
+ eventToken: string;
89
+ command: string;
90
+ class: string;
91
+ attr: string;
92
+ style: string;
93
+ };
94
+ };
60
95
  };
61
96
  /** 組み込みフィルタ名(builtinFilters から自動導出=実装が正本) */
62
97
  filters: string[];
@@ -1001,6 +1001,38 @@ const PROP_VALUE_SEPARATOR = ':'; // 左辺(prop)と右辺(path)の区切り
1001
1001
  const MODIFIER_SEPARATOR = '#'; // prop と修飾子の区切り
1002
1002
  const STATE_NAME_SEPARATOR = '@'; // path と @stateName の区切り
1003
1003
  const FILTER_SEPARATOR = '|'; // フィルタパイプの区切り
1004
+ // 修飾子(`#` 後)の語彙(単一正本)。manifest.syntax.modifiers で公開される。
1005
+ // フラグ形(`#prevent` — 値を取らない)とキー値形(`#init=element` — `=` で値を取る)。
1006
+ // 消費箇所(event/handler・BindingSession・twowayHandler・bindings/initialSync)は
1007
+ // この定数を参照する — 文字列リテラルの散在は tooling への収載漏れの温床だった
1008
+ // (docs/static-wiring-dx-design.md §2-2)。
1009
+ const MODIFIER_PREVENT = 'prevent';
1010
+ const MODIFIER_STOP = 'stop';
1011
+ const MODIFIER_READONLY = 'ro';
1012
+ const MODIFIER_FLAGS = Object.freeze([
1013
+ MODIFIER_PREVENT, MODIFIER_STOP, MODIFIER_READONLY,
1014
+ ]);
1015
+ const MODIFIER_KEY_INIT = 'init';
1016
+ const MODIFIER_KEY_SYNC = 'sync';
1017
+ const MODIFIER_KEYS = Object.freeze([
1018
+ MODIFIER_KEY_INIT, MODIFIER_KEY_SYNC,
1019
+ ]);
1020
+ // bindingType 判別と左辺 namespace の語彙(単一正本)。manifest.syntax.bindingTypes で
1021
+ // 公開される。パーサ(parseBindTextsForElement)とイベント層はこの定数に分岐する。
1022
+ // apply 層のディスパッチマップ(apply/applyChange.ts の applyChangeByFirstSegment)の
1023
+ // キー集合との一致は __tests__/manifest.test.ts の drift テストが強制する —
1024
+ // manifest エントリ(DOM 非依存)から apply 層を import しないための分離。
1025
+ const ELSE_KEYWORD = 'else';
1026
+ const SPREAD_PROP = '...';
1027
+ const EVENT_PROP_PREFIX = 'on';
1028
+ const EVENT_TOKEN_NAMESPACE = 'eventToken';
1029
+ const COMMAND_NAMESPACE = 'command';
1030
+ const CLASS_NAMESPACE = 'class';
1031
+ const ATTR_NAMESPACE = 'attr';
1032
+ const STYLE_NAMESPACE = 'style';
1033
+ // リストインデックス参照名(`$1`..`$N`)の接頭辞(単一正本)。
1034
+ // manifest.syntax.indexParam で公開される。
1035
+ const INDEX_PARAM_PREFIX = '$';
1004
1036
  /**
1005
1037
  * stackIndexByIndexName
1006
1038
  * インデックス名からスタックインデックスへのマッピング
@@ -1012,7 +1044,7 @@ const FILTER_SEPARATOR = '|'; // フィルタパイプの区切り
1012
1044
  */
1013
1045
  const tmpIndexByIndexName = {};
1014
1046
  for (let i = 0; i < MAX_WILDCARD_DEPTH; i++) {
1015
- tmpIndexByIndexName[`$${i + 1}`] = i;
1047
+ tmpIndexByIndexName[`${INDEX_PARAM_PREFIX}${i + 1}`] = i;
1016
1048
  }
1017
1049
  Object.freeze(tmpIndexByIndexName);
1018
1050
  const STATE_CONNECTED_CALLBACK_NAME = "$connectedCallback";
@@ -1064,6 +1096,27 @@ function getWcsManifest() {
1064
1096
  },
1065
1097
  // 正本 STRUCTURAL_BINDING_TYPE_SET から導出(手書きの二重定義を排除)。
1066
1098
  structuralDirectives: Array.from(STRUCTURAL_BINDING_TYPE_SET),
1099
+ modifiers: {
1100
+ flags: MODIFIER_FLAGS,
1101
+ keyValue: MODIFIER_KEYS,
1102
+ eventNamePrefix: EVENT_PROP_PREFIX,
1103
+ },
1104
+ indexParam: {
1105
+ prefix: INDEX_PARAM_PREFIX,
1106
+ maxDepth: MAX_WILDCARD_DEPTH,
1107
+ },
1108
+ bindingTypes: {
1109
+ elseKeyword: ELSE_KEYWORD,
1110
+ spread: SPREAD_PROP,
1111
+ eventPropertyPrefix: EVENT_PROP_PREFIX,
1112
+ propNamespaces: {
1113
+ eventToken: EVENT_TOKEN_NAMESPACE,
1114
+ command: COMMAND_NAMESPACE,
1115
+ class: CLASS_NAMESPACE,
1116
+ attr: ATTR_NAMESPACE,
1117
+ style: STYLE_NAMESPACE,
1118
+ },
1119
+ },
1067
1120
  },
1068
1121
  // 実装(Record のキー)から自動導出。手リストを持たない=ドリフトの構造的排除。
1069
1122
  filters: Object.keys(outputBuiltinFilters),
@@ -0,0 +1,115 @@
1
+ interface IPathInfo {
2
+ readonly id: number;
3
+ readonly path: string;
4
+ readonly segments: string[];
5
+ readonly lastSegment: string;
6
+ readonly cumulativePaths: string[];
7
+ readonly cumulativePathSet: Set<string>;
8
+ readonly cumulativePathInfos: IPathInfo[];
9
+ readonly cumulativePathInfoSet: Set<IPathInfo>;
10
+ readonly parentPath: string | null;
11
+ readonly parentPathInfo: IPathInfo | null;
12
+ readonly wildcardPaths: string[];
13
+ readonly wildcardPathSet: Set<string>;
14
+ readonly indexByWildcardPath: Record<string, number>;
15
+ readonly wildcardPathInfos: IPathInfo[];
16
+ readonly wildcardPathInfoSet: Set<IPathInfo>;
17
+ readonly wildcardParentPaths: string[];
18
+ readonly wildcardParentPathSet: Set<string>;
19
+ readonly wildcardParentPathInfos: IPathInfo[];
20
+ readonly wildcardParentPathInfoSet: Set<IPathInfo>;
21
+ readonly wildcardPositions: number[];
22
+ readonly lastWildcardPath: string | null;
23
+ readonly lastWildcardInfo: IPathInfo | null;
24
+ readonly wildcardCount: number;
25
+ }
26
+
27
+ /**
28
+ * Filter/types.ts
29
+ *
30
+ * Type definition file for filter functions.
31
+ *
32
+ * Main responsibilities:
33
+ * - Defines types for filter functions (FilterFn) and filter functions with options (FilterWithOptionsFn)
34
+ * - Type-safe management of filter name-to-function mappings (FilterWithOptions) and filter function arrays (Filters)
35
+ * - Defines types for retrieving filter functions from built-in filter collections
36
+ *
37
+ * Design points:
38
+ * - Type design enabling flexible filter design and extension
39
+ * - Supports filters with options and combinations of multiple filters
40
+ */
41
+ type FilterFn<T = unknown> = (value: unknown) => T;
42
+
43
+ type BindingType = 'text' | 'prop' | 'event' | 'for' | 'if' | 'elseif' | 'else' | 'radio' | 'checkbox' | 'spread';
44
+ interface IFilterInfo {
45
+ readonly filterName: string;
46
+ readonly args: string[];
47
+ readonly filterFn: FilterFn;
48
+ }
49
+ /**
50
+ * バインディング式のパース結果(DOM 非依存の部分)。`@wcstack/state/parser` の
51
+ * ParseBindTextResult がこれをそのまま公開するため、Node 等の DOM lib 型を
52
+ * ここに足してはならない(足すなら IBindingInfo 側へ)。
53
+ */
54
+ interface IParsedBinding {
55
+ readonly propName: string;
56
+ readonly propSegments: string[];
57
+ readonly propModifiers: string[];
58
+ readonly statePathName: string;
59
+ readonly statePathInfo: IPathInfo;
60
+ readonly stateName: string;
61
+ readonly inFilters: IFilterInfo[];
62
+ readonly outFilters: IFilterInfo[];
63
+ readonly bindingType: BindingType;
64
+ readonly uuid?: string | null;
65
+ }
66
+
67
+ type ParseBindTextResult = IParsedBinding;
68
+
69
+ declare function parseBindTextsForElement(bindText: string): ParseBindTextResult[];
70
+
71
+ declare function parseBindTextForEmbeddedNode(bindText: string): ParseBindTextResult;
72
+
73
+ declare function getPathInfo(path: string): IPathInfo;
74
+
75
+ /**
76
+ * parser.ts — `data-wcs` バインディング構文の正本パーサを tooling 向けに公開する
77
+ * サブパスエントリ(`@wcstack/state/parser`)。
78
+ *
79
+ * `./manifest` と同じ「実装が唯一の正本」パターン(docs/static-wiring-dx-design.md D2)。
80
+ * vscode-wcs の正規表現パーサ・devtools の declaredScan 簡易パーサという複製実装を
81
+ * 段階的にこの正本へ寄せるための土台。
82
+ *
83
+ * 契約:
84
+ * - DOM 非依存・純関数(bindText 文字列 → ParseBindTextResult[])。Node でそのまま動く
85
+ * (__tests__/parser.test.ts が node 環境で検証する)。
86
+ * - **位置情報は持たず、不正構文は raiseError で throw する**。エラー耐性と診断 range の
87
+ * 生成は消費側(vscode-wcs の positional ラッパー)の責務(同 D3)— ランタイムの
88
+ * サイズと責務をここで増やさない。
89
+ * - `getPathInfo` はパス文字列の解析済みビュー(セグメント・ワイルドカード位置・親パス
90
+ * チェーン)を返す純関数。静的依存グラフの親チェーン展開はこの情報から機械的に再現できる。
91
+ * 同一パス → 同一インスタンスの保証は**このエントリのモジュールインスタンス内**でのみ
92
+ * 成立する(`.` エントリは別バンドル=別キャッシュ。ランタイムの PathInfo と identity
93
+ * 比較してはならない)。キャッシュは無制限(evict なし)— 言語サーバー等の長時間
94
+ * プロセスでは入力パス種数に単調比例してメモリが増える点に留意。
95
+ * - `ParseBindTextResult.uuid` はランタイム内部(構造テンプレートのハイドレーション台帳)
96
+ * 用のフィールドで、このパーサの戻り値では常に undefined。
97
+ *
98
+ * 公開面は意図的に最小(公開=恒久契約)。`expandSpread` は live Element と
99
+ * CustomElementRegistry を要するためここには含めない — ブラウザ内の消費者
100
+ * (devtools の declared 正本化)は state 自身が pull API で答える。
101
+ */
102
+
103
+ /**
104
+ * このエントリの内部キャッシュ(PathInfo intern・フィルタ列パース結果)を全て捨てる。
105
+ *
106
+ * 言語サーバー等の**長時間プロセス専用**。編集中の中間パス(`user.n` 等)が
107
+ * 無制限キャッシュに恒久 intern されてメモリが単調増加するため、ドキュメント
108
+ * クローズ等の区切りで呼ぶ。クリア後の getPathInfo は同一パスに**新しい**
109
+ * インスタンスを返す — 「同一パス → 同一参照」の保証はクリアを跨がない。
110
+ * ランタイム(`.` エントリ)にはこの API は無く、呼ばれることもない。
111
+ */
112
+ declare function clearParserCaches(): void;
113
+
114
+ export { clearParserCaches, getPathInfo, parseBindTextForEmbeddedNode, parseBindTextsForElement };
115
+ export type { BindingType, IFilterInfo, IPathInfo, ParseBindTextResult };