Giter Site home page Giter Site logo

leonardfactory / babel-plugin-transform-typescript-metadata Goto Github PK

View Code? Open in Web Editor NEW
216.0 3.0 17.0 1.06 MB

Babel plugin to emit decorator metadata like typescript compiler

License: MIT License

JavaScript 53.52% TypeScript 46.48%
babel babel-plugin typescript decorators reflect-metadata babel-typescript

babel-plugin-transform-typescript-metadata's People

Contributors

darthtrevino avatar dependabot[bot] avatar jeffborg avatar leonardfactory avatar wtho avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

babel-plugin-transform-typescript-metadata's Issues

Emitted type is undefined for enum

Disclaimer: I am not entirely sure I understand everything that is happening here, but I'll try my best to make sense.

I am using Typeorm while compiling Typescript with Babel 7, so I need experimentalDecorators (with @babel/plugin-proposal-decorators) and emitDecoratorMetadata (with this package).

Everything runs fine, but when I run the output code, I get the following error: Data type "undefined" in "CharacterEntity.gender" is not supported by "mysql" database., which refer to:

// CharacterEntity.ts 
@Entity('characters')
export class CharacterEntity {
	// ...

	@Column()
	gender: CharacterGender;

	// ...
}

// CharacterGender.ts
export enum CharacterGender {
	MALE = 'male',
	FEMALE = 'female'
}

When looking at the code procuded by Babel, I believe only these lines are relevant:

_dec9 = (0, _typeorm.Column)(), _dec10 = Reflect.metadata("design:type", typeof _enums.CharacterGender === "undefined" ? Object : _enums.CharacterGender)

// ...

_descriptor4 = _applyDecoratedDescriptor(_class2.prototype, "gender", [_dec9, _dec10], {
  configurable: true,
  enumerable: true,
  writable: true,
  initializer: null
})

// ...

 _initializerDefineProperty(this, "gender", _descriptor4, this);

So this issue is blocking me. Note that everything compiles and runs fine when using the Typescript compiler, which seems to produce:

__decorate([
    typeorm_1.Column(),
    __metadata("design:type", String)
], CharacterEntity.prototype, "gender", void 0);

I hope this is clear enough to provide enough information, it would be great if you could look into this or simply explain what I'm doing wrong :)

Thanks !

Issue with generated code on circular dependency

Issue
It seems like the generated code through this Babel plugin raises an issue in using a variable before it is initialized.

let User = ...
_dec9 = Reflect.metadata("design:type", typeof Profile === "undefined" ? Object : Profile)
...

let Profile = ...
_dec9 = Reflect.metadata("design:type", typeof User === "undefined" ? Object : User)

I did see the same issue reported by someone here - https://stackoverflow.com/questions/61297622/typescript-metadata-reflection-references-other-classes-before-they-are-defined, but I don't think it's closed with a solution to the core problem.

Context
I'm using TypeORM for my interaction with a database. And in this example I defined two entities that need each other (a one-to-one relationship)
I provide a minimal reproduction code in this repo - https://github.com/kelvien/repro-next-circ-metadata/

It seems like you've mentioned this as one of the pitfalls. I'm just wondering if there is an alternate way in solving this issue, and perhaps a longer term solution to this.

ColumnTypeUndefinedError: Column type for Exercise#name is not defined and cannot be guessed.

Despite installing this plugin, I think I still have the same problem. Help is appreciated but honestly I want to give up.

ColumnTypeUndefinedError: Column type for Exercise#name is not defined and cannot be guessed. Make sure you have turned on an "emitDecoratorMetadata": true option in tsconfig.json. Also make sure you have imported "reflect-metadata" on top of the main entry file in your application (before any entity imported).If you are using JavaScript instead of TypeScript you must explicitly provide a column type.

Exercise.tsx

import {Entity,Column, PrimaryGeneratedColumn} from "typeorm/browser";


@Entity("Exercise")
export class Exercise{

    @PrimaryGeneratedColumn()
    id!:number;

    @Column()
    name!: Text;

    @Column()
    notes:Text;

    @Column()
    imageJSON:Text;
}

.babelrc

{
    "plugins": [
      "babel-plugin-transform-typescript-metadata",
      ["@babel/plugin-proposal-decorators", { "legacy": true }],
      ["@babel/plugin-proposal-class-properties", { "loose": true }],
    ],
    "presets": [
      "@babel/preset-typescript"
    ]
  }

snippet of package.json

...

  "devDependencies": {
    "@babel/core": "^7.12.9",
    "@types/node": "^18.0.0",
    "@types/react": "~17.0.21",
    "@types/react-native": "~0.66.13",
    "babel-plugin-transform-typescript-metadata": "^0.2.2",
    "typescript": "~4.3.5"
  },
...

Redefine type always emit Object design:type

Hello,

