@wcstack/typescript 3.5.4 → 4.0.0-rc.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/tsc-core.cjs CHANGED
@@ -28,8 +28,48 @@ __export(tscCore_exports, {
28
28
  module.exports = __toCommonJS(tscCore_exports);
29
29
 
30
30
  // src/language/htmlParse.ts
31
+ function asciiLowerCase(text2) {
32
+ return text2.replace(/[A-Z]+/g, (upper2) => upper2.toLowerCase());
33
+ }
31
34
  function parseWcsScriptBlocks(html, stateTagName = "wcs-state") {
32
- const blocks = [];
35
+ return parseWcsStateElements(html, stateTagName).flatMap((element) => element.scriptBlocks);
36
+ }
37
+ var RAW_TEXT_ELEMENTS = /* @__PURE__ */ new Set([
38
+ "script",
39
+ "style",
40
+ "textarea",
41
+ "title",
42
+ "xmp",
43
+ "iframe",
44
+ "noembed",
45
+ "noframes",
46
+ "noscript",
47
+ "plaintext"
48
+ ]);
49
+ function matchRawTextElement(html, lower2, pos) {
50
+ if (html[pos] !== "<") return null;
51
+ for (const tag of RAW_TEXT_ELEMENTS) {
52
+ const open = matchOpenTag(html, pos, tag);
53
+ if (open === null) continue;
54
+ if (tag === "plaintext") return { tag, open, contentEnd: html.length, closed: false };
55
+ let from = open.end;
56
+ for (; ; ) {
57
+ const idx = lower2.indexOf(`</${tag}`, from);
58
+ if (idx === -1) return { tag, open, contentEnd: html.length, closed: false };
59
+ const after = html[idx + tag.length + 2];
60
+ if (after === void 0 || after === ">" || after === "/" || /\s/.test(after)) return { tag, open, contentEnd: idx, closed: true };
61
+ from = idx + 1;
62
+ }
63
+ }
64
+ return null;
65
+ }
66
+ function afterCloseTag(html, closeStart) {
67
+ const gt = html.indexOf(">", closeStart);
68
+ return gt === -1 ? html.length : gt + 1;
69
+ }
70
+ function parseWcsStateElements(html, stateTagName = "wcs-state") {
71
+ const elements = [];
72
+ const lower2 = asciiLowerCase(html);
33
73
  let pos = 0;
34
74
  const len = html.length;
35
75
  while (pos < len) {
@@ -39,15 +79,27 @@ function parseWcsScriptBlocks(html, stateTagName = "wcs-state") {
39
79
  pos = commentEnd + 3;
40
80
  continue;
41
81
  }
82
+ const raw = matchRawTextElement(html, lower2, pos);
83
+ if (raw !== null) {
84
+ pos = raw.closed ? afterCloseTag(html, raw.contentEnd) : len;
85
+ continue;
86
+ }
42
87
  const wcsMatch = matchOpenTag(html, pos, stateTagName);
43
88
  if (wcsMatch === null) {
44
89
  pos++;
45
90
  continue;
46
91
  }
47
92
  const mountPath = extractAttribute(wcsMatch.tagContent, "mount");
93
+ const bindComponent = parseAttributeNames(wcsMatch.tagContent).has("bind-component");
94
+ const jsonAttr = extractAttribute(wcsMatch.tagContent, "json") ?? void 0;
95
+ const stateAttr = extractAttribute(wcsMatch.tagContent, "state") ?? void 0;
96
+ const srcAttr = extractAttribute(wcsMatch.tagContent, "src") ?? void 0;
97
+ const tagStart = pos;
98
+ const tagEnd = wcsMatch.end;
48
99
  pos = wcsMatch.end;
49
- const wcsCloseIdx = findCloseTag(html, pos, stateTagName);
50
- const wcsEnd = wcsCloseIdx === -1 ? len : wcsCloseIdx;
100
+ const scriptBlocks = [];
101
+ let wcsCloseIdx = findCloseTag(html, pos, stateTagName, lower2);
102
+ let wcsEnd = wcsCloseIdx === -1 ? len : wcsCloseIdx;
51
103
  while (pos < wcsEnd) {
52
104
  if (html.startsWith("<!--", pos)) {
53
105
  const commentEnd = html.indexOf("-->", pos + 4);
@@ -55,47 +107,49 @@ function parseWcsScriptBlocks(html, stateTagName = "wcs-state") {
55
107
  pos = commentEnd + 3;
56
108
  continue;
57
109
  }
58
- const scriptMatch = matchOpenTag(html, pos, "script");
59
- if (scriptMatch === null) {
110
+ const inner = matchRawTextElement(html, lower2, pos);
111
+ if (inner === null) {
60
112
  pos++;
61
113
  continue;
62
114
  }
63
- const typeAttr = extractAttribute(scriptMatch.tagContent, "type");
64
- if (typeAttr?.toLowerCase() !== "module") {
65
- pos = scriptMatch.end;
66
- continue;
115
+ if (inner.tag === "script") {
116
+ const typeAttr = extractAttribute(inner.open.tagContent, "type");
117
+ if (typeAttr?.toLowerCase() === "module" && inner.closed) {
118
+ const contentStart = inner.open.end;
119
+ scriptBlocks.push({
120
+ contentStart,
121
+ contentEnd: inner.contentEnd,
122
+ content: html.slice(contentStart, inner.contentEnd),
123
+ mountPath,
124
+ bindComponent
125
+ });
126
+ }
67
127
  }
68
- const contentStart = scriptMatch.end;
69
- const scriptCloseIdx = findCloseTag(html, contentStart, "script");
70
- if (scriptCloseIdx === -1) {
71
- pos = contentStart;
128
+ if (!inner.closed) {
129
+ pos = len;
130
+ wcsCloseIdx = -1;
131
+ wcsEnd = len;
72
132
  break;
73
133
  }
74
- const contentEnd = scriptCloseIdx;
75
- blocks.push({
76
- contentStart,
77
- contentEnd,
78
- content: html.slice(contentStart, contentEnd),
79
- mountPath
80
- });
81
- pos = html.indexOf(">", scriptCloseIdx) + 1;
82
- if (pos === 0) break;
134
+ pos = afterCloseTag(html, inner.contentEnd);
135
+ if (pos > wcsEnd) {
136
+ wcsCloseIdx = findCloseTag(html, pos, stateTagName, lower2);
137
+ wcsEnd = wcsCloseIdx === -1 ? len : wcsCloseIdx;
138
+ }
83
139
  }
140
+ elements.push({ mountPath, bindComponent, jsonAttr, stateAttr, srcAttr, scriptBlocks, tagStart, tagEnd });
84
141
  pos = wcsEnd;
85
- if (wcsCloseIdx !== -1) {
86
- const closeEnd = html.indexOf(">", wcsCloseIdx);
87
- if (closeEnd !== -1) pos = closeEnd + 1;
88
- }
142
+ if (wcsCloseIdx !== -1) pos = afterCloseTag(html, wcsCloseIdx);
89
143
  }
90
- return blocks;
144
+ return elements;
91
145
  }
92
146
  function matchOpenTag(html, pos, tagName) {
93
147
  if (html[pos] !== "<") return null;
94
148
  const nameStart = pos + 1;
95
149
  const nameEnd = nameStart + tagName.length;
96
150
  if (nameEnd > html.length) return null;
97
- const slice = html.slice(nameStart, nameEnd);
98
- if (slice.toLowerCase() !== tagName.toLowerCase()) return null;
151
+ const slice2 = html.slice(nameStart, nameEnd);
152
+ if (asciiLowerCase(slice2) !== asciiLowerCase(tagName)) return null;
99
153
  const charAfter = html[nameEnd];
100
154
  if (charAfter !== ">" && charAfter !== " " && charAfter !== " " && charAfter !== "\n" && charAfter !== "\r" && charAfter !== "/") {
101
155
  return null;
@@ -124,10 +178,10 @@ function matchOpenTag(html, pos, tagName) {
124
178
  }
125
179
  return null;
126
180
  }
127
- function findCloseTag(html, startPos, tagName) {
181
+ function findCloseTag(html, startPos, tagName, lower2 = asciiLowerCase(html)) {
128
182
  const pattern = "</" + tagName;
129
- const patternLower = pattern.toLowerCase();
130
- const htmlLower = html.toLowerCase();
183
+ const patternLower = asciiLowerCase(pattern);
184
+ const htmlLower = lower2;
131
185
  let pos = startPos;
132
186
  while (pos < html.length) {
133
187
  const idx = htmlLower.indexOf(patternLower, pos);
@@ -143,6 +197,15 @@ function findCloseTag(html, startPos, tagName) {
143
197
  }
144
198
  return -1;
145
199
  }
200
+ function parseAttributeNames(tagContent) {
201
+ const names = /* @__PURE__ */ new Set();
202
+ const attribute = /([^\s"'<>/=]+)(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s"'<>`=]+))?/g;
203
+ let match;
204
+ while ((match = attribute.exec(tagContent)) !== null) {
205
+ names.add(match[1].toLowerCase());
206
+ }
207
+ return names;
208
+ }
146
209
  function extractAttribute(tagContent, attrName) {
147
210
  const regex = new RegExp(
148
211
  `(?:^|\\s)${attrName}\\s*=\\s*(?:"([^"]*)"|'([^']*)'|(\\S+))`,
@@ -153,7 +216,556 @@ function extractAttribute(tagContent, attrName) {
153
216
  return match[1] ?? match[2] ?? match[3] ?? null;
154
217
  }
155
218
 
219
+ // ../state/dist/manifest.esm.js
220
+ var hooks = {};
221
+ function raiseError(message, subject, candidates) {
222
+ throw new Error(`[@wcstack/state] ${message}${hooks.explain?.(message, subject, candidates) ?? ""}`);
223
+ }
224
+ var CODES = [
225
+ "",
226
+ "binding-syntax",
227
+ "template-syntax",
228
+ "binding-path-missing",
229
+ "binding-type-expectation",
230
+ "filter-unknown",
231
+ "filter-arity",
232
+ "getter-cycle",
233
+ "getter-depth-exceeded",
234
+ "index-arity",
235
+ "index-param-range",
236
+ "recursion-unsupported",
237
+ "token-misconfigured",
238
+ "token-undeclared",
239
+ "wildcard-rank",
240
+ "spread-no-bindable",
241
+ "declaration-alias",
242
+ "name-alias"
243
+ ];
244
+ var codeOf = (id) => {
245
+ const c = CODES[id / 100 | 0];
246
+ return c ? `[wcs/${c}] ` : "";
247
+ };
248
+ function text(id, args = []) {
249
+ return hooks.render?.(id, args) ?? `${codeOf(id)}#${id}${args.map((a) => ` ${typeof a === "string" ? JSON.stringify(a) : String(a)}`).join("")}`;
250
+ }
251
+ function raise(id, args, subject, candidates) {
252
+ raiseError(text(id, args), subject, candidates);
253
+ }
254
+ var config = {
255
+ bindAttributeName: "data-wcs",
256
+ commentForPrefix: "wcs-for",
257
+ commentIfPrefix: "wcs-if",
258
+ commentElseIfPrefix: "wcs-elseif",
259
+ commentElsePrefix: "wcs-else",
260
+ tagNames: { state: "wcs-state", ssr: "wcs-ssr" },
261
+ locale: typeof document !== "undefined" ? document.documentElement?.lang || "en" : "en",
262
+ enableContractAnalyzer: false
263
+ };
264
+ var FEATURE_NAMES = ["formats", "diagnostics", "temporal", "list-keys", "scopes", "recursion", "ssr", "devtools"];
265
+ var WILDCARD = "*";
266
+ function optionsRequired(fnName) {
267
+ raise(26, [fnName]);
268
+ }
269
+ function optionMustBeNumber(fnName) {
270
+ raise(27, [fnName]);
271
+ }
272
+ function valueMustBeNumber(fnName) {
273
+ raise(28, [fnName]);
274
+ }
275
+ function valueMustBeDate(fnName) {
276
+ raise(29, [fnName]);
277
+ }
278
+ function valueMustBeArray(fnName) {
279
+ raise(30, [fnName]);
280
+ }
281
+ function validateNumberString(value) {
282
+ if (!value || isNaN(Number(value))) {
283
+ return false;
284
+ }
285
+ return true;
286
+ }
287
+ function numberOption(value, fnName) {
288
+ if (!validateNumberString(value)) {
289
+ optionMustBeNumber(fnName);
290
+ }
291
+ return Number(value);
292
+ }
293
+ function requiredNumberOption(options, index, fnName) {
294
+ return numberOption(options?.[index] ?? optionsRequired(fnName), fnName);
295
+ }
296
+ function firstLiteral(opt, literals) {
297
+ return literals !== void 0 && literals.length > 0 ? literals[0] : opt;
298
+ }
299
+ var eq = (options, literals) => {
300
+ const opt = options?.[0] ?? optionsRequired("eq");
301
+ const literal = firstLiteral(opt, literals);
302
+ return (value) => {
303
+ if (typeof value === "number") {
304
+ if (typeof literal !== "string") {
305
+ return value === literal;
306
+ }
307
+ if (!validateNumberString(opt)) {
308
+ optionMustBeNumber("eq");
309
+ }
310
+ return value === Number(opt);
311
+ }
312
+ if (typeof value === "string") {
313
+ return value === opt;
314
+ }
315
+ return value === literal;
316
+ };
317
+ };
318
+ var ne = (options, literals) => {
319
+ const opt = options?.[0] ?? optionsRequired("ne");
320
+ const literal = firstLiteral(opt, literals);
321
+ return (value) => {
322
+ if (typeof value === "number") {
323
+ if (typeof literal !== "string") {
324
+ return value !== literal;
325
+ }
326
+ if (!validateNumberString(opt)) {
327
+ optionMustBeNumber("ne");
328
+ }
329
+ return value !== Number(opt);
330
+ }
331
+ if (typeof value === "string") {
332
+ return value !== opt;
333
+ }
334
+ return value !== literal;
335
+ };
336
+ };
337
+ var not = () => (value) => !value;
338
+ var numeric = (name, op) => ({
339
+ factory: (options) => {
340
+ const opt = requiredNumberOption(options, 0, name);
341
+ return (value) => {
342
+ if (typeof value !== "number") {
343
+ valueMustBeNumber(name);
344
+ }
345
+ return op(value, opt);
346
+ };
347
+ },
348
+ arity: [1, 1]
349
+ });
350
+ var truthy = () => (value) => !!value;
351
+ var falsy = () => (value) => !value;
352
+ var boolean = () => (value) => Boolean(value);
353
+ var abs = () => (value) => {
354
+ if (typeof value !== "number") {
355
+ valueMustBeNumber("abs");
356
+ }
357
+ return Math.abs(value);
358
+ };
359
+ var clamp = (options) => {
360
+ const min = requiredNumberOption(options, 0, "clamp");
361
+ const max = requiredNumberOption(options, 1, "clamp");
362
+ return (value) => {
363
+ if (typeof value !== "number") {
364
+ valueMustBeNumber("clamp");
365
+ }
366
+ return Math.min(Math.max(value, min), max);
367
+ };
368
+ };
369
+ var number = () => (value) => Number(value);
370
+ var string = () => (value) => String(value);
371
+ var int = () => (value) => parseInt(String(value), 10);
372
+ var float = () => (value) => parseFloat(String(value));
373
+ var defaults = (options, literals) => {
374
+ const opt = options?.[0] ?? optionsRequired("defaults");
375
+ const fallback = firstLiteral(opt, literals);
376
+ return (value) => {
377
+ if (!value) {
378
+ return fallback;
379
+ }
380
+ return value;
381
+ };
382
+ };
383
+ var coalesce = (options, literals) => {
384
+ const opt = options?.[0] ?? optionsRequired("coalesce");
385
+ const fallback = firstLiteral(opt, literals);
386
+ return (value) => value ?? fallback;
387
+ };
388
+ var nullIfEmpty = () => (value) => value === "" ? null : value;
389
+ var coreFilters = {
390
+ eq: { factory: eq, arity: [1, 1] },
391
+ ne: { factory: ne, arity: [1, 1] },
392
+ not: { factory: not, arity: [0, 0] },
393
+ lt: numeric("lt", (value, opt) => value < opt),
394
+ le: numeric("le", (value, opt) => value <= opt),
395
+ gt: numeric("gt", (value, opt) => value > opt),
396
+ ge: numeric("ge", (value, opt) => value >= opt),
397
+ add: numeric("add", (value, opt) => value + opt),
398
+ sub: numeric("sub", (value, opt) => value - opt),
399
+ mul: numeric("mul", (value, opt) => value * opt),
400
+ div: numeric("div", (value, opt) => value / opt),
401
+ mod: numeric("mod", (value, opt) => value % opt),
402
+ abs: { factory: abs, arity: [0, 0] },
403
+ clamp: { factory: clamp, arity: [2, 2] },
404
+ int: { factory: int, arity: [0, 0] },
405
+ float: { factory: float, arity: [0, 0] },
406
+ falsy: { factory: falsy, arity: [0, 0] },
407
+ truthy: { factory: truthy, arity: [0, 0] },
408
+ defaults: { factory: defaults, arity: [1, 1] },
409
+ coalesce: { factory: coalesce, arity: [1, 1] },
410
+ boolean: { factory: boolean, arity: [0, 0] },
411
+ number: { factory: number, arity: [0, 0] },
412
+ string: { factory: string, arity: [0, 0] },
413
+ nullIfEmpty: { factory: nullIfEmpty, arity: [0, 0] }
414
+ };
415
+ var nullishPassthrough = (factory) => (options) => {
416
+ const filterFn = factory(options);
417
+ return (value) => value == null ? value : filterFn(value);
418
+ };
419
+ var toFixed = (options) => {
420
+ const opt = numberOption(options?.[0] ?? "0", "toFixed");
421
+ return (value) => {
422
+ if (typeof value !== "number") {
423
+ valueMustBeNumber("toFixed");
424
+ }
425
+ return value.toFixed(opt);
426
+ };
427
+ };
428
+ var round = (options) => {
429
+ const optValue = Math.pow(10, numberOption(options?.[0] ?? "0", "round"));
430
+ return (value) => {
431
+ if (typeof value !== "number") {
432
+ valueMustBeNumber("round");
433
+ }
434
+ return Math.round(value * optValue) / optValue;
435
+ };
436
+ };
437
+ var floor = (options) => {
438
+ const optValue = Math.pow(10, numberOption(options?.[0] ?? "0", "floor"));
439
+ return (value) => {
440
+ if (typeof value !== "number") {
441
+ valueMustBeNumber("floor");
442
+ }
443
+ return Math.floor(value * optValue) / optValue;
444
+ };
445
+ };
446
+ var ceil = (options) => {
447
+ const optValue = Math.pow(10, numberOption(options?.[0] ?? "0", "ceil"));
448
+ return (value) => {
449
+ if (typeof value !== "number") {
450
+ valueMustBeNumber("ceil");
451
+ }
452
+ return Math.ceil(value * optValue) / optValue;
453
+ };
454
+ };
455
+ var percent = (options) => {
456
+ const opt = numberOption(options?.[0] ?? "0", "percent");
457
+ return (value) => {
458
+ if (typeof value !== "number") {
459
+ valueMustBeNumber("percent");
460
+ }
461
+ return `${(value * 100).toFixed(opt)}%`;
462
+ };
463
+ };
464
+ var unit = (options) => {
465
+ const opt = options?.[0] ?? optionsRequired("unit");
466
+ return (value) => String(value) + opt;
467
+ };
468
+ var seen;
469
+ var valid = "en";
470
+ function defaultLocale() {
471
+ if (config.locale !== seen) {
472
+ seen = config.locale;
473
+ try {
474
+ valid = Intl.getCanonicalLocales(seen)[0];
475
+ } catch {
476
+ console.warn(`[@wcstack/state] ${text(48, [seen])}`);
477
+ valid = "en";
478
+ }
479
+ }
480
+ return valid;
481
+ }
482
+ var locale = (options) => {
483
+ const explicit = options?.[0];
484
+ return (value) => {
485
+ if (typeof value !== "number") {
486
+ valueMustBeNumber("locale");
487
+ }
488
+ return value.toLocaleString(explicit ?? defaultLocale());
489
+ };
490
+ };
491
+ var upper = () => (value) => String(value).toUpperCase();
492
+ var lower = () => (value) => String(value).toLowerCase();
493
+ var capitalize = () => (value) => {
494
+ const v = String(value);
495
+ if (v.length === 0) {
496
+ return v;
497
+ }
498
+ if (v.length === 1) {
499
+ return v.toUpperCase();
500
+ }
501
+ return v.charAt(0).toUpperCase() + v.slice(1);
502
+ };
503
+ var trim = () => (value) => String(value).trim();
504
+ var slice = (options) => {
505
+ const numberedOpts = [requiredNumberOption(options, 0, "slice")];
506
+ const opt2 = options?.[1];
507
+ if (typeof opt2 !== "undefined") {
508
+ numberedOpts.push(numberOption(opt2, "slice"));
509
+ }
510
+ return (value) => String(value).slice(...numberedOpts);
511
+ };
512
+ var padStart = (options) => {
513
+ const opt1 = requiredNumberOption(options, 0, "padStart");
514
+ const opt2 = options?.[1] ?? "0";
515
+ return (value) => String(value).padStart(opt1, opt2);
516
+ };
517
+ var padEnd = (options) => {
518
+ const opt1 = requiredNumberOption(options, 0, "padEnd");
519
+ const opt2 = options?.[1] ?? " ";
520
+ return (value) => String(value).padEnd(opt1, opt2);
521
+ };
522
+ var repeat = (options) => {
523
+ const opt = requiredNumberOption(options, 0, "repeat");
524
+ return (value) => String(value).repeat(opt);
525
+ };
526
+ var reverse = () => (value) => String(value).split("").reverse().join("");
527
+ var truncate = (options) => {
528
+ const maxLength = requiredNumberOption(options, 0, "truncate");
529
+ const suffix = options?.[1] ?? "\u2026";
530
+ return (value) => {
531
+ const v = String(value);
532
+ if (v.length <= maxLength) {
533
+ return v;
534
+ }
535
+ return v.slice(0, maxLength) + suffix;
536
+ };
537
+ };
538
+ var join = (options) => {
539
+ const opt = options?.[0] ?? ", ";
540
+ return (value) => {
541
+ if (!Array.isArray(value)) {
542
+ valueMustBeArray("join");
543
+ }
544
+ return value.join(opt);
545
+ };
546
+ };
547
+ var date = (options) => {
548
+ const explicit = options?.[0];
549
+ return (value) => {
550
+ if (!(value instanceof Date)) {
551
+ valueMustBeDate("date");
552
+ }
553
+ return value.toLocaleDateString(explicit ?? defaultLocale());
554
+ };
555
+ };
556
+ var time = (options) => {
557
+ const explicit = options?.[0];
558
+ return (value) => {
559
+ if (!(value instanceof Date)) {
560
+ valueMustBeDate("time");
561
+ }
562
+ return value.toLocaleTimeString(explicit ?? defaultLocale());
563
+ };
564
+ };
565
+ var datetime = (options) => {
566
+ const explicit = options?.[0];
567
+ return (value) => {
568
+ if (!(value instanceof Date)) {
569
+ valueMustBeDate("datetime");
570
+ }
571
+ return value.toLocaleString(explicit ?? defaultLocale());
572
+ };
573
+ };
574
+ var ymd = (options) => {
575
+ const opt = options?.[0] ?? "-";
576
+ return (value) => {
577
+ if (!(value instanceof Date)) {
578
+ valueMustBeDate("ymd");
579
+ }
580
+ const year = value.getFullYear().toString();
581
+ const month = (value.getMonth() + 1).toString().padStart(2, "0");
582
+ const day = value.getDate().toString().padStart(2, "0");
583
+ return `${year}${opt}${month}${opt}${day}`;
584
+ };
585
+ };
586
+ var hms = (options) => {
587
+ const opt = options?.[0] ?? ":";
588
+ return (value) => {
589
+ if (!(value instanceof Date)) {
590
+ valueMustBeDate("hms");
591
+ }
592
+ const hours = value.getHours().toString().padStart(2, "0");
593
+ const minutes = value.getMinutes().toString().padStart(2, "0");
594
+ const seconds = value.getSeconds().toString().padStart(2, "0");
595
+ return `${hours}${opt}${minutes}${opt}${seconds}`;
596
+ };
597
+ };
598
+ var formatFilters = {
599
+ toFixed: { factory: toFixed, arity: [0, 1] },
600
+ locale: { factory: locale, arity: [0, 1] },
601
+ // The `String(value)` family passes an absent value through (B8 — see nullishPassthrough)
602
+ upper: { factory: nullishPassthrough(upper), arity: [0, 0] },
603
+ lower: { factory: nullishPassthrough(lower), arity: [0, 0] },
604
+ capitalize: { factory: nullishPassthrough(capitalize), arity: [0, 0] },
605
+ trim: { factory: nullishPassthrough(trim), arity: [0, 0] },
606
+ slice: { factory: nullishPassthrough(slice), arity: [1, 2] },
607
+ // The length is required too (the implementation reads both)
608
+ padStart: { factory: nullishPassthrough(padStart), arity: [1, 2] },
609
+ padEnd: { factory: nullishPassthrough(padEnd), arity: [1, 2] },
610
+ repeat: { factory: nullishPassthrough(repeat), arity: [1, 1] },
611
+ reverse: { factory: nullishPassthrough(reverse), arity: [0, 0] },
612
+ truncate: { factory: nullishPassthrough(truncate), arity: [1, 2] },
613
+ join: { factory: join, arity: [0, 1] },
614
+ round: { factory: round, arity: [0, 1] },
615
+ floor: { factory: floor, arity: [0, 1] },
616
+ ceil: { factory: ceil, arity: [0, 1] },
617
+ percent: { factory: percent, arity: [0, 1] },
618
+ unit: { factory: nullishPassthrough(unit), arity: [1, 1] },
619
+ // The locale-dependent three take a locale like `locale` does (`date(ja-JP)`)
620
+ date: { factory: date, arity: [0, 1] },
621
+ time: { factory: time, arity: [0, 1] },
622
+ datetime: { factory: datetime, arity: [0, 1] },
623
+ ymd: { factory: ymd, arity: [0, 1] },
624
+ hms: { factory: hms, arity: [0, 1] }
625
+ };
626
+ var STRUCTURAL_BINDING_TYPE_SET = /* @__PURE__ */ new Set([
627
+ "if",
628
+ "elseif",
629
+ "else",
630
+ "for"
631
+ ]);
632
+ var DELIMITER = ".";
633
+ var BINDING_SEPARATOR = ";";
634
+ var PROP_VALUE_SEPARATOR = ":";
635
+ var MODIFIER_SEPARATOR = "#";
636
+ var FILTER_SEPARATOR = "|";
637
+ var ELSE_KEYWORD = "else";
638
+ var SPREAD_PROP = "...";
639
+ var EVENT_PROP_PREFIX = "on";
640
+ var EVENT_TOKEN_NAMESPACE = "eventToken";
641
+ var COMMAND_NAMESPACE = "command";
642
+ var CLASS_NAMESPACE = "class";
643
+ var ATTR_NAMESPACE = "attr";
644
+ var STYLE_NAMESPACE = "style";
645
+ var MAX_INDEX_PARAM = 128;
646
+ var builtinFilterMeta = {
647
+ // 比較・論理
648
+ eq: { description: "\u7B49\u3057\u3044\u304B\u6BD4\u8F03", hasArgs: true, resultType: "boolean", acceptTypes: "any", minArgs: 1, maxArgs: 1, argTypes: ["any"] },
649
+ ne: { description: "\u7570\u306A\u308B\u304B\u6BD4\u8F03", hasArgs: true, resultType: "boolean", acceptTypes: "any", minArgs: 1, maxArgs: 1, argTypes: ["any"] },
650
+ // `not` は真偽性(truthy / falsy)の反転。`if:` が `Boolean()` で寄せるのと同じ規則で、
651
+ // `else:` はこのフィルタを足した束縛として組み立てられる(structural/createNotFilter.ts)
652
+ not: { description: "\u771F\u507D\u6027\u3092\u53CD\u8EE2\uFF08falsy \u2192 true\uFF09", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
653
+ lt: { description: "\u3088\u308A\u5C0F\u3055\u3044\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
654
+ le: { description: "\u4EE5\u4E0B\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
655
+ gt: { description: "\u3088\u308A\u5927\u304D\u3044\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
656
+ ge: { description: "\u4EE5\u4E0A\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
657
+ // 算術
658
+ add: { description: "\u52A0\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
659
+ sub: { description: "\u6E1B\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
660
+ mul: { description: "\u4E57\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
661
+ div: { description: "\u9664\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
662
+ mod: { description: "\u5270\u4F59", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
663
+ abs: { description: "\u7D76\u5BFE\u5024", hasArgs: false, resultType: "number", acceptTypes: ["number"], minArgs: 0, maxArgs: 0 },
664
+ clamp: { description: "\u7BC4\u56F2\u5185\u306B\u4E38\u3081\u308B (min,max)", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 2, maxArgs: 2, argTypes: ["number", "number"] },
665
+ // 数値フォーマット
666
+ toFixed: { description: "\u56FA\u5B9A\u5C0F\u6570\u70B9\u8868\u8A18", hasArgs: true, resultType: "string", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
667
+ locale: { description: "\u30ED\u30B1\u30FC\u30EB\u5F62\u5F0F\u3067\u6570\u5024\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8", hasArgs: true, resultType: "string", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["string"] },
668
+ // 文字列
669
+ upper: { description: "\u5927\u6587\u5B57\u306B\u5909\u63DB", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
670
+ lower: { description: "\u5C0F\u6587\u5B57\u306B\u5909\u63DB", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
671
+ capitalize: { description: "\u5148\u982D\u6587\u5B57\u3092\u5927\u6587\u5B57\u306B", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
672
+ trim: { description: "\u524D\u5F8C\u306E\u7A7A\u767D\u3092\u524A\u9664", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
673
+ slice: { description: "\u90E8\u5206\u6587\u5B57\u5217 (start[,end])", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "number"] },
674
+ padStart: { description: "\u5148\u982D\u3092\u57CB\u3081\u308B (length[,char]\u3002char \u306E\u65E2\u5B9A\u306F 0 \u2014 JS \u306E\u65E2\u5B9A\u306F\u7A7A\u767D\u306A\u306E\u3067\u6CE8\u610F)", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "string"] },
675
+ padEnd: { description: "\u672B\u5C3E\u3092\u57CB\u3081\u308B (length[,char]\u3002char \u306E\u65E2\u5B9A\u306F\u7A7A\u767D \u2014 JS \u3068\u540C\u3058)", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "string"] },
676
+ repeat: { description: "\u7E70\u308A\u8FD4\u3057 (count)", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
677
+ reverse: { description: "\u6587\u5B57\u9806\u3092\u53CD\u8EE2", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
678
+ truncate: { description: "\u5207\u308A\u8A70\u3081\u3066\u7701\u7565\u8A18\u53F7 (length[,suffix]\u3002suffix \u306E\u65E2\u5B9A\u306F \u2026 \u2014 U+2026 \u306E 1 \u6587\u5B57)", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "string"] },
679
+ join: { description: "\u914D\u5217\u3092\u9023\u7D50 ([separator]\u3002\u65E2\u5B9A\u306F\u30AB\u30F3\u30DE + \u7A7A\u767D)", hasArgs: true, resultType: "string", acceptTypes: ["array"], minArgs: 0, maxArgs: 1, argTypes: ["string"] },
680
+ // 数値パース・丸め
681
+ int: { description: "\u6574\u6570\u306B\u30D1\u30FC\u30B9", hasArgs: false, resultType: "number", acceptTypes: ["string", "number"], minArgs: 0, maxArgs: 0 },
682
+ float: { description: "\u6D6E\u52D5\u5C0F\u6570\u70B9\u6570\u306B\u30D1\u30FC\u30B9", hasArgs: false, resultType: "number", acceptTypes: ["string", "number"], minArgs: 0, maxArgs: 0 },
683
+ round: { description: "\u56DB\u6368\u4E94\u5165", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
684
+ floor: { description: "\u5207\u308A\u4E0B\u3052", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
685
+ ceil: { description: "\u5207\u308A\u4E0A\u3052", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
686
+ percent: { description: "\u30D1\u30FC\u30BB\u30F3\u30C6\u30FC\u30B8\u5F62\u5F0F", hasArgs: true, resultType: "string", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
687
+ // number だけでなく string も受ける。実用チェーンは fix / percent の後ろに繋がり、
688
+ // それらは既に string を返すため(builtinFilters.ts の unit を参照)
689
+ unit: { description: "\u5358\u4F4D\uFF08\u63A5\u5C3E\u8F9E\uFF09\u3092\u4ED8\u52A0", hasArgs: true, resultType: "string", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["string"] },
690
+ // 日付・時刻
691
+ // `locale` と同じくロケールを 1 つ受ける(`date(ja-JP)`)。実装は最初からこれを読んでいたが、
692
+ // メタデータ側が maxArgs: 0 だったため lint と補完が正しい書き方を誤りとして報告していた
693
+ date: { description: "\u30ED\u30B1\u30FC\u30EB\u5F62\u5F0F\u306E\u65E5\u4ED8 ([locale]\u3002\u65E2\u5B9A\u306F config.locale)", hasArgs: true, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 1, argTypes: ["string"] },
694
+ time: { description: "\u30ED\u30B1\u30FC\u30EB\u5F62\u5F0F\u306E\u6642\u523B ([locale]\u3002\u65E2\u5B9A\u306F config.locale)", hasArgs: true, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 1, argTypes: ["string"] },
695
+ datetime: { description: "\u30ED\u30B1\u30FC\u30EB\u5F62\u5F0F\u306E\u65E5\u6642 ([locale]\u3002\u65E2\u5B9A\u306F config.locale)", hasArgs: true, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 1, argTypes: ["string"] },
696
+ ymd: { description: "YYYY-MM-DD \u5F62\u5F0F ([separator]\u3002\u65E2\u5B9A\u306F -)", hasArgs: true, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 1, argTypes: ["string"] },
697
+ hms: { description: "HH:MM:SS \u5F62\u5F0F ([separator]\u3002\u65E2\u5B9A\u306F :)", hasArgs: true, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 1, argTypes: ["string"] },
698
+ // 真偽値・変換
699
+ falsy: { description: "\u507D\u5024\u304B\u5224\u5B9A", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
700
+ truthy: { description: "\u771F\u5024\u304B\u5224\u5B9A", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
701
+ defaults: { description: "\u507D\u5024\u306E\u5834\u5408\u30C7\u30D5\u30A9\u30EB\u30C8\u5024", hasArgs: true, resultType: "passthrough", acceptTypes: "any", minArgs: 1, maxArgs: 1, argTypes: ["any"] },
702
+ coalesce: { description: "null / undefined \u306E\u5834\u5408\u30C7\u30D5\u30A9\u30EB\u30C8\u5024", hasArgs: true, resultType: "passthrough", acceptTypes: "any", minArgs: 1, maxArgs: 1, argTypes: ["any"] },
703
+ boolean: { description: "\u30D6\u30FC\u30EB\u5024\u306B\u5909\u63DB", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
704
+ number: { description: "\u6570\u5024\u306B\u5909\u63DB", hasArgs: false, resultType: "number", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
705
+ string: { description: "\u6587\u5B57\u5217\u306B\u5909\u63DB", hasArgs: false, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
706
+ nullIfEmpty: { description: "\u7A7A\u6587\u5B57\u5217\u3092null\u306B\u5909\u63DB", hasArgs: false, resultType: "passthrough", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 }
707
+ };
708
+ var WCS_MANIFEST_VERSION = 2;
709
+ var builtinFilterAliases = Object.freeze({});
710
+ var DECLARATION_ALIASES = Object.freeze({});
711
+ var STATE_API_ALIASES = Object.freeze({});
712
+ var MODIFIER_FLAGS = Object.freeze(["prevent", "stop", "ro", "direct"]);
713
+ var MODIFIER_KEYS = Object.freeze(["init", "sync"]);
714
+ var INDEX_PARAM_PREFIX = "$";
715
+ var BEHAVIOR_OPTION_KEYS = ["enableMustache", "sameValueGuard", "enableDirectionalInitialSync"];
716
+ function getWcsManifest() {
717
+ return {
718
+ version: WCS_MANIFEST_VERSION,
719
+ syntax: {
720
+ bindAttribute: config.bindAttributeName,
721
+ tagName: config.tagNames.state,
722
+ pathDelimiter: DELIMITER,
723
+ wildcard: WILDCARD,
724
+ delimiters: { binding: BINDING_SEPARATOR, propValue: PROP_VALUE_SEPARATOR, modifier: MODIFIER_SEPARATOR, filter: FILTER_SEPARATOR },
725
+ structuralDirectives: Array.from(STRUCTURAL_BINDING_TYPE_SET),
726
+ modifiers: { flags: MODIFIER_FLAGS, keyValue: MODIFIER_KEYS, eventNamePrefix: EVENT_PROP_PREFIX },
727
+ indexParam: { prefix: INDEX_PARAM_PREFIX, maxDepth: MAX_INDEX_PARAM },
728
+ bindingTypes: {
729
+ elseKeyword: ELSE_KEYWORD,
730
+ spread: SPREAD_PROP,
731
+ eventPropertyPrefix: EVENT_PROP_PREFIX,
732
+ explicitPropertyPrefix: DELIMITER,
733
+ propNamespaces: { eventToken: EVENT_TOKEN_NAMESPACE, command: COMMAND_NAMESPACE, class: CLASS_NAMESPACE, attr: ATTR_NAMESPACE, style: STYLE_NAMESPACE }
734
+ }
735
+ },
736
+ // quoted: `filters` is an internal name the bundles shorten (mangle.mjs)
737
+ "filters": [...Object.keys(coreFilters), ...Object.keys(formatFilters)],
738
+ filterMeta: builtinFilterMeta,
739
+ filterAliases: builtinFilterAliases,
740
+ declarationAliases: DECLARATION_ALIASES,
741
+ apiAliases: STATE_API_ALIASES,
742
+ reservedLifecycle: ["$connectedCallback", "$disconnectedCallback", "$renderedCallback", "$errorCallback", "$stateReadyCallback"],
743
+ reservedStateApi: [
744
+ "$bindables",
745
+ "$commands",
746
+ "$commandTokens",
747
+ "$command",
748
+ "$eventTokens",
749
+ "$on",
750
+ "$stream",
751
+ "$watch",
752
+ "$listKeys",
753
+ "$recursion",
754
+ "$streamStatus",
755
+ "$streamError",
756
+ "$behavior",
757
+ "$features"
758
+ ],
759
+ // every option is a boolean, true when left out (engine.ts `loadTarget`: `typeof … === "boolean"`, `?? true`)
760
+ behaviorOptions: Object.fromEntries(BEHAVIOR_OPTION_KEYS.map((key) => [key, { type: "boolean", default: true }])),
761
+ features: [...FEATURE_NAMES]
762
+ };
763
+ }
764
+
156
765
  // src/language/preamble.ts
766
+ var manifest = getWcsManifest();
767
+ var BEHAVIOR_TYPE = `{ ${Object.entries(manifest.behaviorOptions).map(([key, option]) => `${key}?: ${option.type}`).join("; ")} }`;
768
+ var FEATURE_NAME_TYPE = manifest.features.map((name) => JSON.stringify(name)).join(" | ");
157
769
  var WCS_PREAMBLE = `
158
770
  // --- @wcstack/state type preamble (auto-injected by vscode-wcs) ---
159
771
  type _IsAny<T> = 0 extends (1 & T) ? true : false;
@@ -206,10 +818,6 @@ interface WcsStateApi {
206
818
  $resolve(path: string, indexes: number[], value?: any): any;
207
819
  $dependOn(path: string): void;
208
820
  $untracked<T>(fn: () => T): T;
209
- /** @deprecated $dependOn \u306E\u65E7\u540D\uFF08@wcstack/state 3.2 \u2014 4.0 \u3067\u524A\u9664\u3055\u308C\u308B / removed in 4.0\uFF09 */
210
- $trackDependency(path: string): void;
211
- /** @deprecated $untracked \u306E\u65E7\u540D\uFF08@wcstack/state 3.2 \u2014 4.0 \u3067\u524A\u9664\u3055\u308C\u308B / removed in 4.0\uFF09 */
212
- $untrackDependency<T>(fn: () => T): T;
213
821
  $eq(path: string, key: unknown): boolean;
214
822
  $eqPath(path: string, keyPath: string): boolean;
215
823
  $eqIndex(path: string, level?: number): boolean;
@@ -231,14 +839,12 @@ interface WcsStateApi {
231
839
  // \u672B\u5C3E\u304C \`.**\` \u306E\u30AD\u30FC\u306B\u3082\u540C\u3058\u7D22\u5F15\u3092\u7F6E\u304F\uFF08@wcstack/state \u306E defineState \u3068\u5BFE\uFF09\u3002
232
840
  readonly [key: \`\${string}.**\`]: any;
233
841
  }
234
- // $scan \u306E\u51FA\u529B\u3068 $streams \u306E\u5024\u306F\u3001\u30E9\u30F3\u30BF\u30A4\u30E0\u304C\u5BA3\u8A00\u30AD\u30FC\u306E\u540D\u524D\u3067\u5B9F\u4F53\u5316\u3059\u308B\u30D7\u30ED\u30D1\u30C6\u30A3\u3002T \u306B\u306F\u5BA3\u8A00
235
- // \u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u306E\u4E2D\u306B\u3057\u304B\u73FE\u308C\u306A\u3044\u306E\u3067\u3001getter \u3084\u30E1\u30BD\u30C3\u30C9\u306E this \u304B\u3089\u8AAD\u3081\u308B\u3088\u3046 any \u3067\u5199\u3059\u3002initial \u306E
236
- // \u578B\u306F\u4F7F\u308F\u306A\u3044 \u2014 \u7A7A\u914D\u5217\u306E initial \u304C never[] \u306B\u306A\u308A\u3001\u6B63\u3057\u3044\u8AAD\u307F\uFF08\u8981\u7D20\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\uFF09\u307E\u3067\u578B\u30A8\u30E9\u30FC\u306B\u306A\u308B\u305F\u3081\u3002
842
+ // $stream \u306E\u5024\u306F\u3001\u30E9\u30F3\u30BF\u30A4\u30E0\u304C\u5BA3\u8A00\u30AD\u30FC\u306E\u540D\u524D\u3067\u5B9F\u4F53\u5316\u3059\u308B\u30D7\u30ED\u30D1\u30C6\u30A3\u3002T \u306B\u306F\u5BA3\u8A00\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u306E\u4E2D\u306B\u3057\u304B
843
+ // \u73FE\u308C\u306A\u3044\u306E\u3067\u3001getter \u3084\u30E1\u30BD\u30C3\u30C9\u306E this \u304B\u3089\u8AAD\u3081\u308B\u3088\u3046 any \u3067\u5199\u3059\u3002initial \u306E\u578B\u306F\u4F7F\u308F\u306A\u3044 \u2014 \u7A7A\u914D\u5217\u306E
844
+ // initial \u304C never[] \u306B\u306A\u308A\u3001\u6B63\u3057\u3044\u8AAD\u307F\uFF08\u8981\u7D20\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\uFF09\u307E\u3067\u578B\u30A8\u30E9\u30FC\u306B\u306A\u308B\u305F\u3081\u3002
237
845
  // T \u306B\u540C\u540D\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u3092\u660E\u793A\u7684\u306B\u4E8B\u524D\u5BA3\u8A00\u3057\u3066\u3044\u308C\u3070\u5199\u3055\u306A\u3044\uFF08\u4EA4\u5DEE\u3067\u305D\u306E\u578B\u307E\u3067 any \u306B\u6F70\u3055\u306A\u3044\u305F\u3081\uFF09\u3002
238
846
  type _WcsDeclaredValues<T> =
239
- (T extends { $scan: infer S } ? { [K in Exclude<keyof S & string, keyof T>]: any } : {}) &
240
- (T extends { $stream: infer S } ? { [K in Exclude<keyof S & string, keyof T>]: any } : {}) &
241
- (T extends { $streams: infer S } ? { [K in Exclude<keyof S & string, keyof T>]: any } : {});
847
+ (T extends { $stream: infer S } ? { [K in Exclude<keyof S & string, keyof T>]: any } : {});
242
848
  type _WcsThis<T> = T & WcsStateApi & _WcsPathAccessor<T> & _WcsDeclaredValues<T>;
243
849
  // $listKeys: { "<listPath>": "<field>" | (row) => key }\uFF08list/listKeys.ts\uFF09\u3002
244
850
  // \u30AD\u30FC\u6307\u5B9A\u306E\u95A2\u6570\u5F15\u6570\u306B\u6587\u8108\u578B\u3092\u4E0E\u3048\u308B\u305F\u3081\u3060\u3051\u306E\u5BA3\u8A00\uFF08noImplicitAny \u4E0B\u306E\u507D\u30A8\u30E9\u30FC\u56DE\u907F\uFF09\u3002
@@ -247,23 +853,20 @@ type _WcsListKeys = Record<string, string | ((row: any) => unknown)>;
247
853
  // \u30CF\u30F3\u30C9\u30E9\u5F15\u6570\u306B\u6587\u8108\u578B\u3092\u4E0E\u3048\u308B\u305F\u3081\u3060\u3051\u306E\u5BA3\u8A00\uFF08$listKeys \u3068\u540C\u3058\u7406\u7531\uFF09\u3002
248
854
  // this \u306F ThisType<_WcsThis<T>> \u306B\u3088\u308A state \u578B\u306B\u306A\u308B\u3002
249
855
  type _WcsWatch = Record<string, (cur: any, prev: any, ...indexes: number[]) => void>;
250
- // $scan: { "<output>": { from | on, initial, fold, resetOn? } }\uFF08scan/processScanDeclaration.ts\uFF09\u3002
251
- // fold \u306E\u5F15\u6570\u306B\u6587\u8108\u578B\u3092\u4E0E\u3048\u308B\u305F\u3081\u3060\u3051\u306E\u5BA3\u8A00\u3002from \u3068 on \u3067\u7B2C 2 \u5F15\u6570\u306E\u610F\u5473\u304C\u5909\u308F\u308B\uFF08cur \u304B event\uFF09\u306E\u3067
252
- // \u5F15\u6570\u306F any \u306B\u5012\u3059\u3002fold \u306B this \u306F\u6E21\u3089\u306A\u3044\uFF08\u30E9\u30F3\u30BF\u30A4\u30E0\u306F this \u7121\u3057\u3067\u547C\u3076\uFF09\u306E\u3067 this: void \u3068\u66F8\u304F \u2014
253
- // \u66F8\u304B\u306A\u3044\u3068 defineState \u306E ThisType \u304C\u30E1\u30BD\u30C3\u30C9\u5F62\u306E fold \u306B\u3082 state \u578B\u306E this \u3092\u4E0E\u3048\u3066\u3057\u307E\u3046\u3002
254
- type _WcsScan = Record<string, {
255
- from?: string;
256
- on?: string;
257
- initial: any;
258
- fold: (this: void, acc: any, ...args: any[]) => any;
259
- resetOn?: string[];
260
- }>;
261
856
  // $recursion: { "<anchor>": "<repeat>" }\uFF08recursion/declaration.ts\uFF09\u3002\u521D\u7248\u306F\u5358\u4E00\u306E\u81EA\u5DF1\u518D\u5E30
262
857
  // \u306E\u307F\u3067\u3001\u30A2\u30F3\u30AB\u30FC\u3082\u53CD\u5FA9\u30B5\u30D6\u30D1\u30B9\u3082\u300C\u56FA\u5B9A\u30D7\u30ED\u30D1\u30C6\u30A3\u5217 + \u672B\u5C3E\u306E .*\u300D\u306B\u9650\u308B\u3002\u5F62\u306E\u691C\u8A3C\u306F
263
858
  // service/recursionValidator.ts\uFF08wcs/recursion-declaration-invalid\uFF09\u304C\u62C5\u3046\u3002
264
859
  type _WcsRecursion = Record<string, string>;
860
+ // $behavior: \u305D\u306E\u6728\u306E\u632F\u308B\u821E\u3044\uFF084.0 \u3067 bootstrapState \u304B\u3089\u79FB\u3063\u305F 3 \u30AD\u30FC\u3002\u65E2\u5B9A\u306F\u3069\u308C\u3082 true\uFF09\u3002
861
+ // \u5024\u304C boolean \u3067\u306A\u3044\u5F62\u306F\u578B\u30A8\u30E9\u30FC\u306B\u306A\u308B\u3002\u77E5\u3089\u306A\u3044\u30AD\u30FC\u306F lint\uFF08wcs/behavior-invalid\uFF09\u304C\u5831\u544A\u3059\u308B\u3002
862
+ type _WcsBehavior = ${BEHAVIOR_TYPE};
863
+ // $features: \u305D\u306E state \u304C\u8981\u308B\u5F8C\u4ED8\u3051\uFF084.0\u3002\u5206\u5272 auto \u306F\u8AAD\u307F\u8FBC\u307F\u3001\u5168\u90E8\u5165\u308A\u30FB\u30D0\u30F3\u30C9\u30E9\u306F\u5165\u3063\u3066\u3044\u308B\u304B\u3092\u691C\u67FB\u3059\u308B\uFF09\u3002
864
+ type _WcsFeatureName = ${FEATURE_NAME_TYPE};
265
865
  function defineState<T extends Record<string, any>>(
266
- def: T & { $listKeys?: _WcsListKeys; $watch?: _WcsWatch; $scan?: _WcsScan; $recursion?: _WcsRecursion } & ThisType<_WcsThis<T>>
866
+ def: T & {
867
+ $listKeys?: _WcsListKeys; $watch?: _WcsWatch; $recursion?: _WcsRecursion;
868
+ $behavior?: _WcsBehavior; $features?: readonly _WcsFeatureName[];
869
+ } & ThisType<_WcsThis<T>>
267
870
  ): T { return def; }
268
871
  // --- end preamble ---
269
872
  `;