Summary
I did a full static pass over crates/swc_ecma_transforms_typescript and found several likely performance hotspots. These are all static-analysis findings (no runtime profile attached yet), but they are concentrated in hot traversal paths and enum processing.
Findings
Repeated full scans over Module.body in the main transform pipeline
visit_mut_module calls:
strip_module_items_with_semantic ([transform.rs:127-130, 666-766])
visit_mut_for_ts_import_export ([transform.rs:132, 1464-1667])
then node.visit_mut_children_with(self) ([transform.rs:134])
visit_mut_module_items then does both retain and retain_mut passes again ([transform.rs:158-166]).
visit_mut_stmt re-checks retention (should_retain_stmt) for statements ([transform.rs:336-342]).
This creates multiple O(N) passes over top-level items and repeats hashing/lookups for large modules.
Extra pass on statement vectors in visit_mut_stmts
visit_mut_stmts does a retain_mut transform pass, then a second retain pass for dummy empties ([transform.rs:294-315]).
This can be collapsed into one pass by dropping dummy empties directly in the first traversal.
Per-member AST clone in enum semantic analysis
visit_ts_enum_decl clones each enum member before computing value ([semantic.rs:545-552], especially member.clone()).
transform_ts_enum_member only needs the initializer, so cloning the full TsEnumMember is avoidable.
On large enums with complex initializers, this creates unnecessary clone churn.
Eager fallback cloning in enum evaluator (EnumValueComputer)
compute_bin clones the whole BinExpr up front ([ts_enum.rs:189]).
compute_member clones the whole MemberExpr up front ([ts_enum.rs:265]).
compute_tpl clones the whole Tpl up front ([ts_enum.rs:294]).
These clones are paid even when evaluation succeeds and no opaque fallback is needed.
Duplicate filtering in transform_ts_enum
Members are filtered once when building member_list ([transform.rs:951])
then filtered again with the same predicate before build_assign ([transform.rs:964]).
The second filter appears redundant and adds another pass.
Repeated JSX pragma parsing per module
TypeScriptReact::visit_mut_module parses default pragma strings (React.createElement, React.Fragment) each module visit ([typescript.rs:182-200]).
This can likely be cached per pass instance (or as already-parsed IDs) when config/comments do not override it.
Repeated temporary Vec<Id> allocations from find_pat_ids
Occurs in collect_decl and visit_export_decl ([semantic.rs:210-216, 392-396]).
For modules with many declarations, this repeatedly allocates intermediate vectors instead of streaming directly into target sets/maps.
Suggested optimization order (highest expected impact first)
Fuse/trim module-body passes in transform.rs (finding ecmascript parser #1 ).
Remove per-member clone in enum semantic analysis (finding EcmaScript lexer is inefficient #3 ).
Make enum opaque fallback construction lazy (finding Transformers for ecmascript #4 ).
Remove redundant enum filter pass (finding Handle early errors in ecmascript parser #5 ).
Merge statement cleanup passes (finding Clean up #2 ).
Cache default JSX pragma parsing (finding Internal documentations #6 ).
Replace find_pat_ids temp vectors with iterator/callback-based insertion where possible (finding Travis and codecov #7 ).
Notes
These are static findings; exact impact should be confirmed with benchmark fixtures (e.g. large namespace/enum-heavy TS inputs).
If helpful, I can send a follow-up PR sequence in the same order above, with per-change benchmark deltas.
Summary
I did a full static pass over
crates/swc_ecma_transforms_typescriptand found several likely performance hotspots. These are all static-analysis findings (no runtime profile attached yet), but they are concentrated in hot traversal paths and enum processing.Findings
Repeated full scans over
Module.bodyin the main transform pipelinevisit_mut_modulecalls:strip_module_items_with_semantic([transform.rs:127-130, 666-766])visit_mut_for_ts_import_export([transform.rs:132, 1464-1667])node.visit_mut_children_with(self)([transform.rs:134])visit_mut_module_itemsthen does bothretainandretain_mutpasses again ([transform.rs:158-166]).visit_mut_stmtre-checks retention (should_retain_stmt) for statements ([transform.rs:336-342]).This creates multiple O(N) passes over top-level items and repeats hashing/lookups for large modules.
Extra pass on statement vectors in
visit_mut_stmtsvisit_mut_stmtsdoes aretain_muttransform pass, then a secondretainpass for dummy empties ([transform.rs:294-315]).This can be collapsed into one pass by dropping dummy empties directly in the first traversal.
Per-member AST clone in enum semantic analysis
visit_ts_enum_declclones each enum member before computing value ([semantic.rs:545-552], especiallymember.clone()).transform_ts_enum_memberonly needs the initializer, so cloning the fullTsEnumMemberis avoidable.On large enums with complex initializers, this creates unnecessary clone churn.
Eager fallback cloning in enum evaluator (
EnumValueComputer)compute_binclones the wholeBinExprup front ([ts_enum.rs:189]).compute_memberclones the wholeMemberExprup front ([ts_enum.rs:265]).compute_tplclones the wholeTplup front ([ts_enum.rs:294]).These clones are paid even when evaluation succeeds and no opaque fallback is needed.
Duplicate filtering in
transform_ts_enummember_list([transform.rs:951])build_assign([transform.rs:964]).The second filter appears redundant and adds another pass.
Repeated JSX pragma parsing per module
TypeScriptReact::visit_mut_moduleparses default pragma strings (React.createElement,React.Fragment) each module visit ([typescript.rs:182-200]).This can likely be cached per pass instance (or as already-parsed IDs) when config/comments do not override it.
Repeated temporary
Vec<Id>allocations fromfind_pat_idscollect_declandvisit_export_decl([semantic.rs:210-216, 392-396]).For modules with many declarations, this repeatedly allocates intermediate vectors instead of streaming directly into target sets/maps.
Suggested optimization order (highest expected impact first)
transform.rs(finding ecmascript parser #1).find_pat_idstemp vectors with iterator/callback-based insertion where possible (finding Travis and codecov #7).Notes