@wcstack/lint 3.0.0 → 3.1.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 +49 -1
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -201,6 +201,9 @@ var WcsDiagnosticCode = {
201
201
  // --- built-in wcs-* tag contract (generated/builtinTags.generated.ts が正本) ---
202
202
  // 未知メンバーへのバインド(プロパティ / command. / eventToken. キー)。黙って無視される。
203
203
  TagMemberUnknown: "wcs/tag-member-unknown",
204
+ // タグのメンバー名が "on" で始まる(`once` 等)のに先頭ドット無しで束縛した: ランタイムはイベント束縛にして
205
+ // "ce" イベントを待ち、値は届かない。明示のプロパティ形 `.once:` を提案する(@wcstack/state 3.1・要件 B5 / 3.x 計画 D36)
206
+ OnPrefixedMember: "wcs/on-prefixed-member",
204
207
  // wcBindable 無宣言タグ(wcs-fetch-header 等のヘルパー)への spread。
205
208
  // ランタイム(expandSpread)は raiseError で落とす。
206
209
  SpreadNoBindable: "wcs/spread-no-bindable",
@@ -923,6 +926,7 @@ function getWcsManifest() {
923
926
  elseKeyword: ELSE_KEYWORD,
924
927
  spread: SPREAD_PROP,
925
928
  eventPropertyPrefix: EVENT_PROP_PREFIX,
929
+ explicitPropertyPrefix: DELIMITER,
926
930
  propNamespaces: {
927
931
  eventToken: EVENT_TOKEN_NAMESPACE,
928
932
  command: COMMAND_NAMESPACE,
@@ -2637,6 +2641,7 @@ var ja = {
2637
2641
  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`,
2638
2642
  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`,
2639
2643
  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`,
2644
+ 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`,
2640
2645
  tagCommandUnknown: (name, tag, declared) => `"${name}" \u306F <${tag}> \u306E command \u3067\u306F\u3042\u308A\u307E\u305B\u3093\uFF08\u5BA3\u8A00\u6E08\u307F: ${declared}\uFF09`,
2641
2646
  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`,
2642
2647
  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`,
@@ -2826,6 +2831,7 @@ var en = {
2826
2831
  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}).`,
2827
2832
  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.`,
2828
2833
  tagMemberUnknown: (prop, tag) => `"${prop}" is not a wcBindable member of <${tag}> (bindings to unknown members are silently ignored)`,
2834
+ 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)`,
2829
2835
  tagCommandUnknown: (name, tag, declared) => `"${name}" is not a command of <${tag}> (declared: ${declared})`,
2830
2836
  spreadNoBindable: (tag) => `'...' (spread) requires <${tag}> to expose a valid wcBindable declaration \u2014 this tag declares none, so the runtime raises an error`,
2831
2837
  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})`,
@@ -4150,6 +4156,10 @@ var ELSE_KEYWORD2 = "else";
4150
4156
  var SPREAD_PROP2 = "...";
4151
4157
  var EVENT_PROP_PREFIX2 = "on";
4152
4158
  var EVENT_TOKEN_NAMESPACE2 = "eventToken";
4159
+ var COMMAND_NAMESPACE2 = "command";
4160
+ var CLASS_NAMESPACE2 = "class";
4161
+ var ATTR_NAMESPACE2 = "attr";
4162
+ var STYLE_NAMESPACE2 = "style";
4153
4163
  var INDEX_PARAM_PREFIX2 = "$";
4154
4164
  var tmpIndexByIndexName2 = {};
4155
4165
  for (let i = 0; i < MAX_WILDCARD_DEPTH2; i++) {
@@ -4474,6 +4484,13 @@ function parseStatePart(statePart) {
4474
4484
  };
4475
4485
  }
4476
4486
  var KEYWORDS_WITHOUT_MODIFIERS = /* @__PURE__ */ new Set([ELSE_KEYWORD2, "if", "elseif", "for", SPREAD_PROP2]);
4487
+ var EXPLICIT_PROPERTY_REJECTED_HEADS = /* @__PURE__ */ new Set([
4488
+ CLASS_NAMESPACE2,
4489
+ ATTR_NAMESPACE2,
4490
+ STYLE_NAMESPACE2,
4491
+ COMMAND_NAMESPACE2,
4492
+ EVENT_TOKEN_NAMESPACE2
4493
+ ]);
4477
4494
  function splitBindTexts(bindText) {
4478
4495
  return splitOutsideQuotes(bindText, BINDING_SEPARATOR2);
4479
4496
  }
@@ -4542,6 +4559,19 @@ function parseBindTextsForElement(bindText) {
4542
4559
  } else {
4543
4560
  const stateResult = parseStatePart(statePart);
4544
4561
  const propResult = parsePropPart(propPart);
4562
+ if (propResult.propSegments[0] === "" && propResult.propSegments.length > 1) {
4563
+ const propSegments = propResult.propSegments.slice(1);
4564
+ if (propSegments.includes("") || EXPLICIT_PROPERTY_REJECTED_HEADS.has(propSegments[0])) {
4565
+ 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}`);
4566
+ }
4567
+ return {
4568
+ ...propResult,
4569
+ propName: propSegments.join(DELIMITER2),
4570
+ propSegments,
4571
+ ...stateResult,
4572
+ bindingType: "prop"
4573
+ };
4574
+ }
4545
4575
  if (propResult.propSegments[0] === EVENT_TOKEN_NAMESPACE2) {
4546
4576
  return {
4547
4577
  ...propResult,
@@ -6057,10 +6087,28 @@ function validateBindingAgainstContract(tagName, contract, parsed, property, sta
6057
6087
  const hashIndex = property.indexOf("#");
6058
6088
  const modifiers = hashIndex === -1 ? "" : property.slice(hashIndex + 1);
6059
6089
  property = hashIndex === -1 ? property : property.slice(0, hashIndex);
6090
+ const explicit = property.startsWith(".") && property !== "...";
6091
+ if (explicit) {
6092
+ property = property.slice(1);
6093
+ if (/^(class|style|attr|command|eventToken)(\.|$)/.test(property)) return;
6094
+ }
6060
6095
  if (property === "...") return;
6061
6096
  if (STRUCTURAL_DIRECTIVES2.has(property)) return;
6062
6097
  if (/^(class|style|attr)\./.test(property)) return;
6063
- if (/^on\w/.test(property)) return;
6098
+ if (!explicit && /^on\w/.test(property)) {
6099
+ if (contract.properties.includes(property) || property in contract.inputs) {
6100
+ diagnostics.push({
6101
+ code: WcsDiagnosticCode.OnPrefixedMember,
6102
+ start,
6103
+ end,
6104
+ severity: "warning",
6105
+ tag: tagName,
6106
+ member: property,
6107
+ message: msgs.onPrefixedMember(property, tagName)
6108
+ });
6109
+ }
6110
+ return;
6111
+ }
6064
6112
  const inputNames = Object.keys(contract.inputs);
6065
6113
  if (property.startsWith("command.")) {
6066
6114
  const name = property.slice("command.".length);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wcstack/lint",
3
- "version": "3.0.0",
3
+ "version": "3.1.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": {