elsassph / hxtsdgen

TypeScript declaration file generator for Haxe JavaScript output target
65 stars 12 forks source link

Generation missing for some types #6

Closed fullofcaffeine closed 5 years ago

fullofcaffeine commented 5 years ago

Hi @nadako,

First of all, thanks for taking the time to develop and share hxtsdgen!

I've been experimenting with it lately*[0]. I added it as an extension of hxgenjs and have been playing with it standalone (the default use-case described in its README). For the most part it works great, but I've found one show-stopper (for me) issues so far. I'm not sure if it has to do with the type being complex or it being a third-party haxelib or if that's because the actual type is generated by a macro (at least I think the issue is about, but I'm not 100% sure).

Here's an example:

1) https://github.com/haxe-boilerplate/pwa-ts-haxe-boilerplate-take-2/blob/master/src/hx/client/TinkProxy.hx, this class uses tink_web's Proxy functionality and returns the call to remote.json(). This should return a typed tink Future. 2) hxtsdgen generates it as tink.core._Future.FutureObject, but it renders the d.ts invalid: there's no reference to tink.core._Future.FutureObject anywhere, so it errors with a cannot find namespace "tink" error message in tsc. See: https://github.com/haxe-boilerplate/pwa-ts-haxe-boilerplate-take-2/blob/master/src/ts/client/hx.d.ts#L18. I had to comment the generated line out and add another one with any as the return type to make tsc happy about it.

I was instead expecting hxtsdgen to generate a ts type definition for a typed tink Future (like Future<Resut>, where Result is https://github.com/haxe-boilerplate/pwa-ts-haxe-boilerplate-take-2/blob/master/src/hx/client/TinkProxy.hx#L23 and defined https://github.com/haxe-boilerplate/pwa-ts-haxe-boilerplate-take-2/blob/master/src/hx/ApiResult.hx.

Is that to be expected or is that a scenario that's not currently handled by hxtsdgen? I'm a bit lost here so any insights would be appreciated!

*[0] Here and here. Both experiments use hxtsdgen. The first one combines it with hxgenjs.

elsassph commented 5 years ago

I've just merged a PR I had waiting for a while - can you try with master branch? And otherwise please isolate the generation issue in an example (could be a gist)

fullofcaffeine commented 5 years ago

Hi Philippe, thanks a lot for the reply!

Nice to know there are other people interested in this project, I thought it was dead :)

