@wcstack/lint 1.29.0 → 1.31.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.
Files changed (2) hide show
  1. package/dist/cli.cjs +2420 -118
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -16,7 +16,7 @@ var __copyProps = (to, from, except, desc) => {
16
16
  }
17
17
  return to;
18
18
  };
19
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var __toCommonJS = (mod3) => __copyProps(__defProp({}, "__esModule", { value: true }), mod3);
20
20
 
21
21
  // src/cli.ts
22
22
  var cli_exports = {};
@@ -27,8 +27,34 @@ __export(cli_exports, {
27
27
  resolveCliLocale: () => resolveCliLocale
28
28
  });
29
29
  module.exports = __toCommonJS(cli_exports);
30
+ var import_node_fs2 = require("node:fs");
31
+
32
+ // src/fileReader.ts
30
33
  var import_node_fs = require("node:fs");
31
34
  var import_node_path = require("node:path");
35
+ function createFileReader(htmlPath, read = (p) => (0, import_node_fs.readFileSync)(p, "utf8")) {
36
+ const base = (0, import_node_path.dirname)(htmlPath);
37
+ const cache = /* @__PURE__ */ new Map();
38
+ return (relativePath) => {
39
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(relativePath) || relativePath.startsWith("/")) {
40
+ return void 0;
41
+ }
42
+ if (cache.has(relativePath)) {
43
+ return cache.get(relativePath);
44
+ }
45
+ let content;
46
+ try {
47
+ content = read((0, import_node_path.resolve)(base, relativePath));
48
+ if (content.charCodeAt(0) === 65279) {
49
+ content = content.slice(1);
50
+ }
51
+ } catch {
52
+ content = void 0;
53
+ }
54
+ cache.set(relativePath, content);
55
+ return content;
56
+ };
57
+ }
32
58
 
33
59
  // src/core/offsetToPosition.ts
