@wcstack/state 1.28.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.
package/dist/parser.d.ts CHANGED
@@ -68,7 +68,48 @@ type ParseBindTextResult = IParsedBinding;
68
68
 
69
69
  declare function parseBindTextsForElement(bindText: string): ParseBindTextResult[];
70
70
 
71
+ declare function parseBindTextForEmbeddedNode(bindText: string): ParseBindTextResult;
72
+
71
73
  declare function getPathInfo(path: string): IPathInfo;
72
74
 
73
- export { getPathInfo, parseBindTextsForElement };
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 };
74
115
  export type { BindingType, IFilterInfo, IPathInfo, ParseBindTextResult };
@@ -36,6 +36,16 @@ for (let i = 0; i < MAX_WILDCARD_DEPTH; i++) {
36
36
  Object.freeze(tmpIndexByIndexName);
37
37
 
38
38
  const _cache = new Map();
39
+ /**
40
+ * **tooling 専用**(`@wcstack/state/parser` の clearParserCaches からのみ呼ぶ)。
41
+ * ランタイム文脈で呼んではならない — PathInfo のインスタンス同一性は正規化キー
42
+ * (依存グラフ・アドレス比較)の前提であり、クリアすると同一パスの新旧インスタンスが
43
+ * 併存して identity 比較が黙って壊れる。言語サーバー等の長時間プロセスが、編集中の
44
+ * 中間パス(`user.n` 等)の恒久 intern によるメモリ単調増加を断つための出口。
45
+ */
46
+ function clearPathInfoCacheForTooling() {
47
+ _cache.clear();
48
+ }
39
49
  let id = 0;
40
50
  function getPathInfo(path) {
41
51
  let pathInfo = _cache.get(path);
@@ -138,22 +148,6 @@ class PathInfo {
138
148
  }
139
149
  }
140
150
 
141
- function raiseError(message) {
142
- throw new Error(`[@wcstack/state] ${message}`);
143
- }
144
-
145
- const STRUCTURAL_BINDING_TYPE_SET = new Set([
146
- "if",
147
- "elseif",
148
- "else",
149
- "for",
150
- ]);
151
-
152
- const _config = {
153
- locale: 'en'};
154
- // backward compatible export (read-only usage)
155
- const config = _config;
156
-
157
151
  /**
158
152
  * errorGuidance.ts — エラーメッセージへの self-fix 誘導(GTM 2-5 /
159
153
  * docs/static-wiring-dx-design.md §3)。
@@ -217,12 +211,31 @@ function didYouMean(input, candidates) {
217
211
  /**
218
212
  * lint への誘導(誘導付きメッセージ共通の一文)。
219
213
  * **lint が実際にそのケースを検出するサイトにだけ付ける** — 検出しないケースに
220
- * 付けると「エラー → lint 実行 → clean」の空振りで検証ループの信頼を毀損する
221
- * DCC 宣言・watch の一部 shape・構造型単独バインディング違反は lint 未検出のため
222
- * 付けない。lint 側への検査追加は follow-up)。
214
+ * 付けると「エラー → lint 実行 → clean」の空振りで検証ループの信頼を毀損する。
215
+ * 現在 lint 未検出のため付けないもの: DCC 宣言・watch の空キー / Object.prototype
216
+ * 継承名 / ワイルドカード深度超過。
217
+ * なお hint 付きサイト内でも被覆は部分的でありうる(例: `$watch: ident` の実体が
218
+ * 非オブジェクトだった場合、ランタイムは評価後の値で raise するが lint は宣言 shape
219
+ * から断定できず沈黙する)。サイト粒度の hint ではこの残余は構造的に避けられない。
223
220
  */
224
221
  const LINT_HINT = " Validate statically: npx @wcstack/lint <file>.";
225
222
 
223
+ function raiseError(message) {
224
+ throw new Error(`[@wcstack/state] ${message}`);
225
+ }
226
+
227
+ const STRUCTURAL_BINDING_TYPE_SET = new Set([
228
+ "if",
229
+ "elseif",
230
+ "else",
231
+ "for",
232
+ ]);
233
+
234
+ const _config = {
235
+ locale: 'en'};
236
+ // backward compatible export (read-only usage)
237
+ const config = _config;
238
+
226
239
  /**
227
240
  * errorMessages.ts
228
241
  *
@@ -1269,6 +1282,10 @@ function parseFilters(filterTextList, filterIOType) {
1269
1282
  const trimFn = (s) => s.trim();
1270
1283
 
1271
1284
  const cacheFilterInfos$1 = new Map();
1285
+ /** tooling 専用(parser.ts の clearParserCaches からのみ呼ぶ)。 */
1286
+ function clearPropPartCacheForTooling() {
1287
+ cacheFilterInfos$1.clear();
1288
+ }
1272
1289
  // format: propName#moodifier1,modifier2
1273
1290
  // propName-format: path.to.property (e.g., textContent, style.color, not include :)
1274
1291
  // special path:
@@ -1311,6 +1328,10 @@ function parsePropPart(propPart) {
1311
1328
  }
1312
1329
 
1313
1330
  const cacheFilterInfos = new Map();
1331
+ /** tooling 専用(parser.ts の clearParserCaches からのみ呼ぶ)。 */
1332
+ function clearStatePartCacheForTooling() {
1333
+ cacheFilterInfos.clear();
1334
+ }
1314
1335
  // format: statePath@stateName|filter|filter
1315
1336
  // statePath-format: path.to.property (e.g., user.name.first, users.*.name, users.0.name, not include @)
1316
1337
  // stateName: optional, default is 'default'
@@ -1441,12 +1462,66 @@ function parseBindTextsForElement(bindText) {
1441
1462
  if (results.length > 1) {
1442
1463
  const isIncludeSingleBinding = results.some(r => STRUCTURAL_BINDING_TYPE_SET.has(r.bindingType));
1443
1464
  if (isIncludeSingleBinding) {
1444
- // LINT_HINT は付けない: 単独バインディング検査は lint 側に未実装で、誘導が
1445
- // 空振りする(lint への検査追加は follow-up)。
1446
- raiseError(`[wcs/template-syntax] Invalid bindText: "${bindText}". 'if', 'elseif', 'else', and 'for' bindings must be single binding. Put the structural binding alone in its own data-wcs (e.g. <template data-wcs="for: items">).`);
1465
+ // lint 側の単独バインディング検査(bindingValidator structuralMustBeSingle)が
1466
+ // 同じケースを検出するため誘導を付ける(三面同語彙)。
1467
+ raiseError(`[wcs/template-syntax] Invalid bindText: "${bindText}". 'if', 'elseif', 'else', and 'for' bindings must be single binding. Put the structural binding alone in its own data-wcs (e.g. <template data-wcs="for: items">).${LINT_HINT}`);
1447
1468
  }
1448
1469
  }
1449
1470
  return results;
1450
1471
  }
1451
1472
 
1452
- export { getPathInfo, parseBindTextsForElement };
1473
+ function parseBindTextForEmbeddedNode(bindText) {
1474
+ const stateResult = parseStatePart(bindText);
1475
+ return {
1476
+ propName: 'textContent',
1477
+ propSegments: ['textContent'],
1478
+ propModifiers: [],
1479
+ inFilters: [],
1480
+ ...stateResult,
1481
+ bindingType: 'text',
1482
+ };
1483
+ }
1484
+
1485
+ /**
1486
+ * parser.ts — `data-wcs` バインディング構文の正本パーサを tooling 向けに公開する
1487
+ * サブパスエントリ(`@wcstack/state/parser`)。
1488
+ *
1489
+ * `./manifest` と同じ「実装が唯一の正本」パターン(docs/static-wiring-dx-design.md D2)。
1490
+ * vscode-wcs の正規表現パーサ・devtools の declaredScan 簡易パーサという複製実装を
1491
+ * 段階的にこの正本へ寄せるための土台。
1492
+ *
1493
+ * 契約:
1494
+ * - DOM 非依存・純関数(bindText 文字列 → ParseBindTextResult[])。Node でそのまま動く
1495
+ * (__tests__/parser.test.ts が node 環境で検証する)。
1496
+ * - **位置情報は持たず、不正構文は raiseError で throw する**。エラー耐性と診断 range の
1497
+ * 生成は消費側(vscode-wcs の positional ラッパー)の責務(同 D3)— ランタイムの
1498
+ * サイズと責務をここで増やさない。
1499
+ * - `getPathInfo` はパス文字列の解析済みビュー(セグメント・ワイルドカード位置・親パス
1500
+ * チェーン)を返す純関数。静的依存グラフの親チェーン展開はこの情報から機械的に再現できる。
1501
+ * 同一パス → 同一インスタンスの保証は**このエントリのモジュールインスタンス内**でのみ
1502
+ * 成立する(`.` エントリは別バンドル=別キャッシュ。ランタイムの PathInfo と identity
1503
+ * 比較してはならない)。キャッシュは無制限(evict なし)— 言語サーバー等の長時間
1504
+ * プロセスでは入力パス種数に単調比例してメモリが増える点に留意。
1505
+ * - `ParseBindTextResult.uuid` はランタイム内部(構造テンプレートのハイドレーション台帳)
1506
+ * 用のフィールドで、このパーサの戻り値では常に undefined。
1507
+ *
1508
+ * 公開面は意図的に最小(公開=恒久契約)。`expandSpread` は live Element と
1509
+ * CustomElementRegistry を要するためここには含めない — ブラウザ内の消費者
1510
+ * (devtools の declared 正本化)は state 自身が pull API で答える。
1511
+ */
1512
+ /**
1513
+ * このエントリの内部キャッシュ(PathInfo intern・フィルタ列パース結果)を全て捨てる。
1514
+ *
1515
+ * 言語サーバー等の**長時間プロセス専用**。編集中の中間パス(`user.n` 等)が
1516
+ * 無制限キャッシュに恒久 intern されてメモリが単調増加するため、ドキュメント
1517
+ * クローズ等の区切りで呼ぶ。クリア後の getPathInfo は同一パスに**新しい**
1518
+ * インスタンスを返す — 「同一パス → 同一参照」の保証はクリアを跨がない。
1519
+ * ランタイム(`.` エントリ)にはこの API は無く、呼ばれることもない。
1520
+ */
1521
+ function clearParserCaches() {
1522
+ clearPathInfoCacheForTooling();
1523
+ clearPropPartCacheForTooling();
1524
+ clearStatePartCacheForTooling();
1525
+ }
1526
+
1527
+ export { clearParserCaches, getPathInfo, parseBindTextForEmbeddedNode, parseBindTextsForElement };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wcstack/state",
3
- "version": "1.28.0",
3
+ "version": "1.29.0",
4
4
  "description": "Reactive state management with declarative data binding for Web Components. Zero dependencies, buildless.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.esm.js",