Skip to content

fix(optimizer): keep classes whose definition runs code out of the pure wrapper - #619

Merged
Brooooooklyn merged 4 commits into
mainfrom
fix/wrap-class-side-effects
Oct 23, 2026
Merged

Brooooooklyn merged 4 commits into
mainfrom
fix/wrap-class-side-effects

Conversation

@Brooooooklyn

@Brooooooklyn Brooooooklyn commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Follow-up to #604, fixing the Codex findings on it.

Problem

#604 wraps a class in a /* @__PURE__ */ IIFE when its static members look safe. Some members that run code when the class is defined were not checked. If the class is unused, a bundler drops the IIFE and that code with it.

class A { static ɵfac = f; static { register(A); } }   // register() was dropped

Fix

Shape Angular CLI #604 now
static #r = register() not wrapped wrapped ✗ not wrapped
static { register(A) }, static { y = f() }, if/var blocks not wrapped wrapped ✗ not wrapped
extends registerBase() wrapped ✗ wrapped ✗ not wrapped
[register()]() {} (any element) wrapped ✗ wrapped ✗ not wrapped
static accessor y = f() wrapped ✗ wrapped ✗ not wrapped
@dec export class A {…} – @dec export let A = … (does not parse) not wrapped
@register method() {} wrapped ✗ wrapped ✗ not wrapped
class A {…} + A.ɵfac = f with any of the above wrapped ✗ wrapped ✗ not wrapped
  • These checks run for every class, including one followed by a downleveled A.ɵfac = f.
  • Private static fields and static blocks now follow the CLI: a nonempty block must be exactly this.<name> = <wrappable value>.
  • An impure superclass or computed key, a static accessor initializer and class decorators keep the class out. Here OXC is stricter than the CLI.
  • A superclass must be a declared name (or null, a pure class expression, or a call marked /* @__PURE__ */), since reading ns.Base can run a getter. A computed key must be a literal, a declared name or Symbol.<name>, since turning an object into a key can run its toString.
  • Decorators on the class or on any member keep it out.
  • a || b and the globals undefined, NaN, Infinity and Symbol now count as pure in static values.

Checks

  • New test class_definition_side_effects_stay. cargo test --workspace: 3410 passed.
  • 200 deduped @angular/* fesm2022 files, linked and then optimized: PR wraps 708 classes, CLI 705. None is wrapped only by the CLI, and every output parses. The 3 extra (Renderer2, DestroyRef, MatButtonHarness) only have arrow or template-string statics.

Known limit, shared with the CLI and Babel: a declared name used in ${x}, a + b or as a key, or a setter hit by static { this.x = … }, could still run user code.

Not covered here, and unchanged from main: export default class, classes inside function bodies, and __decorate/tsickle siblings.

🤖 Generated with Claude Code

…re wrapper

A private static field, a static block that is not `this.x = …`, an impure
superclass or computed key, a static accessor initializer and class
decorators all run when the class is defined, so wrapping the class in a
pure IIFE let bundlers drop them. Member reads, logical operators and a
few globals now count as pure, like the Angular CLI's isPure.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Brooooooklyn

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-23T06:59:49.524504Z 87810b3 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: acfb2dea2e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/oxc_angular_compiler/src/optimizer/adjust_static_members.rs Outdated
… keys

A member read can run a getter, so a static value such as `registry.value`
keeps the class unwrapped. Superclasses and computed keys such as `i0.Base`
and `Symbol.iterator` still count as pure: the Angular CLI does not check
those at all.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Brooooooklyn

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a88d0c4e45

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/oxc_angular_compiler/src/optimizer/adjust_static_members.rs Outdated
Comment thread crates/oxc_angular_compiler/src/optimizer/adjust_static_members.rs Outdated
Comment thread crates/oxc_angular_compiler/src/optimizer/adjust_static_members.rs
…class

A class followed by `A.ɵfac = f` skipped the class body checks, so an
impure superclass, computed key, static field or static block was still
wrapped. #604 made `static x = register()` wrap this way; the others were
already wrapped before it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Brooooooklyn

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 269d4a47a1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/oxc_angular_compiler/src/optimizer/adjust_static_members.rs Outdated
Comment thread crates/oxc_angular_compiler/src/optimizer/adjust_static_members.rs
… members out

A superclass must now be a declared name, and a computed key a literal, a
declared name or `Symbol.<name>`: reading `ns.Base` can run a getter, and
turning an object key into a string can run its `toString`. Decorators on
class members run when the class is defined, so those classes stay too.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@Brooooooklyn

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: 87810b3ece

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@Brooooooklyn
Brooooooklyn merged commit e97dd4c into main Oct 23, 2026
10 checks passed
@Brooooooklyn
Brooooooklyn deleted the fix/wrap-class-side-effects branch October 23, 2026 07:23
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.

1 participant