Skip to content

Fix custom decorators#2

Open
ashley-hunter wants to merge 55 commits intomainfrom
fix-custom-decorators
Open

Fix custom decorators#2
ashley-hunter wants to merge 55 commits intomainfrom
fix-custom-decorators

Conversation

@ashley-hunter
Copy link
Copy Markdown
Owner

When @oxc-angular/vite encounters a class with both Angular and non-Angular decorators like @Injectable() and NGXS @State, @selector, or @action, it must lower all decorators – not just Angular ones – when converting class declarations to class expressions.

This PR:

  • Lowers non-Angular class decorators into ClassName = __decorate([…], ClassName) calls.
  • Lowers non-Angular member decorators into __decorate([…], ClassName.prototype, “memberName”, null|void 0) calls, using null for methods/accessors and void 0 for properties, matching TypeScript’s tsc output.
  • Preserves the correct emission order: instance members first, then static members, and finally class-level __decorate, matching TypeScript’s behaviour.
  • Excludes all Angular decorators (@component, @directive, @input, @Inject, etc.) from __decorate lowering since Angular handles these through propDecorators and ctorParameters.
  • Consolidates the member decorator extraction into a single-pass function to reduce code duplication.

renovate Bot and others added 30 commits March 19, 2026 19:04
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…/outputs (voidzero-dev#155)

* fix(compiler): quote object keys containing dots or hyphens in inputs/outputs

Angular's UNSAFE_OBJECT_KEY_NAME_REGEXP requires quoting property keys
that contain `.` or `-` characters (e.g. `fxFlexAlign.xs`). Without
quoting, these produce invalid JavaScript object literals.

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

* fix(compiler): simplify output vector initialization and format key quoting

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
chore(deps): update github-actions

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
chore(deps): update npm packages

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…ev#164)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…ode (voidzero-dev#157)

* fix(compiler): strip abstract keyword from class expressions in JIT mode

* feat(compiler): strip TypeScript syntax from JIT output using oxc_transformer

Add a `strip_typescript()` post-pass after JIT text-edits that uses
oxc_transformer + oxc_codegen to convert TypeScript → JavaScript. This
handles abstract members, type annotations, parameter properties, and
other TS-only syntax that previously leaked into JIT output.

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

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…voidzero-dev#172)

Track expressions using binary operators (??. +), ternary, or unary
operators that referenced component members were incorrectly compiled
as arrow functions, causing `this` to be undefined at runtime.

The root cause was that `expression_contains_context` — a function not
present in Angular's implementation — failed to traverse compound IR
expression types like Binary and Ternary. Instead of patching every
missing variant, this commit aligns with Angular's approach: detect
ContextExpr during the transformExpressionsInExpression callback that
already visits all expression types, setting usesComponentInstance in
the same pass that replaces Context with TrackContext.

This removes ~180 lines of redundant detection code
(expression_contains_context, ast_contains_implicit_receiver) that
duplicated work already done by resolve_names (phase 31) and the
transform visitor.

Output verified against the official Angular compiler (NgtscProgram)
for all test cases.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
renovate Bot and others added 25 commits March 27, 2026 18:30
…ev#178)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…ev#181)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Signed-off-by: LongYinan <lynweklm@gmail.com>
Signed-off-by: LongYinan <lynweklm@gmail.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…ero-dev#192)

The CSS encapsulation code used `bytes[i] as char` to copy characters,
which treats each byte of a multi-byte UTF-8 sequence as a separate
Latin-1 codepoint. This corrupted non-ASCII characters (e.g. bullet •)
that appear after Sass compiles CSS escape sequences like `\2022`.

Replace all 13 instances with `push_utf8_char()` which reads the UTF-8
character width from the leading byte and copies the full character.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…bility (voidzero-dev#193)

The complex regex in the transform filter (`[\\/]`, `(?:\?.*)?$`) was not
reliably evaluated by Vite 8's Rolldown-backed filter mechanism, preventing
the linker from processing excluded node_modules packages like PrimeNG.
Without linking, Angular falls back to JIT which fails with NG0303 for
non-standalone components.

Split filtering into two stages: a simple `/node_modules/` static filter
that any Vite version can evaluate, and precise extension + content checks
inside the handler using JavaScript's native regex engine.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
voidzero-dev#194)

@Injectable() and @Injectable({}) were incorrectly defaulting providedIn
to 'root'. Angular's actual behavior is to omit providedIn entirely when
it's not explicitly specified, as confirmed by the official compliance tests.
…oidzero-dev#197)

* fix(vite): stop swallowing HMR updates for non-component resources

The plugin's handleHotUpdate was returning [] for all CSS/HTML files,
preventing Vite from processing global stylesheets and notifying
PostCSS/Tailwind of content changes. Now only component resource files
(tracked in resourceToComponent) are swallowed; non-component files
flow through Vite's normal HMR. Also emits a synthetic watcher event
when component templates change so Tailwind can rescan for new classes.

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

* fix review: remove synthetic watcher emit, fix test setup

- Remove server.watcher.emit('change', file) for component resources:
  Vite treats HTML changes with no module graph entries as full reloads,
  which would regress template HMR behavior.
- Fix test to call config() with command='serve' so watchMode=true and
  resourceToComponent is actually populated during transform. Tests now
  use real temp files and assert exact return values.

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

* fix: resolve oxlint type-check errors in HMR tests

Use .call() with plugin context for handleHotUpdate to satisfy TS2684,
and remove invalid 'type' property from mock ModuleNode to fix TS2345.

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

* fix: prune stale resourceToComponent entries and fix Windows CI

- Prune old resource→component mappings before re-registering during
  transform, so renamed/removed templateUrl/styleUrls no longer cause
  handleHotUpdate to swallow updates for files that are no longer
  component resources.
- Replace real fs.watch with no-op in tests to avoid EPERM errors on
  Windows when temp files are cleaned up. resourceToComponent is
  populated before watchFn runs, so test coverage is preserved.

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

* fix: re-add pruned resources to Vite watcher

When a component drops a resource from templateUrl/styleUrls, the file
was already unwatched from Vite's chokidar watcher by the custom
fs.watch setup. Pruning the resourceToComponent entry made the file
invisible to both systems. Now re-add pruned files to Vite's watcher
so they can flow through normal HMR if used elsewhere (e.g., as a
global stylesheet). Also skip pruning resources that are still in the
new dependency set.

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

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore(deps): update oxc

* fix: update code for oxc 0.123 API changes (Atom -> Ident)

Agent-Logs-Url: https://github.com/voidzero-dev/oxc-angular-compiler/sessions/e30e0210-0bc0-4fde-89cf-53e615179571

Co-authored-by: Brooooooklyn <3468483+Brooooooklyn@users.noreply.github.com>

* fix: resolve type mismatch errors with --all-features

Fix HashMap/HashSet lookups where Ident keys require proper type conversions

Agent-Logs-Url: https://github.com/voidzero-dev/oxc-angular-compiler/sessions/a7e20639-8c1f-41cd-9213-7290a72152ec

Co-authored-by: Brooooooklyn <3468483+Brooooooklyn@users.noreply.github.com>

* chore: run cargo fmt to fix formatting issues

Agent-Logs-Url: https://github.com/voidzero-dev/oxc-angular-compiler/sessions/bd85e1c3-dac8-400f-905a-65ef81ad4ae1

Co-authored-by: Brooooooklyn <3468483+Brooooooklyn@users.noreply.github.com>

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: anthropic-code-agent[bot] <242468646+Claude@users.noreply.github.com>
Co-authored-by: Brooooooklyn <3468483+Brooooooklyn@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…ev#202)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
When a class has both Angular decorators (e.g. @Injectable) and
non-Angular decorators (e.g. NGXS @State, @selector, @action),
lower all decorators when converting class declarations to class
expressions. Non-Angular member decorators are emitted as __decorate()
calls matching TypeScript's tsc output: null for methods/accessors,
void 0 for properties, instance members before static members.
@ashley-hunter ashley-hunter force-pushed the fix-custom-decorators branch from 8bb6930 to 72b7328 Compare April 1, 2026 22: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.

8 participants