@wcstack/typescript 1.32.0 → 2.0.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.
@@ -121,7 +121,11 @@ var WcsDiagnosticCode = {
121
121
  // --- deprecations ---
122
122
  // 名前付き State(`<wcs-state name>` / `path@name`)。v2 でマウント(`mount=` と接頭辞付きパス)に
123
123
  // 置き換わる(docs/state-mount-design.md D16)。1.x では warning、v2 では parse error と同時に error。
124
- NamedStateDeprecated: "wcs/named-state-deprecated"
124
+ NamedStateDeprecated: "wcs/named-state-deprecated",
125
+ // --- volume mount ---
126
+ // `<wcs-state mount="...">` の値が runtime の validateVolumeMountPath で raise する形
127
+ // (空・空セグメント・ワイルドカード・予約文字 $ # @)。runtime と同条件・同文言(v2)。
128
+ MountPathInvalid: "wcs/mount-path-invalid"
125
129
  };
126
130
  function sortDiagnostics(diagnostics) {
127
131
  const severityRank = { error: 0, warning: 1, info: 2 };
@@ -493,8 +497,8 @@ function parseJsonWithSpans(text) {
493
497
  }
494
498
 
495
499
  // src/core/sidecar/types.ts
496
- var SUPPORTED_SCHEMA_VERSION = 1;
497
- var SUPPORTED_NAMESPACE_VERSION = 1;
500
+ var SUPPORTED_SCHEMA_VERSION = 2;
501
+ var SUPPORTED_NAMESPACE_VERSION = 2;
498
502
 
499
503
  // src/core/sidecar/loader.ts
500
504
  var NAMESPACE_KEYS = ["wcstack.types", "wcstack.async", "wcstack.platformCapabilities", "wcstack.application"];
@@ -531,10 +535,11 @@ function loadManifest(artifact) {
531
535
  return { artifact, manifest: null, ctx, spans: parsed.spans };
532
536
  }
533
537
  if (obj.schemaVersion !== SUPPORTED_SCHEMA_VERSION) {
538
+ const migration = obj.schemaVersion === 1 ? ` schemaVersion 1 (states[name]) predates v2's single state tree \u2014 regenerate with \`wcs-schema emit\`.` : "";
534
539
  ctx.add(
535
540
  WcsDiagnosticCode.ManifestSchemaVersion,
536
541
  pointer("schemaVersion"),
537
- `Unsupported schemaVersion ${obj.schemaVersion}; this reader supports ${SUPPORTED_SCHEMA_VERSION}.`,
542
+ `Unsupported schemaVersion ${obj.schemaVersion}; this reader supports ${SUPPORTED_SCHEMA_VERSION}.${migration}`,
538
543
  "error"
539
544
  );
540
545
  return { artifact, manifest: null, ctx, spans: parsed.spans };
@@ -581,11 +586,10 @@ function validateLoadedSchemas(loaded) {
581
586
  validateComponentSchemas(tag, component, loaded.ctx);
582
587
  }
583
588
  const application = loaded.manifest.manifestExtensions?.["wcstack.application"];
584
- for (const [name, entry] of Object.entries(application?.states ?? {})) {
585
- const schema = entry?.stateSchema;
586
- if (schema === null || typeof schema !== "object" || Array.isArray(schema)) continue;
587
- const ptr = `${pointer("manifestExtensions", "wcstack.application", "states", name)}/stateSchema`;
588
- validateSchemaSubset(schema, ptr, loaded.ctx, schema.$defs ?? {});
589
+ const stateSchema = application?.stateSchema;
590
+ if (stateSchema !== void 0 && stateSchema !== null && typeof stateSchema === "object" && !Array.isArray(stateSchema)) {
591
+ const ptr = pointer("manifestExtensions", "wcstack.application", "stateSchema");
592
+ validateSchemaSubset(stateSchema, ptr, loaded.ctx, stateSchema.$defs ?? {});
589
593
  }
590
594
  }
591
595
  function validateComponentSchemas(tag, component, ctx) {
@@ -1218,7 +1222,6 @@ var MAX_WILDCARD_DEPTH = 128;
1218
1222
  var BINDING_SEPARATOR = ";";
1219
1223
  var PROP_VALUE_SEPARATOR = ":";
1220
1224
  var MODIFIER_SEPARATOR = "#";
1221
- var STATE_NAME_SEPARATOR = "@";
1222
1225
  var FILTER_SEPARATOR = "|";
1223
1226
  var MODIFIER_PREVENT = "prevent";
1224
1227
  var MODIFIER_STOP = "stop";
@@ -1276,7 +1279,6 @@ function getWcsManifest() {
1276
1279
  binding: BINDING_SEPARATOR,
1277
1280
  propValue: PROP_VALUE_SEPARATOR,
1278
1281
  modifier: MODIFIER_SEPARATOR,
1279
- stateName: STATE_NAME_SEPARATOR,
1280
1282
  filter: FILTER_SEPARATOR
1281
1283
  },
1282
1284
  // 正本 STRUCTURAL_BINDING_TYPE_SET から導出(手書きの二重定義を排除)。
@@ -1349,7 +1351,7 @@ var RESERVED_COMMAND_TOKENS_KEY = "$commandTokens";
1349
1351
  var RESERVED_EVENT_TOKENS_KEY = "$eventTokens";
1350
1352
  var RESERVED_LIST_KEYS_KEY = "$listKeys";
1351
1353
  var RESERVED_WATCH_KEY = "$watch";
1352
- function analyzeStatePaths(scriptContent, stateName = "default") {
1354
+ function analyzeStatePaths(scriptContent) {
1353
1355
  const objectContent = extractDefaultExportObject(scriptContent);
1354
1356
  if (!objectContent) return [];
1355
1357
  const paths = [];
@@ -1358,27 +1360,27 @@ function analyzeStatePaths(scriptContent, stateName = "default") {
1358
1360
  const pendingListKeys = [];
1359
1361
  for (const prop of topLevelProps) {
1360
1362
  if (prop.name.startsWith("$")) {
1361
- collectReservedKeyPaths(prop, paths, pendingStreamValues, pendingListKeys, stateName);
1363
+ collectReservedKeyPaths(prop, paths, pendingStreamValues, pendingListKeys);
1362
1364
  continue;
1363
1365
  }
1364
1366
  if (prop.kind === "method") {
1365
- paths.push({ path: prop.name, kind: "method", stateName });
1367
+ paths.push({ path: prop.name, kind: "method" });
1366
1368
  continue;
1367
1369
  }
1368
1370
  if (prop.kind === "getter") {
1369
- if (!paths.some((p) => p.stateName === stateName && p.path === prop.name)) {
1370
- paths.push({ path: prop.name, kind: "computed", stateName });
1371
+ if (!paths.some((p) => p.path === prop.name)) {
1372
+ paths.push({ path: prop.name, kind: "computed" });
1371
1373
  }
1372
1374
  continue;
1373
1375
  }
1374
- pushDataPropertyPaths(prop, paths, stateName);
1376
+ pushDataPropertyPaths(prop, paths);
1375
1377
  }
1376
1378
  for (const streamValue of pendingStreamValues) {
1377
- if (paths.some((p) => p.stateName === stateName && p.path === streamValue.name)) continue;
1378
- pushDataPropertyPaths(streamValue, paths, stateName);
1379
+ if (paths.some((p) => p.path === streamValue.name)) continue;
1380
+ pushDataPropertyPaths(streamValue, paths);
1379
1381
  }
1380
1382
  for (const listKeyEntry of pendingListKeys) {
1381
- pushListKeyPaths(listKeyEntry, paths, stateName);
1383
+ pushListKeyPaths(listKeyEntry, paths);
1382
1384
  }
1383
1385
  return paths;
1384
1386
  }
@@ -1465,7 +1467,7 @@ function findNonObjectWatch(scriptContent) {
1465
1467
  if (!isArrowFunction && !isWholeLiteral) return null;
1466
1468
  return span;
1467
1469
  }
1468
- function collectReservedKeyPaths(prop, paths, pendingStreamValues, pendingListKeys, stateName) {
1470
+ function collectReservedKeyPaths(prop, paths, pendingStreamValues, pendingListKeys) {
1469
1471
  if (prop.name === RESERVED_STREAMS_KEY && prop.kind === "data" && prop.value && isObjectLiteral(prop.value)) {
1470
1472
  const entries = parseTopLevelProperties(extractObjectContent(prop.value));
1471
1473
  for (const entry of entries) {
@@ -1477,20 +1479,20 @@ function collectReservedKeyPaths(prop, paths, pendingStreamValues, pendingListKe
1477
1479
  value: initial?.value,
1478
1480
  typeHint: initial?.typeHint
1479
1481
  });
1480
- paths.push({ path: `$streamStatus.${entry.name}`, kind: "data", typeHint: "string", stateName });
1481
- paths.push({ path: `$streamError.${entry.name}`, kind: "data", stateName });
1482
+ paths.push({ path: `$streamStatus.${entry.name}`, kind: "data", typeHint: "string" });
1483
+ paths.push({ path: `$streamError.${entry.name}`, kind: "data" });
1482
1484
  }
1483
1485
  return;
1484
1486
  }
1485
1487
  if (prop.name === RESERVED_COMMAND_TOKENS_KEY && prop.value) {
1486
1488
  for (const name of extractStringArrayItems(prop.value)) {
1487
- paths.push({ path: `$command.${name}`, kind: "command", stateName });
1489
+ paths.push({ path: `$command.${name}`, kind: "command" });
1488
1490
  }
1489
1491
  return;
1490
1492
  }
1491
1493
  if (prop.name === RESERVED_EVENT_TOKENS_KEY && prop.value) {
1492
1494
  for (const name of extractStringArrayItems(prop.value)) {
1493
- paths.push({ path: name, kind: "eventToken", stateName });
1495
+ paths.push({ path: name, kind: "eventToken" });
1494
1496
  }
1495
1497
  return;
1496
1498
  }
@@ -1502,22 +1504,22 @@ function collectReservedKeyPaths(prop, paths, pendingStreamValues, pendingListKe
1502
1504
  return;
1503
1505
  }
1504
1506
  }
1505
- function pushListKeyPaths(entry, paths, stateName) {
1507
+ function pushListKeyPaths(entry, paths) {
1506
1508
  const listPath = entry.name;
1507
1509
  const segments = listPath.split(".");
1508
1510
  if (listPath.length === 0 || segments.some((s) => s.length === 0) || segments[segments.length - 1] === "*") {
1509
1511
  return;
1510
1512
  }
1511
- const has = (path) => paths.some((p) => p.stateName === stateName && p.path === path);
1512
- if (!has(listPath)) paths.push({ path: listPath, kind: "data", typeHint: "array", stateName });
1513
- if (!has(`${listPath}.*`)) paths.push({ path: `${listPath}.*`, kind: "list", stateName });
1513
+ const has = (path) => paths.some((p) => p.path === path);
1514
+ if (!has(listPath)) paths.push({ path: listPath, kind: "data", typeHint: "array" });
1515
+ if (!has(`${listPath}.*`)) paths.push({ path: `${listPath}.*`, kind: "list" });
1514
1516
  if (!has(`${listPath}.length`)) {
1515
- paths.push({ path: `${listPath}.length`, kind: "data", typeHint: "number", stateName });
1517
+ paths.push({ path: `${listPath}.length`, kind: "data", typeHint: "number" });
1516
1518
  }
1517
1519
  const keyField = extractStringLiteralValue(entry.value);
1518
1520
  if (keyField === null || keyField.includes(".") || keyField.includes("*")) return;
1519
1521
  if (!has(`${listPath}.*.${keyField}`)) {
1520
- paths.push({ path: `${listPath}.*.${keyField}`, kind: "data", stateName });
1522
+ paths.push({ path: `${listPath}.*.${keyField}`, kind: "data" });
1521
1523
  }
1522
1524
  }
1523
1525
  function extractStringLiteralValue(value) {
@@ -1540,17 +1542,17 @@ function extractStringArrayItems(value) {
1540
1542
  return items;
1541
1543
  }
1542
1544
  var MAX_OBJECT_NEST_DEPTH = 5;
1543
- function pushDataPropertyPaths(prop, paths, stateName) {
1544
- pushDataPropertyPathsAt(prop.name, prop, paths, stateName, 0);
1545
+ function pushDataPropertyPaths(prop, paths) {
1546
+ pushDataPropertyPathsAt(prop.name, prop, paths, 0);
1545
1547
  }
1546
- function pushDataPropertyPathsAt(path, prop, paths, stateName, depth) {
1547
- paths.push({ path, kind: "data", typeHint: prop.typeHint, rawInitial: prop.value?.trim(), stateName });
1548
+ function pushDataPropertyPathsAt(path, prop, paths, depth) {
1549
+ paths.push({ path, kind: "data", typeHint: prop.typeHint, rawInitial: prop.value?.trim() });
1548
1550
  if (prop.value && isArrayLiteral(prop.value)) {
1549
- paths.push({ path: `${path}.*`, kind: "list", stateName });
1550
- paths.push({ path: `${path}.length`, kind: "data", typeHint: "number", stateName });
1551
+ paths.push({ path: `${path}.*`, kind: "list" });
1552
+ paths.push({ path: `${path}.length`, kind: "data", typeHint: "number" });
1551
1553
  if (depth >= MAX_OBJECT_NEST_DEPTH) return;
1552
1554
  for (const childProp of extractArrayElementDataProperties(prop.value)) {
1553
- pushDataPropertyPathsAt(`${path}.*.${childProp.name}`, childProp, paths, stateName, depth + 1);
1555
+ pushDataPropertyPathsAt(`${path}.*.${childProp.name}`, childProp, paths, depth + 1);
1554
1556
  }
1555
1557
  return;
1556
1558
  }
@@ -1559,11 +1561,11 @@ function pushDataPropertyPathsAt(path, prop, paths, stateName, depth) {
1559
1561
  const childProps = parseTopLevelProperties(extractObjectContent(prop.value));
1560
1562
  for (const childProp of childProps) {
1561
1563
  if (childProp.kind !== "data") continue;
1562
- pushDataPropertyPathsAt(`${path}.${childProp.name}`, childProp, paths, stateName, depth + 1);
1564
+ pushDataPropertyPathsAt(`${path}.${childProp.name}`, childProp, paths, depth + 1);
1563
1565
  }
1564
1566
  }
1565
1567
  }
1566
- function analyzeJsonPaths(jsonString, stateName = "default") {
1568
+ function analyzeJsonPaths(jsonString) {
1567
1569
  let data;
1568
1570
  try {
1569
1571
  data = JSON.parse(jsonString);
@@ -1572,31 +1574,31 @@ function analyzeJsonPaths(jsonString, stateName = "default") {
1572
1574
  }
1573
1575
  if (typeof data !== "object" || data === null || Array.isArray(data)) return [];
1574
1576
  const paths = [];
1575
- collectJsonPaths(data, "", paths, stateName, 0);
1577
+ collectJsonPaths(data, "", paths, 0);
1576
1578
  return paths;
1577
1579
  }
1578
- function collectJsonPaths(obj, prefix, paths, stateName, depth) {
1580
+ function collectJsonPaths(obj, prefix, paths, depth) {
1579
1581
  if (depth >= MAX_OBJECT_NEST_DEPTH) return;
1580
1582
  for (const [key, value] of Object.entries(obj)) {
1581
1583
  if (prefix === "" && key.startsWith("$")) continue;
1582
1584
  const path = prefix ? `${prefix}.${key}` : key;
1583
- pushJsonValuePaths(path, value, paths, stateName, depth);
1585
+ pushJsonValuePaths(path, value, paths, depth);
1584
1586
  }
1585
1587
  }
1586
- function pushJsonValuePaths(path, value, paths, stateName, depth) {
1587
- paths.push({ path, kind: "data", typeHint: inferJsonTypeHint(value), stateName });
1588
+ function pushJsonValuePaths(path, value, paths, depth) {
1589
+ paths.push({ path, kind: "data", typeHint: inferJsonTypeHint(value) });
1588
1590
  if (Array.isArray(value)) {
1589
- paths.push({ path: `${path}.*`, kind: "list", stateName });
1590
- paths.push({ path: `${path}.length`, kind: "data", typeHint: "number", stateName });
1591
+ paths.push({ path: `${path}.*`, kind: "list" });
1592
+ paths.push({ path: `${path}.length`, kind: "data", typeHint: "number" });
1591
1593
  if (depth >= MAX_OBJECT_NEST_DEPTH) return;
1592
1594
  if (value.length > 0 && typeof value[0] === "object" && value[0] !== null && !Array.isArray(value[0])) {
1593
1595
  const firstElement = value[0];
1594
1596
  for (const [childKey, childValue] of Object.entries(firstElement)) {
1595
- pushJsonValuePaths(`${path}.*.${childKey}`, childValue, paths, stateName, depth + 1);
1597
+ pushJsonValuePaths(`${path}.*.${childKey}`, childValue, paths, depth + 1);
1596
1598
  }
1597
1599
  }
1598
1600
  } else if (typeof value === "object" && value !== null) {
1599
- collectJsonPaths(value, path, paths, stateName, depth + 1);
1601
+ collectJsonPaths(value, path, paths, depth + 1);
1600
1602
  }
1601
1603
  }
1602
1604
  function inferJsonTypeHint(value) {
@@ -1836,23 +1838,21 @@ function inferTypeHint(valueStart) {
1836
1838
  if (v.startsWith("{")) return "object";
1837
1839
  return void 0;
1838
1840
  }
1839
- function analyzeSchemaPaths(schema, stateName = "default") {
1841
+ function analyzeSchemaPaths(schema) {
1840
1842
  const paths = [];
1841
1843
  const defs = schema.$defs ?? {};
1842
- collectSchemaObjectPaths(schema, "", paths, stateName, defs, 0);
1844
+ collectSchemaObjectPaths(schema, "", paths, defs, 0);
1843
1845
  return paths;
1844
1846
  }
1845
- function mergeSchemaCandidates(candidates, applicationStates) {
1846
- if (applicationStates === void 0 || applicationStates.size === 0) return candidates;
1847
+ function mergeSchemaCandidates(candidates, applicationSchema) {
1848
+ if (applicationSchema === void 0) return candidates;
1847
1849
  const schemaCandidates = [];
1848
1850
  const schemaKeys = /* @__PURE__ */ new Set();
1849
- for (const [stateName, schema] of applicationStates) {
1850
- for (const p of analyzeSchemaPaths(schema, stateName)) {
1851
- schemaCandidates.push(p);
1852
- schemaKeys.add(`${stateName} ${p.path}`);
1853
- }
1851
+ for (const p of analyzeSchemaPaths(applicationSchema)) {
1852
+ schemaCandidates.push(p);
1853
+ schemaKeys.add(p.path);
1854
1854
  }
1855
- const kept = candidates.filter((p) => !schemaKeys.has(`${p.stateName} ${p.path}`));
1855
+ const kept = candidates.filter((p) => !schemaKeys.has(p.path));
1856
1856
  return [...kept, ...schemaCandidates];
1857
1857
  }
1858
1858
  function derefSchemaNodes(node, defs) {
@@ -1904,7 +1904,7 @@ function schemaTypeHint(nodes) {
1904
1904
  }
1905
1905
  return hints.size === 0 ? void 0 : [...hints].join("|");
1906
1906
  }
1907
- function collectSchemaObjectPaths(node, prefix, paths, stateName, defs, depth) {
1907
+ function collectSchemaObjectPaths(node, prefix, paths, defs, depth) {
1908
1908
  if (depth >= MAX_OBJECT_NEST_DEPTH) return;
1909
1909
  const seen = /* @__PURE__ */ new Set();
1910
1910
  for (const n of derefSchemaNodes(node, defs)) {
@@ -1913,33 +1913,33 @@ function collectSchemaObjectPaths(node, prefix, paths, stateName, defs, depth) {
1913
1913
  if (seen.has(key)) continue;
1914
1914
  seen.add(key);
1915
1915
  const path = prefix ? `${prefix}.${key}` : key;
1916
- pushSchemaValuePaths(path, child, paths, stateName, defs, depth);
1916
+ pushSchemaValuePaths(path, child, paths, defs, depth);
1917
1917
  }
1918
1918
  }
1919
1919
  }
1920
- function pushSchemaValuePaths(path, node, paths, stateName, defs, depth) {
1920
+ function pushSchemaValuePaths(path, node, paths, defs, depth) {
1921
1921
  const nodes = derefSchemaNodes(node, defs);
1922
1922
  const typeHint = schemaTypeHint(nodes);
1923
- paths.push(withHint({ path, kind: "data", stateName, fromSchema: true }, typeHint));
1923
+ paths.push(withHint({ path, kind: "data", fromSchema: true }, typeHint));
1924
1924
  const items = nodes.map((n) => n.items).find((i) => i !== void 0 && i !== null && typeof i === "object");
1925
1925
  const isArray = items !== void 0 || (typeHint?.split("|").includes("array") ?? false);
1926
1926
  if (isArray) {
1927
1927
  const itemNodes = items !== void 0 ? derefSchemaNodes(items, defs) : [];
1928
- paths.push(withHint({ path: `${path}.*`, kind: "list", stateName, fromSchema: true }, schemaTypeHint(itemNodes)));
1929
- paths.push({ path: `${path}.length`, kind: "data", typeHint: "number", stateName, fromSchema: true });
1928
+ paths.push(withHint({ path: `${path}.*`, kind: "list", fromSchema: true }, schemaTypeHint(itemNodes)));
1929
+ paths.push({ path: `${path}.length`, kind: "data", typeHint: "number", fromSchema: true });
1930
1930
  if (depth >= MAX_OBJECT_NEST_DEPTH) return;
1931
1931
  const seen = /* @__PURE__ */ new Set();
1932
1932
  for (const n of itemNodes) {
1933
1933
  for (const [childKey, childNode] of Object.entries(n.properties ?? {})) {
1934
1934
  if (seen.has(childKey)) continue;
1935
1935
  seen.add(childKey);
1936
- pushSchemaValuePaths(`${path}.*.${childKey}`, childNode, paths, stateName, defs, depth + 1);
1936
+ pushSchemaValuePaths(`${path}.*.${childKey}`, childNode, paths, defs, depth + 1);
1937
1937
  }
1938
1938
  }
1939
1939
  return;
1940
1940
  }
1941
1941
  if (nodes.some((n) => n.properties !== void 0)) {
1942
- collectSchemaObjectPaths(node, path, paths, stateName, defs, depth + 1);
1942
+ collectSchemaObjectPaths(node, path, paths, defs, depth + 1);
1943
1943
  }
1944
1944
  }
1945
1945
  function withHint(candidate, typeHint) {
@@ -1963,7 +1963,7 @@ function parseWcsScriptBlocks(html, stateTagName = "wcs-state") {
1963
1963
  pos++;
1964
1964
  continue;
1965
1965
  }
1966
- const stateName = extractAttribute(wcsMatch.tagContent, "name") ?? "default";
1966
+ const mountPath = extractAttribute(wcsMatch.tagContent, "mount");
1967
1967
  pos = wcsMatch.end;
1968
1968
  const wcsCloseIdx = findCloseTag(html, pos, stateTagName);
1969
1969
  const wcsEnd = wcsCloseIdx === -1 ? len : wcsCloseIdx;
@@ -1995,7 +1995,7 @@ function parseWcsScriptBlocks(html, stateTagName = "wcs-state") {
1995
1995
  contentStart,
1996
1996
  contentEnd,
1997
1997
  content: html.slice(contentStart, contentEnd),
1998
- stateName
1998
+ mountPath
1999
1999
  });
2000
2000
  pos = html.indexOf(">", scriptCloseIdx) + 1;
2001
2001
  if (pos === 0) break;
@@ -2024,7 +2024,7 @@ function parseWcsStateElements(html, stateTagName = "wcs-state") {
2024
2024
  pos++;
2025
2025
  continue;
2026
2026
  }
2027
- const stateName = extractAttribute(wcsMatch.tagContent, "name") ?? "default";
2027
+ const mountPath = extractAttribute(wcsMatch.tagContent, "mount");
2028
2028
  const jsonAttr = extractAttribute(wcsMatch.tagContent, "json") ?? void 0;
2029
2029
  const stateAttr = extractAttribute(wcsMatch.tagContent, "state") ?? void 0;
2030
2030
  const srcAttr = extractAttribute(wcsMatch.tagContent, "src") ?? void 0;
@@ -2061,12 +2061,12 @@ function parseWcsStateElements(html, stateTagName = "wcs-state") {
2061
2061
  contentStart,
2062
2062
  contentEnd: scriptCloseIdx,
2063
2063
  content: html.slice(contentStart, scriptCloseIdx),
2064
- stateName
2064
+ mountPath
2065
2065
  });
2066
2066
  pos = html.indexOf(">", scriptCloseIdx) + 1;
2067
2067
  if (pos === 0) break;
2068
2068
  }
2069
- elements.push({ stateName, jsonAttr, stateAttr, srcAttr, scriptBlocks, tagStart, tagEnd });
2069
+ elements.push({ mountPath, jsonAttr, stateAttr, srcAttr, scriptBlocks, tagStart, tagEnd });
2070
2070
  pos = wcsEnd;
2071
2071
  if (wcsCloseIdx !== -1) {
2072
2072
  const closeEnd = html.indexOf(">", wcsCloseIdx);
@@ -2177,33 +2177,45 @@ function getStatePathsFromHtml(html, stateTagName = "wcs-state", fileReader) {
2177
2177
  return allPaths;
2178
2178
  }
2179
2179
  function resolveElementPaths(element, html, fileReader) {
2180
+ const raw = resolveElementPathsRaw(element, html, fileReader);
2181
+ if (element.mountPath === null) return raw;
2182
+ const prefix = element.mountPath + ".";
2183
+ const out = [];
2184
+ for (const p of raw) {
2185
+ if (p.path.startsWith("$")) continue;
2186
+ if (p.kind === "method" || p.kind === "eventToken") continue;
2187
+ out.push({ ...p, path: prefix + p.path });
2188
+ }
2189
+ return out;
2190
+ }
2191
+ function resolveElementPathsRaw(element, html, fileReader) {
2180
2192
  if (element.stateAttr) {
2181
2193
  const jsonContent = findScriptJsonById(html, element.stateAttr);
2182
2194
  if (jsonContent) {
2183
- const paths = analyzeJsonPaths(jsonContent, element.stateName);
2195
+ const paths = analyzeJsonPaths(jsonContent);
2184
2196
  if (paths.length > 0) return paths;
2185
2197
  }
2186
2198
  }
2187
2199
  if (element.srcAttr && fileReader) {
2188
- const paths = resolveSrcAttribute(element.srcAttr, element.stateName, fileReader);
2200
+ const paths = resolveSrcAttribute(element.srcAttr, fileReader);
2189
2201
  if (paths.length > 0) return paths;
2190
2202
  }
2191
2203
  if (element.jsonAttr) {
2192
- const paths = analyzeJsonPaths(element.jsonAttr, element.stateName);
2204
+ const paths = analyzeJsonPaths(element.jsonAttr);
2193
2205
  if (paths.length > 0) return paths;
2194
2206
  }
2195
2207
  if (element.scriptBlocks.length > 0) {
2196
2208
  return element.scriptBlocks.flatMap(
2197
- (block) => analyzeStatePaths(block.content, block.stateName)
2209
+ (block) => analyzeStatePaths(block.content)
2198
2210
  );
2199
2211
  }
2200
2212
  return [];
2201
2213
  }
2202
- function resolveSrcAttribute(srcPath, stateName, fileReader) {
2214
+ function resolveSrcAttribute(srcPath, fileReader) {
2203
2215
  if (srcPath.endsWith(".json")) {
2204
2216
  const content = fileReader(srcPath);
2205
2217
  if (content) {
2206
- return analyzeJsonPaths(content, stateName);
2218
+ return analyzeJsonPaths(content);
2207
2219
  }
2208
2220
  return [];
2209
2221
  }
@@ -2211,18 +2223,18 @@ function resolveSrcAttribute(srcPath, stateName, fileReader) {
2211
2223
  const tsPath = srcPath.replace(/\.js$/, ".ts");
2212
2224
  const tsContent = fileReader(tsPath);
2213
2225
  if (tsContent) {
2214
- return analyzeStatePaths(tsContent, stateName);
2226
+ return analyzeStatePaths(tsContent);
2215
2227
  }
2216
2228
  const jsContent = fileReader(srcPath);
2217
2229
  if (jsContent) {
2218
- return analyzeStatePaths(jsContent, stateName);
2230
+ return analyzeStatePaths(jsContent);
2219
2231
  }
2220
2232
  return [];
2221
2233
  }
2222
2234
  if (srcPath.endsWith(".ts")) {
2223
2235
  const content = fileReader(srcPath);
2224
2236
  if (content) {
2225
- return analyzeStatePaths(content, stateName);
2237
+ return analyzeStatePaths(content);
2226
2238
  }
2227
2239
  return [];
2228
2240
  }
@@ -2397,8 +2409,20 @@ var ja = {
2397
2409
  devtoolsAfterState: () => `@wcstack/devtools/auto \u306F @wcstack/state/auto \u3088\u308A\u5148\u306B\u8AAD\u307F\u8FBC\u3093\u3067\u304F\u3060\u3055\u3044\uFF08\u5F8C\u3060\u3068\u914D\u7DDA\u53F0\u5E33\u304C\u30E9\u30A4\u30D6\u3067 captured \u3055\u308C\u307E\u305B\u3093\uFF09`,
2398
2410
  baseHrefMissing: () => `@wcstack/router \u3092\u4F7F\u3046 SPA \u306B\u306F <head> \u5185\u306E <base href="/"> \u304C\u5FC5\u8981\u3067\u3059\uFF08\u7121\u3044\u3068\u30C7\u30A3\u30FC\u30D7\u30EA\u30F3\u30AF\u3067 basename \u304C\u8AA4\u5C0E\u51FA\u3055\u308C\u307E\u3059\uFF09`,
2399
2411
  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`,
2400
- namedStateAttrDeprecated: (name) => `<wcs-state name="${name}"> \u306F v2 \u3067\u5EC3\u6B62\u3055\u308C\u307E\u3059\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`,
2401
- namedStatePathDeprecated: (name) => name === "default" ? `"@default" \u306F\u4E0D\u8981\u3067\u3001v2 \u3067\u5EC3\u6B62\u3055\u308C\u307E\u3059\u3002"@default" \u3092\u5916\u3057\u3066\u304F\u3060\u3055\u3044\uFF08docs/state-mount-design.md \xA79\uFF09` : `"@${name}" \u306B\u3088\u308B state \u6307\u5B9A\u306F v2 \u3067\u5EC3\u6B62\u3055\u308C\u307E\u3059\u3002\u30DE\u30A6\u30F3\u30C8\u3057\u305F\u30C4\u30EA\u30FC\u3092 "${name}.<path>" \u3067\u53C2\u7167\u3057\u3066\u304F\u3060\u3055\u3044\uFF08docs/state-mount-design.md \xA79\uFF09`
2412
+ 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`,
2413
+ namedStatePathDeprecated: (name) => name === "default" ? `"@default" \u30BB\u30EC\u30AF\u30BF\u306F v2 \u3067\u64A4\u53BB\u3055\u308C\u307E\u3057\u305F\u3002"@default" \u3092\u5916\u3057\u3066\u304F\u3060\u3055\u3044\uFF08docs/state-mount-design.md \xA79\uFF09` : `"@name" \u30BB\u30EC\u30AF\u30BF\u306F v2 \u3067\u64A4\u53BB\u3055\u308C\u307E\u3057\u305F\uFF081 root 1 \u30C4\u30EA\u30FC\uFF09\u3002\u30DE\u30A6\u30F3\u30C8\u3057\u305F\u30C4\u30EA\u30FC\u3092 "${name}.<path>" \u3067\u53C2\u7167\u3057\u3066\u304F\u3060\u3055\u3044\uFF08docs/state-mount-design.md \xA79\uFF09`,
2414
+ mountPathInvalid: (problem, mountPath) => {
2415
+ switch (problem) {
2416
+ case "empty":
2417
+ return `"mount" \u306B\u306F\u7A7A\u3067\u306A\u3044\u30C4\u30EA\u30FC\u30D1\u30B9\u304C\u5FC5\u8981\u3067\u3059\uFF08runtime: "mount" requires a non-empty tree path.\uFF09`;
2418
+ case "emptySegment":
2419
+ return `"mount" \u30D1\u30B9 "${mountPath}" \u306B\u7A7A\u306E\u30BB\u30B0\u30E1\u30F3\u30C8\u304C\u3042\u308A\u307E\u3059\uFF08runtime: has an empty segment.\uFF09`;
2420
+ case "wildcard":
2421
+ return `"mount" \u30D1\u30B9 "${mountPath}" \u306F\u9759\u7684\u3067\u306A\u3051\u308C\u3070\u306A\u308A\u307E\u305B\u3093 \u2014 \u30EF\u30A4\u30EB\u30C9\u30AB\u30FC\u30C9\u306F\u4F7F\u3048\u307E\u305B\u3093\uFF08runtime: must be static.\uFF09`;
2422
+ default:
2423
+ return `"mount" \u30D1\u30B9 "${mountPath}" \u306B\u4E88\u7D04\u6587\u5B57\uFF08$, #, @\uFF09\u306F\u4F7F\u3048\u307E\u305B\u3093\uFF08runtime: must not use reserved characters.\uFF09`;
2424
+ }
2425
+ }
2402
2426
  };
2403
2427
  var EN_EXPECTED_LABEL = {
2404
2428
  array: "an array-typed path",
@@ -2456,8 +2480,20 @@ var en = {
2456
2480
  devtoolsAfterState: () => `Load @wcstack/devtools/auto BEFORE @wcstack/state/auto (otherwise the wiring ledger is not captured live)`,
2457
2481
  baseHrefMissing: () => `An SPA using @wcstack/router needs <base href="/"> in <head> (without it, deep links misderive the basename)`,
2458
2482
  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`,
2459
- namedStateAttrDeprecated: (name) => `<wcs-state name="${name}"> is deprecated and will be removed in v2. Mount the state onto the root tree with <wcs-state mount="${name}"> and read it as "${name}.<path>" (docs/state-mount-design.md \xA79)`,
2460
- namedStatePathDeprecated: (name) => name === "default" ? `The "@default" selector is redundant and will be removed in v2; drop it (docs/state-mount-design.md \xA79)` : `The "@${name}" state selector is deprecated and will be removed in v2. Read the mounted tree as "${name}.<path>" instead (docs/state-mount-design.md \xA79)`
2483
+ 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)`,
2484
+ namedStatePathDeprecated: (name) => name === "default" ? `The "@default" selector was removed in v2 \u2014 drop it (docs/state-mount-design.md \xA79)` : `The "@name" selector was removed in v2 \u2014 there is a single state tree. Mount the named state onto the tree (<wcs-state mount="...">) and read it as "${name}.<path>" (docs/state-mount-design.md \xA79)`,
2485
+ mountPathInvalid: (problem, mountPath) => {
2486
+ switch (problem) {
2487
+ case "empty":
2488
+ return `"mount" requires a non-empty tree path.`;
2489
+ case "emptySegment":
2490
+ return `"mount" path "${mountPath}" has an empty segment.`;
2491
+ case "wildcard":
2492
+ return `"mount" path "${mountPath}" must be static (wildcards are not allowed).`;
2493
+ default:
2494
+ return `"mount" path "${mountPath}" must not use reserved characters ($, #, @).`;
2495
+ }
2496
+ }
2461
2497
  };
2462
2498
  var CATALOGS = { ja, en };
2463
2499
  function getMessages(locale3) {
@@ -2466,16 +2502,10 @@ function getMessages(locale3) {
2466
2502
 
2467
2503
  // src/service/bindingValidator.ts
2468
2504
  var filterMap = new Map(BUILTIN_FILTERS.map((f) => [f.name, f]));
2469
- function validateBindings(html, attrName, stateTagName = "wcs-state", locale3, fileReader, applicationStates) {
2505
+ function validateBindings(html, attrName, stateTagName = "wcs-state", locale3, fileReader, applicationSchema) {
2470
2506
  const diagnostics = [];
2471
2507
  const msgs = getMessages(locale3);
2472
- const statePaths = mergeSchemaCandidates(getStatePathsFromHtml(html, stateTagName, fileReader), applicationStates);
2473
- const pathsByState = /* @__PURE__ */ new Map();
2474
- for (const p of statePaths) {
2475
- const list = pathsByState.get(p.stateName) ?? [];
2476
- list.push(p);
2477
- pathsByState.set(p.stateName, list);
2478
- }
2508
+ const statePaths = mergeSchemaCandidates(getStatePathsFromHtml(html, stateTagName, fileReader), applicationSchema);
2479
2509
  const attrs = findAllBindAttributes(html, attrName);
2480
2510
  let structuralTemplates = null;
2481
2511
  const getStructuralTemplates = () => {
@@ -2508,7 +2538,7 @@ function validateBindings(html, attrName, stateTagName = "wcs-state", locale3, f
2508
2538
  for (const binding of bindings) {
2509
2539
  const bindingStart = attr.valueStart + pos;
2510
2540
  const parsed = parseBindingExpression(binding);
2511
- const scopedPaths = pathsByState.get(parsed.targetState) ?? [];
2541
+ const scopedPaths = statePaths;
2512
2542
  const scopedPathSet = new Set(scopedPaths.map((p) => p.path));
2513
2543
  const propNoMod = parsed.property.replace(/#.*$/, "").trim();
2514
2544
  if (propNoMod === "...") {
@@ -2592,7 +2622,7 @@ function validateBindings(html, attrName, stateTagName = "wcs-state", locale3, f
2592
2622
  }
2593
2623
  }
2594
2624
  if (checkPath) {
2595
- const schema = applicationStates?.get(parsed.targetState);
2625
+ const schema = applicationSchema;
2596
2626
  const verdict = schema !== void 0 ? validateSchemaPathExistence(checkPath, pathTrimmed, scopedPaths, scopedPathSet, commandNames, schema, msgs) : toMissingVerdict(validatePathExistence(checkPath, pathTrimmed, scopedPaths, scopedPathSet, commandNames, msgs));
2597
2627
  if (verdict) {
2598
2628
  const pathOffset = binding.indexOf(parsed.path);
@@ -2721,7 +2751,7 @@ function validateBindings(html, attrName, stateTagName = "wcs-state", locale3, f
2721
2751
  if (typeReq && resultType !== typeReq.expected) {
2722
2752
  const pathOffset = binding.indexOf(parsed.path);
2723
2753
  const pathStart = bindingStart + pathOffset;
2724
- const schemaDefinite = typeReq.expected === "array" && parsed.filters.length === 0 && applicationStates?.has(parsed.targetState) === true && scopedPaths.some((p) => p.path === pathTrimmed && p.fromSchema === true);
2754
+ const schemaDefinite = typeReq.expected === "array" && parsed.filters.length === 0 && applicationSchema !== void 0 && scopedPaths.some((p) => p.path === pathTrimmed && p.fromSchema === true);
2725
2755
  diagnostics.push({
2726
2756
  code: schemaDefinite ? WcsDiagnosticCode.PathTypeMismatch : WcsDiagnosticCode.BindingTypeExpectation,
2727
2757
  start: pathStart,
@@ -2775,7 +2805,7 @@ function splitBindingExpressions(value) {
2775
2805
  function parseBindingExpression(expr) {
2776
2806
  const colonIndex = expr.indexOf(":");
2777
2807
  if (colonIndex === -1) {
2778
- return { property: expr.trim(), path: null, targetState: "default", filters: [], inputFilters: [] };
2808
+ return { property: expr.trim(), path: null, filters: [], inputFilters: [] };
2779
2809
  }
2780
2810
  const rawProp = expr.slice(0, colonIndex);
2781
2811
  const propSegments = splitByPipe(rawProp);
@@ -2787,9 +2817,8 @@ function parseBindingExpression(expr) {
2787
2817
  const filterSegments = segments.slice(1);
2788
2818
  const atIndex = pathSegment.indexOf("@");
2789
2819
  const path = atIndex !== -1 ? pathSegment.slice(0, atIndex) : pathSegment;
2790
- const targetState = atIndex !== -1 ? pathSegment.slice(atIndex + 1).trim() || "default" : "default";
2791
2820
  const filters = parseFilterSegments(expr, filterSegments, colonIndex + 1 + pathSegment.length + 1);
2792
- return { property, path: path.trim() || null, targetState, filters, inputFilters };
2821
+ return { property, path: path.trim() || null, filters, inputFilters };
2793
2822
  }
2794
2823
  function parseFilterSegments(expr, segments, searchStart) {
2795
2824
  const filters = [];
@@ -3313,11 +3342,11 @@ function isInsideTag(html, offset, tagName) {
3313
3342
  }
3314
3343
 
3315
3344
  // src/service/templateSyntaxValidator.ts
3316
- function validateTemplateSyntax(html, stateTagName, bindAttrName = "data-wcs", locale3, fileReader, applicationStates) {
3345
+ function validateTemplateSyntax(html, stateTagName, bindAttrName = "data-wcs", locale3, fileReader, applicationSchema) {
3317
3346
  const diagnostics = [];
3318
3347
  const msgs = getMessages(locale3);
3319
- const allPaths = mergeSchemaCandidates(getStatePathsFromHtml(html, stateTagName, fileReader), applicationStates);
3320
- const defaultSchema = applicationStates?.get("default");
3348
+ const allPaths = mergeSchemaCandidates(getStatePathsFromHtml(html, stateTagName, fileReader), applicationSchema);
3349
+ const defaultSchema = applicationSchema;
3321
3350
  const missingVerdict = (path, displayPath, pathSet2, scoped) => {
3322
3351
  if (isValidTemplatePath(path, pathSet2, scoped)) return null;
3323
3352
  if (defaultSchema !== void 0 && !path.startsWith("$")) {
@@ -3327,7 +3356,7 @@ function validateTemplateSyntax(html, stateTagName, bindAttrName = "data-wcs", l
3327
3356
  return { code: WcsDiagnosticCode.BindingPathMissing, severity: "warning", message: msgs.pathMissing(displayPath) };
3328
3357
  };
3329
3358
  if (allPaths.length === 0) return diagnostics;
3330
- const defaultPaths = allPaths.filter((p) => p.stateName === "default");
3359
+ const defaultPaths = allPaths;
3331
3360
  const pathSet = new Set(defaultPaths.map((p) => p.path));
3332
3361
  const filterNameSet = new Set(BUILTIN_FILTERS.map((f) => f.name));
3333
3362
  const mustaches = findAllMustacheSyntax(html);
@@ -3353,9 +3382,8 @@ function validateTemplateSyntax(html, stateTagName, bindAttrName = "data-wcs", l
3353
3382
  }
3354
3383
  if (!item.expression) continue;
3355
3384
  const parts = item.expression.split("|");
3356
- let pathPart = (parts[0] || "").trim();
3357
- const atIdx = pathPart.indexOf("@");
3358
- if (atIdx !== -1) pathPart = pathPart.slice(0, atIdx).trim();
3385
+ const pathPart = (parts[0] || "").trim();
3386
+ if (pathPart.includes("@")) continue;
3359
3387
  const insideFor = item.insideTemplate && isInsideForTemplate(html, item.matchStart, bindAttrName);
3360
3388
  if (pathPart && !/^-?\d|^["'`]|^true$|^false$|^null$/.test(pathPart)) {
3361
3389
  if (!insideFor && pathPart.includes("*")) {
@@ -3376,7 +3404,7 @@ function validateTemplateSyntax(html, stateTagName, bindAttrName = "data-wcs", l
3376
3404
  severity: "warning"
3377
3405
  });
3378
3406
  }
3379
- if (insideFor && !pathPart.startsWith(".") && !pathPart.includes("@")) {
3407
+ if (insideFor && !pathPart.startsWith(".")) {
3380
3408
  const indexMatch = /^\$(\d+)$/.exec(pathPart);
3381
3409
  const needed = indexMatch !== null ? Number(indexMatch[1]) : pathPart.includes("*") ? countWildcardSegments(pathPart) : 0;
3382
3410
  if (needed > 0) {
@@ -4838,7 +4866,7 @@ function validateBindingAgainstContract(tagName, contract, parsed, property, sta
4838
4866
  return;
4839
4867
  }
4840
4868
  if (property === "trigger" && "trigger" in contract.inputs && parsed.path) {
4841
- const cand = findDataSlot(getPaths(), parsed.path, parsed.targetState);
4869
+ const cand = findDataSlot(getPaths(), parsed.path);
4842
4870
  if (cand?.rawInitial === "true") {
4843
4871
  diagnostics.push({
4844
4872
  code: WcsDiagnosticCode.TriggerSeededTruthy,
@@ -4852,7 +4880,7 @@ function validateBindingAgainstContract(tagName, contract, parsed, property, sta
4852
4880
  }
4853
4881
  }
4854
4882
  if (tagName === "wcs-storage" && property === "value" && !hasManual && parsed.path && !/(?:^|,)init=(?:element|auto)\b/.test(modifiers)) {
4855
- const cand = findDataSlot(getPaths(), parsed.path, parsed.targetState);
4883
+ const cand = findDataSlot(getPaths(), parsed.path);
4856
4884
  if (cand?.rawInitial !== void 0 && EMPTYISH_SEEDS.has(normalizeSeed(cand.rawInitial))) {
4857
4885
  diagnostics.push({
4858
4886
  code: WcsDiagnosticCode.StorageSeedClobber,
@@ -4866,8 +4894,8 @@ function validateBindingAgainstContract(tagName, contract, parsed, property, sta
4866
4894
  }
4867
4895
  }
4868
4896
  }
4869
- function findDataSlot(paths, path, stateName) {
4870
- return paths.find((c) => c.kind === "data" && c.path === path && c.stateName === stateName);
4897
+ function findDataSlot(paths, path) {
4898
+ return paths.find((c) => c.kind === "data" && c.path === path);
4871
4899
  }
4872
4900
  function normalizeSeed(raw) {
4873
4901
  const compact = raw.replace(/\s+/g, "");
@@ -5142,7 +5170,7 @@ function blankJsComments(code) {
5142
5170
  }
5143
5171
 
5144
5172
  // src/service/watchDeclarationValidator.ts
5145
- var STATE_NAME_SEPARATOR2 = "@";
5173
+ var STATE_NAME_SEPARATOR = "@";
5146
5174
  function validateWatchDeclarations(html, stateTagName = "wcs-state", locale3) {
5147
5175
  const msgs = getMessages(locale3);
5148
5176
  const out = [];
@@ -5159,7 +5187,7 @@ function validateWatchDeclarations(html, stateTagName = "wcs-state", locale3) {
5159
5187
  }
5160
5188
  const entries = analyzeWatchEntries(block.content);
5161
5189
  if (entries.length === 0) continue;
5162
- const paths = analyzeStatePaths(block.content, block.stateName);
5190
+ const paths = analyzeStatePaths(block.content);
5163
5191
  const pathSet = new Set(paths.map((p) => p.path));
5164
5192
  for (const entry of entries) {
5165
5193
  const diagnostic = validateEntry(entry, pathSet, msgs);
@@ -5178,7 +5206,7 @@ function validateWatchDeclarations(html, stateTagName = "wcs-state", locale3) {
5178
5206
  function validateEntry(entry, pathSet, msgs) {
5179
5207
  const { key } = entry;
5180
5208
  const invalid = (message) => ({ code: WcsDiagnosticCode.WatchDeclarationInvalid, message, severity: "error" });
5181
- if (key.includes(STATE_NAME_SEPARATOR2)) {
5209
+ if (key.includes(STATE_NAME_SEPARATOR)) {
5182
5210
  return invalid(msgs.watchKeyCrossState(key));
5183
5211
  }
5184
5212
  if (key.startsWith("$")) {
@@ -5227,7 +5255,6 @@ function validateNamedState(html, attrName, stateTagName = "wcs-state", locale3)
5227
5255
  const diagnostics = [];
5228
5256
  for (const element of parseWcsStateElements(html, stateTagName)) {
5229
5257
  const tagText = html.slice(element.tagStart, element.tagEnd);
5230
- if (/\sbind-component(?=[\s=>/])/i.test(tagText)) continue;
5231
5258
  const match = /(?:^|\s)name\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i.exec(tagText);
5232
5259
  if (match === null) continue;
5233
5260
  const value = match[1] ?? match[2] ?? match[3] ?? "";
@@ -5238,7 +5265,7 @@ function validateNamedState(html, attrName, stateTagName = "wcs-state", locale3)
5238
5265
  start: valueEnd - value.length,
5239
5266
  end: valueEnd,
5240
5267
  message: msgs.namedStateAttrDeprecated(value),
5241
- severity: "warning"
5268
+ severity: "error"
5242
5269
  });
5243
5270
  }
5244
5271
  for (const attr of findAllBindAttributes(html, attrName)) {
@@ -5251,27 +5278,62 @@ function validateNamedState(html, attrName, stateTagName = "wcs-state", locale3)
5251
5278
  start: attr.valueStart + pos + selector.start,
5252
5279
  end: attr.valueStart + pos + selector.end,
5253
5280
  message: msgs.namedStatePathDeprecated(selector.name),
5254
- severity: "warning"
5281
+ severity: "error"
5255
5282
  });
5256
5283
  }
5257
5284
  pos += expr.length + 1;
5258
5285
  }
5259
5286
  }
5260
- for (const mustache of findAllMustacheSyntax(html)) {
5261
- const selector = findStateSelector(mustache.expression, true);
5287
+ for (const item of [...findAllMustacheSyntax(html), ...findAllCommentBindings(html)]) {
5288
+ const selector = findStateSelector(item.expression, true);
5262
5289
  if (selector !== null) {
5263
5290
  diagnostics.push({
5264
5291
  code: WcsDiagnosticCode.NamedStateDeprecated,
5265
- start: mustache.exprStart + selector.start,
5266
- end: mustache.exprStart + selector.end,
5292
+ start: item.exprStart + selector.start,
5293
+ end: item.exprStart + selector.end,
5267
5294
  message: msgs.namedStatePathDeprecated(selector.name),
5268
- severity: "warning"
5295
+ severity: "error"
5269
5296
  });
5270
5297
  }
5271
5298
  }
5272
5299
  return diagnostics;
5273
5300
  }
5274
5301
 
5302
+ // src/service/mountAttrValidator.ts
5303
+ function findMountPathProblem(mountPath) {
5304
+ if (mountPath.length === 0) return "empty";
5305
+ for (const segment of mountPath.split(".")) {
5306
+ if (segment.length === 0) return "emptySegment";
5307
+ if (segment === "*") return "wildcard";
5308
+ if (segment.includes("$") || segment.includes("#") || segment.includes("@")) return "reserved";
5309
+ }
5310
+ return null;
5311
+ }
5312
+ function validateMountAttributes(html, stateTagName = "wcs-state", locale3) {
5313
+ const msgs = getMessages(locale3);
5314
+ const diagnostics = [];
5315
+ for (const element of parseWcsStateElements(html, stateTagName)) {
5316
+ if (element.mountPath === null) continue;
5317
+ const problem = findMountPathProblem(element.mountPath);
5318
+ if (problem === null) continue;
5319
+ const tagText = html.slice(element.tagStart, element.tagEnd);
5320
+ const match = /(?:^|\s)mount\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i.exec(tagText);
5321
+ if (match === null) continue;
5322
+ const value = match[1] ?? match[2] ?? match[3] ?? "";
5323
+ const quoted = match[1] !== void 0 || match[2] !== void 0;
5324
+ const valueEnd = element.tagStart + match.index + match[0].length - (quoted ? 1 : 0);
5325
+ const attrStart = element.tagStart + match.index + (/^\s/.test(match[0]) ? 1 : 0);
5326
+ diagnostics.push({
5327
+ code: WcsDiagnosticCode.MountPathInvalid,
5328
+ start: value.length === 0 ? attrStart : valueEnd - value.length,
5329
+ end: valueEnd + (quoted && value.length === 0 ? 1 : 0),
5330
+ message: msgs.mountPathInvalid(problem, element.mountPath),
5331
+ severity: "error"
5332
+ });
5333
+ }
5334
+ return diagnostics;
5335
+ }
5336
+
5275
5337
  // ../state/dist/parser.esm.js
5276
5338
  var DELIMITER2 = ".";
5277
5339
  var WILDCARD2 = "*";
@@ -5279,7 +5341,6 @@ var MAX_WILDCARD_DEPTH2 = 128;
5279
5341
  var BINDING_SEPARATOR2 = ";";
5280
5342
  var PROP_VALUE_SEPARATOR2 = ":";
5281
5343
  var MODIFIER_SEPARATOR2 = "#";
5282
- var STATE_NAME_SEPARATOR3 = "@";
5283
5344
  var FILTER_SEPARATOR2 = "|";
5284
5345
  var ELSE_KEYWORD2 = "else";
5285
5346
  var SPREAD_PROP2 = "...";
@@ -6135,11 +6196,12 @@ function parseStatePart(statePart) {
6135
6196
  } else {
6136
6197
  stateAndPath = statePart.trim();
6137
6198
  }
6138
- if (stateAndPath.indexOf(STATE_NAME_SEPARATOR3) !== -1) ;
6139
- const [statePathName, stateName = "default"] = stateAndPath.split(STATE_NAME_SEPARATOR3).map(trimFn);
6199
+ if (stateAndPath.indexOf("@") !== -1) {
6200
+ raiseError2(`"${stateAndPath}": the "@name" selector was removed in v2 \u2014 there is a single state tree. Mount the named state onto the tree (<wcs-state mount="...">) and read it by its path prefix instead.`);
6201
+ }
6202
+ const statePathName = stateAndPath;
6140
6203
  const pathInfo = getPathInfo(statePathName);
6141
6204
  return {
6142
- stateName,
6143
6205
  statePathName,
6144
6206
  statePathInfo: pathInfo,
6145
6207
  outFilters: filters
@@ -6162,7 +6224,6 @@ function parseBindTextsForElement(bindText) {
6162
6224
  propModifiers: [],
6163
6225
  statePathName: "#else",
6164
6226
  statePathInfo: pathInfo,
6165
- stateName: "",
6166
6227
  inFilters: [],
6167
6228
  outFilters: [],
6168
6229
  bindingType: "else"
@@ -6262,24 +6323,18 @@ function parseEmbeddedTextWithPositions(expression) {
6262
6323
  error = e.message;
6263
6324
  }
6264
6325
  if (parsed === null) {
6265
- return { exprRange, exprText: expression, parsed, error, propRange: null, pathRange: null, stateNameRange: null };
6326
+ return { exprRange, exprText: expression, parsed, error, propRange: null, pathRange: null };
6266
6327
  }
6267
6328
  const firstPipe = expression.indexOf(delimiters.filter);
6268
6329
  const pathScopeEnd = firstPipe === -1 ? expression.length : firstPipe;
6269
6330
  const pathLocal = locate(expression, parsed.statePathName, 0, pathScopeEnd);
6270
- let stateNameLocal = null;
6271
- const at = expression.indexOf(delimiters.stateName);
6272
- if (at !== -1 && at < pathScopeEnd) {
6273
- stateNameLocal = locate(expression, parsed.stateName, at + 1, pathScopeEnd);
6274
- }
6275
6331
  return {
6276
6332
  exprRange,
6277
6333
  exprText: expression,
6278
6334
  parsed,
6279
6335
  error,
6280
6336
  propRange: null,
6281
- pathRange: pathLocal,
6282
- stateNameRange: stateNameLocal
6337
+ pathRange: pathLocal
6283
6338
  };
6284
6339
  }
6285
6340
  function parseBindTextWithPositions(bindText) {
@@ -6301,23 +6356,18 @@ function parseBindTextWithPositions(bindText) {
6301
6356
  error = e.message;
6302
6357
  }
6303
6358
  if (parsed === null) {
6304
- results.push({ exprRange, exprText: expr, parsed, error, propRange: null, pathRange: null, stateNameRange: null });
6359
+ results.push({ exprRange, exprText: expr, parsed, error, propRange: null, pathRange: null });
6305
6360
  continue;
6306
6361
  }
6307
6362
  const colon = expr.indexOf(delimiters.propValue);
6308
6363
  const propEndLimit = colon === -1 ? expr.length : colon;
6309
6364
  const propLocal = locate(expr, parsed.propName, 0, propEndLimit);
6310
6365
  let pathLocal = null;
6311
- let stateNameLocal = null;
6312
6366
  if (colon !== -1) {
6313
6367
  const stateBase = colon + 1;
6314
6368
  const firstPipe = expr.indexOf(delimiters.filter, stateBase);
6315
6369
  const pathScopeEnd = firstPipe === -1 ? expr.length : firstPipe;
6316
6370
  pathLocal = locate(expr, parsed.statePathName, stateBase, pathScopeEnd);
6317
- const at = expr.indexOf(delimiters.stateName, stateBase);
6318
- if (at !== -1 && at < pathScopeEnd) {
6319
- stateNameLocal = locate(expr, parsed.stateName, at + 1, pathScopeEnd);
6320
- }
6321
6371
  }
6322
6372
  const lift = (range) => range === null ? null : { start: exprStart + range.start, end: exprStart + range.end };
6323
6373
  results.push({
@@ -6326,17 +6376,13 @@ function parseBindTextWithPositions(bindText) {
6326
6376
  parsed,
6327
6377
  error,
6328
6378
  propRange: lift(propLocal),
6329
- pathRange: lift(pathLocal),
6330
- stateNameRange: lift(stateNameLocal)
6379
+ pathRange: lift(pathLocal)
6331
6380
  });
6332
6381
  }
6333
6382
  return results;
6334
6383
  }
6335
6384
 
6336
6385
  // src/core/index/referenceIndex.ts
6337
- function keyOf(stateName, path) {
6338
- return `${stateName}\0${path}`;
6339
- }
6340
6386
  function buildReferenceIndex(html, options = {}) {
6341
6387
  clearParserCaches();
6342
6388
  const bindAttribute = options.bindAttribute ?? "data-wcs";
@@ -6354,13 +6400,11 @@ function buildReferenceIndex(html, options = {}) {
6354
6400
  occurrences.push({
6355
6401
  source: "attribute",
6356
6402
  kind: binding.parsed.propSegments[0] === "eventToken" ? "eventToken" : "path",
6357
- stateName: binding.parsed.stateName,
6358
6403
  path: binding.parsed.statePathName,
6359
6404
  pathRange: lift(binding.pathRange),
6360
6405
  exprRange: lift(binding.exprRange),
6361
6406
  propName: binding.parsed.propName,
6362
6407
  propRange: binding.propRange === null ? null : lift(binding.propRange),
6363
- stateNameRange: binding.stateNameRange === null ? null : lift(binding.stateNameRange),
6364
6408
  bindingType: binding.parsed.bindingType
6365
6409
  });
6366
6410
  }
@@ -6383,22 +6427,21 @@ function buildReferenceIndex(html, options = {}) {
6383
6427
  occurrences.push({
6384
6428
  source: match.kind,
6385
6429
  kind: "path",
6386
- stateName: binding.parsed.stateName,
6387
6430
  path: binding.parsed.statePathName,
6388
6431
  pathRange: shift(binding.pathRange),
6389
6432
  exprRange: { start: match.exprStart, end: match.exprEnd },
6390
6433
  propName: null,
6391
6434
  propRange: null,
6392
- stateNameRange: binding.stateNameRange === null ? null : shift(binding.stateNameRange),
6393
6435
  bindingType: "text"
6394
6436
  });
6395
6437
  }
6396
6438
  const declarations = [];
6397
6439
  for (const block of parseWcsScriptBlocks(html, stateTagName)) {
6440
+ const prefix = block.mountPath === null ? "" : block.mountPath + ".";
6398
6441
  for (const span of analyzeDeclarationSpans(block.content)) {
6442
+ if (prefix !== "" && span.name.startsWith("$")) continue;
6399
6443
  declarations.push({
6400
- stateName: block.stateName,
6401
- name: span.name,
6444
+ name: prefix + span.name,
6402
6445
  kind: span.kind,
6403
6446
  range: { start: block.contentStart + span.start, end: block.contentStart + span.end }
6404
6447
  });
@@ -6407,7 +6450,7 @@ function buildReferenceIndex(html, options = {}) {
6407
6450
  const byPath = /* @__PURE__ */ new Map();
6408
6451
  for (const occurrence of occurrences) {
6409
6452
  if (occurrence.kind !== "path") continue;
6410
- const key = keyOf(occurrence.stateName, occurrence.path);
6453
+ const key = occurrence.path;
6411
6454
  const list = byPath.get(key);
6412
6455
  if (list === void 0) {
6413
6456
  byPath.set(key, [occurrence]);
@@ -6417,22 +6460,22 @@ function buildReferenceIndex(html, options = {}) {
6417
6460
  }
6418
6461
  const declarationByName = /* @__PURE__ */ new Map();
6419
6462
  for (const declaration of declarations) {
6420
- const key = keyOf(declaration.stateName, declaration.name);
6463
+ const key = declaration.name;
6421
6464
  if (!declarationByName.has(key)) declarationByName.set(key, declaration);
6422
6465
  }
6423
6466
  return {
6424
6467
  occurrences,
6425
6468
  declarations,
6426
6469
  problems,
6427
- referencesOf(stateName, path) {
6428
- return (byPath.get(keyOf(stateName, path)) ?? []).slice();
6470
+ referencesOf(path) {
6471
+ return (byPath.get(path) ?? []).slice();
6429
6472
  },
6430
- declarationOf(stateName, path) {
6431
- const exact = declarationByName.get(keyOf(stateName, path));
6473
+ declarationOf(path) {
6474
+ const exact = declarationByName.get(path);
6432
6475
  if (exact !== void 0) return exact;
6433
6476
  const firstSegment = path.split(".")[0];
6434
6477
  if (firstSegment === path) return null;
6435
- return declarationByName.get(keyOf(stateName, firstSegment)) ?? null;
6478
+ return declarationByName.get(firstSegment) ?? null;
6436
6479
  },
6437
6480
  occurrenceAt(offset) {
6438
6481
  for (const occurrence of occurrences) {
@@ -6677,8 +6720,9 @@ function validateUpdatedCallbackDemand(html, stateTagName, bindAttrName, locale3
6677
6720
  for (const block of blocks) {
6678
6721
  const callback = analyzeCallableBodies(block.content).find((entry) => entry.name === STATE_UPDATED_CALLBACK && entry.kind === "method");
6679
6722
  if (callback === void 0) continue;
6680
- const declared = new Set(analyzeStatePaths(block.content, block.stateName).map((p) => p.path));
6681
- const bound = boundPaths.get(block.stateName) ?? /* @__PURE__ */ new Set();
6723
+ if (block.mountPath !== null) continue;
6724
+ const declared = new Set(analyzeStatePaths(block.content).map((p) => p.path));
6725
+ const bound = boundPaths;
6682
6726
  const body = blankComments(callback.body);
6683
6727
  PATH_TEST_LITERAL.lastIndex = 0;
6684
6728
  let match;
@@ -6701,27 +6745,18 @@ function validateUpdatedCallbackDemand(html, stateTagName, bindAttrName, locale3
6701
6745
  return out;
6702
6746
  }
6703
6747
  function collectBoundPaths(html, stateTagName, bindAttrName) {
6704
- const byState = /* @__PURE__ */ new Map();
6705
- const add = (stateName, path) => {
6706
- let set = byState.get(stateName);
6707
- if (set === void 0) {
6708
- set = /* @__PURE__ */ new Set();
6709
- byState.set(stateName, set);
6710
- }
6711
- set.add(path);
6712
- };
6748
+ const bound = /* @__PURE__ */ new Set();
6713
6749
  const index = buildReferenceIndex(html, { bindAttribute: bindAttrName, stateTagName });
6714
6750
  for (const occurrence of index.occurrences) {
6715
- add(occurrence.stateName, occurrence.path);
6751
+ bound.add(occurrence.path);
6716
6752
  if (!occurrence.path.startsWith(".")) continue;
6717
6753
  const forPath = getInnermostForPath(html, occurrence.pathRange.start, bindAttrName);
6718
6754
  if (forPath === null || forPath.startsWith(".")) continue;
6719
- add(
6720
- occurrence.stateName,
6755
+ bound.add(
6721
6756
  occurrence.path === "." ? `${forPath}.*` : `${forPath}.*.${occurrence.path.slice(1)}`
6722
6757
  );
6723
6758
  }
6724
- return byState;
6759
+ return bound;
6725
6760
  }
6726
6761
  function validateSemantics(html, stateTagName = "wcs-state", locale3, bindAttrName = "data-wcs") {
6727
6762
  const out = [];
@@ -6742,22 +6777,19 @@ function discoverApplicationManifest(fileReader) {
6742
6777
  const text = fileReader(relativePath);
6743
6778
  if (text === void 0) continue;
6744
6779
  const loaded = loadManifest({ text, source: relativePath });
6745
- return { relativePath, text, loaded, states: applicationStatesOf(loaded) };
6780
+ return { relativePath, text, loaded, schema: applicationSchemaOf(loaded) };
6746
6781
  }
6747
6782
  return void 0;
6748
6783
  }
6749
- function applicationStatesOf(loaded) {
6750
- const states = /* @__PURE__ */ new Map();
6784
+ function applicationSchemaOf(loaded) {
6751
6785
  const manifest = loaded.manifest;
6752
- if (manifest === null || manifest.kind !== "application") return states;
6786
+ if (manifest === null || manifest.kind !== "application") return void 0;
6753
6787
  const application = manifest.manifestExtensions?.["wcstack.application"];
6754
- for (const [name, entry] of Object.entries(application?.states ?? {})) {
6755
- const schema = entry?.stateSchema;
6756
- if (schema !== null && typeof schema === "object" && !Array.isArray(schema)) {
6757
- states.set(name, schema);
6758
- }
6788
+ const schema = application?.stateSchema;
6789
+ if (schema !== null && typeof schema === "object" && !Array.isArray(schema)) {
6790
+ return schema;
6759
6791
  }
6760
- return states;
6792
+ return void 0;
6761
6793
  }
6762
6794
 
6763
6795
  // src/core/validateDocument.ts
@@ -6766,10 +6798,10 @@ function validateDocument(text, options = {}) {
6766
6798
  const stateTagName = options.stateTagName ?? "wcs-state";
6767
6799
  const locale3 = options.locale;
6768
6800
  const fileReader = options.fileReader;
6769
- const applicationStates = options.applicationStates ?? (fileReader !== void 0 ? discoverApplicationManifest(fileReader)?.states : void 0);
6801
+ const applicationSchema = options.applicationSchema ?? (fileReader !== void 0 ? discoverApplicationManifest(fileReader)?.schema : void 0);
6770
6802
  const out = [];
6771
- out.push(...validateBindings(text, bindAttribute, stateTagName, locale3, fileReader, applicationStates));
6772
- out.push(...validateTemplateSyntax(text, stateTagName, bindAttribute, locale3, fileReader, applicationStates));
6803
+ out.push(...validateBindings(text, bindAttribute, stateTagName, locale3, fileReader, applicationSchema));
6804
+ out.push(...validateTemplateSyntax(text, stateTagName, bindAttribute, locale3, fileReader, applicationSchema));
6773
6805
  out.push(...validateIoNodes(text, bindAttribute, stateTagName, locale3, fileReader));
6774
6806
  out.push(...validateAriaAttributes(text, bindAttribute, locale3));
6775
6807
  out.push(...validateDocumentEnv(text, locale3));
@@ -6777,6 +6809,7 @@ function validateDocument(text, options = {}) {
6777
6809
  out.push(...validateArrayMutations(text, stateTagName, locale3));
6778
6810
  out.push(...validateWatchDeclarations(text, stateTagName, locale3));
6779
6811
  out.push(...validateNamedState(text, bindAttribute, stateTagName, locale3));
6812
+ out.push(...validateMountAttributes(text, stateTagName, locale3));
6780
6813
  for (const d of validateStateTypes(text, stateTagName, locale3)) {
6781
6814
  out.push({ code: WcsDiagnosticCode.TypeAnnotation, start: d.start, end: d.end, message: d.message, severity: d.severity });
6782
6815
  }