I have an issue, when I define a type like this:
export type Uuid = string;

The emit type is:
Object

The full case:

export type Uuid = string;

function Decorate() {
    return (target: any, prop: string): any => {
        const propertyType = Reflect.getMetadata("design:type", target, prop);
        console.log('propertyType', propertyType); // emit the Object type
    }
}

class Foo {
    @Decorate()
    public bar!: Uuid;
}

and my babel config:

// babel.config.js
module.exports = {
    presets: [
        ["@babel/preset-env", { "targets": { "node": "current" }, "modules": "commonjs" }],
        "@babel/preset-typescript"
    ],
    "plugins": [
        "babel-plugin-transform-typescript-metadata",
        ["@babel/plugin-proposal-decorators", { "legacy": true }],
        ["@babel/proposal-class-properties", { "loose": true }],
        "@babel/proposal-object-rest-spread"
    ]
};

I don't know if it's a defect coming from my Babel configuration, or a limitation from @babel/preset-typescript.

Error when import some type from another package

I have an issue, when I import some type from package (linked or regular)
problem like: can't resolve "path/to/my/node_modules/module" or "my type" is not exported from 'path/to/my/module'.

Error:

[email protected] start /Users/edelgarat/Documents/projects/babel-ts-decorator-error
webpack

[webpack-cli] Compilation finished
asset bundle.js 59 KiB [emitted] (name: main)
runtime modules 1.13 KiB 5 modules
cacheable modules 52 KiB
./src/index.ts 1.95 KiB [built] [code generated]
./node_modules/reflect-metadata/Reflect.js 50 KiB [built] [code generated]

ERROR in ./src/index.ts 10:0-73
Module not found: Error: Can't resolve 'test-package/file-with-declaration' in '/Users/edelgarat/Documents/projects/babel-ts-decorator-error/src'

webpack 5.6.0 compiled with 1 error in 631 ms
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] start: webpack
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR! /Users/edelgarat/.npm/_logs/2020-11-22T18_10_36_504Z-debug.log

Notes:

  1. When i remove 'babel-plugin-transform-typescript-metadata', this problem is missing
  2. When i remove "@decorator", this problem is missing

Entry point file:

import {SomeTypeDeclaration} from "test-package/file-with-declaration";

const someDecorator: PropertyDecorator = (target, propertyKey) => {}

class Test {
	@someDecorator
	someProperty: SomeTypeDeclaration = 5;
}

Error:

Module not found: Error: Can't resolve 'test-package/file-with-declaration' in '/Users/edelgarat/Documents/projects/babel-ts-decorator-error/src'

Webpack babel rule:

{
	test: /\.ts$/,
	use: {
		loader: "babel-loader",
		options: {
			presets: [
				["@babel/preset-typescript", {}]
			],
			plugins: [
				["@babel/plugin-proposal-decorators", { "legacy": true }],
				["@babel/plugin-proposal-class-properties", { "loose" : true }],
				"babel-plugin-transform-typescript-metadata",
			]
		}
	}
}

Demo project: https://github.com/edelgarat/babel-plugin-transform-typescript-metadata-import-error

Test stand:

  • Mac OS 10.15.4
  • Node v14.2.0

design:type metadata not created for decorated getter/setter

sample:

@decorator()
get value(): string { ... }

set value(value:string) {}

Typescript annotates the getter/setter with design:type: String for the property "value", the plugin detects it as a method and only annotates design:paramtype if you are decorating the settter, if you are decorating the getter no type information are set.

Property injection example from readme

Hey! I saw this code in the readme:

import { MyService } from './MyService';
import { Configuration } from './Configuration';

@Injectable()
class AnotherService {
  @Inject()
  config: Configuration;

  constructor(private service: MyService) {}
}

I am not sure if this is a pseudo or real code with removed imports. The part I am interested about is property injection using decorators. I've been trying to get something similar to work in typescript, babel 7 and InversifyJS for the past few hours with no success. Apparently babel decorators implementation doesn't allow setting properties from decorator. Would you mind sharing some info? :)

PS. Thanks for this babel plugin btw!

Add info about resolving bundler warnings to README

Hey!
When using this plugin I found that webpack complains about missing exports due to types not being removed by babel when used in inversify decorators. Although everything works fine these warnings can be resolved by using type imports:

import { injectable, inject } from 'inversify';
import type { Service } from './Service';
import { ServiceIdentifier } from './ServiceIdentifier';

@injectable
export class OtherService {
  constructor(
    @inject(ServiceIdentifier) service: Service
  ) {}
}

Just a small suggestion to add this to README if you think it fits there as some people might want to get rid of the warnings but don't know how.

ReferenceError occurs when referencing a class before it's defined

