swc-project / swc

Rust-based platform for the Web
https://swc.rs
Apache License 2.0
30.9k stars 1.2k forks source link

Emit decorator metadata #6824

Open tada5hi opened 1 year ago

tada5hi commented 1 year ago

Describe the bug

When switching from tsc to swc to transpile TypeScript to JavaScript code, the swc transpiler sets for union types with null the metadata to: Object

ts

import {
    Column,
    CreateDateColumn,
    Entity,
    JoinColumn,
    ManyToOne,
    PrimaryGeneratedColumn,
    Unique,
    UpdateDateColumn,
} from 'typeorm';
import { Client, Realm, User } from '@authup/common';
import { UserEntity } from '../user';
import { RealmEntity } from '../realm';

@Entity({ name: 'auth_clients' })
@Unique(['name', 'realm_id'])
export class ClientEntity implements Client {
    @PrimaryGeneratedColumn('uuid')
        id: string;

    @Column({
        type: 'varchar',
        length: 256,
    })
        name: string;

    @Column({
        type: 'text',
        nullable: true,
    })
        description: string | null;

    @Column({
        type: 'varchar',
        length: 256,
        select: false,
        nullable: true,
    })
        secret: string | null;

    @Column({
        type: 'text',
        nullable: true,
    })
        redirect_uri: string | null;

    @Column({
        type: 'varchar',
        length: 512,
        nullable: true,
    })
        grant_types: string | null;

    @Column({
        type: 'varchar',
        length: 512,
        nullable: true,
        default: null,
    })
        scope: string | null;

    @Column({
        type: 'varchar',
        length: 2000,
        nullable: true,
    })
        base_url: string | null;

    @Column({
        type: 'varchar',
        length: 2000,
        nullable: true,
    })
        root_url: string | null;

    @Column({
        type: 'boolean',
        default: false,
    })
        is_confidential: boolean;

    // ------------------------------------------------------------------

    @CreateDateColumn()
        created_at: Date;

    @UpdateDateColumn()
        updated_at: Date;

    // ------------------------------------------------------------------

    @Column({ default: null })
        realm_id: Realm['id'] | null;

    @ManyToOne(() => RealmEntity, { onDelete: 'CASCADE', nullable: true })
    @JoinColumn({ name: 'realm_id' })
        realm: RealmEntity | null;

    @Column({ nullable: true })
        user_id: User['id'] | null;

    @ManyToOne(() => UserEntity, { onDelete: 'CASCADE', nullable: true })
    @JoinColumn({ name: 'user_id' })
        user: UserEntity | null;
}

tsc compilation