34
60
  function createPositionMapper(text) {
@@ -91,6 +117,20 @@ var WcsDiagnosticCode = {
91
117
  TokenUndeclared: "wcs/token-undeclared",
92
118
  TokenMisconfigured: "wcs/token-misconfigured",
93
119
  NestedAssign: "wcs/nested-assign",
120
+ // --- 意味論(構文・存在検査では捕まらない取り違え。service/semanticValidator.ts) ---
121
+ // `$getAll` / `$resolve` の添字の本数がパスの `*` の本数と噛み合わない。
122
+ // ランタイムは同じ code で raiseError する(超過は以前は黙って無視されていた)。
123
+ IndexArity: "wcs/index-arity",
124
+ // ワイルドカードの階数がスコープの段数を超える(`matrix.*.*` を 1 段の for で読む、
125
+ // `$2` を 1 段のループで読む)。既存の「for の外」検査の深さ方向の一般化。
126
+ WildcardRank: "wcs/wildcard-rank",
127
+ // パス getter どうしの循環参照。ランタイムはアドレススタック上限まで再帰してから落ちる。
128
+ GetterCycle: "wcs/getter-cycle",
129
+ // `$updatedCallback` が、どのバインディングにも現れないパスを判定に使っている。
130
+ // 同コールバックは **binding 駆動**(live binding が適用された path しか報告しない)
131
+ // なので、その分岐は一度も実行されない。表示要素が購読の実体になる事故
132
+ // (examples/state-intersect-scroll の README に記録)の静的検出。
133
+ UpdatedCallbackUnbound: "wcs/updated-callback-unbound",
94
134
  // --- <wcs-state> script: $watch declaration ---
95
135
  // ランタイム(watch/processWatchDeclaration.ts)が raiseError で落とす宣言。
96
136
  // 越境 `@` / `$` 始まり / 空キー・空セグメント / 明らかな非関数ハンドラ。
@@ -110,6 +150,9 @@ var WcsDiagnosticCode = {
110
150
  // --- built-in wcs-* tag contract (generated/builtinTags.generated.ts が正本) ---
111
151
  // 未知メンバーへのバインド(プロパティ / command. / eventToken. キー)。黙って無視される。
112
152
  TagMemberUnknown: "wcs/tag-member-unknown",
153
+ // wcBindable 無宣言タグ(wcs-fetch-header 等のヘルパー)への spread。
154
+ // ランタイム(expandSpread)は raiseError で落とす。
155
+ SpreadNoBindable: "wcs/spread-no-bindable",
113
156
  // trigger バインド先スロットの true シード(エッジ検出なし・manual バイパスで即発火)。
114
157
  TriggerSeededTruthy: "wcs/trigger-seeded-truthy",
115
158
  // 非 manual <wcs-storage> value バインド先の空値シード(初期書き戻しが保存値を上書き)。
@@ -128,6 +171,545 @@ function sortDiagnostics(diagnostics) {
128
171
  }
129
172
 
130
173
  // ../state/dist/manifest.esm.js
174
+ var _config = {
175
+ bindAttributeName: "data-wcs",
176
+ tagNames: {
177
+ state: "wcs-state"
178
+ },
179
+ locale: "en"
180
+ };
181
+ var config = _config;
182
+ function raiseError(message) {
183
+ throw new Error(`[@wcstack/state] ${message}`);
184
+ }
185
+ function optionsRequired(fnName) {
186
+ raiseError(`filter ${fnName} requires at least one option`);
187
+ }
188
+ function optionMustBeNumber(fnName) {
189
+ raiseError(`filter ${fnName} requires a number as option`);
190
+ }
191
+ function valueMustBeNumber(fnName) {
192
+ raiseError(`filter ${fnName} requires a number value`);
193
+ }
194
+ function valueMustBeBoolean(fnName) {
195
+ raiseError(`filter ${fnName} requires a boolean value`);
196
+ }
197
+ function valueMustBeDate(fnName) {
198
+ raiseError(`filter ${fnName} requires a date value`);
199
+ }
200
+ function valueMustBeArray(fnName) {
201
+ raiseError(`filter ${fnName} requires an array value`);
202
+ }
203
+ function validateNumberString(value) {
204
+ if (!value || isNaN(Number(value))) {
205
+ return false;
206
+ }
207
+ return true;
208
+ }
209
+ var eq = (options) => {
210
+ const opt = options?.[0] ?? optionsRequired("eq");
211
+ return (value) => {
212
+ if (typeof value === "number") {
213
+ if (!validateNumberString(opt)) {
214
+ optionMustBeNumber("eq");
215
+ }
216
+ return value === Number(opt);
217
+ }
218
+ if (typeof value === "string") {
219
+ return value === opt;
220
+ }
221
+ return value === opt;
222
+ };
223
+ };
224
+ var ne = (options) => {
225
+ const opt = options?.[0] ?? optionsRequired("ne");
226
+ return (value) => {
227
+ if (typeof value === "number") {
228
+ if (!validateNumberString(opt)) {
229
+ optionMustBeNumber("ne");
230
+ }
231
+ return value !== Number(opt);
232
+ }
233
+ if (typeof value === "string") {
234
+ return value !== opt;
235
+ }
236
+ return value !== opt;
237
+ };
238
+ };
239
+ var not = (_options) => {
240
+ return (value) => {
241
+ if (typeof value !== "boolean") {
242
+ valueMustBeBoolean("not");
243
+ }
244
+ return !value;
245
+ };
246
+ };
247
+ var lt = (options) => {
248
+ const opt = options?.[0] ?? optionsRequired("lt");
249
+ if (!validateNumberString(opt)) {
250
+ optionMustBeNumber("lt");
251
+ }
252
+ return (value) => {
253
+ if (typeof value !== "number") {
254
+ valueMustBeNumber("lt");
255
+ }
256
+ return value < Number(opt);
257
+ };
258
+ };
259
+ var le = (options) => {
260
+ const opt = options?.[0] ?? optionsRequired("le");
261
+ if (!validateNumberString(opt)) {
262
+ optionMustBeNumber("le");
263
+ }
264
+ return (value) => {
265
+ if (typeof value !== "number") {
266
+ valueMustBeNumber("le");
267
+ }
268
+ return value <= Number(opt);
269
+ };
270
+ };
271
+ var gt = (options) => {
272
+ const opt = options?.[0] ?? optionsRequired("gt");
273
+ if (!validateNumberString(opt)) {
274
+ optionMustBeNumber("gt");
275
+ }
276
+ return (value) => {
277
+ if (typeof value !== "number") {
278
+ valueMustBeNumber("gt");
279
+ }
280
+ return value > Number(opt);
281
+ };
282
+ };
283
+ var ge = (options) => {
284
+ const opt = options?.[0] ?? optionsRequired("ge");
285
+ if (!validateNumberString(opt)) {
286
+ optionMustBeNumber("ge");
287
+ }
288
+ return (value) => {
289
+ if (typeof value !== "number") {
290
+ valueMustBeNumber("ge");
291
+ }
292
+ return value >= Number(opt);
293
+ };
294
+ };
295
+ var inc = (options) => {
296
+ const opt = options?.[0] ?? optionsRequired("inc");
297
+ if (!validateNumberString(opt)) {
298
+ optionMustBeNumber("inc");
299
+ }
300
+ return (value) => {
301
+ if (typeof value !== "number") {
302
+ valueMustBeNumber("inc");
303
+ }
304
+ return value + Number(opt);
305
+ };
306
+ };
307
+ var dec = (options) => {
308
+ const opt = options?.[0] ?? optionsRequired("dec");
309
+ if (!validateNumberString(opt)) {
310
+ optionMustBeNumber("dec");
311
+ }
312
+ return (value) => {
313
+ if (typeof value !== "number") {
314
+ valueMustBeNumber("dec");
315
+ }
316
+ return value - Number(opt);
317
+ };
318
+ };
319
+ var mul = (options) => {
320
+ const opt = options?.[0] ?? optionsRequired("mul");
321
+ if (!validateNumberString(opt)) {
322
+ optionMustBeNumber("mul");
323
+ }
324
+ return (value) => {
325
+ if (typeof value !== "number") {
326
+ valueMustBeNumber("mul");
327
+ }
328
+ return value * Number(opt);
329
+ };
330
+ };
331
+ var div = (options) => {
332
+ const opt = options?.[0] ?? optionsRequired("div");
333
+ if (!validateNumberString(opt)) {
334
+ optionMustBeNumber("div");
335
+ }
336
+ return (value) => {
337
+ if (typeof value !== "number") {
338
+ valueMustBeNumber("div");
339
+ }
340
+ return value / Number(opt);
341
+ };
342
+ };
343
+ var mod = (options) => {
344
+ const opt = options?.[0] ?? optionsRequired("mod");
345
+ if (!validateNumberString(opt)) {
346
+ optionMustBeNumber("mod");
347
+ }
348
+ return (value) => {
349
+ if (typeof value !== "number") {
350
+ valueMustBeNumber("mod");
351
+ }
352
+ return value % Number(opt);
353
+ };
354
+ };
355
+ var abs = (_options) => {
356
+ return (value) => {
357
+ if (typeof value !== "number") {
358
+ valueMustBeNumber("abs");
359
+ }
360
+ return Math.abs(value);
361
+ };
362
+ };
363
+ var clamp = (options) => {
364
+ const opt1 = options?.[0] ?? optionsRequired("clamp");
365
+ if (!validateNumberString(opt1)) {
366
+ optionMustBeNumber("clamp");
367
+ }
368
+ const opt2 = options?.[1] ?? optionsRequired("clamp");
369
+ if (!validateNumberString(opt2)) {
370
+ optionMustBeNumber("clamp");
371
+ }
372
+ const min = Number(opt1);
373
+ const max = Number(opt2);
374
+ return (value) => {
375
+ if (typeof value !== "number") {
376
+ valueMustBeNumber("clamp");
377
+ }
378
+ return Math.min(Math.max(value, min), max);
379
+ };
380
+ };
381
+ var fix = (options) => {
382
+ const opt = options?.[0] ?? "0";
383
+ if (!validateNumberString(opt)) {
384
+ optionMustBeNumber("fix");
385
+ }
386
+ return (value) => {
387
+ if (typeof value !== "number") {
388
+ valueMustBeNumber("fix");
389
+ }
390
+ return value.toFixed(Number(opt));
391
+ };
392
+ };
393
+ var locale = (options) => {
394
+ const opt = options?.[0] ?? config.locale;
395
+ return (value) => {
396
+ if (typeof value !== "number") {
397
+ valueMustBeNumber("locale");
398
+ }
399
+ return value.toLocaleString(opt);
400
+ };
401
+ };
402
+ var uc = (_options) => {
403
+ return (value) => {
404
+ return String(value).toUpperCase();
405
+ };
406
+ };
407
+ var lc = (_options) => {
408
+ return (value) => {
409
+ return String(value).toLowerCase();
410
+ };
411
+ };
412
+ var cap = (_options) => {
413
+ return (value) => {
414
+ const v = String(value);
415
+ if (v.length === 0) {
416
+ return v;
417
+ }
418
+ if (v.length === 1) {
419
+ return v.toUpperCase();
420
+ }
421
+ return v.charAt(0).toUpperCase() + v.slice(1);
422
+ };
423
+ };
424
+ var trim = (_options) => {
425
+ return (value) => {
426
+ return String(value).trim();
427
+ };
428
+ };
429
+ var slice = (options) => {
430
+ const numberedOpts = [];
431
+ const opt1 = options?.[0] ?? optionsRequired("slice");
432
+ if (!validateNumberString(opt1)) {
433
+ optionMustBeNumber("slice");
434
+ }
435
+ numberedOpts.push(Number(opt1));
436
+ const opt2 = options?.[1];
437
+ if (typeof opt2 !== "undefined") {
438
+ if (!validateNumberString(opt2)) {
439
+ optionMustBeNumber("slice");
440
+ }
441
+ numberedOpts.push(Number(opt2));
442
+ }
443
+ return (value) => {
444
+ return String(value).slice(...numberedOpts);
445
+ };
446
+ };
447
+ var substr = (options) => {
448
+ const opt1 = options?.[0] ?? optionsRequired("substr");
449
+ if (!validateNumberString(opt1)) {
450
+ optionMustBeNumber("substr");
451
+ }
452
+ const opt2 = options?.[1] ?? optionsRequired("substr");
453
+ if (!validateNumberString(opt2)) {
454
+ optionMustBeNumber("substr");
455
+ }
456
+ return (value) => {
457
+ return String(value).substr(Number(opt1), Number(opt2));
458
+ };
459
+ };
460
+ var pad = (options) => {
461
+ const opt1 = options?.[0] ?? optionsRequired("pad");
462
+ if (!validateNumberString(opt1)) {
463
+ optionMustBeNumber("pad");
464
+ }
465
+ const opt2 = options?.[1] ?? "0";
466
+ return (value) => {
467
+ return String(value).padStart(Number(opt1), opt2);
468
+ };
469
+ };
470
+ var rep = (options) => {
471
+ const opt = options?.[0] ?? optionsRequired("rep");
472
+ if (!validateNumberString(opt)) {
473
+ optionMustBeNumber("rep");
474
+ }
475
+ return (value) => {
476
+ return String(value).repeat(Number(opt));
477
+ };
478
+ };
479
+ var rev = (_options) => {
480
+ return (value) => {
481
+ return String(value).split("").reverse().join("");
482
+ };
483
+ };
484
+ var int = (_options) => {
485
+ return (value) => {
486
+ return parseInt(String(value), 10);
487
+ };
488
+ };
489
+ var float = (_options) => {
490
+ return (value) => {
491
+ return parseFloat(String(value));
492
+ };
493
+ };
494
+ var round = (options) => {
495
+ const opt = options?.[0] ?? "0";
496
+ if (!validateNumberString(opt)) {
497
+ optionMustBeNumber("round");
498
+ }
499
+ return (value) => {
500
+ if (typeof value !== "number") {
501
+ valueMustBeNumber("round");
502
+ }
503
+ const optValue = Math.pow(10, Number(opt));
504
+ return Math.round(value * optValue) / optValue;
505
+ };
506
+ };
507
+ var floor = (options) => {
508
+ const opt = options?.[0] ?? "0";
509
+ if (!validateNumberString(opt)) {
510
+ optionMustBeNumber("floor");
511
+ }
512
+ return (value) => {
513
+ if (typeof value !== "number") {
514
+ valueMustBeNumber("floor");
515
+ }
516
+ const optValue = Math.pow(10, Number(opt));
517
+ return Math.floor(value * optValue) / optValue;
518
+ };
519
+ };
520
+ var ceil = (options) => {
521
+ const opt = options?.[0] ?? "0";
522
+ if (!validateNumberString(opt)) {
523
+ optionMustBeNumber("ceil");
524
+ }
525
+ return (value) => {
526
+ if (typeof value !== "number") {
527
+ valueMustBeNumber("ceil");
528
+ }
529
+ const optValue = Math.pow(10, Number(opt));
530
+ return Math.ceil(value * optValue) / optValue;
531
+ };
532
+ };
533
+ var percent = (options) => {
534
+ const opt = options?.[0] ?? "0";
535
+ if (!validateNumberString(opt)) {
536
+ optionMustBeNumber("percent");
537
+ }
538
+ return (value) => {
539
+ if (typeof value !== "number") {
540
+ valueMustBeNumber("percent");
541
+ }
542
+ return `${(value * 100).toFixed(Number(opt))}%`;
543
+ };
544
+ };
545
+ var unit = (options) => {
546
+ const opt = options?.[0] ?? optionsRequired("unit");
547
+ return (value) => {
548
+ if (value === null || typeof value === "undefined") {
549
+ return value;
550
+ }
551
+ return String(value) + opt;
552
+ };
553
+ };
554
+ var join = (options) => {
555
+ const opt = options?.[0] ?? ", ";
556
+ return (value) => {
557
+ if (!Array.isArray(value)) {
558
+ valueMustBeArray("join");
559
+ }
560
+ return value.join(opt);
561
+ };
562
+ };
563
+ var truncate = (options) => {
564
+ const opt1 = options?.[0] ?? optionsRequired("truncate");
565
+ if (!validateNumberString(opt1)) {
566
+ optionMustBeNumber("truncate");
567
+ }
568
+ const maxLength = Number(opt1);
569
+ const suffix = options?.[1] ?? "\u2026";
570
+ return (value) => {
571
+ const v = String(value);
572
+ if (v.length <= maxLength) {
573
+ return v;
574
+ }
575
+ return v.slice(0, maxLength) + suffix;
576
+ };
577
+ };
578
+ var date = (options) => {
579
+ const opt = options?.[0] ?? config.locale;
580
+ return (value) => {
581
+ if (!(value instanceof Date)) {
582
+ valueMustBeDate("date");
583
+ }
584
+ return value.toLocaleDateString(opt);
585
+ };
586
+ };
587
+ var time = (options) => {
588
+ const opt = options?.[0] ?? config.locale;
589
+ return (value) => {
590
+ if (!(value instanceof Date)) {
591
+ valueMustBeDate("time");
592
+ }
593
+ return value.toLocaleTimeString(opt);
594
+ };
595
+ };
596
+ var datetime = (options) => {
597
+ const opt = options?.[0] ?? config.locale;
598
+ return (value) => {
599
+ if (!(value instanceof Date)) {
600
+ valueMustBeDate("datetime");
601
+ }
602
+ return value.toLocaleString(opt);
603
+ };
604
+ };
605
+ var ymd = (options) => {
606
+ const opt = options?.[0] ?? "-";
607
+ return (value) => {
608
+ if (!(value instanceof Date)) {
609
+ valueMustBeDate("ymd");
610
+ }
611
+ const year = value.getFullYear().toString();
612
+ const month = (value.getMonth() + 1).toString().padStart(2, "0");
613
+ const day = value.getDate().toString().padStart(2, "0");
614
+ return `${year}${opt}${month}${opt}${day}`;
615
+ };
616
+ };
617
+ var hms = (options) => {
618
+ const opt = options?.[0] ?? ":";
619
+ return (value) => {
620
+ if (!(value instanceof Date)) {
621
+ valueMustBeDate("hms");
622
+ }
623
+ const hours = value.getHours().toString().padStart(2, "0");
624
+ const minutes = value.getMinutes().toString().padStart(2, "0");
625
+ const seconds = value.getSeconds().toString().padStart(2, "0");
626
+ return `${hours}${opt}${minutes}${opt}${seconds}`;
627
+ };
628
+ };
629
+ var falsy = (_options) => {
630
+ return (value) => value === false || value === null || value === void 0 || value === 0 || value === "" || Number.isNaN(value);
631
+ };
632
+ var truthy = (_options) => {
633
+ return (value) => value !== false && value !== null && value !== void 0 && value !== 0 && value !== "" && !Number.isNaN(value);
634
+ };
635
+ var defaults = (options) => {
636
+ const opt = options?.[0] ?? optionsRequired("defaults");
637
+ return (value) => {
638
+ if (value === false || value === null || value === void 0 || value === 0 || value === "" || Number.isNaN(value)) {
639
+ return opt;
640
+ }
641
+ return value;
642
+ };
643
+ };
644
+ var boolean = (_options) => {
645
+ return (value) => {
646
+ return Boolean(value);
647
+ };
648
+ };
649
+ var number = (_options) => {
650
+ return (value) => {
651
+ return Number(value);
652
+ };
653
+ };
654
+ var string = (_options) => {
655
+ return (value) => {
656
+ return String(value);
657
+ };
658
+ };
659
+ var _null = (_options) => {
660
+ return (value) => {
661
+ return value === "" ? null : value;
662
+ };
663
+ };
664
+ var builtinFilters = {
665
+ "eq": eq,
666
+ "ne": ne,
667
+ "not": not,
668
+ "lt": lt,
669
+ "le": le,
670
+ "gt": gt,
671
+ "ge": ge,
672
+ "inc": inc,
673
+ "dec": dec,
674
+ "mul": mul,
675
+ "div": div,
676
+ "mod": mod,
677
+ "abs": abs,
678
+ "clamp": clamp,
679
+ "fix": fix,
680
+ "locale": locale,
681
+ "uc": uc,
682
+ "lc": lc,
683
+ "cap": cap,
684
+ "trim": trim,
685
+ "slice": slice,
686
+ "substr": substr,
687
+ "pad": pad,
688
+ "rep": rep,
689
+ "rev": rev,
690
+ "truncate": truncate,
691
+ "join": join,
692
+ "int": int,
693
+ "float": float,
694
+ "round": round,
695
+ "floor": floor,
696
+ "ceil": ceil,
697
+ "percent": percent,
698
+ "unit": unit,
699
+ "date": date,
700
+ "time": time,
701
+ "datetime": datetime,
702
+ "ymd": ymd,
703
+ "hms": hms,
704
+ "falsy": falsy,
705
+ "truthy": truthy,
706
+ "defaults": defaults,
707
+ "boolean": boolean,
708
+ "number": number,
709
+ "string": string,
710
+ "null": _null
711
+ };
712
+ var outputBuiltinFilters = builtinFilters;
131
713
  var builtinFilterMeta = {
132
714
  // 比較・論理
133
715
  eq: { description: "\u7B49\u3057\u3044\u304B\u6BD4\u8F03", hasArgs: true, resultType: "boolean", acceptTypes: "any", minArgs: 1, maxArgs: 1, argTypes: ["any"] },
@@ -191,7 +773,14 @@ var STRUCTURAL_BINDING_TYPE_SET = /* @__PURE__ */ new Set([
191
773
  "else",
192
774
  "for"
193
775
  ]);
776
+ var DELIMITER = ".";
777
+ var WILDCARD = "*";
194
778
  var MAX_WILDCARD_DEPTH = 128;
779
+ var BINDING_SEPARATOR = ";";
780
+ var PROP_VALUE_SEPARATOR = ":";
781
+ var MODIFIER_SEPARATOR = "#";
782
+ var STATE_NAME_SEPARATOR = "@";
783
+ var FILTER_SEPARATOR = "|";
195
784
  var MODIFIER_PREVENT = "prevent";
196
785
  var MODIFIER_STOP = "stop";
197
786
  var MODIFIER_READONLY = "ro";
@@ -206,12 +795,99 @@ var MODIFIER_KEYS = Object.freeze([
206
795
  MODIFIER_KEY_INIT,
207
796
  MODIFIER_KEY_SYNC
208
797
  ]);
798
+ var ELSE_KEYWORD = "else";
799
+ var SPREAD_PROP = "...";
800
+ var EVENT_PROP_PREFIX = "on";
801
+ var EVENT_TOKEN_NAMESPACE = "eventToken";
802
+ var COMMAND_NAMESPACE = "command";
803
+ var CLASS_NAMESPACE = "class";
804
+ var ATTR_NAMESPACE = "attr";
805
+ var STYLE_NAMESPACE = "style";
209
806
  var INDEX_PARAM_PREFIX = "$";
210
807
  var tmpIndexByIndexName = {};
211
808
  for (let i = 0; i < MAX_WILDCARD_DEPTH; i++) {
212
809
  tmpIndexByIndexName[`${INDEX_PARAM_PREFIX}${i + 1}`] = i;
213
810
  }
214
811
  Object.freeze(tmpIndexByIndexName);
812
+ var STATE_CONNECTED_CALLBACK_NAME = "$connectedCallback";
813
+ var STATE_DISCONNECTED_CALLBACK_NAME = "$disconnectedCallback";
814
+ var STATE_UPDATED_CALLBACK_NAME = "$updatedCallback";
815
+ var WEBCOMPONENT_STATE_READY_CALLBACK_NAME = "$stateReadyCallback";
816
+ var STATE_BINDABLES_NAME = "$bindables";
817
+ var STATE_COMMANDS_NAME = "$commands";
818
+ var STATE_COMMAND_TOKENS_NAME = "$commandTokens";
819
+ var STATE_COMMAND_NAMESPACE_NAME = "$command";
820
+ var STATE_EVENT_TOKENS_NAME = "$eventTokens";
821
+ var STATE_ON_NAME = "$on";
822
+ var STATE_STREAMS_NAME = "$streams";
823
+ var STATE_WATCH_NAME = "$watch";
824
+ var STATE_LIST_KEYS_NAME = "$listKeys";
825
+ var STATE_STREAM_STATUS_NAMESPACE_NAME = "$streamStatus";
826
+ var STATE_STREAM_ERROR_NAMESPACE_NAME = "$streamError";
827
+ var WCS_MANIFEST_VERSION = 1;
828
+ function getWcsManifest() {
829
+ return {
830
+ version: WCS_MANIFEST_VERSION,
831
+ syntax: {
832
+ bindAttribute: config.bindAttributeName,
833
+ tagName: config.tagNames.state,
834
+ pathDelimiter: DELIMITER,
835
+ wildcard: WILDCARD,
836
+ delimiters: {
837
+ binding: BINDING_SEPARATOR,
838
+ propValue: PROP_VALUE_SEPARATOR,
839
+ modifier: MODIFIER_SEPARATOR,
840
+ stateName: STATE_NAME_SEPARATOR,
841
+ filter: FILTER_SEPARATOR
842
+ },
843
+ // 正本 STRUCTURAL_BINDING_TYPE_SET から導出(手書きの二重定義を排除)。
844
+ structuralDirectives: Array.from(STRUCTURAL_BINDING_TYPE_SET),
845
+ modifiers: {
846
+ flags: MODIFIER_FLAGS,
847
+ keyValue: MODIFIER_KEYS,
848
+ eventNamePrefix: EVENT_PROP_PREFIX
849
+ },
850
+ indexParam: {
851
+ prefix: INDEX_PARAM_PREFIX,
852
+ maxDepth: MAX_WILDCARD_DEPTH
853
+ },
854
+ bindingTypes: {
855
+ elseKeyword: ELSE_KEYWORD,
856
+ spread: SPREAD_PROP,
857
+ eventPropertyPrefix: EVENT_PROP_PREFIX,
858
+ propNamespaces: {
859
+ eventToken: EVENT_TOKEN_NAMESPACE,
860
+ command: COMMAND_NAMESPACE,
861
+ class: CLASS_NAMESPACE,
862
+ attr: ATTR_NAMESPACE,
863
+ style: STYLE_NAMESPACE
864
+ }
865
+ }
866
+ },
867
+ // 実装(Record のキー)から自動導出。手リストを持たない=ドリフトの構造的排除。
868
+ filters: Object.keys(outputBuiltinFilters),
869
+ filterMeta: builtinFilterMeta,
870
+ reservedLifecycle: [
871
+ STATE_CONNECTED_CALLBACK_NAME,
872
+ STATE_DISCONNECTED_CALLBACK_NAME,
873
+ STATE_UPDATED_CALLBACK_NAME,
874
+ WEBCOMPONENT_STATE_READY_CALLBACK_NAME
875
+ ],
876
+ reservedStateApi: [
877
+ STATE_BINDABLES_NAME,
878
+ STATE_COMMANDS_NAME,
879
+ STATE_COMMAND_TOKENS_NAME,
880
+ STATE_COMMAND_NAMESPACE_NAME,
881
+ STATE_EVENT_TOKENS_NAME,
882
+ STATE_ON_NAME,
883
+ STATE_STREAMS_NAME,
884
+ STATE_WATCH_NAME,
885
+ STATE_LIST_KEYS_NAME,
886
+ STATE_STREAM_STATUS_NAMESPACE_NAME,
887
+ STATE_STREAM_ERROR_NAMESPACE_NAME
888
+ ]
889
+ };
890
+ }
215
891
 
216
892
  // src/service/completionData.ts
217
893
  var BUILTIN_FILTERS = Object.entries(builtinFilterMeta).map(
@@ -357,7 +1033,7 @@ function parseWcsStateElements(html, stateTagName = "wcs-state") {
357
1033
  }
358
1034
  return elements;
359
1035
  }
360
- function findScriptJsonById(html, id) {
1036
+ function findScriptJsonById(html, id2) {
361
1037
  let pos = 0;
362
1038
  const len = html.length;
363
1039
  while (pos < len) {
@@ -374,7 +1050,7 @@ function findScriptJsonById(html, id) {
374
1050
  }
375
1051
  const typeAttr = extractAttribute(scriptMatch.tagContent, "type");
376
1052
  const idAttr = extractAttribute(scriptMatch.tagContent, "id");
377
- if (typeAttr?.toLowerCase() === "application/json" && idAttr === id) {
1053
+ if (typeAttr?.toLowerCase() === "application/json" && idAttr === id2) {
378
1054
  const contentStart = scriptMatch.end;
379
1055
  const scriptCloseIdx = findCloseTag(html, contentStart, "script");
380
1056
  if (scriptCloseIdx === -1) return null;
@@ -389,8 +1065,8 @@ function matchOpenTag(html, pos, tagName) {
389
1065
  const nameStart = pos + 1;
390
1066
  const nameEnd = nameStart + tagName.length;
391
1067
  if (nameEnd > html.length) return null;
392
- const slice = html.slice(nameStart, nameEnd);
393
- if (slice.toLowerCase() !== tagName.toLowerCase()) return null;
1068
+ const slice3 = html.slice(nameStart, nameEnd);
1069
+ if (slice3.toLowerCase() !== tagName.toLowerCase()) return null;
394
1070
  const charAfter = html[nameEnd];
395
1071
  if (charAfter !== ">" && charAfter !== " " && charAfter !== " " && charAfter !== "\n" && charAfter !== "\r" && charAfter !== "/") {
396
1072
  return null;
@@ -509,6 +1185,39 @@ function analyzeWatchEntries(scriptContent) {
509
1185
  }
510
1186
  return entries;
511
1187
  }
1188
+ function analyzeDeclarationSpans(scriptContent) {
1189
+ const root = locateDefaultExportObject(scriptContent);
1190
+ if (!root) return [];
1191
+ const out = [];
1192
+ for (const prop of parseTopLevelProperties(root.content)) {
1193
+ if (prop.nameStart === void 0 || prop.nameEnd === void 0) continue;
1194
+ out.push({
1195
+ name: prop.name,
1196
+ kind: prop.kind,
1197
+ start: root.start + prop.nameStart,
1198
+ end: root.start + prop.nameEnd
1199
+ });
1200
+ }
1201
+ return out;
1202
+ }
1203
+ function analyzeCallableBodies(scriptContent) {
1204
+ const root = locateDefaultExportObject(scriptContent);
1205
+ if (!root) return [];
1206
+ const out = [];
1207
+ for (const prop of parseTopLevelProperties(root.content)) {
1208
+ if (prop.kind !== "getter" && prop.kind !== "method") continue;
1209
+ if (prop.nameStart === void 0 || prop.nameEnd === void 0) continue;
1210
+ out.push({
1211
+ name: prop.name,
1212
+ kind: prop.kind,
1213
+ start: root.start + prop.nameStart,
1214
+ end: root.start + prop.nameEnd,
1215
+ body: prop.value ?? "",
1216
+ bodyStart: root.start + (prop.valueStart ?? 0)
1217
+ });
1218
+ }
1219
+ return out;
1220
+ }
512
1221
  function isNonFunctionLiteral(value) {
513
1222
  if (value === void 0) return false;
514
1223
  const trimmed = value.trim();
@@ -620,14 +1329,9 @@ function pushDataPropertyPathsAt(path, prop, paths, stateName, depth) {
620
1329
  if (prop.value && isArrayLiteral(prop.value)) {
621
1330
  paths.push({ path: `${path}.*`, kind: "list", stateName });
622
1331
  paths.push({ path: `${path}.length`, kind: "data", typeHint: "number", stateName });
623
- const elementProps = extractArrayElementProperties(prop.value);
624
- for (const childProp of elementProps) {
625
- paths.push({
626
- path: `${path}.*.${childProp.name}`,
627
- kind: "data",
628
- typeHint: childProp.typeHint,
629
- stateName
630
- });
1332
+ if (depth >= MAX_OBJECT_NEST_DEPTH) return;
1333
+ for (const childProp of extractArrayElementDataProperties(prop.value)) {
1334
+ pushDataPropertyPathsAt(`${path}.*.${childProp.name}`, childProp, paths, stateName, depth + 1);
631
1335
  }
632
1336
  return;
633
1337
  }
@@ -653,25 +1357,27 @@ function analyzeJsonPaths(jsonString, stateName = "default") {
653
1357
  return paths;
654
1358
  }
655
1359
  function collectJsonPaths(obj, prefix, paths, stateName, depth) {
656
- if (depth > 5) return;
1360
+ if (depth >= MAX_OBJECT_NEST_DEPTH) return;
657
1361
  for (const [key, value] of Object.entries(obj)) {
658
1362
  if (prefix === "" && key.startsWith("$")) continue;
659
1363
  const path = prefix ? `${prefix}.${key}` : key;
660
- const typeHint = inferJsonTypeHint(value);
661
- paths.push({ path, kind: "data", typeHint, stateName });
662
- if (Array.isArray(value)) {
663
- paths.push({ path: `${path}.*`, kind: "list", stateName });
664
- paths.push({ path: `${path}.length`, kind: "data", typeHint: "number", stateName });
665
- if (value.length > 0 && typeof value[0] === "object" && value[0] !== null && !Array.isArray(value[0])) {
666
- const firstElement = value[0];
667
- for (const [childKey, childValue] of Object.entries(firstElement)) {
668
- const childPath = `${path}.*.${childKey}`;
669
- paths.push({ path: childPath, kind: "data", typeHint: inferJsonTypeHint(childValue), stateName });
670
- }
1364
+ pushJsonValuePaths(path, value, paths, stateName, depth);
1365
+ }
1366
+ }
1367
+ function pushJsonValuePaths(path, value, paths, stateName, depth) {
1368
+ paths.push({ path, kind: "data", typeHint: inferJsonTypeHint(value), stateName });
1369
+ if (Array.isArray(value)) {
1370
+ paths.push({ path: `${path}.*`, kind: "list", stateName });
1371
+ paths.push({ path: `${path}.length`, kind: "data", typeHint: "number", stateName });
1372
+ if (depth >= MAX_OBJECT_NEST_DEPTH) return;
1373
+ if (value.length > 0 && typeof value[0] === "object" && value[0] !== null && !Array.isArray(value[0])) {
1374
+ const firstElement = value[0];
1375
+ for (const [childKey, childValue] of Object.entries(firstElement)) {
1376
+ pushJsonValuePaths(`${path}.*.${childKey}`, childValue, paths, stateName, depth + 1);
671
1377
  }
672
- } else if (typeof value === "object" && value !== null) {
673
- collectJsonPaths(value, path, paths, stateName, depth + 1);
674
1378
  }
1379
+ } else if (typeof value === "object" && value !== null) {
1380
+ collectJsonPaths(value, path, paths, stateName, depth + 1);
675
1381
  }
676
1382
  }
677
1383
  function inferJsonTypeHint(value) {
@@ -711,17 +1417,32 @@ function parseTopLevelProperties(objectContent) {
711
1417
  const braceStart = match.index + match[0].length - 1;
712
1418
  const body = extractBracedContent(objectContent, scan, braceStart);
713
1419
  regex.lastIndex = braceStart + body.length + 2;
1420
+ return { body, bodyStart: braceStart + 1 };
714
1421
  };
715
1422
  const accessorName = nameAt(1) ?? nameAt(2) ?? nameAt(3);
716
1423
  if (accessorName) {
717
- props.push({ name: accessorName, kind: "getter", nameStart: nameSpan[0], nameEnd: nameSpan[1] });
718
- skipBody();
1424
+ const { body, bodyStart } = skipBody();
1425
+ props.push({
1426
+ name: accessorName,
1427
+ kind: "getter",
1428
+ value: body,
1429
+ valueStart: bodyStart,
1430
+ nameStart: nameSpan[0],
1431
+ nameEnd: nameSpan[1]
1432
+ });
719
1433
  continue;
720
1434
  }
721
1435
  const methodName = nameAt(4) ?? nameAt(5) ?? nameAt(6);
722
1436
  if (methodName) {
723
- props.push({ name: methodName, kind: "method", nameStart: nameSpan[0], nameEnd: nameSpan[1] });
724
- skipBody();
1437
+ const { body, bodyStart } = skipBody();
1438
+ props.push({
1439
+ name: methodName,
1440
+ kind: "method",
1441
+ value: body,
1442
+ valueStart: bodyStart,
1443
+ nameStart: nameSpan[0],
1444
+ nameEnd: nameSpan[1]
1445
+ });
725
1446
  continue;
726
1447
  }
727
1448
  const propName = nameAt(7) ?? nameAt(8) ?? nameAt(9);
@@ -842,21 +1563,15 @@ function extractObjectContent(value) {
842
1563
  if (start === -1) return "";
843
1564
  return extractBracedContent(trimmed, scan, start);
844
1565
  }
845
- function extractArrayElementProperties(value) {
1566
+ function extractArrayElementDataProperties(value) {
846
1567
  const trimmed = value.trim();
847
1568
  if (!trimmed.startsWith("[")) return [];
848
1569
  const scan = maskCommentsAndStrings(trimmed);
849
- const objectStart = scan.indexOf("{");
850
- if (objectStart === -1) return [];
851
- const objectContent = extractBracedContent(trimmed, scan, objectStart);
852
- const props = [];
853
- const allProps = parseTopLevelProperties(objectContent);
854
- for (const prop of allProps) {
855
- if (prop.kind === "data") {
856
- props.push({ name: prop.name, typeHint: prop.typeHint });
857
- }
858
- }
859
- return props;
1570
+ let first = 1;
1571
+ while (first < scan.length && /\s/.test(scan[first])) first++;
1572
+ if (scan[first] !== "{") return [];
1573
+ const objectContent = extractBracedContent(trimmed, scan, first);
1574
+ return parseTopLevelProperties(objectContent).filter((prop) => prop.kind === "data");
860
1575
  }
861
1576
  function extractJsDocType(content, propIndex) {
862
1577
  const before = content.slice(Math.max(0, propIndex - 200), propIndex);
@@ -992,6 +1707,9 @@ function getInnermostForPath(html, offset, bindAttrName = "data-wcs") {
992
1707
  return chain.length === 0 ? null : chain[chain.length - 1];
993
1708
  }
994
1709
  function getEnclosingForPaths(html, offset, bindAttrName = "data-wcs") {
1710
+ return getEnclosingFors(html, offset, bindAttrName).map((entry) => entry.path);
1711
+ }
1712
+ function getEnclosingFors(html, offset, bindAttrName = "data-wcs") {
995
1713
  const escaped = bindAttrName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
996
1714
  const openRegex = new RegExp(
997
1715
  `<template[^>]*${escaped}\\s*=\\s*["']\\s*for\\s*:\\s*([^"']+?)\\s*["']`,
@@ -1005,11 +1723,42 @@ function getEnclosingForPaths(html, offset, bindAttrName = "data-wcs") {
1005
1723
  if (tagEnd === -1 || tagEnd >= offset) continue;
1006
1724
  const depth = getForTemplateDepthAt(html, match.index, offset, bindAttrName);
1007
1725
  if (depth > 0) {
1008
- enclosing.push(match[1].trim());
1726
+ enclosing.push({ path: match[1].trim(), anchor: match.index });
1009
1727
  }
1010
1728
  }
1011
1729
  return enclosing;
1012
1730
  }
1731
+ function countWildcardSegments(path) {
1732
+ let count = 0;
1733
+ for (const segment of path.split(".")) {
1734
+ if (segment === "*") count++;
1735
+ }
1736
+ return count;
1737
+ }
1738
+ function forPathOf(raw) {
1739
+ let path = raw.trim();
1740
+ const pipe = path.indexOf("|");
1741
+ if (pipe !== -1) path = path.slice(0, pipe).trim();
1742
+ const at = path.indexOf("@");
1743
+ if (at !== -1) path = path.slice(0, at).trim();
1744
+ return path;
1745
+ }
1746
+ function getAvailableWildcardRank(html, offset, bindAttrName = "data-wcs") {
1747
+ const chain = getEnclosingForPaths(html, offset, bindAttrName);
1748
+ if (chain.length === 0) return 0;
1749
+ let resolved = "";
1750
+ for (const raw of chain) {
1751
+ const path = forPathOf(raw);
1752
+ if (path === ".") {
1753
+ resolved = `${resolved}.*`;
1754
+ } else if (path.startsWith(".")) {
1755
+ resolved = `${resolved}.*.${path.slice(1)}`;
1756
+ } else {
1757
+ resolved = path;
1758
+ }
1759
+ }
1760
+ return countWildcardSegments(resolved) + 1;
1761
+ }
1013
1762
  function getForTemplateDepthAt(html, openPos, offset, bindAttrName) {
1014
1763
  const tagEnd = html.indexOf(">", openPos);
1015
1764
  if (tagEnd === -1 || tagEnd >= offset) return 0;
@@ -1040,8 +1789,8 @@ function getForTemplateDepthAt(html, openPos, offset, bindAttrName) {
1040
1789
  }
1041
1790
 
1042
1791
  // src/core/messages.ts
1043
- function resolveLocale(locale) {
1044
- if (locale === void 0 || locale === "" || /^ja\b|^ja[-_]/i.test(locale) || locale.toLowerCase() === "ja") return "ja";
1792
+ function resolveLocale(locale3) {
1793
+ if (locale3 === void 0 || locale3 === "" || /^ja\b|^ja[-_]/i.test(locale3) || locale3.toLowerCase() === "ja") return "ja";
1045
1794
  return "en";
1046
1795
  }
1047
1796
  var JA_EXPECTED_LABEL = {
@@ -1063,6 +1812,10 @@ var ja = {
1063
1812
  omittedPathOutsideFor: (p) => `\u7701\u7565\u30D1\u30B9 "${p}" \u306F <template for> \u306E\u5916\u5074\u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`,
1064
1813
  loopIndexOutsideFor: (p) => `\u30EB\u30FC\u30D7\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9 "${p}" \u306F <template for> \u306E\u5916\u5074\u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`,
1065
1814
  resolvedPathInUi: (p) => `\u89E3\u6C7A\u6E08\u307F\u30D1\u30B9 "${p}" \u306F UI \u30D0\u30A4\u30F3\u30C7\u30A3\u30F3\u30B0\u3067\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002\u30D1\u30BF\u30FC\u30F3\u30D1\u30B9\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044`,
1815
+ indexArity: (api, p, req, wc, actual) => `${api}("${p}") \u306E\u6DFB\u5B57\u306F${req === "exact" ? `\u3061\u3087\u3046\u3069 ${wc} \u500B` : `${wc} \u500B\u4EE5\u4E0B`}\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\uFF08\u30D1\u30B9\u4E2D\u306E "*" \u306F ${wc} \u500B\uFF09\u3002${actual} \u500B\u6307\u5B9A\u3055\u308C\u3066\u3044\u307E\u3059`,
1816
+ wildcardRank: (subject, needed, available) => `${subject} \u306F ${needed} \u6BB5\u306E\u30EB\u30FC\u30D7\u304C\u5FC5\u8981\u3067\u3059\u304C\u3001\u73FE\u5728\u306E\u30B9\u30B3\u30FC\u30D7\u306F ${available} \u6BB5\u3067\u3059`,
1817
+ getterCycle: (cycle) => `\u30D1\u30B9 getter \u304C\u5FAA\u74B0\u53C2\u7167\u3057\u3066\u3044\u307E\u3059: ${cycle}`,
1818
+ updatedCallbackUnbound: (p) => `$updatedCallback \u306F binding \u99C6\u52D5\u3067\u3059\u3002"${p}" \u306F\u3053\u306E\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u306E\u3069\u306E\u30D0\u30A4\u30F3\u30C7\u30A3\u30F3\u30B0\u306B\u3082\u73FE\u308C\u306A\u3044\u305F\u3081\u3001\u3053\u306E\u5206\u5C90\u306F\u4E00\u5EA6\u3082\u5B9F\u884C\u3055\u308C\u307E\u305B\u3093\u3002\u63CF\u753B\u306B\u4F9D\u5B58\u305B\u305A\u53CD\u5FDC\u3059\u308B\u306A\u3089 $watch \u3092\u4F7F\u3063\u3066\u304F\u3060\u3055\u3044`,
1066
1819
  handlerFilterNotAllowed: (prop) => `\u30A4\u30D9\u30F3\u30C8\u30CF\u30F3\u30C9\u30E9 "${prop}" \u306B\u30D5\u30A3\u30EB\u30BF\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`,
1067
1820
  typeExpectation: (label, expected, resultType) => `"${label}" \u306B\u306F${JA_EXPECTED_LABEL[expected]}\u304C\u5FC5\u8981\u3067\u3059\uFF08\u73FE\u5728\u306E\u578B: ${resultType}\uFF09`,
1068
1821
  filterUnknown: (n) => `\u30D5\u30A3\u30EB\u30BF "${n}" \u306F\u7D44\u307F\u8FBC\u307F\u30D5\u30A3\u30EB\u30BF\u306B\u5B58\u5728\u3057\u307E\u305B\u3093`,
@@ -1084,6 +1837,7 @@ var ja = {
1084
1837
  arrayIndexAssign: (sp) => `\u914D\u5217\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u3078\u306E\u76F4\u63A5\u4EE3\u5165\u306F\u30EA\u30A2\u30AF\u30C6\u30A3\u30D6\u66F4\u65B0\u3092\u30C8\u30EA\u30AC\u30FC\u3057\u307E\u305B\u3093\u3002this["${sp}"] \u306E\u3088\u3046\u306A\u30C9\u30C3\u30C8\u30D1\u30B9\u4EE3\u5165\u3001\u307E\u305F\u306F with() \u3068\u518D\u4EE3\u5165\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002`,
1085
1838
  tagMemberUnknown: (prop, tag) => `"${prop}" \u306F <${tag}> \u306E wcBindable \u30E1\u30F3\u30D0\u30FC\u3067\u306F\u3042\u308A\u307E\u305B\u3093\uFF08\u672A\u77E5\u30E1\u30F3\u30D0\u30FC\u3078\u306E\u30D0\u30A4\u30F3\u30C9\u306F\u9ED9\u3063\u3066\u7121\u8996\u3055\u308C\u307E\u3059\uFF09`,
1086
1839
  tagCommandUnknown: (name, tag, declared) => `"${name}" \u306F <${tag}> \u306E command \u3067\u306F\u3042\u308A\u307E\u305B\u3093\uFF08\u5BA3\u8A00\u6E08\u307F: ${declared}\uFF09`,
1840
+ spreadNoBindable: (tag) => `'...'\uFF08spread\uFF09\u306F <${tag}> \u306B\u6709\u52B9\u306A wcBindable \u5BA3\u8A00\u304C\u5FC5\u8981\u3067\u3059 \u2014 \u3053\u306E\u30BF\u30B0\u306F\u5BA3\u8A00\u3092\u6301\u305F\u306A\u3044\u305F\u3081\u3001\u30E9\u30F3\u30BF\u30A4\u30E0\u306F\u30A8\u30E9\u30FC\u3092\u9001\u51FA\u3057\u307E\u3059`,
1087
1841
  tagEventTokenKeyUnknown: (name, tag, declared) => `eventToken \u306E\u30AD\u30FC "${name}" \u306F <${tag}> \u306E wcBindable \u30D7\u30ED\u30D1\u30C6\u30A3\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002\u751F DOM \u30A4\u30D9\u30F3\u30C8\u540D\u306F\u767A\u706B\u3057\u307E\u305B\u3093 \u2014 \u30D7\u30ED\u30D1\u30C6\u30A3\u540D\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u5BA3\u8A00\u6E08\u307F: ${declared}\uFF09`,
1088
1842
  didYouMean: (c) => `\u3002\u3082\u3057\u304B\u3057\u3066: "${c}"`,
1089
1843
  none: () => `\u306A\u3057`,
@@ -1112,6 +1866,10 @@ var en = {
1112
1866
  omittedPathOutsideFor: (p) => `Shorthand path "${p}" cannot be used outside a <template for>`,
1113
1867
  loopIndexOutsideFor: (p) => `Loop index "${p}" cannot be used outside a <template for>`,
1114
1868
  resolvedPathInUi: (p) => `Resolved path "${p}" cannot be used in a UI binding. Use a pattern path instead`,
1869
+ indexArity: (api, p, req, wc, actual) => `${api}("${p}") requires ${req === "exact" ? "exactly" : "at most"} ${wc} index(es) ("*" appears ${wc} time(s) in the path) but got ${actual}`,
1870
+ wildcardRank: (subject, needed, available) => `${subject} needs ${needed} enclosing loop level(s) but the current scope provides ${available}`,
1871
+ getterCycle: (cycle) => `Path getters form a dependency cycle: ${cycle}`,
1872
+ updatedCallbackUnbound: (p) => `$updatedCallback is binding-driven. "${p}" is not bound anywhere in this document, so this branch never runs. Use $watch to react without depending on what is rendered`,
1115
1873
  handlerFilterNotAllowed: (prop) => `Filters cannot be applied to event handler "${prop}"`,
1116
1874
  typeExpectation: (label, expected, resultType) => `"${label}" requires ${EN_EXPECTED_LABEL[expected]} (current type: ${resultType})`,
1117
1875
  filterUnknown: (n) => `Filter "${n}" is not a built-in filter`,
@@ -1133,6 +1891,7 @@ var en = {
1133
1891
  arrayIndexAssign: (sp) => `Assigning directly to an array index does not trigger a reactive update. Use a dot-path assignment like this["${sp}"], or with() plus reassignment.`,
1134
1892
  tagMemberUnknown: (prop, tag) => `"${prop}" is not a wcBindable member of <${tag}> (bindings to unknown members are silently ignored)`,
1135
1893
  tagCommandUnknown: (name, tag, declared) => `"${name}" is not a command of <${tag}> (declared: ${declared})`,
1894
+ spreadNoBindable: (tag) => `'...' (spread) requires <${tag}> to expose a valid wcBindable declaration \u2014 this tag declares none, so the runtime raises an error`,
1136
1895
  tagEventTokenKeyUnknown: (name, tag, declared) => `eventToken key "${name}" is not a wcBindable property of <${tag}>. Raw DOM event names never fire \u2014 use the property name (declared: ${declared})`,
1137
1896
  didYouMean: (c) => `. Did you mean "${c}"?`,
1138
1897
  none: () => `none`,
@@ -1143,15 +1902,15 @@ var en = {
1143
1902
  signalsDualEntry: () => `Both @wcstack/signals and @wcstack/signals/dom are imported on this page. On a CDN each entry is a self-contained bundle, so the reactive core is duplicated and reactivity breaks at the seam \u2014 import everything from the single /dom entry`
1144
1903
  };
1145
1904
  var CATALOGS = { ja, en };
1146
- function getMessages(locale) {
1147
- return CATALOGS[resolveLocale(locale)];
1905
+ function getMessages(locale3) {
1906
+ return CATALOGS[resolveLocale(locale3)];
1148
1907
  }
1149
1908
 
1150
1909
  // src/service/bindingValidator.ts
1151
1910
  var filterMap = new Map(BUILTIN_FILTERS.map((f) => [f.name, f]));
1152
- function validateBindings(html, attrName, stateTagName = "wcs-state", locale, fileReader) {
1911
+ function validateBindings(html, attrName, stateTagName = "wcs-state", locale3, fileReader) {
1153
1912
  const diagnostics = [];
1154
- const msgs = getMessages(locale);
1913
+ const msgs = getMessages(locale3);
1155
1914
  const statePaths = getStatePathsFromHtml(html, stateTagName, fileReader);
1156
1915
  const pathsByState = /* @__PURE__ */ new Map();
1157
1916
  for (const p of statePaths) {
@@ -1328,6 +2087,24 @@ function validateBindings(html, attrName, stateTagName = "wcs-state", locale, fi
1328
2087
  severity: "warning"
1329
2088
  });
1330
2089
  }
2090
+ if (insideFor && !pathTrimmed.startsWith(".") && !binding.includes("@")) {
2091
+ const indexMatch = /^\$(\d+)$/.exec(pathTrimmed);
2092
+ const needed = indexMatch !== null ? Number(indexMatch[1]) : pathTrimmed.includes("*") ? countWildcardSegments(pathTrimmed) : 0;
2093
+ if (needed > 0) {
2094
+ const available = getAvailableWildcardRank(html, attr.valueStart, attrName);
2095
+ if (available > 0 && needed > available) {
2096
+ const pathOffset = binding.indexOf(parsed.path);
2097
+ const pathStart = bindingStart + pathOffset;
2098
+ diagnostics.push({
2099
+ code: WcsDiagnosticCode.WildcardRank,
2100
+ start: pathStart,
2101
+ end: pathStart + pathTrimmed.length,
2102
+ message: msgs.wildcardRank(`"${pathTrimmed}"`, needed, available),
2103
+ severity: "warning"
2104
+ });
2105
+ }
2106
+ }
2107
+ }
1331
2108
  if (/\.\d+\.|\.\d+$/.test(pathTrimmed)) {
1332
2109
  const pathOffset = binding.indexOf(parsed.path);
1333
2110
  const pathStart = bindingStart + pathOffset;
@@ -1671,8 +2448,8 @@ function isLiteral(value) {
1671
2448
  }
1672
2449
 
1673
2450
  // src/service/stateTypeValidator.ts
1674
- function validateStateTypes(html, stateTagName = "wcs-state", locale) {
1675
- const msgs = getMessages(locale);
2451
+ function validateStateTypes(html, stateTagName = "wcs-state", locale3) {
2452
+ const msgs = getMessages(locale3);
1676
2453
  const blocks = parseWcsScriptBlocks(html, stateTagName);
1677
2454
  const diagnostics = [];
1678
2455
  for (const block of blocks) {
@@ -1799,8 +2576,8 @@ function isApiRoot(root) {
1799
2576
  // src/service/nestedAssignValidator.ts
1800
2577
  var NESTED_ASSIGN = new RegExp(`${ROOT_DOT}(${CHAIN_ONE_PLUS})${ASSIGN_TAIL}`, "g");
1801
2578
  var PRE_NESTED_INCDEC = new RegExp(`${PRE_INCDEC}${ROOT_DOT}(${CHAIN_ONE_PLUS})`, "g");
1802
- function validateNestedAssigns(html, stateTagName = "wcs-state", locale) {
1803
- const msgs = getMessages(locale);
2579
+ function validateNestedAssigns(html, stateTagName = "wcs-state", locale3) {
2580
+ const msgs = getMessages(locale3);
1804
2581
  const blocks = parseWcsScriptBlocks(html, stateTagName);
1805
2582
  const diagnostics = [];
1806
2583
  for (const block of blocks) {
@@ -1822,7 +2599,7 @@ function findNestedAssigns(script, baseOffset, msgs, out) {
1822
2599
  start,
1823
2600
  end: start + full.length,
1824
2601
  message: msgs.nestedAssign(suggestedPath),
1825
- severity: "warning"
2602
+ severity: "error"
1826
2603
  });
1827
2604
  }
1828
2605
  }
@@ -1851,8 +2628,8 @@ var PRE_BRACKET_INDEX = new RegExp(`${PRE_INCDEC}${ROOT_BRACKET}(${BRACKETS_ONLY
1851
2628
  function toAccessor(path) {
1852
2629
  return /^[A-Za-z_]\w*$/.test(path) ? `this.${path}` : `this["${path}"]`;
1853
2630
  }
1854
- function validateArrayMutations(html, stateTagName = "wcs-state", locale) {
1855
- const msgs = getMessages(locale);
2631
+ function validateArrayMutations(html, stateTagName = "wcs-state", locale3) {
2632
+ const msgs = getMessages(locale3);
1856
2633
  const blocks = parseWcsScriptBlocks(html, stateTagName);
1857
2634
  const diagnostics = [];
1858
2635
  for (const block of blocks) {
@@ -1875,7 +2652,7 @@ function findDestructiveCalls(script, baseOffset, msgs, out) {
1875
2652
  start,
1876
2653
  end: start + full.length,
1877
2654
  message: msgs.arrayMutation(method, ALTERNATIVES[method](toAccessor(statePath))),
1878
- severity: "warning",
2655
+ severity: "error",
1879
2656
  statePath
1880
2657
  });
1881
2658
  }
@@ -1895,7 +2672,7 @@ function findIndexAssigns(script, baseOffset, msgs, out) {
1895
2672
  start,
1896
2673
  end: start + full.length,
1897
2674
  message: msgs.arrayIndexAssign(suggestedPath),
1898
- severity: "warning",
2675
+ severity: "error",
1899
2676
  statePath: suggestedPath
1900
2677
  });
1901
2678
  }
@@ -1962,9 +2739,9 @@ function isInsideTag(html, offset, tagName) {
1962
2739
  }
1963
2740
 
1964
2741
  // src/service/templateSyntaxValidator.ts
1965
- function validateTemplateSyntax(html, stateTagName, bindAttrName = "data-wcs", locale, fileReader) {
2742
+ function validateTemplateSyntax(html, stateTagName, bindAttrName = "data-wcs", locale3, fileReader) {
1966
2743
  const diagnostics = [];
1967
- const msgs = getMessages(locale);
2744
+ const msgs = getMessages(locale3);
1968
2745
  const allPaths = getStatePathsFromHtml(html, stateTagName, fileReader);
1969
2746
  if (allPaths.length === 0) return diagnostics;
1970
2747
  const defaultPaths = allPaths.filter((p) => p.stateName === "default");
@@ -2016,6 +2793,22 @@ function validateTemplateSyntax(html, stateTagName, bindAttrName = "data-wcs", l
2016
2793
  severity: "warning"
2017
2794
  });
2018
2795
  }
2796
+ if (insideFor && !pathPart.startsWith(".") && !pathPart.includes("@")) {
2797
+ const indexMatch = /^\$(\d+)$/.exec(pathPart);
2798
+ const needed = indexMatch !== null ? Number(indexMatch[1]) : pathPart.includes("*") ? countWildcardSegments(pathPart) : 0;
2799
+ if (needed > 0) {
2800
+ const available = getAvailableWildcardRank(html, item.matchStart, bindAttrName);
2801
+ if (available > 0 && needed > available) {
2802
+ diagnostics.push({
2803
+ code: WcsDiagnosticCode.WildcardRank,
2804
+ start: item.exprStart,
2805
+ end: item.exprStart + pathPart.length,
2806
+ message: msgs.wildcardRank(`"${pathPart}"`, needed, available),
2807
+ severity: "warning"
2808
+ });
2809
+ }
2810
+ }
2811
+ }
2019
2812
  if (/\.\d+\.|\.\d+$/.test(pathPart)) {
2020
2813
  diagnostics.push({
2021
2814
  code: WcsDiagnosticCode.TemplateSyntax,
@@ -2079,6 +2872,7 @@ function isValidTemplatePath(path, pathSet, scopedPaths) {
2079
2872
  var BUILTIN_TAGS = {
2080
2873
  "wcs-accelerometer": {
2081
2874
  "package": "accelerometer",
2875
+ "hasWcBindable": true,
2082
2876
  "observedAttributes": [],
2083
2877
  "inputs": {
2084
2878
  "frequency": null
@@ -2097,6 +2891,7 @@ var BUILTIN_TAGS = {
2097
2891
  },
2098
2892
  "wcs-ambient-light-sensor": {
2099
2893
  "package": "ambient-light-sensor",
2894
+ "hasWcBindable": true,
2100
2895
  "observedAttributes": [],
2101
2896
  "inputs": {
2102
2897
  "frequency": null
@@ -2113,6 +2908,7 @@ var BUILTIN_TAGS = {
2113
2908
  },
2114
2909
  "wcs-audio": {
2115
2910
  "package": "audio",
2911
+ "hasWcBindable": true,
2116
2912
  "observedAttributes": [
2117
2913
  "volume",
2118
2914
  "limiter",
@@ -2145,6 +2941,7 @@ var BUILTIN_TAGS = {
2145
2941
  },
2146
2942
  "wcs-voice": {
2147
2943
  "package": "audio",
2944
+ "hasWcBindable": false,
2148
2945
  "observedAttributes": [
2149
2946
  "poly"
2150
2947
  ],
@@ -2154,6 +2951,7 @@ var BUILTIN_TAGS = {
2154
2951
  },
2155
2952
  "wcs-osc": {
2156
2953
  "package": "audio",
2954
+ "hasWcBindable": true,
2157
2955
  "observedAttributes": [
2158
2956
  "frequency",
2159
2957
  "detune",
@@ -2179,6 +2977,7 @@ var BUILTIN_TAGS = {
2179
2977
  },
2180
2978
  "wcs-noise": {
2181
2979
  "package": "audio",
2980
+ "hasWcBindable": true,
2182
2981
  "observedAttributes": [
2183
2982
  "id",
2184
2983
  "out",
@@ -2193,6 +2992,7 @@ var BUILTIN_TAGS = {
2193
2992
  },
2194
2993
  "wcs-biquad": {
2195
2994
  "package": "audio",
2995
+ "hasWcBindable": true,
2196
2996
  "observedAttributes": [
2197
2997
  "frequency",
2198
2998
  "q",
@@ -2218,6 +3018,7 @@ var BUILTIN_TAGS = {
2218
3018
  },
2219
3019
  "wcs-gain": {
2220
3020
  "package": "audio",
3021
+ "hasWcBindable": true,
2221
3022
  "observedAttributes": [
2222
3023
  "gain",
2223
3024
  "id",
@@ -2235,6 +3036,7 @@ var BUILTIN_TAGS = {
2235
3036
  },
2236
3037
  "wcs-delay": {
2237
3038
  "package": "audio",
3039
+ "hasWcBindable": true,
2238
3040
  "observedAttributes": [
2239
3041
  "time",
2240
3042
  "feedback",
@@ -2256,6 +3058,7 @@ var BUILTIN_TAGS = {
2256
3058
  },
2257
3059
  "wcs-shaper": {
2258
3060
  "package": "audio",
3061
+ "hasWcBindable": true,
2259
3062
  "observedAttributes": [
2260
3063
  "amount",
2261
3064
  "id",
@@ -2273,6 +3076,7 @@ var BUILTIN_TAGS = {
2273
3076
  },
2274
3077
  "wcs-env": {
2275
3078
  "package": "audio",
3079
+ "hasWcBindable": true,
2276
3080
  "observedAttributes": [
2277
3081
  "attack",
2278
3082
  "decay",
@@ -2298,6 +3102,7 @@ var BUILTIN_TAGS = {
2298
3102
  },
2299
3103
  "wcs-lfo": {
2300
3104
  "package": "audio",
3105
+ "hasWcBindable": true,
2301
3106
  "observedAttributes": [
2302
3107
  "rate",
2303
3108
  "depth",
@@ -2319,6 +3124,7 @@ var BUILTIN_TAGS = {
2319
3124
  },
2320
3125
  "wcs-analyser": {
2321
3126
  "package": "audio",
3127
+ "hasWcBindable": true,
2322
3128
  "observedAttributes": [
2323
3129
  "fft",
2324
3130
  "smoothing",
@@ -2342,6 +3148,7 @@ var BUILTIN_TAGS = {
2342
3148
  },
2343
3149
  "wcs-broadcast": {
2344
3150
  "package": "broadcast",
3151
+ "hasWcBindable": true,
2345
3152
  "observedAttributes": [
2346
3153
  "name"
2347
3154
  ],
@@ -2362,6 +3169,7 @@ var BUILTIN_TAGS = {
2362
3169
  },
2363
3170
  "wcs-camera": {
2364
3171
  "package": "camera",
3172
+ "hasWcBindable": true,
2365
3173
  "observedAttributes": [
2366
3174
  "facing-mode",
2367
3175
  "device-id",
@@ -2397,6 +3205,7 @@ var BUILTIN_TAGS = {
2397
3205
  },
2398
3206
  "wcs-recorder": {
2399
3207
  "package": "camera",
3208
+ "hasWcBindable": true,
2400
3209
  "observedAttributes": [],
2401
3210
  "inputs": {
2402
3211
  "mimeType": "mime-type",
@@ -2426,6 +3235,7 @@ var BUILTIN_TAGS = {
2426
3235
  },
2427
3236
  "wcs-clipboard": {
2428
3237
  "package": "clipboard",
3238
+ "hasWcBindable": true,
2429
3239
  "observedAttributes": [],
2430
3240
  "inputs": {
2431
3241
  "monitor": "monitor"
@@ -2454,6 +3264,7 @@ var BUILTIN_TAGS = {
2454
3264
  },
2455
3265
  "wcs-contacts": {
2456
3266
  "package": "contacts",
3267
+ "hasWcBindable": true,
2457
3268
  "observedAttributes": [],
2458
3269
  "inputs": {},
2459
3270
  "properties": [
@@ -2469,6 +3280,7 @@ var BUILTIN_TAGS = {
2469
3280
  },
2470
3281
  "wcs-credential": {
2471
3282
  "package": "credential",
3283
+ "hasWcBindable": true,
2472
3284
  "observedAttributes": [],
2473
3285
  "inputs": {},
2474
3286
  "properties": [
@@ -2485,6 +3297,7 @@ var BUILTIN_TAGS = {
2485
3297
  },
2486
3298
  "wcs-debounce": {
2487
3299
  "package": "debounce",
3300
+ "hasWcBindable": true,
2488
3301
  "observedAttributes": [],
2489
3302
  "inputs": {
2490
3303
  "source": null,
@@ -2506,6 +3319,7 @@ var BUILTIN_TAGS = {
2506
3319
  },
2507
3320
  "wcs-throttle": {
2508
3321
  "package": "debounce",
3322
+ "hasWcBindable": true,
2509
3323
  "observedAttributes": [],
2510
3324
  "inputs": {
2511
3325
  "source": null,
@@ -2527,6 +3341,7 @@ var BUILTIN_TAGS = {
2527
3341
  },
2528
3342
  "wcs-defined": {
2529
3343
  "package": "defined",
3344
+ "hasWcBindable": true,
2530
3345
  "observedAttributes": [],
2531
3346
  "inputs": {
2532
3347
  "tags": "tags",
@@ -2545,6 +3360,7 @@ var BUILTIN_TAGS = {
2545
3360
  },
2546
3361
  "wcs-eyedropper": {
2547
3362
  "package": "eyedropper",
3363
+ "hasWcBindable": true,
2548
3364
  "observedAttributes": [],
2549
3365
  "inputs": {},
2550
3366
  "properties": [
@@ -2561,6 +3377,7 @@ var BUILTIN_TAGS = {
2561
3377
  },
2562
3378
  "wcs-fetch": {
2563
3379
  "package": "fetch",
3380
+ "hasWcBindable": true,
2564
3381
  "observedAttributes": [
2565
3382
  "url"
2566
3383
  ],
@@ -2589,6 +3406,7 @@ var BUILTIN_TAGS = {
2589
3406
  },
2590
3407
  "wcs-fetch-header": {
2591
3408
  "package": "fetch",
3409
+ "hasWcBindable": false,
2592
3410
  "observedAttributes": [],
2593
3411
  "inputs": {},
2594
3412
  "properties": [],
@@ -2596,6 +3414,7 @@ var BUILTIN_TAGS = {
2596
3414
  },
2597
3415
  "wcs-fetch-body": {
2598
3416
  "package": "fetch",
3417
+ "hasWcBindable": false,
2599
3418
  "observedAttributes": [],
2600
3419
  "inputs": {},
2601
3420
  "properties": [],
@@ -2603,6 +3422,7 @@ var BUILTIN_TAGS = {
2603
3422
  },
2604
3423
  "wcs-infinite-scroll": {
2605
3424
  "package": "fetch",
3425
+ "hasWcBindable": false,
2606
3426
  "observedAttributes": [
2607
3427
  "target",
2608
3428
  "root",
@@ -2616,6 +3436,7 @@ var BUILTIN_TAGS = {
2616
3436
  },
2617
3437
  "wcs-fullscreen": {
2618
3438
  "package": "fullscreen",
3439
+ "hasWcBindable": true,
2619
3440
  "observedAttributes": [
2620
3441
  "target"
2621
3442
  ],
@@ -2634,6 +3455,7 @@ var BUILTIN_TAGS = {
2634
3455
  },
2635
3456
  "wcs-geo": {
2636
3457
  "package": "geolocation",
3458
+ "hasWcBindable": true,
2637
3459
  "observedAttributes": [],
2638
3460
  "inputs": {
2639
3461
  "highAccuracy": "high-accuracy",
@@ -2665,6 +3487,7 @@ var BUILTIN_TAGS = {
2665
3487
  },
2666
3488
  "wcs-gyroscope": {
2667
3489
  "package": "gyroscope",
3490
+ "hasWcBindable": true,
2668
3491
  "observedAttributes": [],
2669
3492
  "inputs": {
2670
3493
  "frequency": null
@@ -2683,6 +3506,7 @@ var BUILTIN_TAGS = {
2683
3506
  },
2684
3507
  "wcs-idle": {
2685
3508
  "package": "idle",
3509
+ "hasWcBindable": true,
2686
3510
  "observedAttributes": [],
2687
3511
  "inputs": {
2688
3512
  "threshold": "threshold"
@@ -2702,6 +3526,7 @@ var BUILTIN_TAGS = {
2702
3526
  },
2703
3527
  "wcs-intersect": {
2704
3528
  "package": "intersection",
3529
+ "hasWcBindable": true,
2705
3530
  "observedAttributes": [
2706
3531
  "target",
2707
3532
  "root",
@@ -2735,6 +3560,7 @@ var BUILTIN_TAGS = {
2735
3560
  },
2736
3561
  "wcs-magnetometer": {
2737
3562
  "package": "magnetometer",
3563
+ "hasWcBindable": true,
2738
3564
  "observedAttributes": [],
2739
3565
  "inputs": {
2740
3566
  "frequency": null
@@ -2753,6 +3579,7 @@ var BUILTIN_TAGS = {
2753
3579
  },
2754
3580
  "wcs-midi": {
2755
3581
  "package": "midi",
3582
+ "hasWcBindable": true,
2756
3583
  "observedAttributes": [
2757
3584
  "input",
2758
3585
  "output",
@@ -2790,6 +3617,7 @@ var BUILTIN_TAGS = {
2790
3617
  },
2791
3618
  "wcs-network": {
2792
3619
  "package": "network",
3620
+ "hasWcBindable": true,
2793
3621
  "observedAttributes": [],
2794
3622
  "inputs": {},
2795
3623
  "properties": [
@@ -2803,6 +3631,7 @@ var BUILTIN_TAGS = {
2803
3631
  },
2804
3632
  "wcs-notify": {
2805
3633
  "package": "notification",
3634
+ "hasWcBindable": true,
2806
3635
  "observedAttributes": [],
2807
3636
  "inputs": {
2808
3637
  "notice": null,
@@ -2839,6 +3668,7 @@ var BUILTIN_TAGS = {
2839
3668
  },
2840
3669
  "wcs-permission": {
2841
3670
  "package": "permission",
3671
+ "hasWcBindable": true,
2842
3672
  "observedAttributes": [],
2843
3673
  "inputs": {
2844
3674
  "name": "name",
@@ -2856,6 +3686,7 @@ var BUILTIN_TAGS = {
2856
3686
  },
2857
3687
  "wcs-pip": {
2858
3688
  "package": "picture-in-picture",
3689
+ "hasWcBindable": true,
2859
3690
  "observedAttributes": [
2860
3691
  "target"
2861
3692
  ],
@@ -2874,6 +3705,7 @@ var BUILTIN_TAGS = {
2874
3705
  },
2875
3706
  "wcs-pointer-lock": {
2876
3707
  "package": "pointer-lock",
3708
+ "hasWcBindable": true,
2877
3709
  "observedAttributes": [
2878
3710
  "target"
2879
3711
  ],
@@ -2892,6 +3724,7 @@ var BUILTIN_TAGS = {
2892
3724
  },
2893
3725
  "wcs-raf": {
2894
3726
  "package": "raf",
3727
+ "hasWcBindable": true,
2895
3728
  "observedAttributes": [],
2896
3729
  "inputs": {
2897
3730
  "once": "once",
@@ -2917,6 +3750,7 @@ var BUILTIN_TAGS = {
2917
3750
  },
2918
3751
  "wcs-resize": {
2919
3752
  "package": "resize",
3753
+ "hasWcBindable": true,
2920
3754
  "observedAttributes": [
2921
3755
  "target",
2922
3756
  "box",
@@ -2945,6 +3779,7 @@ var BUILTIN_TAGS = {
2945
3779
  },
2946
3780
  "wcs-screen-orientation": {
2947
3781
  "package": "screen-orientation",
3782
+ "hasWcBindable": true,
2948
3783
  "observedAttributes": [],
2949
3784
  "inputs": {},
2950
3785
  "properties": [
@@ -2962,6 +3797,7 @@ var BUILTIN_TAGS = {
2962
3797
  },
2963
3798
  "wcs-share": {
2964
3799
  "package": "share",
3800
+ "hasWcBindable": true,
2965
3801
  "observedAttributes": [],
2966
3802
  "inputs": {},
2967
3803
  "properties": [
@@ -2977,6 +3813,7 @@ var BUILTIN_TAGS = {
2977
3813
  },
2978
3814
  "wcs-speak": {
2979
3815
  "package": "speech",
3816
+ "hasWcBindable": true,
2980
3817
  "observedAttributes": [],
2981
3818
  "inputs": {
2982
3819
  "say": null,
@@ -3007,6 +3844,7 @@ var BUILTIN_TAGS = {
3007
3844
  },
3008
3845
  "wcs-listen": {
3009
3846
  "package": "speech",
3847
+ "hasWcBindable": true,
3010
3848
  "observedAttributes": [],
3011
3849
  "inputs": {
3012
3850
  "lang": "lang",
@@ -3035,6 +3873,7 @@ var BUILTIN_TAGS = {
3035
3873
  },
3036
3874
  "wcs-sse": {
3037
3875
  "package": "sse",
3876
+ "hasWcBindable": true,
3038
3877
  "observedAttributes": [
3039
3878
  "url"
3040
3879
  ],
@@ -3062,6 +3901,7 @@ var BUILTIN_TAGS = {
3062
3901
  },
3063
3902
  "wcs-storage": {
3064
3903
  "package": "storage",
3904
+ "hasWcBindable": true,
3065
3905
  "observedAttributes": [
3066
3906
  "key",
3067
3907
  "type"
@@ -3088,6 +3928,7 @@ var BUILTIN_TAGS = {
3088
3928
  },
3089
3929
  "wcs-tilt": {
3090
3930
  "package": "tilt",
3931
+ "hasWcBindable": true,
3091
3932
  "observedAttributes": [],
3092
3933
  "inputs": {},
3093
3934
  "properties": [
@@ -3107,6 +3948,7 @@ var BUILTIN_TAGS = {
3107
3948
  },
3108
3949
  "wcs-timer": {
3109
3950
  "package": "timer",
3951
+ "hasWcBindable": true,
3110
3952
  "observedAttributes": [
3111
3953
  "interval"
3112
3954
  ],
@@ -3134,6 +3976,7 @@ var BUILTIN_TAGS = {
3134
3976
  },
3135
3977
  "wcs-upload": {
3136
3978
  "package": "upload",
3979
+ "hasWcBindable": true,
3137
3980
  "observedAttributes": [
3138
3981
  "url"
3139
3982
  ],
@@ -3165,6 +4008,7 @@ var BUILTIN_TAGS = {
3165
4008
  },
3166
4009
  "wcs-wakelock": {
3167
4010
  "package": "wakelock",
4011
+ "hasWcBindable": true,
3168
4012
  "observedAttributes": [
3169
4013
  "active",
3170
4014
  "type"
@@ -3186,6 +4030,7 @@ var BUILTIN_TAGS = {
3186
4030
  },
3187
4031
  "wcs-ws": {
3188
4032
  "package": "websocket",
4033
+ "hasWcBindable": true,
3189
4034
  "observedAttributes": [
3190
4035
  "url"
3191
4036
  ],
@@ -3218,6 +4063,7 @@ var BUILTIN_TAGS = {
3218
4063
  },
3219
4064
  "wcs-worker": {
3220
4065
  "package": "worker",
4066
+ "hasWcBindable": true,
3221
4067
  "observedAttributes": [
3222
4068
  "src"
3223
4069
  ],
@@ -3262,19 +4108,37 @@ var DOM_COMMON_PROPERTIES = /* @__PURE__ */ new Set([
3262
4108
  ]);
3263
4109
  var STRUCTURAL_DIRECTIVES2 = /* @__PURE__ */ new Set(["for", "if", "elseif", "else"]);
3264
4110
  var EMPTYISH_SEEDS = /* @__PURE__ */ new Set(["''", '""', "``", "null", "[]", "{}"]);
3265
- function validateIoNodes(html, bindAttribute = "data-wcs", stateTagName = "wcs-state", locale, fileReader) {
4111
+ function validateIoNodes(html, bindAttribute = "data-wcs", stateTagName = "wcs-state", locale3, fileReader) {
3266
4112
  const diagnostics = [];
3267
- const msgs = getMessages(locale);
4113
+ const msgs = getMessages(locale3);
3268
4114
  const occurrences = findBuiltinTagOccurrences(html);
3269
4115
  if (occurrences.length === 0) return diagnostics;
3270
4116
  let statePaths = null;
3271
4117
  const getPaths = () => statePaths ??= getStatePathsFromHtml(html, stateTagName, fileReader);
3272
4118
  for (const occ of occurrences) {
3273
4119
  const contract = BUILTIN_TAGS[occ.tagName];
3274
- if (contract.properties.length === 0 && contract.commands.length === 0 && Object.keys(contract.inputs).length === 0) continue;
3275
4120
  const bindAttr = extractAttributeValue(occ.attrsText, bindAttribute);
3276
4121
  if (!bindAttr) continue;
3277
4122
  const valueStart = occ.attrsStart + bindAttr.valueOffsetInAttrs;
4123
+ if (!contract.hasWcBindable) {
4124
+ let spreadExprOffset = 0;
4125
+ for (const expr of splitBindingExpressions(bindAttr.value)) {
4126
+ const exprStart = valueStart + spreadExprOffset;
4127
+ spreadExprOffset += expr.length + 1;
4128
+ if (parseBindingExpression(expr).property !== "...") continue;
4129
+ const start = exprStart + expr.indexOf("...");
4130
+ diagnostics.push({
4131
+ code: WcsDiagnosticCode.SpreadNoBindable,
4132
+ start,
4133
+ end: start + 3,
4134
+ severity: "error",
4135
+ tag: occ.tagName,
4136
+ message: msgs.spreadNoBindable(occ.tagName)
4137
+ });
4138
+ }
4139
+ continue;
4140
+ }
4141
+ if (contract.properties.length === 0 && contract.commands.length === 0 && Object.keys(contract.inputs).length === 0) continue;
3278
4142
  const hasManual = hasBooleanAttribute(occ.attrsText, "manual");
3279
4143
  let exprOffset = 0;
3280
4144
  for (const expr of splitBindingExpressions(bindAttr.value)) {
@@ -3455,9 +4319,9 @@ function hasBooleanAttribute(attrsText, attrName) {
3455
4319
  }
3456
4320
 
3457
4321
  // src/service/documentEnvValidator.ts
3458
- function validateDocumentEnv(html, locale) {
4322
+ function validateDocumentEnv(html, locale3) {
3459
4323
  const diagnostics = [];
3460
- const msgs = getMessages(locale);
4324
+ const msgs = getMessages(locale3);
3461
4325
  const scanText = blankHtmlComments(html);
3462
4326
  const autos = findWcstackAutoScripts(scanText);
3463
4327
  const stateIndex = autos.findIndex((a) => a.pkg === "state");
@@ -3567,9 +4431,9 @@ function blankJsComments(code) {
3567
4431
  }
3568
4432
 
3569
4433
  // src/service/watchDeclarationValidator.ts
3570
- var STATE_NAME_SEPARATOR = "@";
3571
- function validateWatchDeclarations(html, stateTagName = "wcs-state", locale) {
3572
- const msgs = getMessages(locale);
4434
+ var STATE_NAME_SEPARATOR2 = "@";
4435
+ function validateWatchDeclarations(html, stateTagName = "wcs-state", locale3) {
4436
+ const msgs = getMessages(locale3);
3573
4437
  const out = [];
3574
4438
  for (const block of parseWcsScriptBlocks(html, stateTagName)) {
3575
4439
  const nonObject = findNonObjectWatch(block.content);
@@ -3603,7 +4467,7 @@ function validateWatchDeclarations(html, stateTagName = "wcs-state", locale) {
3603
4467
  function validateEntry(entry, pathSet, msgs) {
3604
4468
  const { key } = entry;
3605
4469
  const invalid = (message) => ({ code: WcsDiagnosticCode.WatchDeclarationInvalid, message, severity: "error" });
3606
- if (key.includes(STATE_NAME_SEPARATOR)) {
4470
+ if (key.includes(STATE_NAME_SEPARATOR2)) {
3607
4471
  return invalid(msgs.watchKeyCrossState(key));
3608
4472
  }
3609
4473
  if (key.startsWith("$")) {
@@ -3625,29 +4489,1490 @@ function validateEntry(entry, pathSet, msgs) {
3625
4489
  return null;
3626
4490
  }
3627
4491
 
3628
- // src/core/validateDocument.ts
3629
- function validateDocument(text, options = {}) {
3630
- const bindAttribute = options.bindAttribute ?? "data-wcs";
3631
- const stateTagName = options.stateTagName ?? "wcs-state";
3632
- const locale = options.locale;
3633
- const fileReader = options.fileReader;
3634
- const out = [];
3635
- out.push(...validateBindings(text, bindAttribute, stateTagName, locale, fileReader));
3636
- out.push(...validateTemplateSyntax(text, stateTagName, bindAttribute, locale, fileReader));
3637
- out.push(...validateIoNodes(text, bindAttribute, stateTagName, locale, fileReader));
3638
- out.push(...validateDocumentEnv(text, locale));
3639
- out.push(...validateArrayMutations(text, stateTagName, locale));
3640
- out.push(...validateWatchDeclarations(text, stateTagName, locale));
3641
- for (const d of validateStateTypes(text, stateTagName, locale)) {
3642
- out.push({ code: WcsDiagnosticCode.TypeAnnotation, start: d.start, end: d.end, message: d.message, severity: d.severity });
3643
- }
3644
- for (const d of validateNestedAssigns(text, stateTagName, locale)) {
3645
- out.push({ code: WcsDiagnosticCode.NestedAssign, start: d.start, end: d.end, message: d.message, severity: d.severity });
3646
- }
3647
- return sortDiagnostics(out);
4492
+ // ../state/dist/parser.esm.js
4493
+ var DELIMITER2 = ".";
4494
+ var WILDCARD2 = "*";
4495
+ var MAX_WILDCARD_DEPTH2 = 128;
4496
+ var BINDING_SEPARATOR2 = ";";
4497
+ var PROP_VALUE_SEPARATOR2 = ":";
4498
+ var MODIFIER_SEPARATOR2 = "#";
4499
+ var STATE_NAME_SEPARATOR3 = "@";
4500
+ var FILTER_SEPARATOR2 = "|";
4501
+ var ELSE_KEYWORD2 = "else";
4502
+ var SPREAD_PROP2 = "...";
4503
+ var EVENT_PROP_PREFIX2 = "on";
4504
+ var EVENT_TOKEN_NAMESPACE2 = "eventToken";
4505
+ var INDEX_PARAM_PREFIX2 = "$";
4506
+ var tmpIndexByIndexName2 = {};
4507
+ for (let i = 0; i < MAX_WILDCARD_DEPTH2; i++) {
4508
+ tmpIndexByIndexName2[`${INDEX_PARAM_PREFIX2}${i + 1}`] = i;
3648
4509
  }
3649
-
3650
- // src/core/sidecar/schemaSubset.ts
4510
+ Object.freeze(tmpIndexByIndexName2);
4511
+ var _cache = /* @__PURE__ */ new Map();
4512
+ function clearPathInfoCacheForTooling() {
4513
+ _cache.clear();
4514
+ }
4515
+ var id = 0;
4516
+ function getPathInfo(path) {
4517
+ let pathInfo = _cache.get(path);
4518
+ if (typeof pathInfo !== "undefined") {
4519
+ return pathInfo;
4520
+ }
4521
+ pathInfo = Object.freeze(new PathInfo(path));
4522
+ _cache.set(path, pathInfo);
4523
+ return pathInfo;
4524
+ }
4525
+ var PathInfo = class {
4526
+ id = ++id;
4527
+ path;
4528
+ segments;
4529
+ lastSegment;
4530
+ cumulativePaths;
4531
+ cumulativePathSet;
4532
+ cumulativePathInfos;
4533
+ cumulativePathInfoSet;
4534
+ parentPath;
4535
+ wildcardPaths;
4536
+ wildcardPathSet;
4537
+ indexByWildcardPath;
4538
+ wildcardPathInfos;
4539
+ wildcardPathInfoSet;
4540
+ wildcardParentPaths;
4541
+ wildcardParentPathSet;
4542
+ wildcardParentPathInfos;
4543
+ wildcardParentPathInfoSet;
4544
+ wildcardPositions;
4545
+ lastWildcardPath;
4546
+ lastWildcardInfo;
4547
+ wildcardCount;
4548
+ parentPathInfo;
4549
+ constructor(path) {
4550
+ const getPattern = (_path) => {
4551
+ return path === _path ? this : getPathInfo(_path);
4552
+ };
4553
+ const segments = path.split(".");
4554
+ const cumulativePaths = [];
4555
+ const cumulativePathInfos = [];
4556
+ const wildcardPaths = [];
4557
+ const indexByWildcardPath = {};
4558
+ const wildcardPathInfos = [];
4559
+ const wildcardParentPaths = [];
4560
+ const wildcardParentPathInfos = [];
4561
+ const wildcardPositions = [];
4562
+ let currentPatternPath = "", prevPatternPath = "";
4563
+ let wildcardCount = 0;
4564
+ for (let i = 0; i < segments.length; i++) {
4565
+ currentPatternPath += segments[i];
4566
+ if (segments[i] === WILDCARD2) {
4567
+ wildcardPaths.push(currentPatternPath);
4568
+ indexByWildcardPath[currentPatternPath] = wildcardCount;
4569
+ wildcardPathInfos.push(getPattern(currentPatternPath));
4570
+ wildcardParentPaths.push(prevPatternPath);
4571
+ wildcardParentPathInfos.push(getPattern(prevPatternPath));
4572
+ wildcardPositions.push(i);
4573
+ wildcardCount++;
4574
+ }
4575
+ cumulativePaths.push(currentPatternPath);
4576
+ cumulativePathInfos.push(getPattern(currentPatternPath));
4577
+ prevPatternPath = currentPatternPath;
4578
+ currentPatternPath += ".";
4579
+ }
4580
+ const lastWildcardPath = wildcardPaths.length > 0 ? wildcardPaths[wildcardPaths.length - 1] : null;
4581
+ const parentPath = cumulativePaths.length > 1 ? cumulativePaths[cumulativePaths.length - 2] : null;
4582
+ this.path = path;
4583
+ this.segments = segments;
4584
+ this.lastSegment = segments[segments.length - 1];
4585
+ this.cumulativePaths = cumulativePaths;
4586
+ this.cumulativePathSet = new Set(cumulativePaths);
4587
+ this.cumulativePathInfos = cumulativePathInfos;
4588
+ this.cumulativePathInfoSet = new Set(cumulativePathInfos);
4589
+ this.wildcardPaths = wildcardPaths;
4590
+ this.wildcardPathSet = new Set(wildcardPaths);
4591
+ this.indexByWildcardPath = indexByWildcardPath;
4592
+ this.wildcardPathInfos = wildcardPathInfos;
4593
+ this.wildcardPathInfoSet = new Set(wildcardPathInfos);
4594
+ this.wildcardParentPaths = wildcardParentPaths;
4595
+ this.wildcardParentPathSet = new Set(wildcardParentPaths);
4596
+ this.wildcardParentPathInfos = wildcardParentPathInfos;
4597
+ this.wildcardParentPathInfoSet = new Set(wildcardParentPathInfos);
4598
+ this.wildcardPositions = wildcardPositions;
4599
+ this.lastWildcardPath = lastWildcardPath;
4600
+ this.lastWildcardInfo = lastWildcardPath ? getPattern(lastWildcardPath) : null;
4601
+ this.parentPath = parentPath;
4602
+ this.parentPathInfo = parentPath ? getPattern(parentPath) : null;
4603
+ this.wildcardCount = wildcardCount;
4604
+ }
4605
+ };
4606
+ function editDistance2(a, b, max) {
4607
+ if (Math.abs(a.length - b.length) > max) {
4608
+ return max + 1;
4609
+ }
4610
+ const prev = new Array(b.length + 1);
4611
+ const curr = new Array(b.length + 1);
4612
+ for (let j = 0; j <= b.length; j++) {
4613
+ prev[j] = j;
4614
+ }
4615
+ for (let i = 1; i <= a.length; i++) {
4616
+ curr[0] = i;
4617
+ for (let j = 1; j <= b.length; j++) {
4618
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
4619
+ curr[j] = Math.min(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost);
4620
+ }
4621
+ for (let j = 0; j <= b.length; j++) {
4622
+ prev[j] = curr[j];
4623
+ }
4624
+ }
4625
+ return prev[b.length];
4626
+ }
4627
+ function didYouMean(input, candidates) {
4628
+ if (input.length === 0) {
4629
+ return "";
4630
+ }
4631
+ const folded = input.toLowerCase();
4632
+ let best = null;
4633
+ let bestDistance = 3;
4634
+ for (const candidate of candidates) {
4635
+ const distance = editDistance2(folded, candidate.toLowerCase(), 2);
4636
+ if (distance < bestDistance) {
4637
+ best = candidate;
4638
+ bestDistance = distance;
4639
+ }
4640
+ }
4641
+ return best !== null ? ` Did you mean "${best}"?` : "";
4642
+ }
4643
+ var LINT_HINT = " Validate statically: npx @wcstack/lint <file>.";
4644
+ function raiseError2(message) {
4645
+ throw new Error(`[@wcstack/state] ${message}`);
4646
+ }
4647
+ var STRUCTURAL_BINDING_TYPE_SET2 = /* @__PURE__ */ new Set([
4648
+ "if",
4649
+ "elseif",
4650
+ "else",
4651
+ "for"
4652
+ ]);
4653
+ var _config2 = {
4654
+ locale: "en"
4655
+ };
4656
+ var config2 = _config2;
4657
+ function optionsRequired2(fnName) {
4658
+ raiseError2(`filter ${fnName} requires at least one option`);
4659
+ }
4660
+ function optionMustBeNumber2(fnName) {
4661
+ raiseError2(`filter ${fnName} requires a number as option`);
4662
+ }
4663
+ function valueMustBeNumber2(fnName) {
4664
+ raiseError2(`filter ${fnName} requires a number value`);
4665
+ }
4666
+ function valueMustBeBoolean2(fnName) {
4667
+ raiseError2(`filter ${fnName} requires a boolean value`);
4668
+ }
4669
+ function valueMustBeDate2(fnName) {
4670
+ raiseError2(`filter ${fnName} requires a date value`);
4671
+ }
4672
+ function valueMustBeArray2(fnName) {
4673
+ raiseError2(`filter ${fnName} requires an array value`);
4674
+ }
4675
+ function validateNumberString2(value) {
4676
+ if (!value || isNaN(Number(value))) {
4677
+ return false;
4678
+ }
4679
+ return true;
4680
+ }
4681
+ var eq2 = (options) => {
4682
+ const opt = options?.[0] ?? optionsRequired2("eq");
4683
+ return (value) => {
4684
+ if (typeof value === "number") {
4685
+ if (!validateNumberString2(opt)) {
4686
+ optionMustBeNumber2("eq");
4687
+ }
4688
+ return value === Number(opt);
4689
+ }
4690
+ if (typeof value === "string") {
4691
+ return value === opt;
4692
+ }
4693
+ return value === opt;
4694
+ };
4695
+ };
4696
+ var ne2 = (options) => {
4697
+ const opt = options?.[0] ?? optionsRequired2("ne");
4698
+ return (value) => {
4699
+ if (typeof value === "number") {
4700
+ if (!validateNumberString2(opt)) {
4701
+ optionMustBeNumber2("ne");
4702
+ }
4703
+ return value !== Number(opt);
4704
+ }
4705
+ if (typeof value === "string") {
4706
+ return value !== opt;
4707
+ }
4708
+ return value !== opt;
4709
+ };
4710
+ };
4711
+ var not2 = (_options) => {
4712
+ return (value) => {
4713
+ if (typeof value !== "boolean") {
4714
+ valueMustBeBoolean2("not");
4715
+ }
4716
+ return !value;
4717
+ };
4718
+ };
4719
+ var lt2 = (options) => {
4720
+ const opt = options?.[0] ?? optionsRequired2("lt");
4721
+ if (!validateNumberString2(opt)) {
4722
+ optionMustBeNumber2("lt");
4723
+ }
4724
+ return (value) => {
4725
+ if (typeof value !== "number") {
4726
+ valueMustBeNumber2("lt");
4727
+ }
4728
+ return value < Number(opt);
4729
+ };
4730
+ };
4731
+ var le2 = (options) => {
4732
+ const opt = options?.[0] ?? optionsRequired2("le");
4733
+ if (!validateNumberString2(opt)) {
4734
+ optionMustBeNumber2("le");
4735
+ }
4736
+ return (value) => {
4737
+ if (typeof value !== "number") {
4738
+ valueMustBeNumber2("le");
4739
+ }
4740
+ return value <= Number(opt);
4741
+ };
4742
+ };
4743
+ var gt2 = (options) => {
4744
+ const opt = options?.[0] ?? optionsRequired2("gt");
4745
+ if (!validateNumberString2(opt)) {
4746
+ optionMustBeNumber2("gt");
4747
+ }
4748
+ return (value) => {
4749
+ if (typeof value !== "number") {
4750
+ valueMustBeNumber2("gt");
4751
+ }
4752
+ return value > Number(opt);
4753
+ };
4754
+ };
4755
+ var ge2 = (options) => {
4756
+ const opt = options?.[0] ?? optionsRequired2("ge");
4757
+ if (!validateNumberString2(opt)) {
4758
+ optionMustBeNumber2("ge");
4759
+ }
4760
+ return (value) => {
4761
+ if (typeof value !== "number") {
4762
+ valueMustBeNumber2("ge");
4763
+ }
4764
+ return value >= Number(opt);
4765
+ };
4766
+ };
4767
+ var inc2 = (options) => {
4768
+ const opt = options?.[0] ?? optionsRequired2("inc");
4769
+ if (!validateNumberString2(opt)) {
4770
+ optionMustBeNumber2("inc");
4771
+ }
4772
+ return (value) => {
4773
+ if (typeof value !== "number") {
4774
+ valueMustBeNumber2("inc");
4775
+ }
4776
+ return value + Number(opt);
4777
+ };
4778
+ };
4779
+ var dec2 = (options) => {
4780
+ const opt = options?.[0] ?? optionsRequired2("dec");
4781
+ if (!validateNumberString2(opt)) {
4782
+ optionMustBeNumber2("dec");
4783
+ }
4784
+ return (value) => {
4785
+ if (typeof value !== "number") {
4786
+ valueMustBeNumber2("dec");
4787
+ }
4788
+ return value - Number(opt);
4789
+ };
4790
+ };
4791
+ var mul2 = (options) => {
4792
+ const opt = options?.[0] ?? optionsRequired2("mul");
4793
+ if (!validateNumberString2(opt)) {
4794
+ optionMustBeNumber2("mul");
4795
+ }
4796
+ return (value) => {
4797
+ if (typeof value !== "number") {
4798
+ valueMustBeNumber2("mul");
4799
+ }
4800
+ return value * Number(opt);
4801
+ };
4802
+ };
4803
+ var div2 = (options) => {
4804
+ const opt = options?.[0] ?? optionsRequired2("div");
4805
+ if (!validateNumberString2(opt)) {
4806
+ optionMustBeNumber2("div");
4807
+ }
4808
+ return (value) => {
4809
+ if (typeof value !== "number") {
4810
+ valueMustBeNumber2("div");
4811
+ }
4812
+ return value / Number(opt);
4813
+ };
4814
+ };
4815
+ var mod2 = (options) => {
4816
+ const opt = options?.[0] ?? optionsRequired2("mod");
4817
+ if (!validateNumberString2(opt)) {
4818
+ optionMustBeNumber2("mod");
4819
+ }
4820
+ return (value) => {
4821
+ if (typeof value !== "number") {
4822
+ valueMustBeNumber2("mod");
4823
+ }
4824
+ return value % Number(opt);
4825
+ };
4826
+ };
4827
+ var abs2 = (_options) => {
4828
+ return (value) => {
4829
+ if (typeof value !== "number") {
4830
+ valueMustBeNumber2("abs");
4831
+ }
4832
+ return Math.abs(value);
4833
+ };
4834
+ };
4835
+ var clamp2 = (options) => {
4836
+ const opt1 = options?.[0] ?? optionsRequired2("clamp");
4837
+ if (!validateNumberString2(opt1)) {
4838
+ optionMustBeNumber2("clamp");
4839
+ }
4840
+ const opt2 = options?.[1] ?? optionsRequired2("clamp");
4841
+ if (!validateNumberString2(opt2)) {
4842
+ optionMustBeNumber2("clamp");
4843
+ }
4844
+ const min = Number(opt1);
4845
+ const max = Number(opt2);
4846
+ return (value) => {
4847
+ if (typeof value !== "number") {
4848
+ valueMustBeNumber2("clamp");
4849
+ }
4850
+ return Math.min(Math.max(value, min), max);
4851
+ };
4852
+ };
4853
+ var fix2 = (options) => {
4854
+ const opt = options?.[0] ?? "0";
4855
+ if (!validateNumberString2(opt)) {
4856
+ optionMustBeNumber2("fix");
4857
+ }
4858
+ return (value) => {
4859
+ if (typeof value !== "number") {
4860
+ valueMustBeNumber2("fix");
4861
+ }
4862
+ return value.toFixed(Number(opt));
4863
+ };
4864
+ };
4865
+ var locale2 = (options) => {
4866
+ const opt = options?.[0] ?? config2.locale;
4867
+ return (value) => {
4868
+ if (typeof value !== "number") {
4869
+ valueMustBeNumber2("locale");
4870
+ }
4871
+ return value.toLocaleString(opt);
4872
+ };
4873
+ };
4874
+ var uc2 = (_options) => {
4875
+ return (value) => {
4876
+ return String(value).toUpperCase();
4877
+ };
4878
+ };
4879
+ var lc2 = (_options) => {
4880
+ return (value) => {
4881
+ return String(value).toLowerCase();
4882
+ };
4883
+ };
4884
+ var cap2 = (_options) => {
4885
+ return (value) => {
4886
+ const v = String(value);
4887
+ if (v.length === 0) {
4888
+ return v;
4889
+ }
4890
+ if (v.length === 1) {
4891
+ return v.toUpperCase();
4892
+ }
4893
+ return v.charAt(0).toUpperCase() + v.slice(1);
4894
+ };
4895
+ };
4896
+ var trim2 = (_options) => {
4897
+ return (value) => {
4898
+ return String(value).trim();
4899
+ };
4900
+ };
4901
+ var slice2 = (options) => {
4902
+ const numberedOpts = [];
4903
+ const opt1 = options?.[0] ?? optionsRequired2("slice");
4904
+ if (!validateNumberString2(opt1)) {
4905
+ optionMustBeNumber2("slice");
4906
+ }
4907
+ numberedOpts.push(Number(opt1));
4908
+ const opt2 = options?.[1];
4909
+ if (typeof opt2 !== "undefined") {
4910
+ if (!validateNumberString2(opt2)) {
4911
+ optionMustBeNumber2("slice");
4912
+ }
4913
+ numberedOpts.push(Number(opt2));
4914
+ }
4915
+ return (value) => {
4916
+ return String(value).slice(...numberedOpts);
4917
+ };
4918
+ };
4919
+ var substr2 = (options) => {
4920
+ const opt1 = options?.[0] ?? optionsRequired2("substr");
4921
+ if (!validateNumberString2(opt1)) {
4922
+ optionMustBeNumber2("substr");
4923
+ }
4924
+ const opt2 = options?.[1] ?? optionsRequired2("substr");
4925
+ if (!validateNumberString2(opt2)) {
4926
+ optionMustBeNumber2("substr");
4927
+ }
4928
+ return (value) => {
4929
+ return String(value).substr(Number(opt1), Number(opt2));
4930
+ };
4931
+ };
4932
+ var pad2 = (options) => {
4933
+ const opt1 = options?.[0] ?? optionsRequired2("pad");
4934
+ if (!validateNumberString2(opt1)) {
4935
+ optionMustBeNumber2("pad");
4936
+ }
4937
+ const opt2 = options?.[1] ?? "0";
4938
+ return (value) => {
4939
+ return String(value).padStart(Number(opt1), opt2);
4940
+ };
4941
+ };
4942
+ var rep2 = (options) => {
4943
+ const opt = options?.[0] ?? optionsRequired2("rep");
4944
+ if (!validateNumberString2(opt)) {
4945
+ optionMustBeNumber2("rep");
4946
+ }
4947
+ return (value) => {
4948
+ return String(value).repeat(Number(opt));
4949
+ };
4950
+ };
4951
+ var rev2 = (_options) => {
4952
+ return (value) => {
4953
+ return String(value).split("").reverse().join("");
4954
+ };
4955
+ };
4956
+ var int2 = (_options) => {
4957
+ return (value) => {
4958
+ return parseInt(String(value), 10);
4959
+ };
4960
+ };
4961
+ var float2 = (_options) => {
4962
+ return (value) => {
4963
+ return parseFloat(String(value));
4964
+ };
4965
+ };
4966
+ var round2 = (options) => {
4967
+ const opt = options?.[0] ?? "0";
4968
+ if (!validateNumberString2(opt)) {
4969
+ optionMustBeNumber2("round");
4970
+ }
4971
+ return (value) => {
4972
+ if (typeof value !== "number") {
4973
+ valueMustBeNumber2("round");
4974
+ }
4975
+ const optValue = Math.pow(10, Number(opt));
4976
+ return Math.round(value * optValue) / optValue;
4977
+ };
4978
+ };
4979
+ var floor2 = (options) => {
4980
+ const opt = options?.[0] ?? "0";
4981
+ if (!validateNumberString2(opt)) {
4982
+ optionMustBeNumber2("floor");
4983
+ }
4984
+ return (value) => {
4985
+ if (typeof value !== "number") {
4986
+ valueMustBeNumber2("floor");
4987
+ }
4988
+ const optValue = Math.pow(10, Number(opt));
4989
+ return Math.floor(value * optValue) / optValue;
4990
+ };
4991
+ };
4992
+ var ceil2 = (options) => {
4993
+ const opt = options?.[0] ?? "0";
4994
+ if (!validateNumberString2(opt)) {
4995
+ optionMustBeNumber2("ceil");
4996
+ }
4997
+ return (value) => {
4998
+ if (typeof value !== "number") {
4999
+ valueMustBeNumber2("ceil");
5000
+ }
5001
+ const optValue = Math.pow(10, Number(opt));
5002
+ return Math.ceil(value * optValue) / optValue;
5003
+ };
5004
+ };
5005
+ var percent2 = (options) => {
5006
+ const opt = options?.[0] ?? "0";
5007
+ if (!validateNumberString2(opt)) {
5008
+ optionMustBeNumber2("percent");
5009
+ }
5010
+ return (value) => {
5011
+ if (typeof value !== "number") {
5012
+ valueMustBeNumber2("percent");
5013
+ }
5014
+ return `${(value * 100).toFixed(Number(opt))}%`;
5015
+ };
5016
+ };
5017
+ var unit2 = (options) => {
5018
+ const opt = options?.[0] ?? optionsRequired2("unit");
5019
+ return (value) => {
5020
+ if (value === null || typeof value === "undefined") {
5021
+ return value;
5022
+ }
5023
+ return String(value) + opt;
5024
+ };
5025
+ };
5026
+ var join2 = (options) => {
5027
+ const opt = options?.[0] ?? ", ";
5028
+ return (value) => {
5029
+ if (!Array.isArray(value)) {
5030
+ valueMustBeArray2("join");
5031
+ }
5032
+ return value.join(opt);
5033
+ };
5034
+ };
5035
+ var truncate2 = (options) => {
5036
+ const opt1 = options?.[0] ?? optionsRequired2("truncate");
5037
+ if (!validateNumberString2(opt1)) {
5038
+ optionMustBeNumber2("truncate");
5039
+ }
5040
+ const maxLength = Number(opt1);
5041
+ const suffix = options?.[1] ?? "\u2026";
5042
+ return (value) => {
5043
+ const v = String(value);
5044
+ if (v.length <= maxLength) {
5045
+ return v;
5046
+ }
5047
+ return v.slice(0, maxLength) + suffix;
5048
+ };
5049
+ };
5050
+ var date2 = (options) => {
5051
+ const opt = options?.[0] ?? config2.locale;
5052
+ return (value) => {
5053
+ if (!(value instanceof Date)) {
5054
+ valueMustBeDate2("date");
5055
+ }
5056
+ return value.toLocaleDateString(opt);
5057
+ };
5058
+ };
5059
+ var time2 = (options) => {
5060
+ const opt = options?.[0] ?? config2.locale;
5061
+ return (value) => {
5062
+ if (!(value instanceof Date)) {
5063
+ valueMustBeDate2("time");
5064
+ }
5065
+ return value.toLocaleTimeString(opt);
5066
+ };
5067
+ };
5068
+ var datetime2 = (options) => {
5069
+ const opt = options?.[0] ?? config2.locale;
5070
+ return (value) => {
5071
+ if (!(value instanceof Date)) {
5072
+ valueMustBeDate2("datetime");
5073
+ }
5074
+ return value.toLocaleString(opt);
5075
+ };
5076
+ };
5077
+ var ymd2 = (options) => {
5078
+ const opt = options?.[0] ?? "-";
5079
+ return (value) => {
5080
+ if (!(value instanceof Date)) {
5081
+ valueMustBeDate2("ymd");
5082
+ }
5083
+ const year = value.getFullYear().toString();
5084
+ const month = (value.getMonth() + 1).toString().padStart(2, "0");
5085
+ const day = value.getDate().toString().padStart(2, "0");
5086
+ return `${year}${opt}${month}${opt}${day}`;
5087
+ };
5088
+ };
5089
+ var hms2 = (options) => {
5090
+ const opt = options?.[0] ?? ":";
5091
+ return (value) => {
5092
+ if (!(value instanceof Date)) {
5093
+ valueMustBeDate2("hms");
5094
+ }
5095
+ const hours = value.getHours().toString().padStart(2, "0");
5096
+ const minutes = value.getMinutes().toString().padStart(2, "0");
5097
+ const seconds = value.getSeconds().toString().padStart(2, "0");
5098
+ return `${hours}${opt}${minutes}${opt}${seconds}`;
5099
+ };
5100
+ };
5101
+ var falsy2 = (_options) => {
5102
+ return (value) => value === false || value === null || value === void 0 || value === 0 || value === "" || Number.isNaN(value);
5103
+ };
5104
+ var truthy2 = (_options) => {
5105
+ return (value) => value !== false && value !== null && value !== void 0 && value !== 0 && value !== "" && !Number.isNaN(value);
5106
+ };
5107
+ var defaults2 = (options) => {
5108
+ const opt = options?.[0] ?? optionsRequired2("defaults");
5109
+ return (value) => {
5110
+ if (value === false || value === null || value === void 0 || value === 0 || value === "" || Number.isNaN(value)) {
5111
+ return opt;
5112
+ }
5113
+ return value;
5114
+ };
5115
+ };
5116
+ var boolean2 = (_options) => {
5117
+ return (value) => {
5118
+ return Boolean(value);
5119
+ };
5120
+ };
5121
+ var number2 = (_options) => {
5122
+ return (value) => {
5123
+ return Number(value);
5124
+ };
5125
+ };
5126
+ var string2 = (_options) => {
5127
+ return (value) => {
5128
+ return String(value);
5129
+ };
5130
+ };
5131
+ var _null2 = (_options) => {
5132
+ return (value) => {
5133
+ return value === "" ? null : value;
5134
+ };
5135
+ };
5136
+ var builtinFilters2 = {
5137
+ "eq": eq2,
5138
+ "ne": ne2,
5139
+ "not": not2,
5140
+ "lt": lt2,
5141
+ "le": le2,
5142
+ "gt": gt2,
5143
+ "ge": ge2,
5144
+ "inc": inc2,
5145
+ "dec": dec2,
5146
+ "mul": mul2,
5147
+ "div": div2,
5148
+ "mod": mod2,
5149
+ "abs": abs2,
5150
+ "clamp": clamp2,
5151
+ "fix": fix2,
5152
+ "locale": locale2,
5153
+ "uc": uc2,
5154
+ "lc": lc2,
5155
+ "cap": cap2,
5156
+ "trim": trim2,
5157
+ "slice": slice2,
5158
+ "substr": substr2,
5159
+ "pad": pad2,
5160
+ "rep": rep2,
5161
+ "rev": rev2,
5162
+ "truncate": truncate2,
5163
+ "join": join2,
5164
+ "int": int2,
5165
+ "float": float2,
5166
+ "round": round2,
5167
+ "floor": floor2,
5168
+ "ceil": ceil2,
5169
+ "percent": percent2,
5170
+ "unit": unit2,
5171
+ "date": date2,
5172
+ "time": time2,
5173
+ "datetime": datetime2,
5174
+ "ymd": ymd2,
5175
+ "hms": hms2,
5176
+ "falsy": falsy2,
5177
+ "truthy": truthy2,
5178
+ "defaults": defaults2,
5179
+ "boolean": boolean2,
5180
+ "number": number2,
5181
+ "string": string2,
5182
+ "null": _null2
5183
+ };
5184
+ var outputBuiltinFilters2 = builtinFilters2;
5185
+ var inputBuiltinFilters = builtinFilters2;
5186
+ var builtinFiltersByFilterIOType = {
5187
+ "input": inputBuiltinFilters,
5188
+ "output": outputBuiltinFilters2
5189
+ };
5190
+ var builtinFilterFn = (name, options) => (filters) => {
5191
+ const filter = filters[name];
5192
+ if (!filter) {
5193
+ raiseError2(`[wcs/filter-unknown] filter not found: ${name}.${didYouMean(name, Object.keys(filters))}${LINT_HINT}`);
5194
+ }
5195
+ return filter(options);
5196
+ };
5197
+ function finalizeArg(text, firstQuoteStart, lastQuoteEnd) {
5198
+ const startLimit = firstQuoteStart === -1 ? text.length : firstQuoteStart;
5199
+ let start = 0;
5200
+ while (start < startLimit && /\s/.test(text[start])) {
5201
+ start++;
5202
+ }
5203
+ const endLimit = lastQuoteEnd === -1 ? 0 : lastQuoteEnd;
5204
+ let end = text.length;
5205
+ while (end > endLimit && /\s/.test(text[end - 1])) {
5206
+ end--;
5207
+ }
5208
+ return text.slice(start, end);
5209
+ }
5210
+ function parseFilterArgs(argsText) {
5211
+ const args = [];
5212
+ let current = "";
5213
+ let inQuote = null;
5214
+ let hasQuote = false;
5215
+ let firstQuoteStart = -1;
5216
+ let lastQuoteEnd = -1;
5217
+ const flush = () => {
5218
+ args.push(finalizeArg(current, firstQuoteStart, lastQuoteEnd));
5219
+ current = "";
5220
+ hasQuote = false;
5221
+ firstQuoteStart = -1;
5222
+ lastQuoteEnd = -1;
5223
+ };
5224
+ for (let i = 0; i < argsText.length; i++) {
5225
+ const char = argsText[i];
5226
+ if (inQuote) {
5227
+ if (char === inQuote) {
5228
+ inQuote = null;
5229
+ } else {
5230
+ if (firstQuoteStart === -1) {
5231
+ firstQuoteStart = current.length;
5232
+ }
5233
+ current += char;
5234
+ lastQuoteEnd = current.length;
5235
+ }
5236
+ } else if (char === '"' || char === "'") {
5237
+ inQuote = char;
5238
+ hasQuote = true;
5239
+ } else if (char === ",") {
5240
+ flush();
5241
+ } else {
5242
+ current += char;
5243
+ }
5244
+ }
5245
+ const last = finalizeArg(current, firstQuoteStart, lastQuoteEnd);
5246
+ if (last || hasQuote) {
5247
+ args.push(last);
5248
+ }
5249
+ return args;
5250
+ }
5251
+ var filterFnByKey = /* @__PURE__ */ new Map();
5252
+ function clearFilterFnCacheForTooling() {
5253
+ filterFnByKey.clear();
5254
+ }
5255
+ function parseFilters(filterTextList, filterIOType) {
5256
+ const builtinFilters3 = builtinFiltersByFilterIOType[filterIOType];
5257
+ const filters = filterTextList.map((filterText) => {
5258
+ const openParenIndex = filterText.indexOf("(");
5259
+ const closeParenIndex = filterText.lastIndexOf(")");
5260
+ if (openParenIndex !== -1 && closeParenIndex === -1) {
5261
+ raiseError2(`Invalid filter format: missing closing parenthesis in "${filterText}"`);
5262
+ }
5263
+ if (closeParenIndex !== -1 && openParenIndex === -1) {
5264
+ raiseError2(`Invalid filter format: missing opening parenthesis in "${filterText}"`);
5265
+ }
5266
+ if (openParenIndex === -1) {
5267
+ const filterName = filterText.trim();
5268
+ const filterKey = `${filterName}():${filterIOType}`;
5269
+ let filterFn = filterFnByKey.get(filterKey);
5270
+ if (typeof filterFn === "undefined") {
5271
+ filterFn = builtinFilterFn(filterName, [])(builtinFilters3);
5272
+ filterFnByKey.set(filterKey, filterFn);
5273
+ }
5274
+ return {
5275
+ filterName,
5276
+ args: [],
5277
+ filterFn
5278
+ };
5279
+ } else {
5280
+ const argsText = filterText.substring(openParenIndex + 1, closeParenIndex);
5281
+ const filterName = filterText.substring(0, openParenIndex).trim();
5282
+ const args = parseFilterArgs(argsText);
5283
+ const filterKey = `${filterName}(${args.join(",")}):${filterIOType}`;
5284
+ let filterFn = filterFnByKey.get(filterKey);
5285
+ if (typeof filterFn === "undefined") {
5286
+ filterFn = builtinFilterFn(filterName, args)(builtinFilters3);
5287
+ filterFnByKey.set(filterKey, filterFn);
5288
+ }
5289
+ return {
5290
+ filterName,
5291
+ args,
5292
+ filterFn
5293
+ };
5294
+ }
5295
+ });
5296
+ return filters;
5297
+ }
5298
+ var trimFn = (s) => s.trim();
5299
+ var cacheFilterInfos$1 = /* @__PURE__ */ new Map();
5300
+ function clearPropPartCacheForTooling() {
5301
+ cacheFilterInfos$1.clear();
5302
+ }
5303
+ function parsePropPart(propPart) {
5304
+ const pos = propPart.indexOf(FILTER_SEPARATOR2);
5305
+ let propText = "";
5306
+ let filterTexts = [];
5307
+ let filtersText = "";
5308
+ let filters = [];
5309
+ if (pos !== -1) {
5310
+ propText = propPart.slice(0, pos).trim();
5311
+ filtersText = propPart.slice(pos + 1).trim();
5312
+ if (cacheFilterInfos$1.has(filtersText)) {
5313
+ filters = cacheFilterInfos$1.get(filtersText);
5314
+ } else {
5315
+ filterTexts = filtersText.split(FILTER_SEPARATOR2).map(trimFn);
5316
+ filters = parseFilters(filterTexts, "input");
5317
+ cacheFilterInfos$1.set(filtersText, filters);
5318
+ }
5319
+ } else {
5320
+ propText = propPart.trim();
5321
+ }
5322
+ const [propName, propModifiersText] = propText.split(MODIFIER_SEPARATOR2).map(trimFn);
5323
+ const propSegments = propName.split(DELIMITER2).map(trimFn);
5324
+ const propModifiers = propModifiersText ? propModifiersText.split(",").map(trimFn) : [];
5325
+ return {
5326
+ propName,
5327
+ propSegments,
5328
+ propModifiers,
5329
+ inFilters: filters
5330
+ };
5331
+ }
5332
+ var cacheFilterInfos = /* @__PURE__ */ new Map();
5333
+ function clearStatePartCacheForTooling() {
5334
+ cacheFilterInfos.clear();
5335
+ }
5336
+ function parseStatePart(statePart) {
5337
+ const pos = statePart.indexOf(FILTER_SEPARATOR2);
5338
+ let stateAndPath = "";
5339
+ let filterTexts = [];
5340
+ let filtersText = "";
5341
+ let filters = [];
5342
+ if (pos !== -1) {
5343
+ stateAndPath = statePart.slice(0, pos).trim();
5344
+ filtersText = statePart.slice(pos + 1).trim();
5345
+ if (cacheFilterInfos.has(filtersText)) {
5346
+ filters = cacheFilterInfos.get(filtersText);
5347
+ } else {
5348
+ filterTexts = filtersText.split(FILTER_SEPARATOR2).map(trimFn);
5349
+ filters = parseFilters(filterTexts, "output");
5350
+ cacheFilterInfos.set(filtersText, filters);
5351
+ }
5352
+ } else {
5353
+ stateAndPath = statePart.trim();
5354
+ }
5355
+ const [statePathName, stateName = "default"] = stateAndPath.split(STATE_NAME_SEPARATOR3).map(trimFn);
5356
+ const pathInfo = getPathInfo(statePathName);
5357
+ return {
5358
+ stateName,
5359
+ statePathName,
5360
+ statePathInfo: pathInfo,
5361
+ outFilters: filters
5362
+ };
5363
+ }
5364
+ function parseBindTextsForElement(bindText) {
5365
+ const [...bindTexts] = bindText.split(BINDING_SEPARATOR2).map(trimFn).filter((s) => s.length > 0);
5366
+ const results = bindTexts.map((bindText2) => {
5367
+ const separatorIndex = bindText2.indexOf(PROP_VALUE_SEPARATOR2);
5368
+ if (separatorIndex === -1) {
5369
+ raiseError2(`Invalid bindText: "${bindText2}". Missing ':' separator between propPart and statePart.`);
5370
+ }
5371
+ const propPart = bindText2.slice(0, separatorIndex).trim();
5372
+ const statePart = bindText2.slice(separatorIndex + 1).trim();
5373
+ if (propPart === ELSE_KEYWORD2) {
5374
+ const pathInfo = getPathInfo("#else");
5375
+ return {
5376
+ propName: ELSE_KEYWORD2,
5377
+ propSegments: [ELSE_KEYWORD2],
5378
+ propModifiers: [],
5379
+ statePathName: "#else",
5380
+ statePathInfo: pathInfo,
5381
+ stateName: "",
5382
+ inFilters: [],
5383
+ outFilters: [],
5384
+ bindingType: "else"
5385
+ };
5386
+ } else if (propPart === SPREAD_PROP2) {
5387
+ const stateResult = parseStatePart(statePart);
5388
+ if (stateResult.outFilters.length > 0) {
5389
+ raiseError2(`Invalid spread binding "${bindText2}": filters are not allowed on spread targets.`);
5390
+ }
5391
+ if (stateResult.statePathName.length === 0) {
5392
+ raiseError2(`Invalid spread binding "${bindText2}": spread target path is required.`);
5393
+ }
5394
+ return {
5395
+ propName: SPREAD_PROP2,
5396
+ propSegments: [SPREAD_PROP2],
5397
+ propModifiers: [],
5398
+ inFilters: [],
5399
+ ...stateResult,
5400
+ bindingType: "spread"
5401
+ };
5402
+ } else if (propPart === "if" || propPart === "elseif" || propPart === "for" || propPart === "radio" || propPart === "checkbox") {
5403
+ const stateResult = parseStatePart(statePart);
5404
+ return {
5405
+ propName: propPart,
5406
+ propSegments: [propPart],
5407
+ propModifiers: [],
5408
+ inFilters: [],
5409
+ ...stateResult,
5410
+ bindingType: propPart
5411
+ };
5412
+ } else {
5413
+ const stateResult = parseStatePart(statePart);
5414
+ const propResult = parsePropPart(propPart);
5415
+ if (propResult.propSegments[0] === EVENT_TOKEN_NAMESPACE2) {
5416
+ return {
5417
+ ...propResult,
5418
+ ...stateResult,
5419
+ bindingType: "event"
5420
+ };
5421
+ }
5422
+ if (propResult.propSegments[0].startsWith(EVENT_PROP_PREFIX2)) {
5423
+ return {
5424
+ ...propResult,
5425
+ ...stateResult,
5426
+ bindingType: "event"
5427
+ };
5428
+ } else {
5429
+ return {
5430
+ ...propResult,
5431
+ ...stateResult,
5432
+ bindingType: "prop"
5433
+ };
5434
+ }
5435
+ }
5436
+ });
5437
+ if (results.length > 1) {
5438
+ const isIncludeSingleBinding = results.some((r) => STRUCTURAL_BINDING_TYPE_SET2.has(r.bindingType));
5439
+ if (isIncludeSingleBinding) {
5440
+ raiseError2(`[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}`);
5441
+ }
5442
+ }
5443
+ return results;
5444
+ }
5445
+ function parseBindTextForEmbeddedNode(bindText) {
5446
+ const stateResult = parseStatePart(bindText);
5447
+ return {
5448
+ propName: "textContent",
5449
+ propSegments: ["textContent"],
5450
+ propModifiers: [],
5451
+ inFilters: [],
5452
+ ...stateResult,
5453
+ bindingType: "text"
5454
+ };
5455
+ }
5456
+ function clearParserCaches() {
5457
+ clearPathInfoCacheForTooling();
5458
+ clearPropPartCacheForTooling();
5459
+ clearStatePartCacheForTooling();
5460
+ clearFilterFnCacheForTooling();
5461
+ }
5462
+
5463
+ // src/core/parser/positionalParser.ts
5464
+ var { delimiters } = getWcsManifest().syntax;
5465
+ function locate(haystack, needle, from, to) {
5466
+ if (needle.length === 0) return null;
5467
+ const index = haystack.indexOf(needle, from);
5468
+ if (index === -1 || index + needle.length > to) return null;
5469
+ return { start: index, end: index + needle.length };
5470
+ }
5471
+ function parseEmbeddedTextWithPositions(expression) {
5472
+ const exprRange = { start: 0, end: expression.length };
5473
+ let parsed = null;
5474
+ let error = null;
5475
+ try {
5476
+ parsed = parseBindTextForEmbeddedNode(expression);
5477
+ } catch (e) {
5478
+ error = e.message;
5479
+ }
5480
+ if (parsed === null) {
5481
+ return { exprRange, exprText: expression, parsed, error, propRange: null, pathRange: null, stateNameRange: null };
5482
+ }
5483
+ const firstPipe = expression.indexOf(delimiters.filter);
5484
+ const pathScopeEnd = firstPipe === -1 ? expression.length : firstPipe;
5485
+ const pathLocal = locate(expression, parsed.statePathName, 0, pathScopeEnd);
5486
+ let stateNameLocal = null;
5487
+ const at = expression.indexOf(delimiters.stateName);
5488
+ if (at !== -1 && at < pathScopeEnd) {
5489
+ stateNameLocal = locate(expression, parsed.stateName, at + 1, pathScopeEnd);
5490
+ }
5491
+ return {
5492
+ exprRange,
5493
+ exprText: expression,
5494
+ parsed,
5495
+ error,
5496
+ propRange: null,
5497
+ pathRange: pathLocal,
5498
+ stateNameRange: stateNameLocal
5499
+ };
5500
+ }
5501
+ function parseBindTextWithPositions(bindText) {
5502
+ const results = [];
5503
+ const segments = bindText.split(delimiters.binding);
5504
+ let segmentStart = 0;
5505
+ for (const segment of segments) {
5506
+ const leading = segment.length - segment.trimStart().length;
5507
+ const expr = segment.trim();
5508
+ const exprStart = segmentStart + leading;
5509
+ segmentStart += segment.length + delimiters.binding.length;
5510
+ if (expr.length === 0) continue;
5511
+ const exprRange = { start: exprStart, end: exprStart + expr.length };
5512
+ let parsed = null;
5513
+ let error = null;
5514
+ try {
5515
+ parsed = parseBindTextsForElement(expr)[0] ?? null;
5516
+ } catch (e) {
5517
+ error = e.message;
5518
+ }
5519
+ if (parsed === null) {
5520
+ results.push({ exprRange, exprText: expr, parsed, error, propRange: null, pathRange: null, stateNameRange: null });
5521
+ continue;
5522
+ }
5523
+ const colon = expr.indexOf(delimiters.propValue);
5524
+ const propEndLimit = colon === -1 ? expr.length : colon;
5525
+ const propLocal = locate(expr, parsed.propName, 0, propEndLimit);
5526
+ let pathLocal = null;
5527
+ let stateNameLocal = null;
5528
+ if (colon !== -1) {
5529
+ const stateBase = colon + 1;
5530
+ const firstPipe = expr.indexOf(delimiters.filter, stateBase);
5531
+ const pathScopeEnd = firstPipe === -1 ? expr.length : firstPipe;
5532
+ pathLocal = locate(expr, parsed.statePathName, stateBase, pathScopeEnd);
5533
+ const at = expr.indexOf(delimiters.stateName, stateBase);
5534
+ if (at !== -1 && at < pathScopeEnd) {
5535
+ stateNameLocal = locate(expr, parsed.stateName, at + 1, pathScopeEnd);
5536
+ }
5537
+ }
5538
+ const lift = (range) => range === null ? null : { start: exprStart + range.start, end: exprStart + range.end };
5539
+ results.push({
5540
+ exprRange,
5541
+ exprText: expr,
5542
+ parsed,
5543
+ error,
5544
+ propRange: lift(propLocal),
5545
+ pathRange: lift(pathLocal),
5546
+ stateNameRange: lift(stateNameLocal)
5547
+ });
5548
+ }
5549
+ return results;
5550
+ }
5551
+
5552
+ // src/core/index/referenceIndex.ts
5553
+ function keyOf(stateName, path) {
5554
+ return `${stateName}\0${path}`;
5555
+ }
5556
+ function buildReferenceIndex(html, options = {}) {
5557
+ clearParserCaches();
5558
+ const bindAttribute = options.bindAttribute ?? "data-wcs";
5559
+ const stateTagName = options.stateTagName ?? "wcs-state";
5560
+ const occurrences = [];
5561
+ const problems = [];
5562
+ for (const attr of findAllBindAttributes(html, bindAttribute)) {
5563
+ for (const binding of parseBindTextWithPositions(attr.value)) {
5564
+ const lift = (range) => ({ start: attr.valueStart + range.start, end: attr.valueStart + range.end });
5565
+ if (binding.parsed === null) {
5566
+ problems.push({ message: binding.error ?? "parse error", range: lift(binding.exprRange) });
5567
+ continue;
5568
+ }
5569
+ if (binding.pathRange === null) continue;
5570
+ occurrences.push({
5571
+ source: "attribute",
5572
+ kind: binding.parsed.propSegments[0] === "eventToken" ? "eventToken" : "path",
5573
+ stateName: binding.parsed.stateName,
5574
+ path: binding.parsed.statePathName,
5575
+ pathRange: lift(binding.pathRange),
5576
+ exprRange: lift(binding.exprRange),
5577
+ propName: binding.parsed.propName,
5578
+ propRange: binding.propRange === null ? null : lift(binding.propRange),
5579
+ stateNameRange: binding.stateNameRange === null ? null : lift(binding.stateNameRange),
5580
+ bindingType: binding.parsed.bindingType
5581
+ });
5582
+ }
5583
+ }
5584
+ const textMatches = [
5585
+ ...findAllMustacheSyntax(html),
5586
+ ...findAllCommentBindings(html)
5587
+ ];
5588
+ for (const match of textMatches) {
5589
+ const binding = parseEmbeddedTextWithPositions(match.expression);
5590
+ const shift = (range) => ({
5591
+ start: match.exprStart + range.start,
5592
+ end: match.exprStart + range.end
5593
+ });
5594
+ if (binding.parsed === null) {
5595
+ problems.push({ message: binding.error ?? "parse error", range: shift(binding.exprRange) });
5596
+ continue;
5597
+ }
5598
+ if (binding.pathRange === null) continue;
5599
+ occurrences.push({
5600
+ source: match.kind,
5601
+ kind: "path",
5602
+ stateName: binding.parsed.stateName,
5603
+ path: binding.parsed.statePathName,
5604
+ pathRange: shift(binding.pathRange),
5605
+ exprRange: { start: match.exprStart, end: match.exprEnd },
5606
+ propName: null,
5607
+ propRange: null,
5608
+ stateNameRange: binding.stateNameRange === null ? null : shift(binding.stateNameRange),
5609
+ bindingType: "text"
5610
+ });
5611
+ }
5612
+ const declarations = [];
5613
+ for (const block of parseWcsScriptBlocks(html, stateTagName)) {
5614
+ for (const span of analyzeDeclarationSpans(block.content)) {
5615
+ declarations.push({
5616
+ stateName: block.stateName,
5617
+ name: span.name,
5618
+ kind: span.kind,
5619
+ range: { start: block.contentStart + span.start, end: block.contentStart + span.end }
5620
+ });
5621
+ }
5622
+ }
5623
+ const byPath = /* @__PURE__ */ new Map();
5624
+ for (const occurrence of occurrences) {
5625
+ if (occurrence.kind !== "path") continue;
5626
+ const key = keyOf(occurrence.stateName, occurrence.path);
5627
+ const list = byPath.get(key);
5628
+ if (list === void 0) {
5629
+ byPath.set(key, [occurrence]);
5630
+ } else {
5631
+ list.push(occurrence);
5632
+ }
5633
+ }
5634
+ const declarationByName = /* @__PURE__ */ new Map();
5635
+ for (const declaration of declarations) {
5636
+ const key = keyOf(declaration.stateName, declaration.name);
5637
+ if (!declarationByName.has(key)) declarationByName.set(key, declaration);
5638
+ }
5639
+ return {
5640
+ occurrences,
5641
+ declarations,
5642
+ problems,
5643
+ referencesOf(stateName, path) {
5644
+ return (byPath.get(keyOf(stateName, path)) ?? []).slice();
5645
+ },
5646
+ declarationOf(stateName, path) {
5647
+ const exact = declarationByName.get(keyOf(stateName, path));
5648
+ if (exact !== void 0) return exact;
5649
+ const firstSegment = path.split(".")[0];
5650
+ if (firstSegment === path) return null;
5651
+ return declarationByName.get(keyOf(stateName, firstSegment)) ?? null;
5652
+ },
5653
+ occurrenceAt(offset) {
5654
+ for (const occurrence of occurrences) {
5655
+ if (offset >= occurrence.pathRange.start && offset < occurrence.pathRange.end) {
5656
+ return occurrence;
5657
+ }
5658
+ }
5659
+ return null;
5660
+ }
5661
+ };
5662
+ }
5663
+
5664
+ // src/service/semanticValidator.ts
5665
+ var STATE_UPDATED_CALLBACK = "$updatedCallback";
5666
+ var API_CALL = /\.\s*\$(getAll|resolve)\s*\(/g;
5667
+ var STRING_LITERAL = /^\s*(["'])((?:\\.|(?!\1)[^\\])*)\1\s*$/;
5668
+ function splitCallArgs(source, open) {
5669
+ const args = [];
5670
+ const starts = [];
5671
+ let depth = 0;
5672
+ let argStart = open;
5673
+ let i = open;
5674
+ while (i < source.length) {
5675
+ const ch = source[i];
5676
+ if (ch === '"' || ch === "'" || ch === "`") {
5677
+ const quote = ch;
5678
+ i++;
5679
+ while (i < source.length) {
5680
+ if (source[i] === "\\") {
5681
+ i += 2;
5682
+ continue;
5683
+ }
5684
+ if (source[i] === quote) {
5685
+ i++;
5686
+ break;
5687
+ }
5688
+ i++;
5689
+ }
5690
+ continue;
5691
+ }
5692
+ if (ch === "(" || ch === "[" || ch === "{") {
5693
+ depth++;
5694
+ i++;
5695
+ continue;
5696
+ }
5697
+ if (ch === ")" && depth === 0) {
5698
+ args.push(source.slice(argStart, i));
5699
+ starts.push(argStart);
5700
+ return { args, starts, end: i + 1 };
5701
+ }
5702
+ if (ch === ")" || ch === "]" || ch === "}") {
5703
+ depth--;
5704
+ i++;
5705
+ continue;
5706
+ }
5707
+ if (ch === "," && depth === 0) {
5708
+ args.push(source.slice(argStart, i));
5709
+ starts.push(argStart);
5710
+ argStart = i + 1;
5711
+ i++;
5712
+ continue;
5713
+ }
5714
+ i++;
5715
+ }
5716
+ return null;
5717
+ }
5718
+ function literalString(arg) {
5719
+ const match = STRING_LITERAL.exec(arg);
5720
+ return match === null ? null : match[2];
5721
+ }
5722
+ function literalArrayLength(arg) {
5723
+ const trimmed = arg.trim();
5724
+ if (!trimmed.startsWith("[") || !trimmed.endsWith("]")) return null;
5725
+ const inner = trimmed.slice(1, -1);
5726
+ if (inner.trim().length === 0) return 0;
5727
+ if (/(^|[^.])\.\.\./.test(inner)) return null;
5728
+ const parts = splitCallArgs(`${inner})`, 0);
5729
+ if (parts === null) return null;
5730
+ return parts.args.filter((part) => part.trim().length > 0).length;
5731
+ }
5732
+ function validateIndexArity(script, scriptStart, locale3) {
5733
+ const msgs = getMessages(locale3);
5734
+ const out = [];
5735
+ API_CALL.lastIndex = 0;
5736
+ let match;
5737
+ while ((match = API_CALL.exec(script)) !== null) {
5738
+ const api = `$${match[1]}`;
5739
+ const parsed = splitCallArgs(script, match.index + match[0].length);
5740
+ if (parsed === null) continue;
5741
+ API_CALL.lastIndex = parsed.end;
5742
+ if (parsed.args.length < 2) continue;
5743
+ const path = literalString(parsed.args[0]);
5744
+ if (path === null) continue;
5745
+ const actual = literalArrayLength(parsed.args[1]);
5746
+ if (actual === null) continue;
5747
+ const wildcardCount = countWildcardSegments(path);
5748
+ const requirement = api === "$resolve" ? "exact" : "atMost";
5749
+ const mismatched = requirement === "exact" ? actual !== wildcardCount : actual > wildcardCount;
5750
+ if (!mismatched) continue;
5751
+ const argText = parsed.args[1];
5752
+ const leading = argText.length - argText.trimStart().length;
5753
+ out.push({
5754
+ code: WcsDiagnosticCode.IndexArity,
5755
+ start: scriptStart + parsed.starts[1] + leading,
5756
+ end: scriptStart + parsed.starts[1] + argText.trimEnd().length,
5757
+ message: msgs.indexArity(api, path, requirement, wildcardCount, actual),
5758
+ severity: "warning"
5759
+ });
5760
+ }
5761
+ return out;
5762
+ }
5763
+ var READ_BRACKET = /\bthis\s*\??\.\s*\[\s*(["'])((?:\\.|(?!\1)[^\\])*)\1\s*\]|\bthis\s*\??\[\s*(["'])((?:\\.|(?!\3)[^\\])*)\3\s*\]/g;
5764
+ var READ_DOT = /\bthis\s*\??\.\s*([A-Za-z_]\w*)/g;
5765
+ var READ_API = /\bthis\s*\??\.\s*\$(?:getAll|resolve)\s*\(\s*(["'])((?:\\.|(?!\1)[^\\])*)\1/g;
5766
+ function collectReadPaths(body) {
5767
+ const paths = /* @__PURE__ */ new Set();
5768
+ for (const [regex, groups] of [
5769
+ [READ_BRACKET, [2, 4]],
5770
+ [READ_API, [2]],
5771
+ [READ_DOT, [1]]
5772
+ ]) {
5773
+ regex.lastIndex = 0;
5774
+ let match;
5775
+ while ((match = regex.exec(body)) !== null) {
5776
+ for (const group of groups) {
5777
+ const value = match[group];
5778
+ if (value !== void 0 && value.length > 0 && !value.startsWith("$")) {
5779
+ paths.add(value);
5780
+ }
5781
+ }
5782
+ }
5783
+ }
5784
+ return paths;
5785
+ }
5786
+ function validateGetterCycles(script, scriptStart, locale3) {
5787
+ const msgs = getMessages(locale3);
5788
+ const getters = analyzeCallableBodies(script).filter((entry) => entry.kind === "getter");
5789
+ if (getters.length === 0) return [];
5790
+ const declared = new Set(getters.map((getter) => getter.name));
5791
+ const edges = /* @__PURE__ */ new Map();
5792
+ for (const getter of getters) {
5793
+ const targets = [];
5794
+ for (const read of collectReadPaths(getter.body)) {
5795
+ if (declared.has(read)) targets.push(read);
5796
+ }
5797
+ edges.set(getter.name, targets);
5798
+ }
5799
+ const gray = /* @__PURE__ */ new Set();
5800
+ const black = /* @__PURE__ */ new Set();
5801
+ const stack = [];
5802
+ const cyclesByEntry = /* @__PURE__ */ new Map();
5803
+ const visit = (name) => {
5804
+ if (black.has(name)) return;
5805
+ if (gray.has(name)) {
5806
+ const from = stack.indexOf(name);
5807
+ const cycle = stack.slice(from).concat(name).join(" -> ");
5808
+ for (const member of stack.slice(from)) {
5809
+ if (!cyclesByEntry.has(member)) cyclesByEntry.set(member, cycle);
5810
+ }
5811
+ return;
5812
+ }
5813
+ gray.add(name);
5814
+ stack.push(name);
5815
+ for (const next of edges.get(name) ?? []) {
5816
+ visit(next);
5817
+ }
5818
+ stack.pop();
5819
+ gray.delete(name);
5820
+ black.add(name);
5821
+ };
5822
+ for (const getter of getters) {
5823
+ visit(getter.name);
5824
+ }
5825
+ if (cyclesByEntry.size === 0) return [];
5826
+ const out = [];
5827
+ for (const getter of getters) {
5828
+ const cycle = cyclesByEntry.get(getter.name);
5829
+ if (cycle === void 0) continue;
5830
+ out.push({
5831
+ code: WcsDiagnosticCode.GetterCycle,
5832
+ start: scriptStart + getter.start,
5833
+ end: scriptStart + getter.end,
5834
+ message: msgs.getterCycle(cycle),
5835
+ severity: "warning"
5836
+ });
5837
+ }
5838
+ return out;
5839
+ }
5840
+ function blankComments(source) {
5841
+ const out = source.split("");
5842
+ let i = 0;
5843
+ while (i < source.length) {
5844
+ const ch = source[i];
5845
+ if (ch === '"' || ch === "'" || ch === "`") {
5846
+ const quote = ch;
5847
+ i++;
5848
+ while (i < source.length) {
5849
+ if (source[i] === "\\") {
5850
+ i += 2;
5851
+ continue;
5852
+ }
5853
+ if (source[i] === quote) {
5854
+ i++;
5855
+ break;
5856
+ }
5857
+ i++;
5858
+ }
5859
+ continue;
5860
+ }
5861
+ if (ch === "/" && source[i + 1] === "/") {
5862
+ while (i < source.length && source[i] !== "\n") {
5863
+ out[i] = " ";
5864
+ i++;
5865
+ }
5866
+ continue;
5867
+ }
5868
+ if (ch === "/" && source[i + 1] === "*") {
5869
+ while (i < source.length && !(source[i] === "*" && source[i + 1] === "/")) {
5870
+ out[i] = " ";
5871
+ i++;
5872
+ }
5873
+ if (i < source.length) {
5874
+ out[i] = " ";
5875
+ out[i + 1] = " ";
5876
+ i += 2;
5877
+ }
5878
+ continue;
5879
+ }
5880
+ i++;
5881
+ }
5882
+ return out.join("");
5883
+ }
5884
+ var PATH_TEST_LITERAL = /(?:\.\s*(?:includes|indexOf)\s*\(\s*|[!=]==\s*)(["'])((?:\\.|(?!\1)[^\\])*)\1/g;
5885
+ function validateUpdatedCallbackDemand(html, stateTagName, bindAttrName, locale3) {
5886
+ const blocks = parseWcsScriptBlocks(html, stateTagName);
5887
+ if (blocks.length === 0) return [];
5888
+ const hasCallback = blocks.some((block) => block.content.includes(STATE_UPDATED_CALLBACK));
5889
+ if (!hasCallback) return [];
5890
+ const msgs = getMessages(locale3);
5891
+ const boundPaths = collectBoundPaths(html, stateTagName, bindAttrName);
5892
+ const out = [];
5893
+ for (const block of blocks) {
5894
+ const callback = analyzeCallableBodies(block.content).find((entry) => entry.name === STATE_UPDATED_CALLBACK && entry.kind === "method");
5895
+ if (callback === void 0) continue;
5896
+ const declared = new Set(analyzeStatePaths(block.content, block.stateName).map((p) => p.path));
5897
+ const bound = boundPaths.get(block.stateName) ?? /* @__PURE__ */ new Set();
5898
+ const body = blankComments(callback.body);
5899
+ PATH_TEST_LITERAL.lastIndex = 0;
5900
+ let match;
5901
+ const reported = /* @__PURE__ */ new Set();
5902
+ while ((match = PATH_TEST_LITERAL.exec(body)) !== null) {
5903
+ const path = match[2];
5904
+ if (path.length === 0 || !declared.has(path) || bound.has(path)) continue;
5905
+ if (reported.has(path)) continue;
5906
+ reported.add(path);
5907
+ const quoteAt = match.index + match[0].length - path.length - 1;
5908
+ out.push({
5909
+ code: WcsDiagnosticCode.UpdatedCallbackUnbound,
5910
+ start: block.contentStart + callback.bodyStart + quoteAt,
5911
+ end: block.contentStart + callback.bodyStart + quoteAt + path.length,
5912
+ message: msgs.updatedCallbackUnbound(path),
5913
+ severity: "warning"
5914
+ });
5915
+ }
5916
+ }
5917
+ return out;
5918
+ }
5919
+ function collectBoundPaths(html, stateTagName, bindAttrName) {
5920
+ const byState = /* @__PURE__ */ new Map();
5921
+ const add = (stateName, path) => {
5922
+ let set = byState.get(stateName);
5923
+ if (set === void 0) {
5924
+ set = /* @__PURE__ */ new Set();
5925
+ byState.set(stateName, set);
5926
+ }
5927
+ set.add(path);
5928
+ };
5929
+ const index = buildReferenceIndex(html, { bindAttribute: bindAttrName, stateTagName });
5930
+ for (const occurrence of index.occurrences) {
5931
+ add(occurrence.stateName, occurrence.path);
5932
+ if (!occurrence.path.startsWith(".")) continue;
5933
+ const forPath = getInnermostForPath(html, occurrence.pathRange.start, bindAttrName);
5934
+ if (forPath === null || forPath.startsWith(".")) continue;
5935
+ add(
5936
+ occurrence.stateName,
5937
+ occurrence.path === "." ? `${forPath}.*` : `${forPath}.*.${occurrence.path.slice(1)}`
5938
+ );
5939
+ }
5940
+ return byState;
5941
+ }
5942
+ function validateSemantics(html, stateTagName = "wcs-state", locale3, bindAttrName = "data-wcs") {
5943
+ const out = [];
5944
+ for (const block of parseWcsScriptBlocks(html, stateTagName)) {
5945
+ out.push(...validateIndexArity(block.content, block.contentStart, locale3));
5946
+ out.push(...validateGetterCycles(block.content, block.contentStart, locale3));
5947
+ }
5948
+ out.push(...validateUpdatedCallbackDemand(html, stateTagName, bindAttrName, locale3));
5949
+ return out;
5950
+ }
5951
+
5952
+ // src/core/validateDocument.ts
5953
+ function validateDocument(text, options = {}) {
5954
+ const bindAttribute = options.bindAttribute ?? "data-wcs";
5955
+ const stateTagName = options.stateTagName ?? "wcs-state";
5956
+ const locale3 = options.locale;
5957
+ const fileReader = options.fileReader;
5958
+ const out = [];
5959
+ out.push(...validateBindings(text, bindAttribute, stateTagName, locale3, fileReader));
5960
+ out.push(...validateTemplateSyntax(text, stateTagName, bindAttribute, locale3, fileReader));
5961
+ out.push(...validateIoNodes(text, bindAttribute, stateTagName, locale3, fileReader));
5962
+ out.push(...validateDocumentEnv(text, locale3));
5963
+ out.push(...validateSemantics(text, stateTagName, locale3, bindAttribute));
5964
+ out.push(...validateArrayMutations(text, stateTagName, locale3));
5965
+ out.push(...validateWatchDeclarations(text, stateTagName, locale3));
5966
+ for (const d of validateStateTypes(text, stateTagName, locale3)) {
5967
+ out.push({ code: WcsDiagnosticCode.TypeAnnotation, start: d.start, end: d.end, message: d.message, severity: d.severity });
5968
+ }
5969
+ for (const d of validateNestedAssigns(text, stateTagName, locale3)) {
5970
+ out.push({ code: WcsDiagnosticCode.NestedAssign, start: d.start, end: d.end, message: d.message, severity: d.severity });
5971
+ }
5972
+ return sortDiagnostics(out);
5973
+ }
5974
+
5975
+ // src/core/sidecar/schemaSubset.ts
3651
5976
  var ALLOWED_SCHEMA_KEYWORDS = /* @__PURE__ */ new Set([
3652
5977
  "type",
3653
5978
  "properties",
@@ -4266,29 +6591,6 @@ function runValidation(inputs, options = {}) {
4266
6591
  function classify(path) {
4267
6592
  return path.endsWith(".manifest.json") ? "manifest" : "html";
4268
6593
  }
4269
- function createFileReader(htmlPath, read = (p) => (0, import_node_fs.readFileSync)(p, "utf8")) {
4270
- const base = (0, import_node_path.dirname)(htmlPath);
4271
- const cache = /* @__PURE__ */ new Map();
4272
- return (relativePath) => {
4273
- if (/^[a-z][a-z0-9+.-]*:\/\//i.test(relativePath) || relativePath.startsWith("/")) {
4274
- return void 0;
4275
- }
4276
- if (cache.has(relativePath)) {
4277
- return cache.get(relativePath);
4278
- }
4279
- let content;
4280
- try {
4281
- content = read((0, import_node_path.resolve)(base, relativePath));
4282
- if (content.charCodeAt(0) === 65279) {
4283
- content = content.slice(1);
4284
- }
4285
- } catch {
4286
- content = void 0;
4287
- }
4288
- cache.set(relativePath, content);
4289
- return content;
4290
- };
4291
- }
4292
6594
  function parseArgs(argv) {
4293
6595
  const options = {};
4294
6596
  const files = [];
@@ -4313,7 +6615,7 @@ function resolveCliLocale(explicit, env = process.env) {
4313
6615
  }
4314
6616
  function main(argv) {
4315
6617
  const { options, files } = parseArgs(argv);
4316
- const locale = resolveCliLocale(options.locale);
6618
+ const locale3 = resolveCliLocale(options.locale);
4317
6619
  if (files.length === 0) {
4318
6620
  process.stderr.write("usage: wcs-validate [--attr=data-wcs] [--state-tag=wcs-state] [--lang=ja|en] <file> [<file> ...]\n");
4319
6621
  return 2;
@@ -4322,7 +6624,7 @@ function main(argv) {
4322
6624
  for (const path of files) {
4323
6625
  let text;
4324
6626
  try {
4325
- text = (0, import_node_fs.readFileSync)(path, "utf8");
6627
+ text = (0, import_node_fs2.readFileSync)(path, "utf8");
4326
6628
  } catch (e) {
4327
6629
  process.stderr.write(`cannot read ${path}: ${e.message}
4328
6630
  `);
@@ -4331,7 +6633,7 @@ function main(argv) {
4331
6633
  const kind = classify(path);
4332
6634
  inputs.push({ source: path, text, kind, fileReader: kind === "html" ? createFileReader(path) : void 0 });
4333
6635
  }
4334
- const result = runValidation(inputs, { ...options, locale });
6636
+ const result = runValidation(inputs, { ...options, locale: locale3 });
4335
6637
  for (const line of result.lines) {
4336
6638
  process.stdout.write(line + "\n");
4337
6639
  }