@wcstack/typescript 4.10.0 → 4.11.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.10.0";
644
+ var version = "4.11.0";
645
645
  var pkg = {
646
646
  version: version};
647
647
 
@@ -58,7 +58,8 @@ var WcsDiagnosticCode = {
58
58
  PathReadonly: "wcs/path-readonly",
59
59
  PathReservedName: "wcs/path-reserved-name",
60
60
  // lint の限界の告知(作者の誤りではない): `export default { … }` のトップレベルの spread が持ち込むキーは読めないので、
61
- // stateSchema の無い state のパスは検査しない — それを spread の上で 1 回だけ言う。info。
61
+ // stateSchema の無い state のパスは検査しない — それを spread の上で 1 回だけ言う。info。値の読めないキー(辿れない名前、
62
+ // 読めない spread を持つオブジェクトリテラルの種 `draft: { ...makeDraft() }`)の下を束ねたときも、キーの上で 1 回言う。
62
63
  PathDynamicUnknown: "wcs/path-dynamic-unknown",
63
64
  // lint の限界の告知(作者の誤りではない): 読めない `<wcs-state src>`(/ から始まるパス・URL・無いファイル)の state は
64
65
  // パスもスクリプトの規則も検査しない — それを src の上で 1 回だけ言う。info(docs/seam-apps.md、prod-booking)。
@@ -264,6 +265,16 @@ var WcsDiagnosticCode = {
264
265
  RouterOutletMisplaced: "wcs/router-outlet-misplaced",
265
266
  // @wcstack/signals と /dom エントリの同一ページ混在(リアクティブコア二重化)。
266
267
  SignalsDualEntry: "wcs/signals-dual-entry",
268
+ // wcstack を自分で読み込むページが、あるパッケージのタグ(`<wcs-upload>`・`<wcs-upload-header>`)を書くのに、その
269
+ // パッケージのスクリプトを読み込んでいない。要素は定義されず、束縛は待ち続け、コンソールにも何も出ない(継ぎ目アプリ
270
+ // homeroom — 保存が「送信中 0%」で止まった)。パッケージごとに 1 回、最初のタグに。読めないローカルのスクリプトがある
271
+ // ページ・autoloader の `@components/` が覆うタグ・wcstack を自分で読み込まないページ(断片・バンドラ)では黙る。warning。
272
+ TagPackageMissing: "wcs/tag-package-missing",
273
+ // ページの URL が、lint の規則の版(lint を作った @wcstack/state の版)より新しい minor の wcstack を固定している
274
+ // (`@wcstack/state@4.11.0` と lint 4.10.1)。古い lint は新しい規則を知らず、新しい正しい書き方を error にもする
275
+ // (homeroom — 4.2.0 の lint が 4.10 の `datetime(ja-JP,short,Asia/Tokyo)` を `wcs/filter-arity` に)。ページに 1 回、
276
+ // いちばん新しい固定に。版の無い URL・major だけの `@4`・lint の方が新しいときは黙る。warning。
277
+ LintVersionBehind: "wcs/lint-version-behind",
267
278
  // `<wcs-route>`(またはレイアウトのテンプレート)の直下のテキストの `{{ }}`。最初に着いたルートでしか束ねられず、
268
279
  // 遷移で入ったルートでは書いたままの文字が出る(router の README「Where route content lives」— docs/seam-apps.md、
269
280
  // router-admin)。warning。
@@ -728,12 +739,12 @@ function loadManifest(artifact) {
728
739
  for (const ns of NAMESPACE_KEYS) {
729
740
  const nsObj = extensions[ns];
730
741
  if (nsObj !== null && typeof nsObj === "object") {
731
- const version2 = nsObj.version;
732
- if (typeof version2 === "number" && version2 !== SUPPORTED_NAMESPACE_VERSION) {
742
+ const version3 = nsObj.version;
743
+ if (typeof version3 === "number" && version3 !== SUPPORTED_NAMESPACE_VERSION) {
733
744
  ctx.add(
734
745
  WcsDiagnosticCode.ManifestNamespaceVersion,
735
746
  pointer("manifestExtensions", ns, "version"),
736
- `Namespace "${ns}" version ${version2} is unsupported (expected ${SUPPORTED_NAMESPACE_VERSION}).`,
747
+ `Namespace "${ns}" version ${version3} is unsupported (expected ${SUPPORTED_NAMESPACE_VERSION}).`,
737
748
  "warning"
738
749
  );
739
750
  }
@@ -2803,7 +2814,11 @@ function getWcsManifest() {
2803
2814
  };
2804
2815
  }
2805
2816
 
2817
+ // ../state/package.json
2818
+ var version = "4.11.0";
2819
+
2806
2820
  // src/service/wcsManifest.ts
2821
+ var ENGINE_VERSION = version;
2807
2822
  var NATIVE_COMMANDS2 = getWcsManifest().nativeCommands ?? null;
2808
2823
  function nativeCommandsOf(tag) {
2809
2824
  if (NATIVE_COMMANDS2 === null) return null;
@@ -8531,10 +8546,10 @@ pp.readWord = function() {
8531
8546
  }
8532
8547
  return this.finishToken(type, word);
8533
8548
  };
8534
- var version = "8.18.0";
8549
+ var version2 = "8.18.0";
8535
8550
  Parser.acorn = {
8536
8551
  Parser,
8537
- version,
8552
+ version: version2,
8538
8553
  defaultOptions,
8539
8554
  Position,
8540
8555
  SourceLocation,
@@ -10077,19 +10092,100 @@ function pushDataPropertyPaths(prop, paths, typedefs, scope) {
10077
10092
  }
10078
10093
  function pushDataPropertyPathsAt(path, prop, paths, depth, typedefs, scope) {
10079
10094
  const followed = scope === void 0 ? null : followValue(prop, scope);
10095
+ let candidate;
10096
+ let unread = null;
10080
10097
  if (followed === null) {
10081
- paths.push({ path, kind: "data", typeHint: prop.typeHint, rawInitial: prop.value?.trim() });
10082
- pushLiteralStructurePaths(path, prop, paths, depth, typedefs, scope);
10098
+ candidate = { path, kind: "data", typeHint: prop.typeHint, rawInitial: prop.value?.trim() };
10099
+ paths.push(candidate);
10100
+ unread = pushLiteralStructurePaths(path, prop, paths, depth, typedefs, scope);
10083
10101
  } else {
10084
10102
  const value = followed.value;
10085
10103
  const shapeHint = value === null ? void 0 : inferTypeHint(value.text);
10086
10104
  const typeHint = prop.typeHint ?? (shapeHint === "array" || shapeHint === "object" ? shapeHint : void 0);
10087
10105
  const opaque = (value === null || !isReadableLiteral(value.text)) && prop.declaredType === void 0 ? { opaque: { ...followed.name !== void 0 ? { name: followed.name } : {}, ...followed.from !== void 0 ? { from: followed.from } : {} } } : {};
10088
- paths.push(withHint({ path, kind: "data", rawInitial: prop.value?.trim(), ...opaque }, typeHint));
10089
- if (value !== null) pushLiteralStructurePaths(path, { ...prop, value: value.text }, paths, depth, typedefs, value.scope);
10106
+ candidate = withHint({ path, kind: "data", rawInitial: prop.value?.trim(), ...opaque }, typeHint);
10107
+ paths.push(candidate);
10108
+ if (value !== null) unread = pushLiteralStructurePaths(path, { ...prop, value: value.text }, paths, depth, typedefs, value.scope);
10109
+ }
10110
+ if (unread !== null && candidate.opaque === void 0 && prop.declaredType === void 0) {
10111
+ candidate.opaque = { spread: unread.text, ...unread.from !== void 0 ? { from: unread.from } : {} };
10090
10112
  }
10091
10113
  if (prop.declaredType !== void 0) pushDeclaredShapePaths(path, prop.declaredType, paths, depth, typedefs);
10092
10114
  }
10115
+ var MAX_SPREAD_HOPS = 8;
10116
+ function objectLiteralKeys(content, scope, shorthands, hops = 0) {
10117
+ const explicit = parseTopLevelProperties(content);
10118
+ const props = shorthands ? withShorthands(content, explicit) : explicit;
10119
+ const spreads = findObjectSpreads(content);
10120
+ if (spreads.length === 0) {
10121
+ return { keys: props.filter((p) => p.kind === "data").map((prop) => ({ prop, scope })), unread: null };
10122
+ }
10123
+ const items = [
10124
+ ...props.map((prop) => ({ at: prop.nameStart ?? 0, prop })),
10125
+ ...spreads.map((s) => ({ at: s.start, spread: s.text }))
10126
+ ].sort((a, b) => a.at - b.at);
10127
+ const keys = /* @__PURE__ */ new Map();
10128
+ const put = (key) => {
10129
+ keys.delete(key.prop.name);
10130
+ keys.set(key.prop.name, key);
10131
+ };
10132
+ let unread = null;
10133
+ for (const item of items) {
10134
+ if ("prop" in item) {
10135
+ put({ prop: item.prop, scope });
10136
+ continue;
10137
+ }
10138
+ const literal2 = hops < MAX_SPREAD_HOPS ? spreadLiteral(item.spread, scope) : { unread: { text: item.spread } };
10139
+ if ("unread" in literal2) {
10140
+ unread ??= literal2.unread;
10141
+ continue;
10142
+ }
10143
+ if (literal2.text === null) continue;
10144
+ const nested = objectLiteralKeys(extractObjectContent(literal2.text), literal2.scope, true, hops + 1);
10145
+ for (const key of nested.keys) put(key);
10146
+ if (nested.unread !== null) unread ??= { text: item.spread };
10147
+ }
10148
+ return { keys: [...keys.values()].filter((k) => k.prop.kind === "data"), unread };
10149
+ }
10150
+ function spreadLiteral(spread, scope) {
10151
+ const expr = unwrapFreeze(spread.replace(/^\.\.\./, ""));
10152
+ if (expr === "null" || expr === "undefined") return { text: null };
10153
+ if (isObjectLiteral(expr)) return { text: expr, scope };
10154
+ if (!isBindingName(expr) || scope === void 0) return { unread: { text: spread } };
10155
+ const from = scope.importOf(expr);
10156
+ const unread = { unread: { text: spread, ...from !== void 0 ? { from } : {} } };
10157
+ let current2 = scope.resolveName(expr);
10158
+ for (let hops = 0; current2 !== null && hops < MAX_SPREAD_HOPS; hops++) {
10159
+ const inner = unwrapFreeze(current2.text);
10160
+ if (isObjectLiteral(inner)) return { text: inner, scope: current2.scope };
10161
+ if (!isBindingName(inner)) return unread;
10162
+ current2 = current2.scope.resolveName(inner);
10163
+ }
10164
+ return unread;
10165
+ }
10166
+ function findObjectSpreads(content) {
10167
+ const scan = maskCommentsAndStrings(content).replace(/\/\*[\s\S]*?\*\/|\/\/[^\n]*/g, (c) => " ".repeat(c.length));
10168
+ const out = [];
10169
+ let depth = 0;
10170
+ let start = 0;
10171
+ for (let i = 0; i <= scan.length; i++) {
10172
+ const ch = scan[i];
10173
+ if (ch === "{" || ch === "[" || ch === "(") {
10174
+ depth++;
10175
+ } else if (ch === "}" || ch === "]" || ch === ")") {
10176
+ depth--;
10177
+ } else if (ch === "," && depth === 0 || i === scan.length) {
10178
+ const segment = scan.slice(start, i);
10179
+ const lead = segment.length - segment.trimStart().length;
10180
+ if (segment.trimStart().startsWith("...")) {
10181
+ const end = start + segment.trimEnd().length;
10182
+ out.push({ start: start + lead, text: content.slice(start + lead, end) });
10183
+ }
10184
+ start = i + 1;
10185
+ }
10186
+ }
10187
+ return out;
10188
+ }
10093
10189
  var WORD_LITERALS = /* @__PURE__ */ new Set(["true", "false", "null", "undefined", "NaN", "Infinity", "this"]);
10094
10190
  function isBindingName(text3) {
10095
10191
  return /^[$A-Za-z_][$\w]*$/.test(text3) && !WORD_LITERALS.has(text3);
@@ -10157,23 +10253,30 @@ function pushDeclaredShapePaths(path, type, paths, depth, typedefs) {
10157
10253
  }
10158
10254
  function pushLiteralStructurePaths(path, prop, paths, depth, typedefs, scope) {
10159
10255
  if (prop.value && isArrayLiteral(prop.value)) {
10160
- paths.push({ path: `${path}.*`, kind: "list" });
10256
+ const row = { path: `${path}.*`, kind: "list" };
10257
+ paths.push(row);
10161
10258
  paths.push({ path: `${path}.length`, kind: "data", typeHint: "number" });
10162
- if (depth >= MAX_OBJECT_NEST_DEPTH) return;
10163
- for (const childProp of extractArrayElementDataProperties(prop.value)) {
10164
- pushDataPropertyPathsAt(`${path}.*.${childProp.name}`, childProp, paths, depth + 1, typedefs, scope);
10259
+ if (depth >= MAX_OBJECT_NEST_DEPTH) return null;
10260
+ const first = firstRowObjectContent(prop.value);
10261
+ if (first === null) return null;
10262
+ const { keys, unread } = objectLiteralKeys(first, scope, false);
10263
+ for (const key of keys) {
10264
+ pushDataPropertyPathsAt(`${path}.*.${key.prop.name}`, key.prop, paths, depth + 1, typedefs, key.scope);
10165
10265
  }
10166
- return;
10266
+ if (unread !== null && prop.declaredType === void 0) {
10267
+ row.opaque = { spread: unread.text, ...unread.from !== void 0 ? { from: unread.from } : {} };
10268
+ }
10269
+ return null;
10167
10270
  }
10168
10271
  if (prop.value && isObjectLiteral(prop.value)) {
10169
- if (depth >= MAX_OBJECT_NEST_DEPTH) return;
10170
- const content = extractObjectContent(prop.value);
10171
- const childProps = withShorthands(content, parseTopLevelProperties(content));
10172
- for (const childProp of childProps) {
10173
- if (childProp.kind !== "data") continue;
10174
- pushDataPropertyPathsAt(`${path}.${childProp.name}`, childProp, paths, depth + 1, typedefs, scope);
10272
+ if (depth >= MAX_OBJECT_NEST_DEPTH) return null;
10273
+ const { keys, unread } = objectLiteralKeys(extractObjectContent(prop.value), scope, true);
10274
+ for (const key of keys) {
10275
+ pushDataPropertyPathsAt(`${path}.${key.prop.name}`, key.prop, paths, depth + 1, typedefs, key.scope);
10175
10276
  }
10277
+ return unread;
10176
10278
  }
10279
+ return null;
10177
10280
  }
10178
10281
  function analyzeJsonPaths(jsonString) {
10179
10282
  let data2;
@@ -10446,15 +10549,18 @@ function extractObjectContent(value) {
10446
10549
  if (start === -1) return "";
10447
10550
  return extractBracedContent(trimmed, scan, start);
10448
10551
  }
10449
- function extractArrayElementDataProperties(value) {
10552
+ function firstRowObjectContent(value) {
10450
10553
  const trimmed = value.trim();
10451
- if (!trimmed.startsWith("[")) return [];
10554
+ if (!trimmed.startsWith("[")) return null;
10452
10555
  const scan = maskCommentsAndStrings(trimmed);
10453
10556
  let first = 1;
10454
10557
  while (first < scan.length && /\s/.test(scan[first])) first++;
10455
- if (scan[first] !== "{") return [];
10456
- const objectContent = extractBracedContent(trimmed, scan, first);
10457
- return parseTopLevelProperties(objectContent).filter((prop) => prop.kind === "data");
10558
+ if (scan[first] !== "{") return null;
10559
+ return extractBracedContent(trimmed, scan, first);
10560
+ }
10561
+ function extractArrayElementDataProperties(value) {
10562
+ const content = firstRowObjectContent(value);
10563
+ return content === null ? [] : parseTopLevelProperties(content).filter((prop) => prop.kind === "data");
10458
10564
  }
10459
10565
  function normalizeJsDocType(typeExpr) {
10460
10566
  const parts = typeExpr.split("|").map((p) => p.trim());
@@ -11837,6 +11943,7 @@ var ja = {
11837
11943
  stateSrcUnread: (src) => `"${src}" \u3092\u8AAD\u3081\u306A\u3044\u306E\u3067\u3001\u3053\u306E state \u306E\u30D1\u30B9\u3082\u30B9\u30AF\u30EA\u30D7\u30C8\u306E\u898F\u5247\u3082\u691C\u67FB\u3057\u3066\u3044\u307E\u305B\u3093\u3002src \u306F\u3053\u306E\u30D5\u30A1\u30A4\u30EB\u304B\u3089\u306E\u76F8\u5BFE\u30D1\u30B9\u3067\u8AAD\u307F\u307E\u3059\uFF08URL \u306F\u8AAD\u307E\u305A\u3001/ \u304B\u3089\u59CB\u307E\u308B\u30D1\u30B9\u306F wcs-validate --root=<\u30B5\u30A4\u30C8\u306E\u30EB\u30FC\u30C8> \u306E\u3068\u304D\u3060\u3051\u305D\u306E\u4E0B\u3067\u8AAD\u307F\u307E\u3059\uFF09\u3002\u30B5\u30FC\u30D0\u30FC\u3068\u540C\u3058\u4E26\u3073\u306B\u7F6E\u3044\u305F\u30D5\u30A1\u30A4\u30EB\u3092\u3001\u3053\u306E\u30D5\u30A1\u30A4\u30EB\u304B\u3089\u306E\u76F8\u5BFE\u30D1\u30B9\u3067\u6307\u3059\u304B\u3001--root \u3092\u6E21\u3057\u3066\u304F\u3060\u3055\u3044`,
11838
11944
  pathDynamicUnknownValue: (path, n, name, from) => `"${path}" \u306E\u5024${name === void 0 ? "" : from === void 0 ? `\uFF08${name}\uFF09` : `\uFF08${name}\u3002"${from}" \u304B\u3089 import\uFF09`}\u306F\u9759\u7684\u306B\u8AAD\u3081\u306A\u3044\u306E\u3067\u3001\u305D\u306E\u4E0B\u306B\u675F\u306D\u305F\u30D1\u30B9\uFF08${n} \u4EF6\uFF09\u306F\u691C\u67FB\u3057\u3066\u3044\u307E\u305B\u3093\u3002\u30AD\u30FC\u306B JSDoc \u306E @type \u2014 \u5F62\u304B\u3001\u30E2\u30B8\u30E5\u30FC\u30EB\u306E\u30EA\u30C6\u30E9\u30EB\u3092\u6307\u3059 typeof import("./file.js").name\uFF08\u8F9E\u66F8\u306A\u3089\u5168\u90E8\u306E\u30AD\u30FC\u3092\u6301\u3064\u65E2\u5B9A\u306E\u8A00\u8A9E\u306E\u30D5\u30A1\u30A4\u30EB\uFF09\u2014 \u3092\u4ED8\u3051\u308B\u304B\u3001wcstack.manifest.json \u306E stateSchema \u306B\u5BA3\u8A00\u3059\u308B\u3068\u691C\u67FB\u3055\u308C\u307E\u3059`,
11839
11945
  pathDynamicUnknownSpread: (sp) => `${sp} \u304C\u6301\u3061\u8FBC\u3080\u30AD\u30FC\u306F\u9759\u7684\u306B\u8AAD\u3081\u306A\u3044\u306E\u3067\u3001\u3053\u306E state \u306E\u30D1\u30B9\u306F\u691C\u67FB\u3057\u3066\u3044\u307E\u305B\u3093\uFF08\u675F\u7E1B\u30FBgetter \u306E\u4E2D\u306E\u8AAD\u307F\u30FB$watch \u306E\u30AD\u30FC\uFF09\u3002\u30AD\u30FC\u3092 wcstack.manifest.json \u306E stateSchema \u306B\u5BA3\u8A00\u3059\u308B\u3068\u691C\u67FB\u3055\u308C\u307E\u3059\u3002npx wcs-schema\uFF08@wcstack/typescript\uFF09\u304C state \u306E\u578B\uFF08JSDoc\u30FBTypeScript\uFF09\u304B\u3089\u4F5C\u308C\u307E\u3059`,
11946
+ pathDynamicUnknownObjectSpread: (path, n, sp, from) => `${sp}${from === void 0 ? "" : `\uFF08"${from}" \u304B\u3089 import\uFF09`}\u304C "${path}" \u306B\u6301\u3061\u8FBC\u3080\u30AD\u30FC\u306F\u9759\u7684\u306B\u8AAD\u3081\u306A\u3044\u306E\u3067\u3001\u305D\u306E\u4E0B\u306B\u675F\u306D\u305F\u30D1\u30B9\uFF08${n} \u4EF6\uFF09\u306F\u691C\u67FB\u3057\u3066\u3044\u307E\u305B\u3093\u3002\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u30EA\u30C6\u30E9\u30EB\u3092\u675F\u7E1B\u3059\u308B\u30E2\u30B8\u30E5\u30FC\u30EB\u306E const \u3092 spread \u3059\u308B\u304B\u3001\u30AD\u30FC\u306B\u5F62\u3092\u8868\u3059 JSDoc \u306E @type \u3092\u4ED8\u3051\u308B\u304B\u3001wcstack.manifest.json \u306E stateSchema \u306B\u5BA3\u8A00\u3059\u308B\u3068\u691C\u67FB\u3055\u308C\u307E\u3059`,
11840
11947
  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`,
11841
11948
  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`,
11842
11949
  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`,
@@ -11904,6 +12011,8 @@ var ja = {
11904
12011
  routerOutletMisplaced: () => `\u3053\u306E <wcs-outlet> \u306F <wcs-router> \u306E\u76F4\u5F8C\u306B\u7121\u3044\u306E\u3067\u3001\u3069\u306E router \u3082\u4F7F\u3044\u307E\u305B\u3093\u3002router \u306F\u81EA\u5206\u306E\u76F4\u5F8C\u306E\u8981\u7D20\u3060\u3051\u3092 outlet \u3068\u3057\u3066\u4F7F\u3044\u3001\u305D\u3053\u306B <wcs-outlet> \u304C\u7121\u3051\u308C\u3070\u81EA\u524D\u306E outlet \u3092\u4F5C\u308A\u307E\u3059\u3002\u30EB\u30FC\u30C8\u306F router \u306E\u76F4\u5F8C\u306B\u63CF\u304B\u308C\u3001\u3053\u306E outlet \u306F\u7A7A\u306E\u307E\u307E\u3067\u3059 \u2014 <wcs-router> \u306E\u76F4\u5F8C\u3078\u79FB\u3057\u3066\u304F\u3060\u3055\u3044`,
11905
12012
  signalsDualEntry: () => `@wcstack/signals \u3068 @wcstack/signals/dom \u304C\u540C\u4E00\u30DA\u30FC\u30B8\u304B\u3089 import \u3055\u308C\u3066\u3044\u307E\u3059\u3002CDN \u3067\u306F\u5404\u30A8\u30F3\u30C8\u30EA\u304C\u81EA\u5DF1\u5B8C\u7D50\u30D0\u30F3\u30C9\u30EB\u306E\u305F\u3081\u30EA\u30A2\u30AF\u30C6\u30A3\u30D6\u30B3\u30A2\u304C\u4E8C\u91CD\u5316\u3057\u3001\u5883\u754C\u3067\u53CD\u5FDC\u304C\u58CA\u308C\u307E\u3059 \u2014 \u3059\u3079\u3066 /dom \u30A8\u30F3\u30C8\u30EA\u304B\u3089 import \u3057\u3066\u304F\u3060\u3055\u3044`,
11906
12013
  signalsImportMapBoth: () => `\u3053\u306E import map \u306F @wcstack/signals \u3068 @wcstack/signals/dom \u306E\u4E21\u65B9\u3092\u5272\u308A\u5F53\u3066\u3066\u3044\u307E\u3059\u3002CDN \u3067\u306F\u5404\u30A8\u30F3\u30C8\u30EA\u304C\u30EA\u30A2\u30AF\u30C6\u30A3\u30D6\u30B3\u30A2\u3092\u6301\u3064\u306E\u3067\u3001@wcstack/signals \u3092 import \u3059\u308B\u30E2\u30B8\u30E5\u30FC\u30EB\uFF08\u3053\u306E\u30DA\u30FC\u30B8\u306E\u3082\u306E\u3067\u3082\u3001\u8AAD\u307F\u8FBC\u3080 .js \u3067\u3082\uFF09\u304C 2 \u3064\u76EE\u306E\u30B3\u30A2\u3092\u6301\u3061\u3001\u5883\u754C\u3067\u53CD\u5FDC\u304C\u58CA\u308C\u307E\u3059\u3002@wcstack/signals/dom \u3060\u3051\u3092\u5272\u308A\u5F53\u3066\u3066\u304F\u3060\u3055\u3044\uFF08\u30B3\u30A2\u306E\u5168\u90E8\u3092 export \u3057\u307E\u3059\uFF09`,
12014
+ tagPackageMissing: (tags, pkg, url) => `${tags.map((t) => `<${t}>`).join("\u30FB")} \u306F ${pkg} \u306E\u30BF\u30B0\u3067\u3059\u304C\u3001\u3053\u306E\u30DA\u30FC\u30B8\u306F ${pkg} \u306E\u30B9\u30AF\u30EA\u30D7\u30C8\u3092\u8AAD\u307F\u8FBC\u3093\u3067\u3044\u307E\u305B\u3093\u3002\u8981\u7D20\u306F\u5B9A\u7FA9\u3055\u308C\u306A\u3044\u306E\u3067\u3001\u305D\u306E\u675F\u7E1B\u306F\u5F85\u3061\u7D9A\u3051\u3066\u4F55\u3082\u8D77\u304D\u305A\u3001\u30B3\u30F3\u30BD\u30FC\u30EB\u306B\u3082\u4F55\u3082\u51FA\u307E\u305B\u3093 \u2014 <script type="module" src="${url}"></script> \u3067\u8AAD\u307F\u8FBC\u3093\u3067\u304F\u3060\u3055\u3044`,
12015
+ lintVersionBehind: (spec, version3, minor, lint) => `\u3053\u306E\u30DA\u30FC\u30B8\u306F ${spec} \u3092\u56FA\u5B9A\u3057\u3066\u3044\u307E\u3059\u304C\u3001\u3053\u306E lint \u306E\u898F\u5247\uFF08@wcstack ${lint}\uFF09\u3088\u308A\u65B0\u3057\u3044 minor \u3067\u3059\u3002${minor} \u3067\u52A0\u308F\u3063\u305F\u898F\u5247\u306F\u691C\u67FB\u3055\u308C\u305A\u3001${minor} \u306E\u6B63\u3057\u3044\u66F8\u304D\u65B9\u304C error \u306B\u306A\u308B\u3053\u3068\u3082\u3042\u308A\u307E\u3059 \u2014 @wcstack/lint \u3092 ${version3} \u306B\u4E0A\u3052\u3066\u304F\u3060\u3055\u3044\uFF08npm i -D @wcstack/lint@${version3}\u3002VS Code \u306E\u62E1\u5F35\u306F ${minor} \u306B\u5BFE\u5FDC\u3059\u308B\u7248\u3078\uFF09`,
11907
12016
  routeBareMustache: (inLayout) => inLayout ? `\u30EC\u30A4\u30A2\u30A6\u30C8\u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306E\u76F4\u4E0B\u306E\u30C6\u30AD\u30B9\u30C8\u306E {{ }} \u306F\u3001\u9077\u79FB\u3067\u306F\u675F\u306D\u3089\u308C\u307E\u305B\u3093 \u2014 \u8981\u7D20\u3067\u5305\u3093\u3067\u304F\u3060\u3055\u3044\uFF08<span>{{ \u2026 }}</span>\uFF09` : `<wcs-route> \u306E\u76F4\u4E0B\u306E\u30C6\u30AD\u30B9\u30C8\u306E {{ }} \u306F\u3001\u6700\u521D\u306B\u7740\u3044\u305F\u30EB\u30FC\u30C8\u3067\u3057\u304B\u675F\u306D\u3089\u308C\u307E\u305B\u3093\u3002\u9077\u79FB\u3067\u5165\u3063\u305F\u30EB\u30FC\u30C8\u3067\u306F\u66F8\u3044\u305F\u307E\u307E\u306E\u6587\u5B57\u304C\u51FA\u307E\u3059 \u2014 \u8981\u7D20\u3067\u5305\u3093\u3067\u304F\u3060\u3055\u3044\uFF08<h1>{{ \u2026 }}</h1>\uFF09`,
11908
12017
  layoutSlotMissing: (l) => `\u30EC\u30A4\u30A2\u30A6\u30C8 "${l}" \u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306B\u65E2\u5B9A\u306E <slot>\uFF08name \u306E\u7121\u3044\u3082\u306E\uFF09\u304C\u3042\u308A\u307E\u305B\u3093\u3002\u3053\u306E <wcs-layout> \u306E\u540D\u524D\u4ED8\u304D\u30B9\u30ED\u30C3\u30C8\u306E\u5916\u306E\u4E2D\u8EAB\uFF08\u5165\u308C\u5B50\u306E\u30EB\u30FC\u30C8\u3068\u305D\u306E\u30DA\u30FC\u30B8\uFF09\u306F\u8868\u793A\u3055\u308C\u307E\u305B\u3093 \u2014 \u30DA\u30FC\u30B8\u3092\u7F6E\u304F\u5834\u6240\u306B <slot></slot> \u3092\u66F8\u3044\u3066\u304F\u3060\u3055\u3044`,
11909
12018
  namedStateAttrDeprecated: (name) => `name \u5C5E\u6027\u306F v2 \u3067\u64A4\u53BB\u3055\u308C\u307E\u3057\u305F\uFF081 root 1 \u30C4\u30EA\u30FC\uFF09\u3002\u30EB\u30FC\u30C8\u30C4\u30EA\u30FC\u3078\u306E\u30DE\u30A6\u30F3\u30C8 <wcs-state mount="${name}"> \u306B\u7F6E\u304D\u63DB\u3048\u3001\u30D1\u30B9\u306F "${name}.<path>" \u3067\u53C2\u7167\u3057\u3066\u304F\u3060\u3055\u3044\uFF08docs/state-mount-design.md \xA79\uFF09`,
@@ -12050,6 +12159,7 @@ var en = {
12050
12159
  stateSrcUnread: (src) => `"${src}" cannot be read, so this state's paths and script rules are not checked. A src is read relative to this file (a URL is not read, and a path from / only under wcs-validate --root=<the site's root>): point it at the file laid out as on the server, relative to this file, or pass --root`,
12051
12160
  pathDynamicUnknownValue: (path, n, name, from) => `The value of "${path}"${name === void 0 ? "" : from === void 0 ? ` (${name})` : ` (${name}, imported from "${from}")`} cannot be read statically, so the ${n === 1 ? "path" : `${n} paths`} bound under it ${n === 1 ? "is" : "are"} not checked. Give the key a JSDoc @type \u2014 its shape, or typeof import("./file.js").name for a module's literal (for a dictionary, the default language's file, which has every key) \u2014 or declare it in the stateSchema of wcstack.manifest.json to have them checked`,
12052
12161
  pathDynamicUnknownSpread: (sp) => `The keys ${sp} brings in cannot be read statically, so this state's paths are not checked (bindings, reads in getters, $watch keys). Declare the keys in the stateSchema of wcstack.manifest.json to have them checked; npx wcs-schema (@wcstack/typescript) derives it from the state's types (JSDoc or TypeScript)`,
12162
+ pathDynamicUnknownObjectSpread: (path, n, sp, from) => `The keys ${sp}${from === void 0 ? "" : ` (imported from "${from}")`} brings into "${path}" cannot be read statically, so the ${n === 1 ? "path" : `${n} paths`} bound under it ${n === 1 ? "is" : "are"} not checked. Spread a const of the module bound to an object literal, give the key a JSDoc @type with its shape, or declare it in the stateSchema of wcstack.manifest.json to have them checked`,
12053
12163
  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})`,
12054
12164
  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`,
12055
12165
  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`,
@@ -12117,6 +12227,8 @@ var en = {
12117
12227
  routerOutletMisplaced: () => `This <wcs-outlet> is not right after a <wcs-router>, so no router uses it: a router uses only the element right after it as its outlet, and makes an outlet of its own there when that is not a <wcs-outlet>. The routes render right after the router and this outlet stays empty \u2014 move it right after the <wcs-router>`,
12118
12228
  signalsDualEntry: () => `Both @wcstack/signals and @wcstack/signals/dom are imported on this page. On a CDN each entry is a self-contained bundle, so the reactive core is duplicated and reactivity breaks at the seam \u2014 import everything from the single /dom entry`,
12119
12229
  signalsImportMapBoth: () => `This import map maps both @wcstack/signals and @wcstack/signals/dom. On a CDN each entry carries its own reactive core, so a module that imports @wcstack/signals \u2014 this page's, or a .js file it loads \u2014 gets a second core and reactivity breaks at the seam. Map only @wcstack/signals/dom (it exports the whole core)`,
12230
+ tagPackageMissing: (tags, pkg, url) => `${tags.map((t) => `<${t}>`).join(", ")} ${tags.length === 1 ? "is a tag" : "are tags"} of ${pkg}, and this page loads no script of ${pkg}: the element is never defined, so its bindings wait and nothing happens, without a word in the console. Load it with <script type="module" src="${url}"></script>`,
12231
+ lintVersionBehind: (spec, version3, minor, lint) => `This page pins ${spec}, a newer minor than the rules of this lint (@wcstack ${lint}): what ${minor} added is not checked, and correct ${minor} syntax can be reported as an error. Upgrade @wcstack/lint to ${version3} (npm i -D @wcstack/lint@${version3}; the VS Code extension to its release for ${minor})`,
12120
12232
  routeBareMustache: (inLayout) => inLayout ? `{{ }} in text directly under a layout template is not bound on a navigation. Wrap it in an element (<span>{{ \u2026 }}</span>)` : `{{ }} in text directly under <wcs-route> is bound only on the landing route: a route entered by navigation shows it as written. Wrap it in an element (<h1>{{ \u2026 }}</h1>)`,
12121
12233
  layoutSlotMissing: (l) => `The template of layout "${l}" has no default <slot> (one without a name), so what this <wcs-layout> holds outside the named slots \u2014 the nested routes and their pages \u2014 is not shown. Put a <slot></slot> where the page goes`,
12122
12234
  namedStateAttrDeprecated: (name) => `The "name" attribute was removed in v2 \u2014 there is a single state tree per root. Mount this state onto the tree instead: <wcs-state mount="${name}"> and read it as "${name}.<path>" (docs/state-mount-design.md \xA79)`,
@@ -15950,6 +16062,281 @@ function findMisplacedOutlets(html) {
15950
16062
  return routerWithoutOutlet ? misplaced : [];
15951
16063
  }
15952
16064
 
16065
+ // src/service/packageLoadValidator.ts
16066
+ var CORE_TAG_PACKAGES = {
16067
+ "wcs-state": "state",
16068
+ "wcs-ssr": "state",
16069
+ "wcs-router": "router",
16070
+ "wcs-route": "router",
16071
+ "wcs-outlet": "router",
16072
+ "wcs-layout": "router",
16073
+ "wcs-layout-outlet": "router",
16074
+ "wcs-link": "router",
16075
+ "wcs-head": "router",
16076
+ "wcs-guard-handler": "router",
16077
+ "wcs-autoloader": "autoloader",
16078
+ "wcs-devtools": "devtools"
16079
+ };
16080
+ function packageOfTag(tag) {
16081
+ if (Object.hasOwn(BUILTIN_TAGS, tag)) return BUILTIN_TAGS[tag].package;
16082
+ return Object.hasOwn(CORE_TAG_PACKAGES, tag) ? CORE_TAG_PACKAGES[tag] : void 0;
16083
+ }
16084
+ var SCOPED_NAME = /@wcstack\/([a-z0-9-]+)/g;
16085
+ var REPO_DIST = /\/packages\/([a-z0-9-]+)\/dist\//g;
16086
+ var BUNDLE = /(?:^|[/"'`\s])wcstack(?:@[^/"'`\s]+)?\/(?:auto\b|dist\/)/;
16087
+ var PINNED = /(?:@wcstack\/([a-z0-9-]+)|(?:^|(?<=[/"'`\s]))wcstack)@(\d+)\.(\d+)(?:\.(\d+))?(-[0-9A-Za-z.-]+)?/g;
16088
+ function namedPackages(text3) {
16089
+ const out = [];
16090
+ for (const m of text3.matchAll(SCOPED_NAME)) out.push(m[1]);
16091
+ for (const m of text3.matchAll(REPO_DIST)) out.push(m[1]);
16092
+ if (BUNDLE.test(text3)) out.push("wcstack");
16093
+ return out.flatMap((p) => p === "wcstack" ? [...BUNDLE_PACKAGES] : [p]);
16094
+ }
16095
+ var MAX_FILES2 = 32;
16096
+ var MAX_DEPTH = 4;
16097
+ function validatePackageLoads(html, locale2, fileReader) {
16098
+ const msgs = getMessages(locale2);
16099
+ const scan = blankHtmlComments(html);
16100
+ const loads = collectPageLoads(scan, fileReader);
16101
+ const out = [];
16102
+ const lint = parseVersion(ENGINE_VERSION);
16103
+ let newest = null;
16104
+ for (const ref2 of loads.references) {
16105
+ for (const m of ref2.text.matchAll(PINNED)) {
16106
+ const pin = {
16107
+ spec: m[0],
16108
+ version: m[0].slice(m[0].lastIndexOf("@") + 1),
16109
+ major: Number(m[2]),
16110
+ minor: Number(m[3]),
16111
+ patch: m[4] === void 0 ? 0 : Number(m[4])
16112
+ };
16113
+ if (newest === null || comparePins(pin, newest.pin) > 0) {
16114
+ newest = { pin, start: ref2.start + m.index, end: ref2.start + m.index + m[0].length };
16115
+ }
16116
+ }
16117
+ }
16118
+ if (lint !== null && newest !== null && newest.pin.major === lint.major && newest.pin.minor > lint.minor) {
16119
+ out.push({
16120
+ code: WcsDiagnosticCode.LintVersionBehind,
16121
+ start: newest.start,
16122
+ end: newest.end,
16123
+ severity: "warning",
16124
+ message: msgs.lintVersionBehind(newest.pin.spec, newest.pin.version, `${newest.pin.major}.${newest.pin.minor}`, ENGINE_VERSION)
16125
+ });
16126
+ }
16127
+ if (!loads.own || loads.unclear) return out;
16128
+ const autoloader = loads.autoloader;
16129
+ const components = loads.mapKeys.filter((k) => k.startsWith("@components/"));
16130
+ const defined = new Set([...loads.definedTags].map((t) => packageOfTag(t)).filter((p) => p !== void 0));
16131
+ const byPackage = /* @__PURE__ */ new Map();
16132
+ for (const tag of findWcsTags(scan)) {
16133
+ const pkg = packageOfTag(tag.name);
16134
+ if (pkg === void 0 || loads.pkgs.has(pkg) || defined.has(pkg)) continue;
16135
+ if (autoloader && tag.name !== "wcs-autoloader" && components.some((k) => coversTag(k, tag.name))) continue;
16136
+ const seen2 = byPackage.get(pkg);
16137
+ if (seen2 === void 0) byPackage.set(pkg, { tags: [tag.name], start: tag.start, end: tag.end });
16138
+ else if (!seen2.tags.includes(tag.name)) seen2.tags.push(tag.name);
16139
+ }
16140
+ const version3 = suggestedVersion(loads.references);
16141
+ for (const [pkg, at2] of byPackage) {
16142
+ out.push({
16143
+ code: WcsDiagnosticCode.TagPackageMissing,
16144
+ start: at2.start,
16145
+ end: at2.end,
16146
+ severity: "warning",
16147
+ tag: at2.tags[0],
16148
+ message: msgs.tagPackageMissing(at2.tags, `@wcstack/${pkg}`, `https://esm.run/@wcstack/${pkg}${version3 === null ? "" : `@${version3}`}/auto`)
16149
+ });
16150
+ }
16151
+ return out;
16152
+ }
16153
+ function comparePins(a, b) {
16154
+ return a.major - b.major || a.minor - b.minor || a.patch - b.patch;
16155
+ }
16156
+ function parseVersion(version3) {
16157
+ const m = /^(\d+)\.(\d+)/.exec(version3);
16158
+ return m === null ? null : { major: Number(m[1]), minor: Number(m[2]) };
16159
+ }
16160
+ function suggestedVersion(references) {
16161
+ const versions = /* @__PURE__ */ new Set();
16162
+ for (const ref2 of references) {
16163
+ for (const m of ref2.text.matchAll(PINNED)) versions.add(m[0].slice(m[0].lastIndexOf("@") + 1));
16164
+ }
16165
+ return versions.size === 1 ? [...versions][0] : null;
16166
+ }
16167
+ function coversTag(key, tag) {
16168
+ const body = key.slice("@components/".length);
16169
+ if (body.endsWith("/")) {
16170
+ const prefix = body.slice(0, -1).replace(/\|[^/]*$/, "").replace(/\//g, "-");
16171
+ return prefix !== "" && tag.startsWith(`${prefix}-`);
16172
+ }
16173
+ return body.replace(/\|.*$/, "") === tag;
16174
+ }
16175
+ function markupOf(scan) {
16176
+ return scan.replace(
16177
+ /(<(script|style)\b[^>]*>)([\s\S]*?)(<\/\2\s*>)/gi,
16178
+ (_m, open, _name, body, close) => open + " ".repeat(body.length) + close
16179
+ );
16180
+ }
16181
+ function findWcsTags(scan) {
16182
+ const out = [];
16183
+ for (const m of markupOf(scan).matchAll(/<(wcs-[a-z0-9-]+)(?=[\s/>])/gi)) {
16184
+ const start = m.index + 1;
16185
+ out.push({ name: m[1].toLowerCase(), start, end: start + m[1].length });
16186
+ }
16187
+ return out;
16188
+ }
16189
+ function autoloaderModules(scan, imports) {
16190
+ const markup = markupOf(scan);
16191
+ const tags = /* @__PURE__ */ new Set();
16192
+ for (const m of markup.matchAll(/<([a-z][a-z0-9]*-[a-z0-9-]*)(?=[\s/>])/gi)) tags.add(m[1].toLowerCase());
16193
+ for (const m of markup.matchAll(/\sis\s*=\s*["']([a-z][a-z0-9]*-[a-z0-9-]*)["']/gi)) tags.add(m[1].toLowerCase());
16194
+ for (const tag of tags) if (tag.startsWith("wcs-")) tags.delete(tag);
16195
+ const out = [];
16196
+ for (const [key, value] of imports) {
16197
+ if (!key.startsWith("@components/") || isUrl(value)) continue;
16198
+ const body = key.slice("@components/".length);
16199
+ if (!body.endsWith("/")) {
16200
+ if (!body.startsWith("wcs-")) out.push(pagePath(value));
16201
+ continue;
16202
+ }
16203
+ const prefix = body.slice(0, -1).replace(/\|[^/]*$/, "").replace(/\//g, "-");
16204
+ for (const tag of tags) {
16205
+ if (prefix !== "" && tag.startsWith(`${prefix}-`)) out.push(pagePath(`${value}${tag.slice(prefix.length + 1)}.js`));
16206
+ }
16207
+ }
16208
+ return out;
16209
+ }
16210
+ function collectPageLoads(scan, fileReader) {
16211
+ const loads = {
16212
+ pkgs: /* @__PURE__ */ new Set(),
16213
+ definedTags: /* @__PURE__ */ new Set(),
16214
+ own: false,
16215
+ unclear: false,
16216
+ autoloader: false,
16217
+ imports: /* @__PURE__ */ new Map(),
16218
+ mapKeys: [],
16219
+ references: []
16220
+ };
16221
+ const name = (text3, own2) => {
16222
+ const pkgs = namedPackages(text3);
16223
+ for (const p of pkgs) loads.pkgs.add(p);
16224
+ if (own2 && pkgs.length > 0) loads.own = true;
16225
+ };
16226
+ const locals = [];
16227
+ const specifiers = [];
16228
+ const scriptRegex = /<script\b((?:"[^"]*"|'[^']*'|[^>"'])*)>([\s\S]*?)<\/script\s*>/gi;
16229
+ let match;
16230
+ while ((match = scriptRegex.exec(scan)) !== null) {
16231
+ const attrs = match[1];
16232
+ const type = (attrValue(attrs, "type") ?? "").trim().toLowerCase();
16233
+ const src = extractSrc(`<script${attrs}>`);
16234
+ const bodyStart = match.index + match[0].indexOf(">") + 1;
16235
+ if (src !== null) {
16236
+ const start = match.index + src.offsetInTag;
16237
+ loads.references.push({ text: src.value, start });
16238
+ name(src.value, true);
16239
+ if (namedPackages(src.value).length === 0 && !isUrl(src.value)) locals.push(pagePath(src.value));
16240
+ continue;
16241
+ }
16242
+ if (type === "importmap") {
16243
+ readImportMap(match[2], bodyStart, loads, name);
16244
+ continue;
16245
+ }
16246
+ if (type !== "" && type !== "module" && !/^(?:text|application)\/(?:x-)?(?:javascript|ecmascript)$/.test(type)) continue;
16247
+ const body = blankJsComments(match[2]);
16248
+ name(body, false);
16249
+ for (const im of body.matchAll(/(?:\bfrom\s*|\bimport\s*\(?\s*)(["'])([^"'\n]*)\1/g)) {
16250
+ const start = bodyStart + im.index + im[0].indexOf(im[1]) + 1;
16251
+ loads.references.push({ text: im[2], start });
16252
+ name(im[2], true);
16253
+ specifiers.push(im[2]);
16254
+ }
16255
+ }
16256
+ for (const m of scan.matchAll(/<link\b((?:"[^"]*"|'[^']*'|[^>"'])*)>/gi)) {
16257
+ if (!/^\s*modulepreload\s*$/i.test(attrValue(m[1], "rel") ?? "")) continue;
16258
+ const href = attrValue(m[1], "href");
16259
+ if (href !== null) name(href, false);
16260
+ }
16261
+ for (const spec of specifiers) {
16262
+ if (namedPackages(spec).length > 0) continue;
16263
+ const target = resolveSpecifier(spec, loads.imports);
16264
+ if (target === void 0 || namedPackages(target).length > 0 || isUrl(target)) continue;
16265
+ if (isRelative(target)) locals.push(pagePath(target));
16266
+ }
16267
+ loads.autoloader = loads.pkgs.has("autoloader") || /<wcs-autoloader\b/i.test(scan);
16268
+ if (loads.autoloader) locals.push(...autoloaderModules(scan, loads.imports));
16269
+ if (locals.length > 0) readLocalModules(locals, fileReader, loads);
16270
+ return loads;
16271
+ }
16272
+ function readImportMap(body, bodyStart, loads, name) {
16273
+ for (const m of body.matchAll(/"((?:[^"\\]|\\.)*)"/g)) {
16274
+ loads.references.push({ text: m[1], start: bodyStart + m.index + 1 });
16275
+ name(m[1], true);
16276
+ }
16277
+ let parsed = null;
16278
+ try {
16279
+ parsed = JSON.parse(body);
16280
+ } catch {
16281
+ return;
16282
+ }
16283
+ const imports = parsed?.imports;
16284
+ if (imports === null || typeof imports !== "object") return;
16285
+ for (const [key, value] of Object.entries(imports)) {
16286
+ loads.mapKeys.push(key);
16287
+ if (typeof value === "string") loads.imports.set(key, value);
16288
+ }
16289
+ }
16290
+ function resolveSpecifier(spec, imports) {
16291
+ if (isUrl(spec) || isRelative(spec)) return spec;
16292
+ if (imports.has(spec)) return imports.get(spec);
16293
+ let best;
16294
+ for (const key of imports.keys()) {
16295
+ if (key.endsWith("/") && spec.startsWith(key) && (best === void 0 || key.length > best.length)) best = key;
16296
+ }
16297
+ return best === void 0 ? void 0 : imports.get(best) + spec.slice(best.length);
16298
+ }
16299
+ function isUrl(spec) {
16300
+ return /^[a-z][a-z0-9+.-]*:/i.test(spec) || spec.startsWith("//");
16301
+ }
16302
+ function isRelative(spec) {
16303
+ return spec.startsWith("./") || spec.startsWith("../") || spec.startsWith("/");
16304
+ }
16305
+ function pagePath(src) {
16306
+ return isRelative(src) ? src : `./${src}`;
16307
+ }
16308
+ function readLocalModules(entries, fileReader, loads) {
16309
+ if (fileReader === void 0) {
16310
+ loads.unclear = true;
16311
+ return;
16312
+ }
16313
+ const seen2 = /* @__PURE__ */ new Set();
16314
+ const queue = entries.map((spec) => ({ spec, from: "", depth: 0 }));
16315
+ while (queue.length > 0) {
16316
+ const { spec, from, depth } = queue.shift();
16317
+ const path = joinModulePath(from, spec);
16318
+ if (seen2.has(path)) continue;
16319
+ if (seen2.size >= MAX_FILES2 || depth > MAX_DEPTH) {
16320
+ loads.unclear = true;
16321
+ return;
16322
+ }
16323
+ seen2.add(path);
16324
+ const text3 = fileReader(path);
16325
+ if (text3 === void 0) {
16326
+ loads.unclear = true;
16327
+ return;
16328
+ }
16329
+ for (const p of namedPackages(text3)) loads.pkgs.add(p);
16330
+ for (const m of text3.matchAll(/["'`](wcs-[a-z0-9-]+)["'`]/g)) loads.definedTags.add(m[1]);
16331
+ for (const im of text3.matchAll(/(?:\bfrom\s*|\bimport\s*\(?\s*)(["'])([^"'\n]*)\1/g)) {
16332
+ if (namedPackages(im[2]).length > 0) continue;
16333
+ const target = resolveSpecifier(im[2], loads.imports);
16334
+ if (target === void 0 || namedPackages(target).length > 0 || isUrl(target) || !isRelative(target)) continue;
16335
+ queue.push({ spec: target, from: isRelative(im[2]) ? path : "", depth: depth + 1 });
16336
+ }
16337
+ }
16338
+ }
16339
+
15953
16340
  // src/service/watchDeclarationValidator.ts
15954
16341
  var STATE_NAME_SEPARATOR = "@";
15955
16342
  function validateWatchDeclarations(html, stateTagName = "wcs-state", locale2, fileReader) {
@@ -17940,7 +18327,7 @@ function validateScriptReads(html, stateTagName = "wcs-state", locale2, fileRead
17940
18327
  code: WcsDiagnosticCode.PathDynamicUnknown,
17941
18328
  start: block.contentStart + span.start,
17942
18329
  end: block.contentStart + span.end,
17943
- message: msgs.pathDynamicUnknownValue(path, count, candidate.opaque?.name, candidate.opaque?.from),
18330
+ message: candidate.opaque?.spread !== void 0 ? msgs.pathDynamicUnknownObjectSpread(path, count, candidate.opaque.spread, candidate.opaque.from) : msgs.pathDynamicUnknownValue(path, count, candidate.opaque?.name, candidate.opaque?.from),
17944
18331
  severity: "info"
17945
18332
  });
17946
18333
  }
@@ -18179,6 +18566,7 @@ function validateText(text3, options, applicationSchema) {
18179
18566
  out.push(...validateAriaAttributes(text3, bindAttribute, locale2));
18180
18567
  out.push(...validateLiveRegions(text3, bindAttribute, stateTagName, locale2));
18181
18568
  out.push(...validateDocumentEnv(text3, locale2));
18569
+ out.push(...validatePackageLoads(text3, locale2, fileReader));
18182
18570
  out.push(...validateSemantics(text3, stateTagName, locale2, bindAttribute));
18183
18571
  out.push(...validateScriptStateUses(text3, stateTagName, locale2, bindAttribute));
18184
18572
  out.push(...validateScriptReads(text3, stateTagName, locale2, fileReader, applicationSchema, bindAttribute));
@@ -643,7 +643,7 @@ function loadSchemaCore() {
643
643
  return cached;
644
644
  }
645
645
 
646
- var version = "4.10.0";
646
+ var version = "4.11.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.10.0";
28
+ var version = "4.11.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.10.0",
3
+ "version": "4.11.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",