I pulled your changes for hxtsdgen and tried compiling again. Now it errors but at least it shows what it would generate otherwise (before it'd just generate the wrong type), which seems to be now the correct type with the correct type parameter:tink.core.Outcome<Result, tink.Error>. The error says:

Uncaught exception Cannot render type tink.core.Outcome<Result, tink.Error> into a TypeScript declaration (TODO?)

The full stacktrace:

pwa-ts-haxe-boilerplate-take-2 (master●)$ haxe build-client.hxml                                                                                          [2.5.0]
/home/fullofcaffeine/haxe/haxe_libraries/hxtsdgen/0.0.1/github/8244c170445c7f763045f2eca18a1b77beab8688/src/hxtsdgen/TypeRenderer.hx:83: characters 17-22 : Uncaught exception Cannot render type tink.core.Outcome<Result, tink.Error> into a TypeScript declaration (TODO?)
/home/fullofcaffeine/haxe/haxe_libraries/hxtsdgen/0.0.1/github/8244c170445c7f763045f2eca18a1b77beab8688/src/hxtsdgen/TypeRenderer.hx:70: characters 25-95 : Called from here
/home/fullofcaffeine/haxe/haxe_libraries/hxtsdgen/0.0.1/github/8244c170445c7f763045f2eca18a1b77beab8688/src/hxtsdgen/TypeRenderer.hx:29: characters 79-97 : Called from here
/home/fullofcaffeine/haxe/haxe_libraries/hxtsdgen/0.0.1/github/8244c170445c7f763045f2eca18a1b77beab8688/src/hxtsdgen/TypeRenderer.hx:29: characters 49-98 : Called from here
/home/fullofcaffeine/haxe/haxe_libraries/hxtsdgen/0.0.1/github/8244c170445c7f763045f2eca18a1b77beab8688/src/hxtsdgen/TypeRenderer.hx:51: characters 25-95 : Called from here
/home/fullofcaffeine/haxe/haxe_libraries/hxtsdgen/0.0.1/github/8244c170445c7f763045f2eca18a1b77beab8688/src/hxtsdgen/TypeRenderer.hx:70: characters 25-95 : Called from here
/home/fullofcaffeine/haxe/haxe_libraries/hxtsdgen/0.0.1/github/8244c170445c7f763045f2eca18a1b77beab8688/src/hxtsdgen/TypeRenderer.hx:70: characters 25-95 : Called from here
/home/fullofcaffeine/haxe/haxe_libraries/hxtsdgen/0.0.1/github/8244c170445c7f763045f2eca18a1b77beab8688/src/hxtsdgen/TypeRenderer.hx:51: characters 25-95 : Called from here
/home/fullofcaffeine/haxe/haxe_libraries/hxtsdgen/0.0.1/github/8244c170445c7f763045f2eca18a1b77beab8688/src/hxtsdgen/TypeRenderer.hx:70: characters 25-95 : Called from here
/home/fullofcaffeine/haxe/haxe_libraries/hxtsdgen/0.0.1/github/8244c170445c7f763045f2eca18a1b77beab8688/src/hxtsdgen/Generator.hx:129: characters 75-96 : Called from here
/home/fullofcaffeine/haxe/haxe_libraries/hxtsdgen/0.0.1/github/8244c170445c7f763045f2eca18a1b77beab8688/src/hxtsdgen/Generator.hx:185: characters 44-111 : Called from here
/home/fullofcaffeine/haxe/haxe_libraries/hxtsdgen/0.0.1/github/8244c170445c7f763045f2eca18a1b77beab8688/src/hxtsdgen/Generator.hx:206: characters 21-42 : Called from here
/home/fullofcaffeine/haxe/haxe_libraries/hxtsdgen/0.0.1/github/8244c170445c7f763045f2eca18a1b77beab8688/src/hxtsdgen/Generator.hx:98: characters 60-73 : Called from here
/home/fullofcaffeine/haxe/haxe_libraries/hxtsdgen/0.0.1/github/8244c170445c7f763045f2eca18a1b77beab8688/src/hxtsdgen/Generator.hx:143: lines 143-212 : Called from here
/home/fullofcaffeine/haxe/haxe_libraries/hxtsdgen/0.0.1/github/8244c170445c7f763045f2eca18a1b77beab8688/src/hxtsdgen/Generator.hx:75: characters 39-67 : Called from here
/home/fullofcaffeine/haxe/haxe_libraries/hxtsdgen/0.0.1/github/8244c170445c7f763045f2eca18a1b77beab8688/src/hxtsdgen/Generator.hx:54: characters 40-61 : Called from here

And otherwise please isolate the generation issue in an example (could be a gist)

This project isolates the issue. The relevant files are:

You can reproduce by installing the required libs (I use Lix: lix download, I'm using Haxe 4.0.0-rc.2+92c7833) and then trying to compile with the build-client.hxml, and you'll get the error/stacktrace I've shown above.

benmerckx commented 5 years ago

@fullofcaffeine seems like enums are not supported in the output (yet): https://github.com/nadako/hxtsdgen/blob/8244c170445c7f763045f2eca18a1b77beab8688/src/hxtsdgen/TypeRenderer.hx#L82-L83 Newer haxe versions define enums as objects in js (http://try-haxe.mrcdk.com/#35864).

enum MyEnum {
  A;
  B(a: Int, b: String);
}

Compiles values to a structure like this:

{
  _hx_index: 0,
  __enum__: "MyEnum"
}

{
  _hx_index: 1,
  a: a,
  b: b,
  __enum__: "MyEnum"
}

To use that in ts (and have some type safety) you'd have to generate a number of typings:

enum MyEnumIndex { // Or some other name
    A = 0,
    B = 1
}

type MyEnumValue = // Again random name here
    | {_hx_index: MyEnumIndex.A}
    | {_hx_index: MyEnumIndex.B, a: number, b: string}

type MyEnum = {
  A: {_hx_index: MyEnumIndex.A}
  B(a: number, b: string): {_hx_index: MyEnumIndex.B, a: number, b: string}
}

To render it somewhat useable on the ts side:

const myenumvalue = MyEnum.B(1, 'one')
switch (myenumvalue._hx_index) {
  case MyEnumIndex.A: console.log('A'); break
  case MyEnumIndex.B: console.log(myenumvalue.a, myenumvalue.b)
}
fullofcaffeine commented 5 years ago

Ah, indeed! Thanks for elaborating!

Even though it'd be great to support the typing and emulate enums at the TS side, one possible workaround to avoid this kind of complexity now is to just handle all enums at the Haxe side. I'll try it out with the new patch from @elsassph and report my findings here.

nadako commented 5 years ago

FYI There are plans to rename that field to $index, see https://github.com/HaxeFoundation/haxe/issues/7165. In general one should not rely on enum internal structure tho...

fullofcaffeine commented 5 years ago

So, I changed the sample code to handle the Outcome at the Haxe level, see: https://github.com/haxe-boilerplate/pwa-ts-haxe-boilerplate-take-2/blob/master/src/hx/client/TinkProxy.hx#L17, but now I'm getting a StackOverflow error when compiling. Seems related to https://github.com/nadako/hxtsdgen/issues/5.

To reproduce, just try compiling with the build-client.hxml hxml file. It will hang for a while and then fail with the aforementioned error.

fullofcaffeine commented 5 years ago

FYI There are plans to rename that field to $index, see HaxeFoundation/haxe#7165. In general one should not rely on enum internal structure tho...

Opening a parenthesis here, but I have to ask - what is that field about? Is it documented somewhere?

nadako commented 5 years ago

It's not documented, because it's an implementation detail, but it's the enum constructor index, obviously :-P

fullofcaffeine commented 5 years ago

@nadako Got it :)

elsassph commented 5 years ago

Some good points here: when I use this tool, for what is a public API, I use an #if define to replace some typedefs with interfaces, and of course only use statics instead of enums.

elsassph commented 5 years ago

But maybe @benmerckx 's suggestion for enums could be usable, but enums internal representation seems to be a loving target: it was an Array, and now is replaced by an object (as Ben described).

fullofcaffeine commented 5 years ago

Some good points here: when I use this tool, for what is a public API, I use an #if define to replace some typedefs with interfaces, and of course only use statics instead of enums.

Interesting. Do you have a gist of this approach somewhere?

and of course only use statics instead of enums.

What do you mean? Could you exemplify?

elsassph commented 5 years ago

New features since a few PRs were merged:

However, for this specific issue, types are still NOT "transitively" emitted; that is if a function returns or expects a certain type, hxtsdgen won't automatically export the referenced type. You must annotate everything explicitly for now.

francescoagati commented 5 years ago

Tink json and json2object can serialize enum i think

elsassph commented 5 years ago

@francescoagati serialization is a different topic unfortunately. Haxe compiler doesn't do anything with @:expose and enums: they aren't exposed to the JS world.