@vesk/vesk-cli 0.2.41 → 0.2.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +107 -27
  2. package/package.json +5 -5
package/dist/cli.js CHANGED
@@ -2283,6 +2283,16 @@ function runInHydrateBlock(fn) {
2283
2283
  throw error;
2284
2284
  }
2285
2285
  }
2286
+ function recordClaim(root3, record) {
2287
+ claimRegistry.set(record.el, record);
2288
+ if (!root3) return;
2289
+ const records = walkerClaimRecords.get(root3);
2290
+ if (records) records.push(record);
2291
+ else walkerClaimRecords.set(root3, [record]);
2292
+ }
2293
+ function isAdopted(el) {
2294
+ return claimRegistry.get(el)?.state === "adopted";
2295
+ }
2286
2296
  function reportHydrationIssue(issue) {
2287
2297
  if (!__mismatchHandler) return;
2288
2298
  try {
@@ -2304,13 +2314,15 @@ function reportMiss(kind, detail, loud) {
2304
2314
  }
2305
2315
  if (loud) devWarn(`${kind}: ${detail}`);
2306
2316
  }
2307
- function stampClaimed(el) {
2308
- if (__hydrateDevMode) {
2309
- try {
2310
- el.setAttribute(CLAIMED_ATTR, "");
2311
- } catch {
2312
- }
2313
- }
2317
+ function recordAdopted(root3, el, expectedTag) {
2318
+ recordClaim(root3, {
2319
+ state: "adopted",
2320
+ el,
2321
+ owner: root3,
2322
+ expectedTag,
2323
+ actualTag: el.tagName.toLowerCase(),
2324
+ detached: false
2325
+ });
2314
2326
  }
2315
2327
  function stripDirectTextNodes(el) {
2316
2328
  let text = "";
@@ -2361,8 +2373,8 @@ function scanTwins(container) {
2361
2373
  let a = false;
2362
2374
  let b = false;
2363
2375
  try {
2364
- a = el.hasAttribute(CLAIMED_ATTR);
2365
- b = prev.hasAttribute(CLAIMED_ATTR);
2376
+ a = isAdopted(el);
2377
+ b = isAdopted(prev);
2366
2378
  } catch {
2367
2379
  continue;
2368
2380
  }
@@ -2405,6 +2417,30 @@ function auditHydration(container) {
2405
2417
  }
2406
2418
  if (!sample && container.outerHTML) sample = String(container.outerHTML).slice(0, 800);
2407
2419
  }
2420
+ const structuralRecords = [];
2421
+ const seenRecords = /* @__PURE__ */ new Set();
2422
+ const collectWalkerRecords = (el) => {
2423
+ const records = walkerClaimRecords.get(el);
2424
+ if (records) {
2425
+ for (const record of records) {
2426
+ if (!seenRecords.has(record)) {
2427
+ seenRecords.add(record);
2428
+ structuralRecords.push(record);
2429
+ }
2430
+ }
2431
+ }
2432
+ for (let i = 0; i < el.children.length; i++) collectWalkerRecords(el.children[i]);
2433
+ };
2434
+ collectWalkerRecords(container);
2435
+ const structuralGhosts = structuralRecords.filter((record) => record.state === "ghost");
2436
+ if (structuralGhosts.length > 0) {
2437
+ unclaimed += structuralGhosts.length;
2438
+ if (orphanNames.length < 5) {
2439
+ orphanNames.push(
2440
+ `${structuralGhosts.length} structural hydration ghost(s) (${structuralGhosts.slice(0, 3).map((record) => `<${record.actualTag}> expected <${record.expectedTag}>`).join(", ")})`
2441
+ );
2442
+ }
2443
+ }
2408
2444
  const twinRes = scanTwins(container);
2409
2445
  const issues = [];
2410
2446
  if (unclaimed > 0) {
@@ -2432,6 +2468,14 @@ function auditHydration(container) {
2432
2468
  } catch {
2433
2469
  }
2434
2470
  }
2471
+ for (const record of structuralGhosts) {
2472
+ try {
2473
+ if (record.detached || !record.owner || record.el.parentNode !== record.owner) continue;
2474
+ record.el.remove();
2475
+ record.detached = true;
2476
+ } catch {
2477
+ }
2478
+ }
2435
2479
  }
2436
2480
  if (__mismatchHandler) {
2437
2481
  for (const issue of issues) {
@@ -2462,7 +2506,7 @@ ${report.sample}`
2462
2506
  }
2463
2507
  function underClaimedAncestor(el, container) {
2464
2508
  for (let n = el; n && n !== container; n = n.parentElement) {
2465
- if (n.nodeType === 1 && n.hasAttribute(CLAIMED_ATTR)) return true;
2509
+ if (n.nodeType === 1 && isAdopted(n)) return true;
2466
2510
  }
2467
2511
  return false;
2468
2512
  }
@@ -2523,7 +2567,7 @@ function checkMarkerIdentity(marker, el) {
2523
2567
  }
2524
2568
  }
2525
2569
  }
2526
- function adoptElement(marker, tag) {
2570
+ function adoptElement(root3, marker, tag) {
2527
2571
  const el = marker.nextElementSibling;
2528
2572
  if (!el) {
2529
2573
  marker.remove();
@@ -2534,10 +2578,10 @@ function adoptElement(marker, tag) {
2534
2578
  marker.remove();
2535
2579
  stripDirectTextNodes(el);
2536
2580
  captureSsrElementChildren(el);
2537
- stampClaimed(el);
2581
+ recordAdopted(root3, el, tag || el.tagName.toLowerCase());
2538
2582
  return el;
2539
2583
  }
2540
- function adoptElementRaw(marker, tag) {
2584
+ function adoptElementRaw(root3, marker, tag) {
2541
2585
  const el = marker.nextElementSibling;
2542
2586
  if (!el) {
2543
2587
  marker.remove();
@@ -2547,7 +2591,7 @@ function adoptElementRaw(marker, tag) {
2547
2591
  checkMarkerIdentity(marker, el);
2548
2592
  marker.remove();
2549
2593
  captureSsrElementChildren(el);
2550
- stampClaimed(el);
2594
+ recordAdopted(root3, el, tag || el.tagName.toLowerCase());
2551
2595
  return el;
2552
2596
  }
2553
2597
  function createHydrateWalker(container, markerList) {
@@ -2752,14 +2796,15 @@ function hydrateOnInteraction(container, componentFn, props, options = {}) {
2752
2796
  }
2753
2797
  };
2754
2798
  }
2755
- var __hydrateDevMode, CLAIMED_ATTR, __hydrateStrict, __mismatchHandler, _SHOW_COMMENT, _FILTER_ACCEPT, _FILTER_SKIP, WalkerEngine, StructuralWalker;
2799
+ var __hydrateDevMode, claimRegistry, walkerClaimRecords, __hydrateStrict, __mismatchHandler, _SHOW_COMMENT, _FILTER_ACCEPT, _FILTER_SKIP, WalkerEngine, StructuralWalker;
2756
2800
  var init_hydrate = __esm({
2757
2801
  "../runtime/src/hydrate.ts"() {
2758
2802
  "use strict";
2759
2803
  init_ripple_runtime();
2760
2804
  init_ripple_blocks();
2761
2805
  __hydrateDevMode = true;
2762
- CLAIMED_ATTR = "data-vsk-claimed";
2806
+ claimRegistry = /* @__PURE__ */ new WeakMap();
2807
+ walkerClaimRecords = /* @__PURE__ */ new WeakMap();
2763
2808
  __hydrateStrict = false;
2764
2809
  __mismatchHandler = null;
2765
2810
  _SHOW_COMMENT = 128;
@@ -2844,7 +2889,7 @@ var init_hydrate = __esm({
2844
2889
  break;
2845
2890
  }
2846
2891
  this.idx++;
2847
- const adopted = adoptElement(tm.comment, tag);
2892
+ const adopted = adoptElement(this.root, tm.comment, tag);
2848
2893
  if (adopted === null) {
2849
2894
  tm.state = "claimed";
2850
2895
  break;
@@ -2896,7 +2941,7 @@ ${String(this.root.outerHTML).slice(0, 800)}` : ""),
2896
2941
  break;
2897
2942
  }
2898
2943
  this.idx++;
2899
- const adopted = adoptElementRaw(tm.comment, tag);
2944
+ const adopted = adoptElementRaw(this.root, tm.comment, tag);
2900
2945
  if (adopted === null) {
2901
2946
  tm.state = "claimed";
2902
2947
  break;
@@ -2986,7 +3031,7 @@ ${String(this.root.outerHTML).slice(0, 800)}` : ""),
2986
3031
  tm.comment.remove();
2987
3032
  stripDirectTextNodes(el);
2988
3033
  captureSsrElementChildren(el);
2989
- stampClaimed(el);
3034
+ recordAdopted(this.root, el, el.tagName.toLowerCase());
2990
3035
  return { el };
2991
3036
  }
2992
3037
  claimByKey(key, options) {
@@ -3160,12 +3205,37 @@ ${String(this.root.outerHTML).slice(0, 800)}` : ""),
3160
3205
  const el = this.els[target];
3161
3206
  if (tag && el.tagName.toLowerCase() !== tag) {
3162
3207
  this.idx = this.advancePastSkippable(target + 1);
3208
+ const ghost = {
3209
+ state: "ghost",
3210
+ el,
3211
+ owner: this.root,
3212
+ expectedTag: tag || "div",
3213
+ actualTag: el.tagName.toLowerCase(),
3214
+ detached: false
3215
+ };
3216
+ recordClaim(this.root, ghost);
3217
+ if (this.root && el.parentNode === this.root) {
3218
+ try {
3219
+ el.remove();
3220
+ ghost.detached = true;
3221
+ } catch {
3222
+ }
3223
+ }
3224
+ const fresh2 = document.createElement(tag || "div");
3225
+ recordClaim(this.root, {
3226
+ state: "fresh",
3227
+ el: fresh2,
3228
+ owner: this.root,
3229
+ expectedTag: tag || "div",
3230
+ actualTag: fresh2.tagName.toLowerCase(),
3231
+ detached: false
3232
+ });
3163
3233
  reportMiss(
3164
3234
  "tag-mismatch",
3165
- `descriptor wanted <${tag}> but the SSR slot holds <${el.tagName.toLowerCase()}>; consuming one slot and rendering fresh.`,
3235
+ `descriptor wanted <${tag}> but the SSR slot holds <${el.tagName.toLowerCase()}>; consumed one slot, detached the local ghost, and rendered fresh.`,
3166
3236
  false
3167
3237
  );
3168
- return document.createElement(tag || "div");
3238
+ return fresh2;
3169
3239
  }
3170
3240
  if (this.adopted.has(el)) {
3171
3241
  target = this.advancePastSkippable(target + 1);
@@ -3175,10 +3245,19 @@ ${String(this.root.outerHTML).slice(0, 800)}` : ""),
3175
3245
  this.adopted.add(el);
3176
3246
  if (!raw2) stripDirectTextNodes(el);
3177
3247
  captureSsrElementChildren(el);
3178
- stampClaimed(el);
3248
+ recordAdopted(this.root, el, tag || el.tagName.toLowerCase());
3179
3249
  return el;
3180
3250
  }
3181
3251
  this.idx = this.els.length;
3252
+ const fresh = document.createElement(tag || "div");
3253
+ recordClaim(this.root, {
3254
+ state: "fresh",
3255
+ el: fresh,
3256
+ owner: this.root,
3257
+ expectedTag: tag || "div",
3258
+ actualTag: fresh.tagName.toLowerCase(),
3259
+ detached: false
3260
+ });
3182
3261
  reportMiss(
3183
3262
  "exhausted",
3184
3263
  `hydration claim missed <${tag || "element"}>; the client rendered more or different content than SSR.`,
@@ -3187,7 +3266,7 @@ ${String(this.root.outerHTML).slice(0, 800)}` : ""),
3187
3266
  // nodes) — telemetry-only, mirroring the marker engine.
3188
3267
  false
3189
3268
  );
3190
- return document.createElement(tag || "div");
3269
+ return fresh;
3191
3270
  }
