You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* fix(v4): preserve callsites in parse stack traces
* fix(v4): await the async parse wrappers so the callee stays on the chain
`Error.captureStackTrace(e, callee)` is skip-until-seen: V8 discards frames until it
meets `callee`, and if it never meets it, it discards them all. An async function that
returns its inner promise without awaiting has already left the async chain by the time
the rejection is built, so its frame is not there to be found and `err.stack` comes back
as the message line alone.
That made all four async codec paths return an empty stack where main returned a usable
one, which is the opposite of this branch's purpose. Instance `.parseAsync()` had the
same defect on main already; it is fixed here too, since it is the same one-word change
and the same invariant.
The existing coverage could not catch this. An async function body runs synchronously up
to its first `await`, so `z.string()` never suspends and its callee is always still on
the chain. The new test uses an async refinement and an async codec, and fails without
this fix.
* test(treeshake): re-measure the ceilings against the current base
The three raises were measured against a base five commits stale. Merging current
main puts `zod-mini-object` at exactly its ceiling and the other two at 18 bytes,
back in the 16-21 band this file's own comment records as having broken within a
day. Re-measured on the merged tree: 2808 / 3128 / 4301, so the ceilings move to
28 bytes of headroom each, which is what the comment claims.
* test(treeshake): attribute the ceiling raise to the right cause
The comment booked the whole 2813 / 3130 / 4288 raise to the callee threading. Measured
against the merge base, this branch costs +13 / +17 / +16; the remainder is drift on
main since those numbers were last set, and main alone had already reached 4285 against
its own 4288. A file whose job is recording what caused each raise should say which
part was which.
* The failure message prints the measured size, so updating is mechanical.
39
39
*/
40
40
constCEILINGS: Record<string,number>={
41
-
"zod-mini-boolean": 2813,
42
-
// Raised from 3130 in the commit that caused it: string length checks now measure code points, so any bundle using `.min`/`.max`/`.length` on a string carries the surrogate scan. Measured 3257; 28 bytes of headroom to match the others. `zod-mini-object` does not move — a bundle with no length check still carries none of it.
43
-
"zod-mini-string": 3285,
44
-
// Raised from 4257 in the commit that caused it: the construction-time discriminator check writes a WeakMap entry from `$ZodObject`, so every bundle containing `z.object` carries it. Measured 4260; 28 bytes of headroom to match the other two.
45
-
"zod-mini-object": 4288,
41
+
// Raised from 2813 / 3285 / 4288 by the commit that caused it: threading a `callee` to `Error.captureStackTrace` from every throwing parse entry point costs +13 / +17 / +16, since a bundle that parses at all carries it. Measured 2808 / 3271 / 4301 here; 28 bytes of headroom each. The per-fixture notes below record what each ceiling already carried before this.
42
+
"zod-mini-boolean": 2836,
43
+
// Also carries the code-point string length scan: `.min`/`.max`/`.length` on a string pulls in the surrogate walk.
44
+
"zod-mini-string": 3299,
45
+
// Also carries the construction-time discriminator check, which writes a WeakMap entry from `$ZodObject`, so every bundle containing `z.object` pays for it whether or not it builds a discriminated union.
test("async errors that fail after suspending capture the caller stack frame",async()=>{
793
+
// `Error.captureStackTrace` is skip-until-seen: when it cannot find its callee it discards every frame, not just the ones above. An async wrapper that returns its inner promise without awaiting has already left the async chain by the time the rejection is built, so its callee is unfindable and the stack comes back empty. Only a schema that actually suspends reaches that path — the sync cases above run straight through to their first await and pass either way.
0 commit comments