@wcstack/typescript 3.0.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -566,7 +566,7 @@ function loadSchemaCore() {
566
566
  return cached;
567
567
  }
568
568
 
569
- var version = "3.0.0";
569
+ var version = "3.2.0";
570
570
  var pkg = {
571
571
  version: version};
572
572
 
@@ -147,6 +147,12 @@ var WcsDiagnosticCode = {
147
147
  // --- built-in wcs-* tag contract (generated/builtinTags.generated.ts が正本) ---
148
148
  // 未知メンバーへのバインド(プロパティ / command. / eventToken. キー)。黙って無視される。
149
149
  TagMemberUnknown: "wcs/tag-member-unknown",
150
+ // タグのメンバー名が "on" で始まる(`once` 等)のに先頭ドット無しで束縛した: ランタイムはイベント束縛にして
151
+ // "ce" イベントを待ち、値は届かない。明示のプロパティ形 `.once:` を提案する(@wcstack/state 3.1・要件 B5 / 3.x 計画 D36)
152
+ OnPrefixedMember: "wcs/on-prefixed-member",
153
+ // 3.x の間だけ残る旧名(フィルタ `uc` → `upper`、`$trackDependency` → `$dependOn` …)を書いた(info)。
154
+ // 動くが 4.0 で外れるので正式名を提案する(@wcstack/state 3.2・要件 B12 / 3.x 計画 D39)
155
+ NameAlias: "wcs/name-alias",
150
156
  // wcBindable 無宣言タグ(wcs-fetch-header 等のヘルパー)への spread。
151
157
  // ランタイム(expandSpread)は raiseError で落とす。
152
158
  SpreadNoBindable: "wcs/spread-no-bindable",
@@ -691,6 +697,18 @@ function valueMustBeDate(fnName) {
691
697
  function valueMustBeArray(fnName) {
692
698
  raiseError(`filter ${fnName} requires an array value`);
693
699
  }
700
+ var builtinFilterAliases = {
701
+ inc: "add",
702
+ dec: "sub",
703
+ fix: "toFixed",
704
+ uc: "upper",
705
+ lc: "lower",
706
+ cap: "capitalize",
707
+ rep: "repeat",
708
+ rev: "reverse",
709
+ pad: "padStart",
710
+ null: "nullIfEmpty"
711
+ };
694
712
  function validateNumberString(value) {
695
713
  if (!value || isNaN(Number(value))) {
696
714
  return false;
@@ -786,25 +804,25 @@ var ge = (options) => {
786
804
  };
787
805
  };
788
806
  var inc = (options) => {
789
- const opt = options?.[0] ?? optionsRequired("inc");
807
+ const opt = options?.[0] ?? optionsRequired("add");
790
808
  if (!validateNumberString(opt)) {
791
- optionMustBeNumber("inc");
809
+ optionMustBeNumber("add");
792
810
  }
793
811
  return (value) => {
794
812
  if (typeof value !== "number") {
795
- valueMustBeNumber("inc");
813
+ valueMustBeNumber("add");
796
814
  }
797
815
  return value + Number(opt);
798
816
  };
799
817
  };
800
818
  var dec = (options) => {
801
- const opt = options?.[0] ?? optionsRequired("dec");
819
+ const opt = options?.[0] ?? optionsRequired("sub");
802
820
  if (!validateNumberString(opt)) {
803
- optionMustBeNumber("dec");
821
+ optionMustBeNumber("sub");
804
822
  }
805
823
  return (value) => {
806
824
  if (typeof value !== "number") {
807
- valueMustBeNumber("dec");
825
+ valueMustBeNumber("sub");
808
826
  }
809
827
  return value - Number(opt);
810
828
  };
@@ -874,11 +892,11 @@ var clamp = (options) => {
874
892
  var fix = (options) => {
875
893
  const opt = options?.[0] ?? "0";
876
894
  if (!validateNumberString(opt)) {
877
- optionMustBeNumber("fix");
895
+ optionMustBeNumber("toFixed");
878
896
  }
879
897
  return (value) => {
880
898
  if (typeof value !== "number") {
881
- valueMustBeNumber("fix");
899
+ valueMustBeNumber("toFixed");
882
900
  }
883
901
  return value.toFixed(Number(opt));
884
902
  };
@@ -951,19 +969,29 @@ var substr = (options) => {
951
969
  };
952
970
  };
953
971
  var pad = (options) => {
954
- const opt1 = options?.[0] ?? optionsRequired("pad");
972
+ const opt1 = options?.[0] ?? optionsRequired("padStart");
955
973
  if (!validateNumberString(opt1)) {
956
- optionMustBeNumber("pad");
974
+ optionMustBeNumber("padStart");
957
975
  }
958
976
  const opt2 = options?.[1] ?? "0";
959
977
  return (value) => {
960
978
  return String(value).padStart(Number(opt1), opt2);
961
979
  };
962
980
  };
981
+ var padEnd = (options) => {
982
+ const opt1 = options?.[0] ?? optionsRequired("padEnd");
983
+ if (!validateNumberString(opt1)) {
984
+ optionMustBeNumber("padEnd");
985
+ }
986
+ const opt2 = options?.[1] ?? " ";
987
+ return (value) => {
988
+ return String(value).padEnd(Number(opt1), opt2);
989
+ };
990
+ };
963
991
  var rep = (options) => {
964
- const opt = options?.[0] ?? optionsRequired("rep");
992
+ const opt = options?.[0] ?? optionsRequired("repeat");
965
993
  if (!validateNumberString(opt)) {
966
- optionMustBeNumber("rep");
994
+ optionMustBeNumber("repeat");
967
995
  }
968
996
  return (value) => {
969
997
  return String(value).repeat(Number(opt));
@@ -1135,6 +1163,11 @@ var defaults = (options, literals) => {
1135
1163
  return value;
1136
1164
  };
1137
1165
  };
1166
+ var coalesce = (options, literals) => {
1167
+ const opt = options?.[0] ?? optionsRequired("coalesce");
1168
+ const fallback = literals !== void 0 && literals.length > 0 ? literals[0] : opt;
1169
+ return (value) => value ?? fallback;
1170
+ };
1138
1171
  var boolean = (_options) => {
1139
1172
  return (value) => {
1140
1173
  return Boolean(value);
@@ -1163,24 +1196,25 @@ var builtinFilters = {
1163
1196
  "le": le,
1164
1197
  "gt": gt,
1165
1198
  "ge": ge,
1166
- "inc": inc,
1167
- "dec": dec,
1199
+ "add": inc,
1200
+ "sub": dec,
1168
1201
  "mul": mul,
1169
1202
  "div": div,
1170
1203
  "mod": mod,
1171
1204
  "abs": abs,
1172
1205
  "clamp": clamp,
1173
- "fix": fix,
1206
+ "toFixed": fix,
1174
1207
  "locale": locale,
1175
- "uc": uc,
1176
- "lc": lc,
1177
- "cap": cap,
1208
+ "upper": uc,
1209
+ "lower": lc,
1210
+ "capitalize": cap,
1178
1211
  "trim": trim,
1179
1212
  "slice": slice,
1180
1213
  "substr": substr,
1181
- "pad": pad,
1182
- "rep": rep,
1183
- "rev": rev,
1214
+ "padStart": pad,
1215
+ "padEnd": padEnd,
1216
+ "repeat": rep,
1217
+ "reverse": rev,
1184
1218
  "truncate": truncate,
1185
1219
  "join": join,
1186
1220
  "int": int,
@@ -1198,10 +1232,11 @@ var builtinFilters = {
1198
1232
  "falsy": falsy,
1199
1233
  "truthy": truthy,
1200
1234
  "defaults": defaults,
1235
+ "coalesce": coalesce,
1201
1236
  "boolean": boolean,
1202
1237
  "number": number,
1203
1238
  "string": string,
1204
- "null": _null
1239
+ "nullIfEmpty": _null
1205
1240
  };
1206
1241
  var outputBuiltinFilters = builtinFilters;
1207
1242
  var builtinFilterMeta = {
@@ -1214,26 +1249,27 @@ var builtinFilterMeta = {
1214
1249
  gt: { description: "\u3088\u308A\u5927\u304D\u3044\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
1215
1250
  ge: { description: "\u4EE5\u4E0A\u304B", hasArgs: true, resultType: "boolean", acceptTypes: ["number", "string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
1216
1251
  // 算術
1217
- inc: { description: "\u52A0\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
1218
- dec: { description: "\u6E1B\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
1252
+ add: { description: "\u52A0\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
1253
+ sub: { description: "\u6E1B\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
1219
1254
  mul: { description: "\u4E57\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
1220
1255
  div: { description: "\u9664\u7B97", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
1221
1256
  mod: { description: "\u5270\u4F59", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
1222
1257
  abs: { description: "\u7D76\u5BFE\u5024", hasArgs: false, resultType: "number", acceptTypes: ["number"], minArgs: 0, maxArgs: 0 },
1223
1258
  clamp: { description: "\u7BC4\u56F2\u5185\u306B\u4E38\u3081\u308B (min,max)", hasArgs: true, resultType: "number", acceptTypes: ["number"], minArgs: 2, maxArgs: 2, argTypes: ["number", "number"] },
1224
1259
  // 数値フォーマット
1225
- fix: { description: "\u56FA\u5B9A\u5C0F\u6570\u70B9\u8868\u8A18", hasArgs: true, resultType: "string", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
1260
+ toFixed: { description: "\u56FA\u5B9A\u5C0F\u6570\u70B9\u8868\u8A18", hasArgs: true, resultType: "string", acceptTypes: ["number"], minArgs: 0, maxArgs: 1, argTypes: ["number"] },
1226
1261
  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"] },
1227
1262
  // 文字列
1228
- uc: { description: "\u5927\u6587\u5B57\u306B\u5909\u63DB", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
1229
- lc: { description: "\u5C0F\u6587\u5B57\u306B\u5909\u63DB", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
1230
- cap: { description: "\u5148\u982D\u6587\u5B57\u3092\u5927\u6587\u5B57\u306B", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
1263
+ upper: { description: "\u5927\u6587\u5B57\u306B\u5909\u63DB", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
1264
+ lower: { description: "\u5C0F\u6587\u5B57\u306B\u5909\u63DB", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
1265
+ capitalize: { description: "\u5148\u982D\u6587\u5B57\u3092\u5927\u6587\u5B57\u306B", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
1231
1266
  trim: { description: "\u524D\u5F8C\u306E\u7A7A\u767D\u3092\u524A\u9664", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
1232
1267
  slice: { description: "\u90E8\u5206\u6587\u5B57\u5217 (start[,end])", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "number"] },
1233
1268
  substr: { description: "\u90E8\u5206\u6587\u5B57\u5217 (pos,len)", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "number"] },
1234
- pad: { description: "\u30D1\u30C7\u30A3\u30F3\u30B0 (length[,char])", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "string"] },
1235
- rep: { description: "\u7E70\u308A\u8FD4\u3057 (count)", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
1236
- rev: { description: "\u6587\u5B57\u9806\u3092\u53CD\u8EE2", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
1269
+ padStart: { description: "\u5148\u982D\u3092\u57CB\u3081\u308B (length[,char])", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "string"] },
1270
+ padEnd: { description: "\u672B\u5C3E\u3092\u57CB\u3081\u308B (length[,char])", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "string"] },
1271
+ repeat: { description: "\u7E70\u308A\u8FD4\u3057 (count)", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 1, argTypes: ["number"] },
1272
+ reverse: { description: "\u6587\u5B57\u9806\u3092\u53CD\u8EE2", hasArgs: false, resultType: "string", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 },
1237
1273
  truncate: { description: "\u5207\u308A\u8A70\u3081\u3066\u7701\u7565\u8A18\u53F7 (length[,suffix])", hasArgs: true, resultType: "string", acceptTypes: ["string"], minArgs: 1, maxArgs: 2, argTypes: ["number", "string"] },
1238
1274
  join: { description: "\u914D\u5217\u3092\u9023\u7D50 ([separator])", hasArgs: true, resultType: "string", acceptTypes: ["array"], minArgs: 0, maxArgs: 1, argTypes: ["string"] },
1239
1275
  // 数値パース・丸め
@@ -1256,10 +1292,11 @@ var builtinFilterMeta = {
1256
1292
  falsy: { description: "\u507D\u5024\u304B\u5224\u5B9A", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
1257
1293
  truthy: { description: "\u771F\u5024\u304B\u5224\u5B9A", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
1258
1294
  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"] },
1295
+ 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"] },
1259
1296
  boolean: { description: "\u30D6\u30FC\u30EB\u5024\u306B\u5909\u63DB", hasArgs: false, resultType: "boolean", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
1260
1297
  number: { description: "\u6570\u5024\u306B\u5909\u63DB", hasArgs: false, resultType: "number", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
1261
1298
  string: { description: "\u6587\u5B57\u5217\u306B\u5909\u63DB", hasArgs: false, resultType: "string", acceptTypes: "any", minArgs: 0, maxArgs: 0 },
1262
- null: { description: "\u7A7A\u6587\u5B57\u5217\u3092null\u306B\u5909\u63DB", hasArgs: false, resultType: "passthrough", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 }
1299
+ nullIfEmpty: { description: "\u7A7A\u6587\u5B57\u5217\u3092null\u306B\u5909\u63DB", hasArgs: false, resultType: "passthrough", acceptTypes: ["string"], minArgs: 0, maxArgs: 0 }
1263
1300
  };
1264
1301
  var STRUCTURAL_BINDING_TYPE_SET = /* @__PURE__ */ new Set([
1265
1302
  "if",
@@ -1304,7 +1341,7 @@ for (let i = 0; i < MAX_WILDCARD_DEPTH; i++) {
1304
1341
  Object.freeze(tmpIndexByIndexName);
1305
1342
  var STATE_CONNECTED_CALLBACK_NAME = "$connectedCallback";
1306
1343
  var STATE_DISCONNECTED_CALLBACK_NAME = "$disconnectedCallback";
1307
- var STATE_UPDATED_CALLBACK_NAME = "$updatedCallback";
1344
+ var STATE_UPDATED_CALLBACK_NAME = "$renderedCallback";
1308
1345
  var STATE_ERROR_CALLBACK_NAME = "$errorCallback";
1309
1346
  var WEBCOMPONENT_STATE_READY_CALLBACK_NAME = "$stateReadyCallback";
1310
1347
  var STATE_BINDABLES_NAME = "$bindables";
@@ -1313,7 +1350,7 @@ var STATE_COMMAND_TOKENS_NAME = "$commandTokens";
1313
1350
  var STATE_COMMAND_NAMESPACE_NAME = "$command";
1314
1351
  var STATE_EVENT_TOKENS_NAME = "$eventTokens";
1315
1352
  var STATE_ON_NAME = "$on";
1316
- var STATE_STREAMS_NAME = "$streams";
1353
+ var STATE_STREAMS_NAME = "$stream";
1317
1354
  var STATE_WATCH_NAME = "$watch";
1318
1355
  var STATE_SCAN_NAME = "$scan";
1319
1356
  var STATE_RECURSION_NAME = "$recursion";
@@ -1350,6 +1387,7 @@ function getWcsManifest() {
1350
1387
  elseKeyword: ELSE_KEYWORD,
1351
1388
  spread: SPREAD_PROP,
1352
1389
  eventPropertyPrefix: EVENT_PROP_PREFIX,
1390
+ explicitPropertyPrefix: DELIMITER,
1353
1391
  propNamespaces: {
1354
1392
  eventToken: EVENT_TOKEN_NAMESPACE,
1355
1393
  command: COMMAND_NAMESPACE,
@@ -1362,6 +1400,7 @@ function getWcsManifest() {
1362
1400
  // 実装(Record のキー)から自動導出。手リストを持たない=ドリフトの構造的排除。
1363
1401
  filters: Object.keys(outputBuiltinFilters),
1364
1402
  filterMeta: builtinFilterMeta,
1403
+ filterAliases: builtinFilterAliases,
1365
1404
  reservedLifecycle: [
1366
1405
  STATE_CONNECTED_CALLBACK_NAME,
1367
1406
  STATE_DISCONNECTED_CALLBACK_NAME,
@@ -1388,6 +1427,9 @@ function getWcsManifest() {
1388
1427
  }
1389
1428
 
1390
1429
  // src/service/completionData.ts
1430
+ function canonicalFilterName(name) {
1431
+ return Object.prototype.hasOwnProperty.call(builtinFilterAliases, name) ? builtinFilterAliases[name] : name;
1432
+ }
1391
1433
  var BUILTIN_FILTERS = Object.entries(builtinFilterMeta).map(
1392
1434
  ([name, meta]) => ({ name, ...meta })
1393
1435
  );
@@ -1563,7 +1605,7 @@ function coversSuffix(spec, familySuffix, suffix) {
1563
1605
  }
1564
1606
 
1565
1607
  // src/service/stateAnalyzer.ts
1566
- var RESERVED_STREAMS_KEY = "$streams";
1608
+ var RESERVED_STREAMS_KEYS = /* @__PURE__ */ new Set(["$stream", "$streams"]);
1567
1609
  var RESERVED_COMMAND_TOKENS_KEY = "$commandTokens";
1568
1610
  var RESERVED_EVENT_TOKENS_KEY = "$eventTokens";
1569
1611
  var RESERVED_LIST_KEYS_KEY = "$listKeys";
@@ -1935,7 +1977,7 @@ function findNonObjectDeclaration(scriptContent, key, rejectArray = false) {
1935
1977
  return span;
1936
1978
  }
1937
1979
  function collectReservedKeyPaths(prop, paths, pendingStreamValues, pendingListKeys) {
1938
- if (prop.name === RESERVED_STREAMS_KEY && prop.kind === "data" && prop.value && isObjectLiteral(prop.value)) {
1980
+ if (RESERVED_STREAMS_KEYS.has(prop.name) && prop.kind === "data" && prop.value && isObjectLiteral(prop.value)) {
1939
1981
  const entries = parseTopLevelProperties(extractObjectContent(prop.value));
1940
1982
  for (const entry of entries) {
1941
1983
  if (entry.kind !== "data" || entry.name.startsWith("$")) continue;
@@ -3064,6 +3106,8 @@ var ja = {
3064
3106
  arrayMutation: (m, alt) => `\u914D\u5217\u306E\u7834\u58CA\u7684\u30E1\u30BD\u30C3\u30C9 "${m}" \u306F\u30EA\u30A2\u30AF\u30C6\u30A3\u30D6\u66F4\u65B0\u3092\u30C8\u30EA\u30AC\u30FC\u3057\u307E\u305B\u3093\uFF08\u540C\u4E00\u53C2\u7167\u306E\u81EA\u5DF1\u518D\u4EE3\u5165\u3067\u3082\u8981\u7D20\u306E\u8FFD\u52A0\u30FB\u524A\u9664\u306F\u53CD\u6620\u3055\u308C\u307E\u305B\u3093\uFF09\u3002\u975E\u7834\u58CA\u30E1\u30BD\u30C3\u30C9\u3068\u518D\u4EE3\u5165\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\uFF08\u4F8B: ${alt}\uFF09\u3002`,
3065
3107
  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`,
3066
3108
  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`,
3109
+ nameAlias: (written, canonical) => `"${written}" \u306F "${canonical}" \u306E\u65E7\u540D\u3067\u3059\u30023.x \u306E\u9593\u306F\u52D5\u304D\u307E\u3059\u304C 4.0 \u3067\u5916\u308C\u308B\u306E\u3067\u3001"${canonical}" \u3068\u66F8\u3044\u3066\u304F\u3060\u3055\u3044\uFF08@wcstack/state 3.2\uFF09`,
3110
+ onPrefixedMember: (member, tag) => `"${member}" \u306F <${tag}> \u306E\u30E1\u30F3\u30D0\u30FC\u3067\u3059\u304C\u3001"on" \u3067\u59CB\u307E\u308B\u540D\u524D\u306F\u30A4\u30D9\u30F3\u30C8\u675F\u7E1B\u306B\u306A\u308A\uFF08"${member.slice(2)}" \u30A4\u30D9\u30F3\u30C8\u3092\u5F85\u3064\uFF09\u3001\u5024\u306F\u5C4A\u304D\u307E\u305B\u3093\u3002\u30D7\u30ED\u30D1\u30C6\u30A3\u3068\u3057\u3066\u675F\u7E1B\u3059\u308B\u306B\u306F ".${member}:" \u3068\u66F8\u3044\u3066\u304F\u3060\u3055\u3044\uFF08@wcstack/state 3.1\uFF09`,
3067
3111
  tagCommandUnknown: (name, tag, declared) => `"${name}" \u306F <${tag}> \u306E command \u3067\u306F\u3042\u308A\u307E\u305B\u3093\uFF08\u5BA3\u8A00\u6E08\u307F: ${declared}\uFF09`,
3068
3112
  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`,
3069
3113
  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`,
@@ -3253,6 +3297,8 @@ var en = {
3253
3297
  arrayMutation: (m, alt) => `Destructive array method "${m}" does not trigger a reactive update (re-assigning the same reference does not reflect added/removed elements either). Use a non-destructive method with reassignment (e.g. ${alt}).`,
3254
3298
  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.`,
3255
3299
  tagMemberUnknown: (prop, tag) => `"${prop}" is not a wcBindable member of <${tag}> (bindings to unknown members are silently ignored)`,
3300
+ nameAlias: (written, canonical) => `"${written}" is the old name of "${canonical}". It works through 3.x and goes in 4.0 \u2014 write "${canonical}" (@wcstack/state 3.2)`,
3301
+ onPrefixedMember: (member, tag) => `"${member}" is a member of <${tag}>, but a name starting with "on" makes an event binding (it listens for a "${member.slice(2)}" event) and the value never arrives. Write ".${member}:" to bind the property (@wcstack/state 3.1)`,
3256
3302
  tagCommandUnknown: (name, tag, declared) => `"${name}" is not a command of <${tag}> (declared: ${declared})`,
3257
3303
  spreadNoBindable: (tag) => `'...' (spread) requires <${tag}> to expose a valid wcBindable declaration \u2014 this tag declares none, so the runtime raises an error`,
3258
3304
  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})`,
@@ -3385,7 +3431,6 @@ function validateBindings(html, attrName, stateTagName = "wcs-state", locale2, f
3385
3431
  structuralTemplates ??= collectStructuralTemplates(html, attrName);
3386
3432
  return structuralTemplates;
3387
3433
  };
3388
- const filterNameSet = new Set(BUILTIN_FILTERS.map((f) => f.name));
3389
3434
  for (const attr of attrs) {
3390
3435
  const bindings = splitBindingExpressions(attr.value);
3391
3436
  const nonEmptyCount = bindings.filter((b) => b.trim().length > 0).length;
@@ -3719,7 +3764,17 @@ function parseFilterSegments(expr, segments, searchStart) {
3719
3764
  }
3720
3765
  function validateFilterUsage(filter, bindingStart, msgs) {
3721
3766
  const diagnostics = [];
3722
- const info = filterMap.get(filter.name);
3767
+ const canonical = canonicalFilterName(filter.name);
3768
+ const info = filterMap.get(canonical);
3769
+ if (info && canonical !== filter.name) {
3770
+ diagnostics.push({
3771
+ code: WcsDiagnosticCode.NameAlias,
3772
+ start: bindingStart + filter.offset,
3773
+ end: bindingStart + filter.offset + filter.name.length,
3774
+ message: msgs.nameAlias(filter.name, canonical),
3775
+ severity: "info"
3776
+ });
3777
+ }
3723
3778
  if (!info) {
3724
3779
  diagnostics.push({
3725
3780
  code: WcsDiagnosticCode.FilterUnknown,
@@ -4349,8 +4404,17 @@ function validateTemplateSyntax(html, stateTagName, bindAttrName = "data-wcs", l
4349
4404
  }
4350
4405
  for (let i = 1; i < parts.length; i++) {
4351
4406
  const filterName = parts[i].trim().replace(/\(.*$/, "");
4352
- if (filterName && !filterNameSet.has(filterName)) {
4353
- const filterOffset = item.expression.indexOf(parts[i]);
4407
+ const filterOffset = item.expression.indexOf(parts[i]) + (parts[i].length - parts[i].trimStart().length);
4408
+ const canonical = canonicalFilterName(filterName);
4409
+ if (filterName && canonical !== filterName && filterNameSet.has(canonical)) {
4410
+ diagnostics.push({
4411
+ code: WcsDiagnosticCode.NameAlias,
4412
+ start: item.exprStart + filterOffset,
4413
+ end: item.exprStart + filterOffset + filterName.length,
4414
+ message: msgs.nameAlias(filterName, canonical),
4415
+ severity: "info"
4416
+ });
4417
+ } else if (filterName && !filterNameSet.has(filterName)) {
4354
4418
  diagnostics.push({
4355
4419
  code: WcsDiagnosticCode.FilterUnknown,
4356
4420
  start: item.exprStart + filterOffset,
@@ -4385,6 +4449,10 @@ var ELSE_KEYWORD2 = "else";
4385
4449
  var SPREAD_PROP2 = "...";
4386
4450
  var EVENT_PROP_PREFIX2 = "on";
4387
4451
  var EVENT_TOKEN_NAMESPACE2 = "eventToken";
4452
+ var COMMAND_NAMESPACE2 = "command";
4453
+ var CLASS_NAMESPACE2 = "class";
4454
+ var ATTR_NAMESPACE2 = "attr";
4455
+ var STYLE_NAMESPACE2 = "style";
4388
4456
  var INDEX_PARAM_PREFIX2 = "$";
4389
4457
  var tmpIndexByIndexName2 = {};
4390
4458
  for (let i = 0; i < MAX_WILDCARD_DEPTH2; i++) {
@@ -4709,6 +4777,13 @@ function parseStatePart(statePart) {
4709
4777
  };
4710
4778
  }
4711
4779
  var KEYWORDS_WITHOUT_MODIFIERS = /* @__PURE__ */ new Set([ELSE_KEYWORD2, "if", "elseif", "for", SPREAD_PROP2]);
4780
+ var EXPLICIT_PROPERTY_REJECTED_HEADS = /* @__PURE__ */ new Set([
4781
+ CLASS_NAMESPACE2,
4782
+ ATTR_NAMESPACE2,
4783
+ STYLE_NAMESPACE2,
4784
+ COMMAND_NAMESPACE2,
4785
+ EVENT_TOKEN_NAMESPACE2
4786
+ ]);
4712
4787
  function splitBindTexts(bindText) {
4713
4788
  return splitOutsideQuotes(bindText, BINDING_SEPARATOR2);
4714
4789
  }
@@ -4777,6 +4852,19 @@ function parseBindTextsForElement(bindText) {
4777
4852
  } else {
4778
4853
  const stateResult = parseStatePart(statePart);
4779
4854
  const propResult = parsePropPart(propPart);
4855
+ if (propResult.propSegments[0] === "" && propResult.propSegments.length > 1) {
4856
+ const propSegments = propResult.propSegments.slice(1);
4857
+ if (propSegments.includes("") || EXPLICIT_PROPERTY_REJECTED_HEADS.has(propSegments[0])) {
4858
+ raiseError2(`[wcs/binding-syntax] "${propPart}": a leading "." binds an element property by name \u2014 write a non-empty property that is not a namespace (${[...EXPLICIT_PROPERTY_REJECTED_HEADS].join(", ")}).${LINT_HINT}`);
4859
+ }
4860
+ return {
4861
+ ...propResult,
4862
+ propName: propSegments.join(DELIMITER2),
4863
+ propSegments,
4864
+ ...stateResult,
4865
+ bindingType: "prop"
4866
+ };
4867
+ }
4780
4868
  if (propResult.propSegments[0] === EVENT_TOKEN_NAMESPACE2) {
4781
4869
  return {
4782
4870
  ...propResult,
@@ -6292,10 +6380,28 @@ function validateBindingAgainstContract(tagName, contract, parsed, property, sta
6292
6380
  const hashIndex = property.indexOf("#");
6293
6381
  const modifiers = hashIndex === -1 ? "" : property.slice(hashIndex + 1);
6294
6382
  property = hashIndex === -1 ? property : property.slice(0, hashIndex);
6383
+ const explicit = property.startsWith(".") && property !== "...";
6384
+ if (explicit) {
6385
+ property = property.slice(1);
6386
+ if (/^(class|style|attr|command|eventToken)(\.|$)/.test(property)) return;
6387
+ }
6295
6388
  if (property === "...") return;
6296
6389
  if (STRUCTURAL_DIRECTIVES2.has(property)) return;
6297
6390
  if (/^(class|style|attr)\./.test(property)) return;
6298
- if (/^on\w/.test(property)) return;
6391
+ if (!explicit && /^on\w/.test(property)) {
6392
+ if (contract.properties.includes(property) || property in contract.inputs) {
6393
+ diagnostics.push({
6394
+ code: WcsDiagnosticCode.OnPrefixedMember,
6395
+ start,
6396
+ end,
6397
+ severity: "warning",
6398
+ tag: tagName,
6399
+ member: property,
6400
+ message: msgs.onPrefixedMember(property, tagName)
6401
+ });
6402
+ }
6403
+ return;
6404
+ }
6299
6405
  const inputNames = Object.keys(contract.inputs);
6300
6406
  if (property.startsWith("command.")) {
6301
6407
  const name = property.slice("command.".length);
@@ -7066,7 +7172,8 @@ var RECURSION_APIS = ["getAll", "setAll", "resolve", "postUpdate", "trackDepende
7066
7172
  var UNSUPPORTED_API_SITE = {
7067
7173
  $resolve: "resolve",
7068
7174
  $postUpdate: "postUpdate",
7069
- $trackDependency: "trackDependency"
7175
+ $trackDependency: "trackDependency",
7176
+ $dependOn: "trackDependency"
7070
7177
  };
7071
7178
  var BRACKET_ASSIGNMENT = new RegExp(`${ROOT_BRACKET}${ASSIGN_TAIL}`, "g");
7072
7179
  var PRE_BRACKET_INCDEC = new RegExp(`${PRE_INCDEC}${ROOT_BRACKET}`, "g");
@@ -10026,16 +10133,16 @@ pp$5.parseExprOp = function(left, leftStartPos, leftStartLoc, minPrec, forInit)
10026
10133
  if (prec != null && (!forInit || this.type !== types$1._in)) {
10027
10134
  if (prec > minPrec) {
10028
10135
  var logical = this.type === types$1.logicalOR || this.type === types$1.logicalAND;
10029
- var coalesce = this.type === types$1.coalesce;
10030
- if (coalesce) {
10136
+ var coalesce2 = this.type === types$1.coalesce;
10137
+ if (coalesce2) {
10031
10138
  prec = types$1.logicalAND.binop;
10032
10139
  }
10033
10140
  var op = this.value;
10034
10141
  this.next();
10035
10142
  var startPos = this.start, startLoc = this.startLoc;
10036
10143
  var right = this.parseExprOp(this.parseMaybeUnary(null, false, false, forInit), startPos, startLoc, prec, forInit);
10037
- var node = this.buildBinary(leftStartPos, leftStartLoc, left, right, op, logical || coalesce);
10038
- if (logical && this.type === types$1.coalesce || coalesce && (this.type === types$1.logicalOR || this.type === types$1.logicalAND)) {
10144
+ var node = this.buildBinary(leftStartPos, leftStartLoc, left, right, op, logical || coalesce2);
10145
+ if (logical && this.type === types$1.coalesce || coalesce2 && (this.type === types$1.logicalOR || this.type === types$1.logicalAND)) {
10039
10146
  this.raiseRecoverable(this.start, "Logical expressions and coalesce expressions cannot be mixed. Wrap either by parentheses");
10040
10147
  }
10041
10148
  return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, forInit);
@@ -13286,8 +13393,9 @@ function parse3(input, options) {
13286
13393
  // src/service/scriptAst.ts
13287
13394
  var PREFIX = "(async function* () {\n";
13288
13395
  var SUFFIX = "\n})";
13289
- var PATH_ARG_APIS = /* @__PURE__ */ new Set(["$getAll", "$resolve", "$trackDependency"]);
13290
- var UNTRACK_API = "$untrackDependency";
13396
+ var PATH_ARG_APIS = /* @__PURE__ */ new Set(["$getAll", "$resolve", "$dependOn", "$trackDependency"]);
13397
+ var TRACK_APIS = /* @__PURE__ */ new Set(["$dependOn", "$trackDependency"]);
13398
+ var UNTRACK_APIS = /* @__PURE__ */ new Set(["$untracked", "$untrackDependency"]);
13291
13399
  function collectGetterReads(body) {
13292
13400
  let program;
13293
13401
  try {
@@ -13512,7 +13620,7 @@ function visitCall(node, scope, out) {
13512
13620
  const { segments, base } = resolveChain(callee);
13513
13621
  if (isThisRoot(base, scope) && segments.length === 1 && segments[0].text !== null) {
13514
13622
  const api = segments[0].text;
13515
- if (api === UNTRACK_API) return;
13623
+ if (UNTRACK_APIS.has(api)) return;
13516
13624
  if (PATH_ARG_APIS.has(api)) {
13517
13625
  const first = node.arguments[0];
13518
13626
  const path = first !== void 0 && first.type !== "SpreadElement" ? literalString2(first) : null;
@@ -13520,7 +13628,7 @@ function visitCall(node, scope, out) {
13520
13628
  out.push({
13521
13629
  path,
13522
13630
  chain: null,
13523
- form: api === "$trackDependency" ? "track" : "api",
13631
+ form: TRACK_APIS.has(api) ? "track" : "api",
13524
13632
  callee: false,
13525
13633
  written: false,
13526
13634
  start: node.start - PREFIX.length,
@@ -13703,7 +13811,35 @@ function buildReferenceIndex(html, options = {}) {
13703
13811
  }
13704
13812
 
13705
13813
  // src/service/semanticValidator.ts
13706
- var STATE_UPDATED_CALLBACK = "$updatedCallback";
13814
+ var STATE_UPDATED_CALLBACKS = /* @__PURE__ */ new Set(["$renderedCallback", "$updatedCallback"]);
13815
+ var OLD_API_NAMES = { $trackDependency: "$dependOn", $untrackDependency: "$untracked" };
13816
+ var OLD_DECLARATION_KEYS = { $streams: "$stream", $updatedCallback: "$renderedCallback" };
13817
+ var OLD_API_CALL = /\.\s*(\$trackDependency|\$untrackDependency)\b/g;
13818
+ var OLD_DECLARATION_KEY = /(^|[{,\s])(\$streams|\$updatedCallback)(?=\s*[:(])/g;
13819
+ function validateNameAliases(script, scriptStart, locale2) {
13820
+ const msgs = getMessages(locale2);
13821
+ const scan = blankComments(script);
13822
+ const out = [];
13823
+ const push2 = (name, canonical, offset2) => {
13824
+ out.push({
13825
+ code: WcsDiagnosticCode.NameAlias,
13826
+ start: scriptStart + offset2,
13827
+ end: scriptStart + offset2 + name.length,
13828
+ message: msgs.nameAlias(name, canonical),
13829
+ severity: "info"
13830
+ });
13831
+ };
13832
+ OLD_API_CALL.lastIndex = 0;
13833
+ let match;
13834
+ while ((match = OLD_API_CALL.exec(scan)) !== null) {
13835
+ push2(match[1], OLD_API_NAMES[match[1]], match.index + match[0].length - match[1].length);
13836
+ }
13837
+ OLD_DECLARATION_KEY.lastIndex = 0;
13838
+ while ((match = OLD_DECLARATION_KEY.exec(scan)) !== null) {
13839
+ push2(match[2], OLD_DECLARATION_KEYS[match[2]], match.index + match[1].length);
13840
+ }
13841
+ return out;
13842
+ }
13707
13843
  var API_CALL = /\.\s*\$(getAll|setAll|resolve)\s*\(/g;
13708
13844
  function validateIndexArity(script, scriptStart, locale2) {
13709
13845
  const msgs = getMessages(locale2);
@@ -13885,13 +14021,13 @@ var PATH_TEST_LITERAL = /(?:\.\s*(?:includes|indexOf)\s*\(\s*|[!=]==\s*)(["'])((
13885
14021
  function validateUpdatedCallbackDemand(html, stateTagName, bindAttrName, locale2) {
13886
14022
  const blocks = parseWcsScriptBlocks(html, stateTagName);
13887
14023
  if (blocks.length === 0) return [];
13888
- const hasCallback = blocks.some((block) => block.content.includes(STATE_UPDATED_CALLBACK));
14024
+ const hasCallback = blocks.some((block) => [...STATE_UPDATED_CALLBACKS].some((name) => block.content.includes(name)));
13889
14025
  if (!hasCallback) return [];
13890
14026
  const msgs = getMessages(locale2);
13891
14027
  const boundPaths = collectBoundPaths(html, stateTagName, bindAttrName);
13892
14028
  const out = [];
13893
14029
  for (const block of blocks) {
13894
- const callback = analyzeCallableBodies(block.content).find((entry) => entry.name === STATE_UPDATED_CALLBACK && entry.kind === "method");
14030
+ const callback = analyzeCallableBodies(block.content).find((entry) => STATE_UPDATED_CALLBACKS.has(entry.name) && entry.kind === "method");
13895
14031
  if (callback === void 0) continue;
13896
14032
  if (block.mountPath !== null) continue;
13897
14033
  const declared = new Set(analyzeStatePaths(block.content).map((p) => p.path));
@@ -13938,6 +14074,7 @@ function validateSemantics(html, stateTagName = "wcs-state", locale2, bindAttrNa
13938
14074
  const getNestedWriteRoots = () => nestedWriteRoots ??= collectNestedWriteRoots(html, stateTagName, bindAttrName, blocks);
13939
14075
  for (const block of blocks) {
13940
14076
  out.push(...validateIndexArity(block.content, block.contentStart, locale2));
14077
+ out.push(...validateNameAliases(block.content, block.contentStart, locale2));
13941
14078
  out.push(...validateGetterCycles(block.content, block.contentStart, locale2));
13942
14079
  out.push(...validateGetterUntrackedReads(block.content, block.contentStart, getNestedWriteRoots, locale2));
13943
14080
  }
package/dist/tsc-core.cjs CHANGED
@@ -204,7 +204,11 @@ interface WcsStateApi {
204
204
  $setAll<V = any>(path: string, indexes: number[], values: readonly V[], options: { spread: true }): number;
205
205
  $postUpdate(path: string): void;
206
206
  $resolve(path: string, indexes: number[], value?: any): any;
207
+ $dependOn(path: string): void;
208
+ $untracked<T>(fn: () => T): T;
209
+ /** @deprecated $dependOn \u306E\u65E7\u540D\uFF08@wcstack/state 3.2 \u2014 4.0 \u3067\u5916\u308C\u308B\uFF09 */
207
210
  $trackDependency(path: string): void;
211
+ /** @deprecated $untracked \u306E\u65E7\u540D\uFF08@wcstack/state 3.2 \u2014 4.0 \u3067\u5916\u308C\u308B\uFF09 */
208
212
  $untrackDependency<T>(fn: () => T): T;
209
213
  $eq(path: string, key: unknown): boolean;
210
214
  $eqPath(path: string, keyPath: string): boolean;
@@ -233,6 +237,7 @@ interface WcsStateApi {
233
237
  // 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
234
238
  type _WcsDeclaredValues<T> =
235
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 } : {}) &
236
241
  (T extends { $streams: infer S } ? { [K in Exclude<keyof S & string, keyof T>]: any } : {});
237
242
  type _WcsThis<T> = T & WcsStateApi & _WcsPathAccessor<T> & _WcsDeclaredValues<T>;
238
243
  // $listKeys: { "<listPath>": "<field>" | (row) => key }\uFF08list/listKeys.ts\uFF09\u3002
@@ -567,7 +567,7 @@ function loadSchemaCore() {
567
567
  return cached;
568
568
  }
569
569
 
570
- var version = "3.0.0";
570
+ var version = "3.2.0";
571
571
  var pkg = {
572
572
  version: version};
573
573
 
package/dist/wcs-tsc.mjs CHANGED
@@ -5,7 +5,7 @@ import { tmpdir } from 'node:os';
5
5
  import { dirname, join, isAbsolute, resolve, basename } from 'node:path';
6
6
  import { fileURLToPath } from 'node:url';
7
7
 
8
- var version = "3.0.0";
8
+ var version = "3.2.0";
9
9
  var pkg = {
10
10
  version: version};
11
11
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wcstack/typescript",
3
- "version": "3.0.0",
3
+ "version": "3.2.0",
4
4
  "description": "TypeScript tooling for wcstack apps: wcs-schema generates the sidecar stateSchema from a typed state file, so wcs-validate checks data-wcs paths against real types in CI and every editor.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.esm.js",