Skip to content

closes #652: class methods from precompiled .js drop on instance (v0.5.795) - #664

Merged
proggeramlug merged 1 commit into
mainfrom
loop/652-precompiled-js-classes
May 10, 2026
Merged

closes #652: class methods from precompiled .js drop on instance (v0.5.795)#664
proggeramlug merged 1 commit into
mainfrom
loop/652-precompiled-js-classes

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Summary

Closes #652 — class methods from precompiled .js files in node_modules drop on instance. typeof p.query was undefined, fields silently missing, blocking any precompiled npm-published package that exposes a class with instance methods (@perryts/mysql's Pool / Connection, several others).

Root cause: cjs_wrap.rs left every class X { ... } declaration INSIDE the synthetic IIFE that re-shapes module.exports. Perry's HIR saw the class as exported: false (it lived in a closure body, not at module scope), and the consumer's named import resolved to _cjs.X — a runtime property access, not the class declaration. new ClassRef(...) then allocated an empty *ObjectHeader with no constructor + no methods.

Fix: new extract_top_level_class_decls(source) helper does a brace-balanced scan (handles strings / template literals / line + block comments) of the CJS source and hoists top-level class X { ... } declarations OUT of the IIFE to the outer module scope. The IIFE body still has the original exports.X = X reference, but it now resolves via closure. Hoisted class names are emitted as export { X }; (direct re-export) so the consumer's named import resolves to the actual class. Detection is conservative — only class keyword at column-0 + optional indent — so nested classes inside functions / blocks stay inside the IIFE.

Test fixture

New test-files/issue_652/ exercises the full pattern:

  • node_modules/minilib/index.js with class Base { greet() {} } + class Pool extends Base { async query() {} } + exports.{Base,Pool} = ...
  • main.ts imports both, instantiates them, calls instance methods + super() + async methods

Out of scope

Classes whose body references module / exports / require directly (class X { static foo = require('./y') }) — uncommon for precompiled npm output; the current implementation hoists the class block before the IIFE runs, so any require() inside the class body wouldn't work. Filed as a separate followup if it surfaces.

Test plan

  • Issue's original repro shape: new Pool({url}).query("SELECT 1") returns {rows:[{sql,ok:true}]}
  • extends + super() works
  • Multiple classes in one file all hoist
  • 7 sanity tests pass byte-identical to Node

…5.795)

Pre-fix typeof p.query was undefined for any class imported from a .js
file in node_modules: cjs_wrap left class declarations INSIDE the
synthetic IIFE, so HIR saw them as exported: false and the consumer's
named import resolved to a runtime _cjs.X property access (not the
class). new ClassRef(...) allocated an empty ObjectHeader with no
ctor + no methods; p.query / p.url / Object.keys(p) all empty.

Fix: new extract_top_level_class_decls helper does brace-balanced
scan of CJS source, hoists top-level class declarations OUT of the
IIFE to outer module scope, emits direct `export { X }` re-exports.
The IIFE body still has `exports.X = X` referencing the hoisted
class via closure, so default-export `_cjs.X` shape keeps working.

Detection is conservative — only column-0 + optional indent class
keyword — so nested classes stay inside the IIFE.

Validation: new regression test test-files/issue_652/ with extends
+ super() + async methods + multiple classes. 7 sanity tests
byte-identical to Node.

Out of scope: classes whose body references module/exports/require
directly — uncommon for precompiled npm output, filed separately.
@proggeramlug
proggeramlug merged commit 7010353 into main May 10, 2026
2 of 10 checks passed
@TheHypnoo
TheHypnoo deleted the loop/652-precompiled-js-classes branch May 16, 2026 12:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

class methods from precompiled .js (node_modules) drop on instance — typeof p.query is undefined

1 participant