3192
3271
  nextElement(tag, skipK = 0) {
3193
3272
  return this.claimAt(tag, skipK, false);
@@ -3236,7 +3315,7 @@ ${String(this.root.outerHTML).slice(0, 800)}` : ""),
3236
3315
  this.adopted.add(el);
3237
3316
  stripDirectTextNodes(el);
3238
3317
  captureSsrElementChildren(el);
3239
- stampClaimed(el);
3318
+ recordAdopted(this.root, el, el.tagName.toLowerCase());
3240
3319
  return { el };
3241
3320
  }
3242
3321
  this.idx = this.els.length;
@@ -23367,7 +23446,8 @@ function Form(props, registry, hydrate) {
23367
23446
  return `<form ${attrStr}>${children || ""}</form>`;
23368
23447
  }
23369
23448
  if (hydrate && hydrate.nextElement) {
23370
- let form2 = hydrate.nextElement("form");
23449
+ const skipK = typeof hydrate.takeSkipK === "function" ? hydrate.takeSkipK() : 0;
23450
+ let form2 = hydrate.nextElement("form", skipK);
23371
23451
  if (form2 && !form2.parentNode && hydrate.root) {
23372
23452
  const existing = hydrate.root.querySelector("form");
23373
23453
  if (existing) form2 = existing;
@@ -29213,7 +29293,7 @@ function emitComponentCall(ctx2, node, tracked2, effectsVar, parentVar, compPref
29213
29293
  const frag = ctx2.n();
29214
29294
  const wipeMount = ctx2.linkNames.has(node.componentName);
29215
29295
  const savedHydrate = ctx2.hydrate;
29216
- if (wipeMount) ctx2.hydrate = false;
29296
+ if (wipeMount || ctx2.selfClaimNames.has(node.componentName)) ctx2.hydrate = false;
29217
29297
  ctx2.push(`const ${frag} = (() => { const $f = document.createDocumentFragment();`);
29218
29298
  const savedEffects = ctx2.effects;
29219
29299
  ctx2.effects = [];
@@ -43760,7 +43840,7 @@ function emitComponentCall2(ctx2, node, tracked2, effectsVar, parentVar, compPre
43760
43840
  const frag = ctx2.n();
43761
43841
  const wipeMount = ctx2.linkNames.has(node.componentName);
43762
43842
  const savedHydrate = ctx2.hydrate;
43763
- if (wipeMount)
43843
+ if (wipeMount || ctx2.selfClaimNames.has(node.componentName))
43764
43844
  ctx2.hydrate = false;
43765
43845
  ctx2.push(`const ${frag} = (() => { const $f = document.createDocumentFragment();`);
43766
43846
  const savedEffects = ctx2.effects;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vesk/vesk-cli",
3
- "version": "0.2.41",
3
+ "version": "0.2.42",
4
4
  "type": "module",
5
5
  "description": "Vesk — compiler-first framework for the post-VDOM web. vesk dev, vesk build.",
6
6
  "bin": {
@@ -8,10 +8,10 @@
8
8
  },
9
9
  "main": "./dist/cli.js",
10
10
  "dependencies": {
11
- "@vesk/adapter": "^0.2.41",
12
- "@vesk/compiler": "^0.2.41",
13
- "@vesk/plugin-tailwind": "^0.2.41",
14
- "@vesk/runtime": "^0.2.41",
11
+ "@vesk/adapter": "^0.2.42",
12
+ "@vesk/compiler": "^0.2.42",
13
+ "@vesk/plugin-tailwind": "^0.2.42",
14
+ "@vesk/runtime": "^0.2.42",
15
15
  "esrap": "^2.3.0",
16
16
  "typescript": "^5.8.0",
17
17
  "ws": "^8.18.0",