@wcstack/typescript 4.8.0 → 4.9.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
@@ -641,7 +641,7 @@ function loadSchemaCore() {
641
641
  return cached;
642
642
  }
643
643
 
644
- var version = "4.8.0";
644
+ var version = "4.9.0";
645
645
  var pkg = {
646
646
  version: version};
647
647
 
@@ -115,6 +115,9 @@ var WcsDiagnosticCode = {
115
115
  // (state README「依存追跡の境界」規則 1)。ランタイムは素のアクセスと区別できないので
116
116
  // 静的にしか検出できない。対象はオブジェクトリテラル初期値のルートだけ(配列は `items`
117
117
  // の依存で足りる — 行の置換は `items` 自体を書き換え、in-place 変異は array-mutation が止める)。
118
+ // 読んだパスをページの束縛(組み込みタグの spread・書き戻す束縛・要素の出力)が書くなら error(その書き込みは
119
+ // getter に届かないと断定できる — 継ぎ目アプリ family-ledger)、スクリプトの書き込みだけなら warning(ルートも
120
+ // 置き換えるなら壊れない)。時刻・`location` を読む getter も同じ code(warning)。
118
121
  GetterUntrackedRead: "wcs/getter-untracked-read",
119
122
  OnHandlerThis: "wcs/on-handler-this",
120
123
  // --- <wcs-state> script: $watch declaration ---
@@ -1213,7 +1216,7 @@ var SENTENCES = {
1213
1216
  [
1214
1217
  29
1215
1218
  /* FilterValueNotDate */
1216
- ]: (fn, v) => `filter ${fn} requires a date value (a Date), not ${was(v)}${typeof v === "string" || typeof v === "number" ? " \u2014 make the Date where it is read: a getter returning new Date(\u2026)" : ""}`,
1219
+ ]: (fn, v) => `filter ${fn} requires a date value (a Date), not ${was(v)}${typeof v === "string" || typeof v === "number" ? " \u2014 make the Date where it is read: a getter returning new Date(\u2026)" : ""}${typeof v === "string" && /^\d{4}-\d\d-\d\d$/.test(v) ? `. A date-only string is a day, not a moment: new Date(${JSON.stringify(v)}) is midnight UTC, the day before west of Greenwich \u2014 new Date(y, m - 1, d) is that day where the page is` : ""}`,
1217
1220
  [
1218
1221
  52
1219
1222
  /* FilterStyleInvalid */
@@ -3311,10 +3314,10 @@ var RESERVED_WATCH_KEY = "$watch";
3311
3314
  var RESERVED_SCAN_KEY = "$scan";
3312
3315
  var RESERVED_RECURSION_KEY = RECURSION_KEY;
3313
3316
  function analyzeStatePaths(scriptContent) {
3314
- const objectContent = extractDefaultExportObject(scriptContent);
3315
- if (!objectContent) return [];
3317
+ const root = locateDefaultExportObject(scriptContent);
3318
+ if (!root || !root.content) return [];
3316
3319
  const paths = [];
3317
- const topLevelProps = parseTopLevelProperties(objectContent);
3320
+ const topLevelProps = parseTopLevelProperties(root.content);
3318
3321
  const pendingStreamValues = [];
3319
3322
  const pendingListKeys = [];
3320
3323
  const recursionSpec = specFromRecursionValue(topLevelProps.find((p) => p.name === RESERVED_RECURSION_KEY));
@@ -3361,7 +3364,7 @@ function analyzeStatePaths(scriptContent) {
3361
3364
  }
3362
3365
  }
3363
3366
  collectRowShapesFromAssignments(scriptContent, paths);
3364
- collectGetterResultShapes(topLevelProps, effectiveDescriptors, paths);
3367
+ collectGetterResultShapes(scriptContent, root.start, topLevelProps, effectiveDescriptors, paths);
3365
3368
  return paths;
3366
3369
  }
3367
3370
  function specFromRecursionValue(prop) {
@@ -3773,23 +3776,45 @@ var ROW_PRESERVING_METHODS = /* @__PURE__ */ new Set([
3773
3776
  ]);
3774
3777
  var ROW_PICKING_METHODS = /* @__PURE__ */ new Set(["find", "findLast", "at"]);
3775
3778
  var MAX_GETTER_SHAPE_PASSES = 4;
3776
- function collectGetterResultShapes(props, effective, paths) {
3779
+ function collectGetterResultShapes(script, rootStart, props, effective, paths) {
3777
3780
  const getters = /* @__PURE__ */ new Map();
3778
3781
  for (const prop of props) {
3779
3782
  if (prop.kind !== "getter" || prop.accessor !== "get" || prop.value === void 0) continue;
3780
3783
  if (prop.name.startsWith("$") || hasRecursionWildcard(prop.name) || effective.get(prop.name) === "data") continue;
3781
3784
  getters.set(prop.name, prop);
3782
3785
  }
3786
+ const assignments = collectAssignments(script, rootStart, props);
3783
3787
  for (let pass = 0; pass < MAX_GETTER_SHAPE_PASSES; pass++) {
3784
3788
  const before = paths.length;
3785
3789
  for (const [name, prop] of getters) {
3786
3790
  const shape = getterResultShape(prop.value, paths);
3787
3791
  if (shape !== null) applyResultShape(name, shape, paths);
3788
3792
  }
3793
+ const aliasesByBody = /* @__PURE__ */ new Map();
3794
+ for (const assignment of assignments) {
3795
+ let aliases = /* @__PURE__ */ new Map();
3796
+ if (assignment.body !== null) {
3797
+ aliases = aliasesByBody.get(assignment.body) ?? collectAliases(assignment.body, paths);
3798
+ aliasesByBody.set(assignment.body, aliases);
3799
+ }
3800
+ const shape = expressionShape(assignment.expr, paths, aliases);
3801
+ if (shape !== null) applyAssignedShape(assignment.target, shape, paths);
3802
+ }
3789
3803
  if (paths.length === before) break;
3790
3804
  }
3791
3805
  }
3792
3806
  function getterResultShape(body, paths) {
3807
+ const scan = maskCommentsAndStrings(body);
3808
+ const aliases = collectAliases(body, paths);
3809
+ const shapes = [];
3810
+ for (const m of scan.matchAll(/\breturn\b/g)) {
3811
+ const start = m.index + m[0].length;
3812
+ const shape = expressionShape(readExpression(body, scan, start), paths, aliases);
3813
+ if (shape !== null) shapes.push(shape);
3814
+ }
3815
+ return shapes.length === 0 ? null : mergeShapes(shapes);
3816
+ }
3817
+ function collectAliases(body, paths) {
3793
3818
  const scan = maskCommentsAndStrings(body);
3794
3819
  const aliases = /* @__PURE__ */ new Map();
3795
3820
  for (const m of scan.matchAll(/\b(?:const|let|var)\s+([$\w]+)\s*=(?![=>])/g)) {
@@ -3799,13 +3824,36 @@ function getterResultShape(body, paths) {
3799
3824
  const shape = expressionShape(readExpression(body, scan, start), paths, aliases);
3800
3825
  if (shape !== null) aliases.set(name, shape);
3801
3826
  }
3802
- const shapes = [];
3803
- for (const m of scan.matchAll(/\breturn\b/g)) {
3804
- const start = m.index + m[0].length;
3805
- const shape = expressionShape(readExpression(body, scan, start), paths, aliases);
3806
- if (shape !== null) shapes.push(shape);
3827
+ return aliases;
3828
+ }
3829
+ var PLAIN_ASSIGN = new RegExp(String.raw`\bthis\s*(?:\.\s*([$\w]+)|\[\s*["']([^"']+)["']\s*\])\s*=(?![=>])`, "gd");
3830
+ function collectAssignments(script, rootStart, props) {
3831
+ const scan = maskCommentsAndStrings(script);
3832
+ const bodies = props.filter((p) => (p.kind === "getter" || p.kind === "method") && p.value !== void 0 && p.valueStart !== void 0).map((p) => ({ start: rootStart + p.valueStart, body: p.value }));
3833
+ const out = [];
3834
+ PLAIN_ASSIGN.lastIndex = 0;
3835
+ let match;
3836
+ while ((match = PLAIN_ASSIGN.exec(scan)) !== null) {
3837
+ if (/\.\s*$/.test(scan.slice(Math.max(0, match.index - 8), match.index))) continue;
3838
+ const span = match.indices[1] ?? match.indices[2];
3839
+ const target = script.slice(span[0], span[1]);
3840
+ if (target.startsWith("$") || target.includes("*")) continue;
3841
+ const expr = readExpression(script, scan, match.index + match[0].length);
3842
+ const owner = bodies.find((b) => b.start <= match.index && match.index < b.start + b.body.length);
3843
+ out.push({ target, expr, body: owner?.body ?? null });
3844
+ }
3845
+ return out;
3846
+ }
3847
+ function applyAssignedShape(target, shape, paths) {
3848
+ const declared = paths.find((p) => p.path === target);
3849
+ if (declared === void 0 || declared.kind !== "data") return;
3850
+ if (hasPath(paths, `${target}.*`)) {
3851
+ if (shape.isList) applyResultShape(target, shape, paths);
3852
+ return;
3853
+ }
3854
+ if (!shape.isList && declared.rawInitial !== void 0 && isObjectLiteral(declared.rawInitial)) {
3855
+ applyResultShape(target, shape, paths);
3807
3856
  }
3808
- return shapes.length === 0 ? null : mergeShapes(shapes);
3809
3857
  }
3810
3858
  function readExpression(text3, scan, start) {
3811
3859
  let depth = 0;
@@ -3860,9 +3908,7 @@ function expressionShape(text3, paths, aliases) {
3860
3908
  }
3861
3909
  } else if (scan.startsWith("(")) {
3862
3910
  const inner = extractDelimitedContent(expr, scan, 0, "(", ")");
3863
- const base = expressionShape(inner, paths, aliases);
3864
- if (base === null) return null;
3865
- shape = base;
3911
+ shape = expressionShape(inner, paths, aliases) ?? OPAQUE;
3866
3912
  rest = inner.length + 2;
3867
3913
  } else {
3868
3914
  const base = readBase(expr, scan, aliases, paths);
@@ -4211,9 +4257,6 @@ function locateDefaultExportObject(script) {
4211
4257
  const braceIndex = scan.indexOf(match[1], match.index);
4212
4258
  return { content: extractBracedContent(script, scan, braceIndex), start: braceIndex + 1 };
4213
4259
  }
4214
- function extractDefaultExportObject(script) {
4215
- return locateDefaultExportObject(script)?.content ?? null;
4216
- }
4217
4260
  function parseTopLevelProperties(objectContent, allowEmptyDataKeys = false) {
4218
4261
  const props = [];
4219
4262
  const scan = maskCommentsAndStrings(objectContent);
@@ -11408,6 +11451,7 @@ var ja = {
11408
11451
  pathReadonlyTwoWay: (p, prop) => `"${p}" \u306F setter \u306E\u7121\u3044 getter \u3067\u3059\u304C\u3001${prop}: \u306F\u8AAD\u8005\u306E\u5165\u529B\u3092\u66F8\u304D\u623B\u3059\u306E\u3067\u3001\u5165\u529B\u306E\u305F\u3073\u306B\u66F8\u304D\u8FBC\u307F\u304C\u5931\u6557\u3057\u307E\u3059\uFF08"${p}" is a getter without a setter\uFF09\u3002setter \u3092\u8DB3\u3059\uFF08set "${p}"(v) { \u2026 }\uFF09\u304B\u3001#ro \u3067\u4E00\u65B9\u5411\u306B\u3057\u3066\u304F\u3060\u3055\u3044\uFF08${prop}#ro: ${p}\uFF09`,
11409
11452
  submitWithoutPrevent: (h) => `onsubmit \u306B #prevent \u304C\u7121\u304F\u3001"${h}" \u3082 preventDefault \u3092\u547C\u3073\u307E\u305B\u3093\u3002\u30D6\u30E9\u30A6\u30B6\u306F\u30D5\u30A9\u30FC\u30E0\u3082\u9001\u308B\u306E\u3067\u3001\u30DA\u30FC\u30B8\u304C\u8AAD\u307F\u76F4\u3055\u308C\u308B\u304B\u3001router \u304C\u3042\u308C\u3070 GET \u304C\u6B04\u306E\u5024\uFF08\u30D1\u30B9\u30EF\u30FC\u30C9\u3082\uFF09\u3092 URL \u3068\u5C65\u6B74\u306B\u8F09\u305B\u307E\u3059\u3002onsubmit#prevent: ${h} \u3068\u66F8\u304F\u304B\u3001\u30CF\u30F3\u30C9\u30E9\u3067 event.preventDefault() \u3092\u547C\u3093\u3067\u304F\u3060\u3055\u3044`,
11410
11453
  getterUntrackedRead: (root, sp) => `\u3053\u3053\u3067\u8FFD\u8DE1\u3055\u308C\u308B\u306E\u306F "${root}" \u3060\u3051\u3067\u3059\u3002"${sp}" \u304C\u5909\u308F\u3063\u3066\u3082\u3053\u306E getter \u306F\u518D\u8A55\u4FA1\u3055\u308C\u307E\u305B\u3093\uFF08\u30D1\u30B9\u8AAD\u307F\u53D6\u308A\u306E\u5148\u306E\u7D20\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u30A2\u30AF\u30BB\u30B9\u306F\u8FFD\u8DE1\u3055\u308C\u306A\u3044\uFF09\u3002this["${sp}"] \u3067\u8AAD\u3093\u3067\u304F\u3060\u3055\u3044`,
11454
+ getterUntrackedReadBound: (root, sp, binding, tag, written) => `\u3053\u3053\u3067\u8FFD\u8DE1\u3055\u308C\u308B\u306E\u306F "${root}" \u3060\u3051\u3067\u3059\u304C\u3001<${tag}> \u306E\u675F\u7E1B "${binding}" \u306F "${written}" \u3092\u30D1\u30B9\u3067\u66F8\u304D\u307E\u3059\u3002\u305D\u306E\u66F8\u304D\u8FBC\u307F\u306F\u3053\u306E getter \u306B\u5C4A\u304B\u305A\u3001getter \u306F\u524D\u306B\u8A08\u7B97\u3057\u305F\u5024\u3092\u8FD4\u3057\u7D9A\u3051\u307E\u3059\uFF08\u30D1\u30B9\u8AAD\u307F\u53D6\u308A\u306E\u5148\u306E\u7D20\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u30A2\u30AF\u30BB\u30B9\u306F\u8FFD\u8DE1\u3055\u308C\u306A\u3044\uFF09\u3002this["${sp}"] \u3067\u8AAD\u3093\u3067\u304F\u3060\u3055\u3044`,
11411
11455
  handlerFilterNotAllowed: (prop) => `\u30A4\u30D9\u30F3\u30C8\u30CF\u30F3\u30C9\u30E9 "${prop}" \u306B\u30D5\u30A3\u30EB\u30BF\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093`,
11412
11456
  typeExpectation: (label, expected, resultType) => `"${label}" \u306B\u306F${JA_EXPECTED_LABEL[expected]}\u304C\u5FC5\u8981\u3067\u3059\uFF08\u73FE\u5728\u306E\u578B: ${resultType}\uFF09`,
11413
11457
  filterUnknown: (n) => `\u30D5\u30A3\u30EB\u30BF "${n}" \u306F\u7D44\u307F\u8FBC\u307F\u30D5\u30A3\u30EB\u30BF\u306B\u5B58\u5728\u3057\u307E\u305B\u3093`,
@@ -11618,6 +11662,7 @@ var en = {
11618
11662
  pathReadonlyTwoWay: (p, prop) => `"${p}" is a getter without a setter, and ${prop}: writes back what the reader enters, so every edit fails ("${p}" is a getter without a setter). Add a setter (set "${p}"(v) { \u2026 }), or bind it one way with #ro (${prop}#ro: ${p})`,
11619
11663
  submitWithoutPrevent: (h) => `onsubmit has no #prevent and "${h}" does not call preventDefault, so the browser submits the form too: the page reloads, or with the router a GET puts the fields (a password too) in the URL and the history. Write onsubmit#prevent: ${h}, or call event.preventDefault() in the handler`,
11620
11664
  getterUntrackedRead: (root, sp) => `Only "${root}" is tracked here: the getter is not re-evaluated when "${sp}" changes (plain property access after a path read is not tracked). Read this["${sp}"] instead`,
11665
+ getterUntrackedReadBound: (root, sp, binding, tag, written) => `Only "${root}" is tracked here, but the binding "${binding}" on <${tag}> writes "${written}" by path: that write never reaches this getter, which keeps returning the value it last computed (plain property access after a path read is not tracked). Read this["${sp}"] instead`,
11621
11666
  handlerFilterNotAllowed: (prop) => `Filters cannot be applied to event handler "${prop}"`,
11622
11667
  typeExpectation: (label, expected, resultType) => `"${label}" requires ${EN_EXPECTED_LABEL[expected]} (current type: ${resultType})`,
11623
11668
  filterUnknown: (n) => `Filter "${n}" is not a built-in filter`,
@@ -12355,7 +12400,8 @@ function openTagBefore(html, valueStart) {
12355
12400
  return lt2 === -1 ? "" : html.slice(lt2, valueStart);
12356
12401
  }
12357
12402
  function writesBack(attr, prop, written) {
12358
- if (written.split("#").slice(1).some((modifier) => modifier.trim() === "ro")) return false;
12403
+ const modifiers = written.split("#").slice(1).flatMap((part) => part.split(","));
12404
+ if (modifiers.some((modifier) => modifier.trim() === "ro")) return false;
12359
12405
  if (prop === "radio" || prop === "checkbox") return true;
12360
12406
  const tag = attr.tagName;
12361
12407
  if (tag === void 0 || tag.includes("-")) return false;
@@ -14298,6 +14344,9 @@ var BUILTIN_TAGS = {
14298
14344
  "withCredentials": "with-credentials",
14299
14345
  "events": "events",
14300
14346
  "raw": "raw",
14347
+ "autoReconnect": "auto-reconnect",
14348
+ "reconnectInterval": "reconnect-interval",
14349
+ "maxReconnects": "max-reconnects",
14301
14350
  "staleAfter": "stale-after",
14302
14351
  "manual": "manual",
14303
14352
  "trigger": null
@@ -14425,6 +14474,14 @@ var BUILTIN_TAGS = {
14425
14474
  "abort"
14426
14475
  ]
14427
14476
  },
14477
+ "wcs-upload-header": {
14478
+ "package": "upload",
14479
+ "hasWcBindable": false,
14480
+ "observedAttributes": [],
14481
+ "inputs": {},
14482
+ "properties": [],
14483
+ "commands": []
14484
+ },
14428
14485
  "wcs-view-transition": {
14429
14486
  "package": "view-transition",
14430
14487
  "hasWcBindable": true,
@@ -16713,7 +16770,7 @@ function validateGetterCycles(script, scriptStart, locale2) {
16713
16770
  }
16714
16771
  return out;
16715
16772
  }
16716
- function validateGetterUntrackedReads(script, scriptStart, nestedWriteRoots, locale2) {
16773
+ function validateGetterUntrackedReads(script, scriptStart, mountPath, nestedWriteRoots, bindingWrites, locale2) {
16717
16774
  const getters = analyzeCallableBodies(script).filter((entry) => entry.kind === "getter" && entry.accessor === "get");
16718
16775
  if (getters.length === 0) return [];
16719
16776
  const objectRoots = /* @__PURE__ */ new Set();
@@ -16731,18 +16788,66 @@ function validateGetterUntrackedReads(script, scriptStart, nestedWriteRoots, loc
16731
16788
  if (read.written) continue;
16732
16789
  const segments = read.callee ? read.chain.slice(0, -1) : read.chain;
16733
16790
  if (segments.length < 2 || !objectRoots.has(segments[0])) continue;
16734
- if (!nestedWriteRoots().has(segments[0])) continue;
16791
+ const prefix = mountPath === null ? [] : mountPath.split(".");
16792
+ const write = boundWriteOf([...prefix, ...segments], prefix.length + read.path.split(".").length, bindingWrites());
16793
+ if (write === void 0 && !nestedWriteRoots().has([...prefix, segments[0]].join("."))) continue;
16794
+ const sp = segments.join(".");
16735
16795
  out.push({
16736
16796
  code: WcsDiagnosticCode.GetterUntrackedRead,
16737
16797
  start: scriptStart + getter.bodyStart + read.start,
16738
16798
  end: scriptStart + getter.bodyStart + read.end,
16739
- message: msgs.getterUntrackedRead(segments[0], segments.join(".")),
16740
- severity: "warning"
16799
+ message: write === void 0 ? msgs.getterUntrackedRead(segments[0], sp) : msgs.getterUntrackedReadBound(segments[0], sp, write.binding, write.tag, write.path),
16800
+ severity: write === void 0 ? "warning" : "error"
16741
16801
  });
16742
16802
  }
16743
16803
  }
16744
16804
  return out;
16745
16805
  }
16806
+ function boundWriteOf(segments, tracked, writes) {
16807
+ return writes.find((write) => {
16808
+ const written = write.path.split(".");
16809
+ if (written.length <= tracked || written.length > segments.length) return false;
16810
+ return written.every((s, i) => s === segments[i] || s === "*" && /^\d+$/.test(segments[i]));
16811
+ });
16812
+ }
16813
+ function collectBindingWrites(html, bindAttrName) {
16814
+ const out = [];
16815
+ const ignored = findIgnoredRanges(html, bindAttrName);
16816
+ for (const attr of findAllBindAttributes(html, bindAttrName)) {
16817
+ if (ignored.some(([start, end]) => attr.valueStart >= start && attr.valueStart < end)) continue;
16818
+ const tag = attr.tagName ?? "";
16819
+ const contract = BUILTIN_TAGS[tag];
16820
+ const outputs = contract?.hasWcBindable === true ? contract.properties : null;
16821
+ const bindings = parseBindTextWithPositions(attr.value);
16822
+ bindings.forEach((binding, index) => {
16823
+ const parsed = binding.parsed;
16824
+ if (parsed === null || binding.pathRange === null) return;
16825
+ let path = parsed.statePathName;
16826
+ if (path.startsWith(".")) {
16827
+ const at2 = attr.valueStart + binding.pathRange.start;
16828
+ const list = getRowShorthandForPath(html, at2, bindAttrName) === null ? null : getResolvedForListPath(html, at2, bindAttrName);
16829
+ if (list === null) return;
16830
+ path = path === "." ? `${list}.*` : `${list}.*.${path.slice(1)}`;
16831
+ }
16832
+ const write = (written) => {
16833
+ out.push({ path: written, binding: binding.exprText, tag });
16834
+ };
16835
+ if (parsed.bindingType === "spread") {
16836
+ if (outputs === null) return;
16837
+ const later = new Set(bindings.slice(index + 1).flatMap((b) => b.parsed?.bindingType === "prop" ? [b.parsed.propName] : []));
16838
+ for (const output of outputs) if (!later.has(output)) write(`${path}.${output}`);
16839
+ return;
16840
+ }
16841
+ if (parsed.propModifiers.includes("ro")) return;
16842
+ if (parsed.bindingType === "radio" || parsed.bindingType === "checkbox") {
16843
+ write(path);
16844
+ } else if (parsed.bindingType === "prop" && (writesBack(attr, parsed.propName, parsed.propName) || outputs?.includes(parsed.propName) === true)) {
16845
+ write(path);
16846
+ }
16847
+ });
16848
+ }
16849
+ return out;
16850
+ }
16746
16851
  function validateGetterLocationReads(script, scriptStart, locale2) {
16747
16852
  if (!script.includes("location")) return [];
16748
16853
  const msgs = getMessages(locale2);
@@ -17073,12 +17178,21 @@ function validateSemantics(html, stateTagName = "wcs-state", locale2, bindAttrNa
17073
17178
  const blocks = parseLoadedScriptBlocks(html, stateTagName);
17074
17179
  let nestedWriteRoots = null;
17075
17180
  const getNestedWriteRoots = () => nestedWriteRoots ??= collectNestedWriteRoots(html, stateTagName, bindAttrName, blocks);
17181
+ let bindingWrites = null;
17182
+ const getBindingWrites = () => bindingWrites ??= collectBindingWrites(html, bindAttrName);
17076
17183
  for (const block of blocks) {
17077
17184
  out.push(...validateIndexArity(block.content, block.contentStart, locale2));
17078
17185
  out.push(...validateNameAliases(block.content, block.contentStart, locale2, block.mountPath));
17079
17186
  out.push(...validateIndexParamReads(block.content, block.contentStart, locale2));
17080
17187
  out.push(...validateGetterCycles(block.content, block.contentStart, locale2));
17081
- out.push(...validateGetterUntrackedReads(block.content, block.contentStart, getNestedWriteRoots, locale2));
17188
+ out.push(...validateGetterUntrackedReads(
17189
+ block.content,
17190
+ block.contentStart,
17191
+ block.mountPath,
17192
+ getNestedWriteRoots,
17193
+ getBindingWrites,
17194
+ locale2
17195
+ ));
17082
17196
  out.push(...validateGetterLocationReads(block.content, block.contentStart, locale2));
17083
17197
  out.push(...validateGetterClockReads(block.content, block.contentStart, locale2));
17084
17198
  out.push(...validateOnHandlerThis(block.content, block.contentStart, locale2));
@@ -643,7 +643,7 @@ function loadSchemaCore() {
643
643
  return cached;
644
644
  }
645
645
 
646
- var version = "4.8.0";
646
+ var version = "4.9.0";
647
647
  var pkg = {
648
648
  version: version};
649
649
 
package/dist/wcs-tsc.mjs CHANGED
@@ -25,7 +25,7 @@ function unsupportedTypeScriptMessage(version) {
25
25
  return `@wcstack/typescript runs on TypeScript 5 or 6, and the project has TypeScript ${version}, which has no JavaScript compiler API: npm i -D typescript@6`;
26
26
  }
27
27
 
28
- var version = "4.8.0";
28
+ var version = "4.9.0";
29
29
  var pkg = {
30
30
  version: version};
31
31
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wcstack/typescript",
3
- "version": "4.8.0",
3
+ "version": "4.9.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",