Hi Leonardo,
You mentioned in this stackoverflow discussion that you attempt prevent causing ReferenceErrors by using the typeof operator, but I showed how they can occur anyway and you said "let me check because this seems like a bug". After much head-scratching, I figured out why this is the case.

let x = 8;
console.log(typeof x); // "number"
console.log(typeof y); // "undefined"
console.log(typeof z); // ReferenceError: cannot access variable z before initialization
let z = 9;

If you don't define something at all, the typeof operator will give you "undefined". But in my case the class was defined too late, and that for some reason causes a ReferenceError. I don't know what to use instead of typeof (maybe a try-catch?) but I just wanted to let you know about this weird language kludge and how you could improve your plugin.

missing class metadata in parameter-decorated classes

When I transpile a simple class, which has a decorated parameter as such

class Compilee {
  constructor(@SomeDecorator() param) { }
}

then tsc will (with emitDecoratorMetadata) also set __metadata("design:paramtypes", ...) on the class itself.
This does not happen in this plugin yet.

For a reconstruction, see https://gist.github.com/wtho/0db9f9f4d224ae85d65ad9e54293abdb

Do you think this functionally could be added to this plugin?

I could give it a try, but it would probably create more coupling between the two visitors, I think you should decide how this happens.

Unexpected token problem

I may be barking up the wrong tree but is the library intended to fix the issue where TypeORM will not seem to work with Next.JS.

The error I get is:

/Users/jelling/dev/pw/longboard/next-js/jon/entities/person.ts:1
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
       ^