"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClientEntity = void 0;
const typeorm_1 = require("typeorm");
const user_1 = require("../user");
const realm_1 = require("../realm");
let ClientEntity = class ClientEntity {
};
__decorate([
    (0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
    __metadata("design:type", String)
], ClientEntity.prototype, "id", void 0);
__decorate([
    (0, typeorm_1.Column)({
        type: 'varchar',
        length: 256,
    }),
    __metadata("design:type", String)
], ClientEntity.prototype, "name", void 0);
__decorate([
    (0, typeorm_1.Column)({
        type: 'text',
        nullable: true,
    }),
    __metadata("design:type", String)
], ClientEntity.prototype, "description", void 0);
__decorate([
    (0, typeorm_1.Column)({
        type: 'varchar',
        length: 256,
        select: false,
        nullable: true,
    }),
    __metadata("design:type", String)
], ClientEntity.prototype, "secret", void 0);
__decorate([
    (0, typeorm_1.Column)({
        type: 'text',
        nullable: true,
    }),
    __metadata("design:type", String)
], ClientEntity.prototype, "redirect_uri", void 0);
__decorate([
    (0, typeorm_1.Column)({
        type: 'varchar',
        length: 512,
        nullable: true,
    }),
    __metadata("design:type", String)
], ClientEntity.prototype, "grant_types", void 0);
__decorate([
    (0, typeorm_1.Column)({
        type: 'varchar',
        length: 512,
        nullable: true,
        default: null,
    }),
    __metadata("design:type", String)
], ClientEntity.prototype, "scope", void 0);
__decorate([
    (0, typeorm_1.Column)({
        type: 'varchar',
        length: 2000,
        nullable: true,
    }),
    __metadata("design:type", String)
], ClientEntity.prototype, "base_url", void 0);
__decorate([
    (0, typeorm_1.Column)({
        type: 'varchar',
        length: 2000,
        nullable: true,
    }),
    __metadata("design:type", String)
], ClientEntity.prototype, "root_url", void 0);
__decorate([
    (0, typeorm_1.Column)({
        type: 'boolean',
        default: false,
    }),
    __metadata("design:type", Boolean)
], ClientEntity.prototype, "is_confidential", void 0);
__decorate([
    (0, typeorm_1.CreateDateColumn)(),
    __metadata("design:type", Date)
], ClientEntity.prototype, "created_at", void 0);
__decorate([
    (0, typeorm_1.UpdateDateColumn)(),
    __metadata("design:type", Date)
], ClientEntity.prototype, "updated_at", void 0);
__decorate([
    (0, typeorm_1.Column)({ default: null }),
    __metadata("design:type", Object)
], ClientEntity.prototype, "realm_id", void 0);
__decorate([
    (0, typeorm_1.ManyToOne)(() => realm_1.RealmEntity, { onDelete: 'CASCADE', nullable: true }),
    (0, typeorm_1.JoinColumn)({ name: 'realm_id' }),
    __metadata("design:type", realm_1.RealmEntity)
], ClientEntity.prototype, "realm", void 0);
__decorate([
    (0, typeorm_1.Column)({ nullable: true }),
    __metadata("design:type", Object)
], ClientEntity.prototype, "user_id", void 0);
__decorate([
    (0, typeorm_1.ManyToOne)(() => user_1.UserEntity, { onDelete: 'CASCADE', nullable: true }),
    (0, typeorm_1.JoinColumn)({ name: 'user_id' }),
    __metadata("design:type", user_1.UserEntity)
], ClientEntity.prototype, "user", void 0);
ClientEntity = __decorate([
    (0, typeorm_1.Entity)({ name: 'auth_clients' }),
    (0, typeorm_1.Unique)(['name', 'realm_id'])
], ClientEntity);
exports.ClientEntity = ClientEntity;
//# sourceMappingURL=entity.js.map

swc compilation

"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "ClientEntity", {
    enumerable: true,
    get: ()=>ClientEntity
});
const _typeorm = require("typeorm");
const _user = require("../user");
const _realm = require("../realm");
var __decorate = (void 0) && (void 0).__decorate || function(decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (void 0) && (void 0).__metadata || function(k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
let ClientEntity = class ClientEntity {
};
__decorate([
    (0, _typeorm.PrimaryGeneratedColumn)('uuid'),
    __metadata("design:type", String)
], ClientEntity.prototype, "id", void 0);
__decorate([
    (0, _typeorm.Column)({
        type: 'varchar',
        length: 256
    }),
    __metadata("design:type", String)
], ClientEntity.prototype, "name", void 0);
__decorate([
    (0, _typeorm.Column)({
        type: 'text',
        nullable: true
    }),
    __metadata("design:type", Object)
], ClientEntity.prototype, "description", void 0);
__decorate([
    (0, _typeorm.Column)({
        type: 'varchar',
        length: 256,
        select: false,
        nullable: true
    }),
    __metadata("design:type", Object)
], ClientEntity.prototype, "secret", void 0);
__decorate([
    (0, _typeorm.Column)({
        type: 'text',
        nullable: true
    }),
    __metadata("design:type", Object)
], ClientEntity.prototype, "redirect_uri", void 0);
__decorate([
    (0, _typeorm.Column)({
        type: 'varchar',
        length: 512,
        nullable: true
    }),
    __metadata("design:type", Object)
], ClientEntity.prototype, "grant_types", void 0);
__decorate([
    (0, _typeorm.Column)({
        type: 'varchar',
        length: 512,
        nullable: true,
        default: null
    }),
    __metadata("design:type", Object)
], ClientEntity.prototype, "scope", void 0);
__decorate([
    (0, _typeorm.Column)({
        type: 'varchar',
        length: 2000,
        nullable: true
    }),
    __metadata("design:type", Object)
], ClientEntity.prototype, "base_url", void 0);
__decorate([
    (0, _typeorm.Column)({
        type: 'varchar',
        length: 2000,
        nullable: true
    }),
    __metadata("design:type", Object)
], ClientEntity.prototype, "root_url", void 0);
__decorate([
    (0, _typeorm.Column)({
        type: 'boolean',
        default: false
    }),
    __metadata("design:type", Boolean)
], ClientEntity.prototype, "is_confidential", void 0);
__decorate([
    (0, _typeorm.CreateDateColumn)(),
    __metadata("design:type", typeof Date === "undefined" ? Object : Date)
], ClientEntity.prototype, "created_at", void 0);
__decorate([
    (0, _typeorm.UpdateDateColumn)(),
    __metadata("design:type", typeof Date === "undefined" ? Object : Date)
], ClientEntity.prototype, "updated_at", void 0);
__decorate([
    (0, _typeorm.Column)({
        default: null
    }),
    __metadata("design:type", Object)
], ClientEntity.prototype, "realm_id", void 0);
__decorate([
    (0, _typeorm.ManyToOne)(()=>_realm.RealmEntity, {
        onDelete: 'CASCADE',
        nullable: true
    }),
    (0, _typeorm.JoinColumn)({
        name: 'realm_id'
    }),
    __metadata("design:type", Object)
], ClientEntity.prototype, "realm", void 0);
__decorate([
    (0, _typeorm.Column)({
        nullable: true
    }),
    __metadata("design:type", Object)
], ClientEntity.prototype, "user_id", void 0);
__decorate([
    (0, _typeorm.ManyToOne)(()=>_user.UserEntity, {
        onDelete: 'CASCADE',
        nullable: true
    }),
    (0, _typeorm.JoinColumn)({
        name: 'user_id'
    }),
    __metadata("design:type", Object)
], ClientEntity.prototype, "user", void 0);
ClientEntity = __decorate([
    (0, _typeorm.Entity)({
        name: 'auth_clients'
    }),
    (0, _typeorm.Unique)([
        'name',
        'realm_id'
    ])
], ClientEntity);

Input code

No response

Config

{
    "$schema": "https://json.schemastore.org/swcrc",
    "module": {
        "type": "commonjs"
    },
    "jsc": {
        "target": "es2016",
        "parser": {
            "syntax": "typescript",
            "decorators": true
        },
        "transform": {
            "decoratorMetadata": true,
            "legacyDecorator": true
        },
        "loose": true
    }
}

Playground link

No response

Expected behavior

It should choose the non null type in preference like the tsc compiler does. But I'm also not sure if the behavior differs in several aspects. I only noticed it for the union type.

Actual behavior

No response

Version

1.3.26

Additional context

No response

tada5hi commented 1 year ago

@kdy1 this would be really great if this works in the future :blush:, than it would also possible to transpile codebases which are based on decorators, like typeorm for example.

kdy1 commented 1 year ago

It's definitely not a priority and I'm very busy. Also, please don't write comments like +1

tada5hi commented 1 year ago

6809

tada5hi commented 1 year ago

It's definitely not a priority and I'm very busy. Also, please don't write comments like +1

No problem ✌️. Nevertheless, thank you very much. Swc is a really nice transpiler and besides the decorator problem, which makes it unusable for some libraries/application, i hadn't any real problems with it yet.

joshghent commented 10 months ago

I would really love this feature if it can be supported! Our particular use case is that we are using the Routing-controllers. Thanks for SWC 🎉