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
{{ message }}
Repository navigation
hasMutableExportedBinding skips destructured declarations, so a live exported binding still gets settled #74
Reading through the sealCjsExports work from #73, I think hasMutableExportedBinding misses destructured declarations, which lets exactly the case it guards against through.
The isIdentifier check sits before both branches, so any binding pattern is dropped early. That misses two shapes:
exportlet{ counter }=obj;// never returns true
let{ counter }=obj;// counter never lands in mutableLocals,export{counter};// so the named-export scan below misses it too
Either way hasMutableExportedBinding returns false, settling stays enabled, and the accessor gets snapshotted. That produces the divergence the comment right above the function describes: require(pkg).counter keeps reporting the load-time value while import { counter } reports the current one.
const destructuring is correctly irrelevant here — it's filtered by the isConst check above. The gap is only for let/var binding patterns.
Treating a non-const declaration with a binding pattern as mutable would close the first shape; collecting the destructured element names into mutableLocals would close the second.
I have not built a package to reproduce this end to end — it's a read of the code as merged, and the same lines are on main now (src/compile.ts:156). If destructured exports are outside what zshy intends to support, this is not worth your time.
To be upfront about where this came from: I found it with a code review tool I am building (ReviewGate) while running it over real repositories, then read the function and checked each shape against it by hand before writing this up. Close it if I have misread the intent.
Activity
pullfrog commentedon Sep 8, 2026