SyntaxError: Unexpected token {

I have worked with TypeORM extensively and typically this is because the code is expecting Javascript / the project needs to be run with ts-node. But this happens even when running npm run start after running npm run build and all of the TS should be JS at that point.

A zip of my project is attached.

nextjs typeorm wtf.zip

Add an option to disable the translation of parameter decorators

This particular translation causes problems with esbuild and esbuild-based frameworks like vite.

esbuild does not support TypeScript's emitDecoratorMetadata functionality, so we must use this brilliant Babel plugin to inject the missing metadata before running esbuild.
On the other hand, esbuild can handle TypeScript's parameter decorators perfectly well. Internally, esbuild does the same kind of translation as this Babel plugin + @babel/plugin-proposal-decorators (in legacy mode), but implemented differently.
But if this Babel plugin translates parameter decorators to function expressions, and the result is fed to esbuild, then esbuild errors out.
Therefore, could you please add an option to disable the translation of parameter decorators?

Thanks!

Adding this plugin to the plugin list breaks other Babel functionality

Hi @leonardfactory,
I noticed that when I add this plugin to my plugin list it breaks the other transformations in the config. I get this error message when it's in there:

C:\Users\Robbie\Code\ginger\src\backend\resolvers\RecipeResolver.ts:1       
(function (exports, require, module, __filename, __dirname) { import {      
                                                                     ^      

SyntaxError: Unexpected token {

This is the same error message I get if I do not use Babel at all (or remove the react-app preset). If I don't use the plugin, metadata reflection doesn't work (and TypeORM gives me errors) but everything else does. My package.json babel config is this:

"babel": {
    "plugins": [
      "babel-plugin-transform-typescript-metadata",
      "@babel/plugin-proposal-optional-chaining",
      "@babel/plugin-proposal-nullish-coalescing-operator"
    ],
    "presets": [
      "react-app"
    ]
  }

If you need more information, my project repository is here: https://github.com/RobbieGM/ginger
Thanks for your help!

Example usage with babel standalone

Is there an example of how to use your plugin with babel standalone? Is it just the same as with babelrc? I get the following error if I try to use it:

Error: Invalid plugin specified in Babel options: "babel-plugin-transform-typescript-metadata"

I am creating an online code editor that and I wanted to use your plugin with babel to transpile (Angular) TypeScript but I can't seem to get Angular services working using @Injectable. Any help would be greatly appreciated

order of applied class/constr-param decorators different than in tsc

When I compile

@ClassDec()
export class Decoratee {
  constructor(@ParamDec() param: string) {}
}

with tsc I end up with (I replaced some tslib calls with what they will be replaced with):

let Decoratee = class Decoratee {
    constructor(param) { }
};
Decoratee = tslib_1.__decorate([
    ClassDec(),
    ParamDec(),
    Reflect.metadata("design:paramtypes", [String])
], TokenService);

tslib then will call these three decorators on Decoratee, starting with the last one (Reflect.metadata), then alls ParamDec, and finally ClassDec`.

Using this plugin, I get something like this, with the order being differently:

var _dec, _dec2, _class;
var Decoratee = (
  _dec = (0, ClassDec)(),
  _dec2 = Reflect.metadata("design:paramtypes", [String]),
  _dec(
    _class = _dec2(
      _class = function Decoratee(param) {}
    ) || _class
  ) || _class
);
(0, ParamDec)()(Decoratee, undefined, 0);

Compiling this with babel will in some cases have different results, if libraries/frameworks rely on a consistent order. I do not know, if the order is defined in the metadata proposal, did not find anything so far. I think you mentioned this issue also at the bottom of README.md. Specifically in the Angular DI, the @Injectable decorator expects all @Injects inside the constructor parameter to already have been applied.

ESNext module doesn't seem to be working

While this plugin is getting us most of the way to working experimental decorators in typescript (thank you!) it doesn't seem to work if the module in tsconfig.json is set to esnext.

I am trying to get this working in a library that uses inversifyJS dependency injection, and export to both umd and es modules outputs. When compiling to commonjs modules it works fine, but with esnext modules, babel starts replacing the decorator functions' this property with undefined:

(!) thishas been rewritten toundefinedhttps://rollupjs.org/guide/en#error-this-is-undefined src\Book.js 3: import { typeof as _typeof } from "\0rollupPluginBabelHelpers.js"; 4: 5: var __decorate = this && this.__decorate || function (decorators, target, key, desc) {

The last line above changes to the following after babel finishes:
var __decorate = undefined && undefined.__decorate || function (decorators, target, key, desc) {
which unfortunately breaks everything.

[survey] TypeScript and Babel feedback needed

Hello guys, I'd like to start saying a big thank you to everyone, for your support and using this project. Given that, and having this project in production, I've started to see some issues between the TS world and the babel world (even small ones), and I'd like to give this project a direction based on real needs, current usage, etc.

Before proceeding with my own thoughts however, I'd like to ask you to tell me some info about your usage, especially:

  • Are you using it in production?
  • What is your stack? Which techs do you use that need this plugin?
  • Do you use it in the Frontend, in the Backend or both?
  • Why did you use babel / babel-loader with this plugin instead of pure tsc / ts-loader?
  • Is there any particular issue you got that is not covered by this plugin / other plugins?

I know your time is precious, and I'll understand if you don't find a moment to answer, but I think this will be precious feedback for all the community, not only for this project.
I'd like to see if there is something else I/we can do, and having the bigger picture could allow us to make our job easier, faster and more precise.

Thank you ๐Ÿ™ ,
Leonardo

design:paramtypes does not work with object assignment

Been using type-graphql and came across this issue

Here is a sample class which returns a void type for the argument

class Demo {
  @Method()
  test(@Args(): { destructedProp } : ClassType) {}
}

This sample works

class Demo {
  @Method()
  test(@Args(): arg : ClassType) {}
}

It seems the param.type here https://github.com/leonardfactory/babel-plugin-transform-typescript-metadata/blob/master/src/metadata/serializeType.ts#L25 is ObjectPattern and this results in returning voidZero()

Class method does not emit 'design:returntype' and 'design:type'

const decorator = (): PropertyDecorator => {
  return (target: object, propertyKey: string | symbol) => {
    console.log(Reflect.getMetadataKeys(target, propertyKey));
  };
};

class Testing2 {
  @decorator()
  test(): string {
    return 'hello';
  }
}

using tsc, it would print [ 'design:returntype', 'design:paramtypes', 'design:type' ]
using babel with this plugin, it would print [ 'design:paramtypes' ]

Reference Error "X is not defined"

@leonardfactory @wtho
When working with Nestjs and aws sdk, any injections of AWS sdk are not being tranformed properly. I think the issue is somewhere in here. when the condition expression fails for typeof Type === 'undefined' ? Object : Type it falls back to default type which for example is AWS.S3 and later js has no idea of how to resolve AWS.

reproduction of the issue is here. The original issue was filed in babel repro as #12150

Happy to work on this, but will need more guidence on what actually needs to be fixed.

Enums types with propery decorators are incorrectly transformed

There seems to be some issues around transforming property decorators that has Enum as a type.
Here is what is different:

Given

export function ExampleDecorator(): PropertyDecorator {
  return (target, propertyKey): void => {
   // trying to get type like this
    const type = Reflect.getMetadata('design:type', target, propertyKey);
    console.log(type) 
  };
}

enum DEMO {
  PROP_1 = '1',
  PROP_2 = 2
}
class A {
  @ExampleDecorator()
  stringProp: string

  @ExampleDecorator()
  demoProp: DEMO
}

Here is what is printed to stdout

[Function: String]
{ '2': 'PROP_2', PROP_1: '1', PROP_2: 2 }  // not sure why the type of an enum is converted to this

However, running the same code through tsc, this is what is returned (and I believe is correct)

[Function: String]
[Function: Object]

Reproduction repo:
https://github.com/whimzyLive/incorrect-enum-transform
@leonardfactory do you know something on what might be casuing this difference.

Support new decorators proposal

Any chance of supporting the new decorators proposal - i.e. not requiring the legacy flag for @babel/plugin-proposal-decorators?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.