@wcstack/lint 1.31.0 → 1.32.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 +147 -18
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -118,7 +118,7 @@ var WcsDiagnosticCode = {
118
118
  TokenMisconfigured: "wcs/token-misconfigured",
119
119
  NestedAssign: "wcs/nested-assign",
120
120
  // --- 意味論(構文・存在検査では捕まらない取り違え。service/semanticValidator.ts) ---
121
- // `$getAll` / `$resolve` の添字の本数がパスの `*` の本数と噛み合わない。
121
+ // `$getAll` / `$setAll` / `$resolve` の添字の本数がパスの `*` の本数と噛み合わない。
122
122
  // ランタイムは同じ code で raiseError する(超過は以前は黙って無視されていた)。
123
123
  IndexArity: "wcs/index-arity",
124
124
  // ワイルドカードの階数がスコープの段数を超える(`matrix.*.*` を 1 段の for で読む、
@@ -157,6 +157,11 @@ var WcsDiagnosticCode = {
157
157
  TriggerSeededTruthy: "wcs/trigger-seeded-truthy",
158
158
  // 非 manual <wcs-storage> value バインド先の空値シード(初期書き戻しが保存値を上書き)。
159
159
  StorageSeedClobber: "wcs/storage-seed-clobber",
160
+ // --- accessibility (docs/a11y-design.md §8 / D9) ---
161
+ // `attr.aria-*` バインドの属性名が WAI-ARIA に存在しない(タイポ)。
162
+ // setAttribute はそのまま書き、支援技術は黙って無視する。severity は warning
163
+ // (error 昇格時は packages/lint/scripts/smoke-test.mjs の対ケース更新が必須)。
164
+ AriaAttrUnknown: "wcs/aria-attr-unknown",
160
165
  // --- document-level load configuration ---
161
166
  // @wcstack/state/auto より後に他 wcstack /auto が読まれている。
162
167
  ScriptOrder: "wcs/script-order",
@@ -391,12 +396,12 @@ var fix = (options) => {
391
396
  };
392
397
  };
393
398
  var locale = (options) => {
394
- const opt = options?.[0] ?? config.locale;
399
+ const explicit = options?.[0];
395
400
  return (value) => {
396
401
  if (typeof value !== "number") {
397
402
  valueMustBeNumber("locale");
398
403
  }
399
- return value.toLocaleString(opt);
404
+ return value.toLocaleString(explicit ?? config.locale);
400
405
  };
401
406
  };
402
407
  var uc = (_options) => {
@@ -576,30 +581,30 @@ var truncate = (options) => {
576
581
  };
577
582
  };
578
583
  var date = (options) => {
579
- const opt = options?.[0] ?? config.locale;
584
+ const explicit = options?.[0];
580
585
  return (value) => {
581
586
  if (!(value instanceof Date)) {
582
587
  valueMustBeDate("date");
583
588
  }
584
- return value.toLocaleDateString(opt);
589
+ return value.toLocaleDateString(explicit ?? config.locale);
585
590
  };
586
591
  };
587
592
  var time = (options) => {
588
- const opt = options?.[0] ?? config.locale;
593
+ const explicit = options?.[0];
589
594
  return (value) => {
590
595
  if (!(value instanceof Date)) {
591
596
  valueMustBeDate("time");
592
597
  }
593
- return value.toLocaleTimeString(opt);
598
+ return value.toLocaleTimeString(explicit ?? config.locale);
594
599
  };
595
600
  };
596
601
  var datetime = (options) => {
597
- const opt = options?.[0] ?? config.locale;
602
+ const explicit = options?.[0];
598
603
  return (value) => {
599
604
  if (!(value instanceof Date)) {
600
605
  valueMustBeDate("datetime");
601
606
  }
602
- return value.toLocaleString(opt);
607
+ return value.toLocaleString(explicit ?? config.locale);
603
608
  };
604
609
  };
605
610
  var ymd = (options) => {
@@ -1839,6 +1844,7 @@ var ja = {
1839
1844
  tagCommandUnknown: (name, tag, declared) => `"${name}" \u306F <${tag}> \u306E command \u3067\u306F\u3042\u308A\u307E\u305B\u3093\uFF08\u5BA3\u8A00\u6E08\u307F: ${declared}\uFF09`,
1840
1845
  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`,
1841
1846
  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`,
1847
+ ariaAttrUnknown: (name) => `"${name}" \u306F WAI-ARIA \u306E\u5C5E\u6027\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002setAttribute \u306F\u305D\u306E\u307E\u307E\u66F8\u304D\u8FBC\u307F\u307E\u3059\u304C\u3001\u652F\u63F4\u6280\u8853\u306B\u306F\u9ED9\u3063\u3066\u7121\u8996\u3055\u308C\u307E\u3059`,
1842
1848
  didYouMean: (c) => `\u3002\u3082\u3057\u304B\u3057\u3066: "${c}"`,
1843
1849
  none: () => `\u306A\u3057`,
1844
1850
  triggerSeededTruthy: (path) => `trigger \u30D0\u30A4\u30F3\u30C9\u5148 "${path}" \u304C true \u3067\u30B7\u30FC\u30C9\u3055\u308C\u3066\u3044\u307E\u3059\u3002trigger \u306F\u30A8\u30C3\u30B8\u691C\u51FA\u306A\u3057\uFF08truthy \u66F8\u304D\u8FBC\u307F\u3067\u5373\u767A\u706B\u30FBmanual \u3082\u30D0\u30A4\u30D1\u30B9\uFF09\u306E\u305F\u3081\u3001\u30D0\u30A4\u30F3\u30C9\u6642\u306B\u5373\u767A\u706B\u3057\u307E\u3059\u3002false \u3067\u30B7\u30FC\u30C9\u3057\u3066\u304F\u3060\u3055\u3044`,
@@ -1893,6 +1899,7 @@ var en = {
1893
1899
  tagCommandUnknown: (name, tag, declared) => `"${name}" is not a command of <${tag}> (declared: ${declared})`,
1894
1900
  spreadNoBindable: (tag) => `'...' (spread) requires <${tag}> to expose a valid wcBindable declaration \u2014 this tag declares none, so the runtime raises an error`,
1895
1901
  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})`,
1902
+ ariaAttrUnknown: (name) => `"${name}" is not a WAI-ARIA attribute. setAttribute writes it anyway, and assistive technology silently ignores it`,
1896
1903
  didYouMean: (c) => `. Did you mean "${c}"?`,
1897
1904
  none: () => `none`,
1898
1905
  triggerSeededTruthy: (path) => `The trigger-bound slot "${path}" is seeded with true. trigger has no edge detection (any truthy write fires, and it bypasses manual), so it fires immediately at bind. Seed it with false`,
@@ -4006,6 +4013,35 @@ var BUILTIN_TAGS = {
4006
4013
  "abort"
4007
4014
  ]
4008
4015
  },
4016
+ "wcs-view-transition": {
4017
+ "package": "view-transition",
4018
+ "hasWcBindable": true,
4019
+ "observedAttributes": [
4020
+ "mode",
4021
+ "naming",
4022
+ "naming-limit",
4023
+ "reduced-motion",
4024
+ "types",
4025
+ "disabled",
4026
+ "for"
4027
+ ],
4028
+ "inputs": {
4029
+ "disabled": "disabled",
4030
+ "mode": "mode",
4031
+ "naming": "naming",
4032
+ "namingLimit": "naming-limit",
4033
+ "reducedMotion": "reduced-motion",
4034
+ "types": "types",
4035
+ "participants": "for"
4036
+ },
4037
+ "properties": [
4038
+ "active",
4039
+ "error"
4040
+ ],
4041
+ "commands": [
4042
+ "skip"
4043
+ ]
4044
+ },
4009
4045
  "wcs-wakelock": {
4010
4046
  "package": "wakelock",
4011
4047
  "hasWcBindable": true,
@@ -4318,6 +4354,98 @@ function hasBooleanAttribute(attrsText, attrName) {
4318
4354
  return new RegExp(`(?:^|\\s)${attrName}(?:\\s|=|$)`, "i").test(attrsText);
4319
4355
  }
4320
4356
 
4357
+ // src/service/ariaValidator.ts
4358
+ var ARIA_ATTRIBUTES = /* @__PURE__ */ new Set([
4359
+ // widget attributes
4360
+ "aria-autocomplete",
4361
+ "aria-checked",
4362
+ "aria-disabled",
4363
+ "aria-errormessage",
4364
+ "aria-expanded",
4365
+ "aria-haspopup",
4366
+ "aria-hidden",
4367
+ "aria-invalid",
4368
+ "aria-label",
4369
+ "aria-level",
4370
+ "aria-modal",
4371
+ "aria-multiline",
4372
+ "aria-multiselectable",
4373
+ "aria-orientation",
4374
+ "aria-placeholder",
4375
+ "aria-pressed",
4376
+ "aria-readonly",
4377
+ "aria-required",
4378
+ "aria-selected",
4379
+ "aria-sort",
4380
+ "aria-valuemax",
4381
+ "aria-valuemin",
4382
+ "aria-valuenow",
4383
+ "aria-valuetext",
4384
+ // live region attributes
4385
+ "aria-busy",
4386
+ "aria-live",
4387
+ "aria-relevant",
4388
+ "aria-atomic",
4389
+ // drag-and-drop (deprecated in 1.1, still valid names)
4390
+ "aria-dropeffect",
4391
+ "aria-grabbed",
4392
+ // relationship attributes
4393
+ "aria-activedescendant",
4394
+ "aria-colcount",
4395
+ "aria-colindex",
4396
+ "aria-colindextext",
4397
+ "aria-colspan",
4398
+ "aria-controls",
4399
+ "aria-describedby",
4400
+ "aria-details",
4401
+ "aria-flowto",
4402
+ "aria-labelledby",
4403
+ "aria-owns",
4404
+ "aria-posinset",
4405
+ "aria-rowcount",
4406
+ "aria-rowindex",
4407
+ "aria-rowindextext",
4408
+ "aria-rowspan",
4409
+ "aria-setsize",
4410
+ // global additions
4411
+ "aria-current",
4412
+ "aria-keyshortcuts",
4413
+ "aria-roledescription",
4414
+ // 1.3 additions with broad implementation
4415
+ "aria-braillelabel",
4416
+ "aria-brailleroledescription",
4417
+ "aria-description"
4418
+ ]);
4419
+ function validateAriaAttributes(html, bindAttribute = "data-wcs", locale3) {
4420
+ const diagnostics = [];
4421
+ const msgs = getMessages(locale3);
4422
+ for (const attr of findAllBindAttributes(html, bindAttribute)) {
4423
+ let exprOffset = 0;
4424
+ for (const expr of splitBindingExpressions(attr.value)) {
4425
+ const exprStart = attr.valueStart + exprOffset;
4426
+ exprOffset += expr.length + 1;
4427
+ const property = parseBindingExpression(expr).property;
4428
+ if (!property) continue;
4429
+ const bare = property.split("#")[0];
4430
+ if (!bare.toLowerCase().startsWith("attr.aria-")) continue;
4431
+ const ariaName = bare.slice("attr.".length).toLowerCase();
4432
+ if (ARIA_ATTRIBUTES.has(ariaName)) continue;
4433
+ const propIndex = expr.indexOf(property);
4434
+ const start = propIndex === -1 ? exprStart : exprStart + propIndex;
4435
+ const end = propIndex === -1 ? exprStart + expr.length : start + property.length;
4436
+ diagnostics.push({
4437
+ code: WcsDiagnosticCode.AriaAttrUnknown,
4438
+ start,
4439
+ end,
4440
+ severity: "warning",
4441
+ member: ariaName,
4442
+ message: msgs.ariaAttrUnknown(ariaName) + suggestion(ariaName, [...ARIA_ATTRIBUTES], msgs)
4443
+ });
4444
+ }
4445
+ }
4446
+ return diagnostics;
4447
+ }
4448
+
4321
4449
  // src/service/documentEnvValidator.ts
4322
4450
  function validateDocumentEnv(html, locale3) {
4323
4451
  const diagnostics = [];
@@ -4863,12 +4991,12 @@ var fix2 = (options) => {
4863
4991
  };
4864
4992
  };
4865
4993
  var locale2 = (options) => {
4866
- const opt = options?.[0] ?? config2.locale;
4994
+ const explicit = options?.[0];
4867
4995
  return (value) => {
4868
4996
  if (typeof value !== "number") {
4869
4997
  valueMustBeNumber2("locale");
4870
4998
  }
4871
- return value.toLocaleString(opt);
4999
+ return value.toLocaleString(explicit ?? config2.locale);
4872
5000
  };
4873
5001
  };
4874
5002
  var uc2 = (_options) => {
@@ -5048,30 +5176,30 @@ var truncate2 = (options) => {
5048
5176
  };
5049
5177
  };
5050
5178
  var date2 = (options) => {
5051
- const opt = options?.[0] ?? config2.locale;
5179
+ const explicit = options?.[0];
5052
5180
  return (value) => {
5053
5181
  if (!(value instanceof Date)) {
5054
5182
  valueMustBeDate2("date");
5055
5183
  }
5056
- return value.toLocaleDateString(opt);
5184
+ return value.toLocaleDateString(explicit ?? config2.locale);
5057
5185
  };
5058
5186
  };
5059
5187
  var time2 = (options) => {
5060
- const opt = options?.[0] ?? config2.locale;
5188
+ const explicit = options?.[0];
5061
5189
  return (value) => {
5062
5190
  if (!(value instanceof Date)) {
5063
5191
  valueMustBeDate2("time");
5064
5192
  }
5065
- return value.toLocaleTimeString(opt);
5193
+ return value.toLocaleTimeString(explicit ?? config2.locale);
5066
5194
  };
5067
5195
  };
5068
5196
  var datetime2 = (options) => {
5069
- const opt = options?.[0] ?? config2.locale;
5197
+ const explicit = options?.[0];
5070
5198
  return (value) => {
5071
5199
  if (!(value instanceof Date)) {
5072
5200
  valueMustBeDate2("datetime");
5073
5201
  }
5074
- return value.toLocaleString(opt);
5202
+ return value.toLocaleString(explicit ?? config2.locale);
5075
5203
  };
5076
5204
  };
5077
5205
  var ymd2 = (options) => {
@@ -5663,7 +5791,7 @@ function buildReferenceIndex(html, options = {}) {
5663
5791
 
5664
5792
  // src/service/semanticValidator.ts
5665
5793
  var STATE_UPDATED_CALLBACK = "$updatedCallback";
5666
- var API_CALL = /\.\s*\$(getAll|resolve)\s*\(/g;
5794
+ var API_CALL = /\.\s*\$(getAll|setAll|resolve)\s*\(/g;
5667
5795
  var STRING_LITERAL = /^\s*(["'])((?:\\.|(?!\1)[^\\])*)\1\s*$/;
5668
5796
  function splitCallArgs(source, open) {
5669
5797
  const args = [];
@@ -5959,6 +6087,7 @@ function validateDocument(text, options = {}) {
5959
6087
  out.push(...validateBindings(text, bindAttribute, stateTagName, locale3, fileReader));
5960
6088
  out.push(...validateTemplateSyntax(text, stateTagName, bindAttribute, locale3, fileReader));
5961
6089
  out.push(...validateIoNodes(text, bindAttribute, stateTagName, locale3, fileReader));
6090
+ out.push(...validateAriaAttributes(text, bindAttribute, locale3));
5962
6091
  out.push(...validateDocumentEnv(text, locale3));
5963
6092
  out.push(...validateSemantics(text, stateTagName, locale3, bindAttribute));
5964
6093
  out.push(...validateArrayMutations(text, stateTagName, locale3));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wcstack/lint",
3
- "version": "1.31.0",
3
+ "version": "1.32.0",
4
4
  "description": "Static-contract validator CLI (wcs-validate) for wcstack data-wcs bindings and wcstack.manifest.json sidecars. Thin npm wrapper around the wcstack-intellisense validator core.",
5
5
  "type": "module",
6
6
  "bin": {