Skip to content

transformer: decorator.legacy = true and target = 'es2021' do not work together on class fields #9129

@e111077

Description

@e111077

Issue

When setting a target <= es2021 and using legacy decorators with a class member, the transformer does not apply the legacy decorator.

Context

Lit custom elements use a @property({...}) publicVarName = ... and @state() private privateVarName = ... legacy decorators until the standard decorators are supported. This requires:

  • decorator.legacy = true
  • assumptions.setPublicClassFields = true
    • We need this so __define is not used as it overwrites decorators that set accessors
    • We need this.property = ... in the constructor()

The reason I'm setting target es2021 is so that we do not use class members for properties as they are not compatible with experimental decorators creating class accessors.

Reproduction

Unfortunately seems like the OXC playground is not up to date with the latest version of the transformer so here is my setup:

Input:

// src/index.ts
import { html, LitElement } from 'lit';
import { customElement, property } from 'lit/decorators.js';

@customElement('my-element')
export class MyElement extends LitElement {
  @property({type: Number}) count = 0;

  render() {
    return html`<button @click=${() => {this.count++}}>${this.count}</button>`;
  }
}

// oxc-config.mjs
{
  target: 'es2021',
  decorator: {
    legacy: true,
  },
  assumptions: {
    setPublicClassFields: true,
  }
}

output

import { html, LitElement } from "lit";
import { customElement, property } from "lit/decorators.js";
import _decorate from "@babel/runtime/helpers/decorate";
let MyElement = class MyElement extends LitElement {
        constructor(..._args) {
                super(..._args);
                this.count = 0;
        }
        render() {
                return html`<button @click=${() => {
                        this.count++;
                }}>${this.count}</button>`;
        }
};
MyElement = _decorate([customElement("my-element")], MyElement);
export { MyElement };

Expected

import { html, LitElement } from "lit";
import { customElement, property } from "lit/decorators.js";
import _decorate from "@babel/runtime/helpers/decorate";
let MyElement = class MyElement extends LitElement {
        constructor(..._args) {
                super(..._args);
                this.count = 0;
        }
        render() {
                return html`<button @click=${() => {
                        this.count++;
                }}>${this.count}</button>`;
        }
};
+ _decorate([property({ type: Number })], MyElement.prototype, "count", void 0);
MyElement = _decorate([customElement("my-element")], MyElement);
export { MyElement };

Metadata

Metadata

Assignees

Labels

C-bugCategory - BugP-highPriority - High

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions