adamko-dev / kotlinx-serialization-typescript-generator

KxsTsGen :: Generate TypeScript interfaces from Kotlin classes
https://adamko-dev.github.io/kotlinx-serialization-typescript-generator/
Apache License 2.0
53 stars 5 forks source link

Handle naming conflicts from internally defined subclass #116

Open mdechdee opened 10 months ago

mdechdee commented 10 months ago

I have a use case here where kotlin have internal subclass

@Serializable
data class A(val c: C){
    enum class C{
        one
    }
}

@Serializable
data class B(val c: C){
    enum class C {
        two
    }
}

@Serializable
data class Test(
    val a: A,
    val b: B
)

the generated ts definition of class Test is

export interface Test {
  a: A;
  b: B;
}

export interface A {
  c: C;
}

export interface B {
  c: C;
}

export enum C {
  one = "one",
}

export enum C {
  two = "two",
}

which has some naming conflicts on enum C. Do we have a way to handle this? I see some unimplemented namespace, could it be used here?

aSemy commented 10 months ago

Thanks for the report! It's an interesting case, I'll have a think about it.

The generator could wrap each nested C class in a separate TS namespace, but that could make other generated code more verbose.

You could specify a distinct @SerialName for each C class, but that's manual and repetitive.

I've tried to make the generator as open and flexible as possible, so please try experimenting with overriding the default generator, and if you find something that works then please share it here.

aSemy commented 8 months ago

Hey @mdechdee, I've had a play around and I think I've finally got the namespace grouping working. I had implemented the skeleton for it, but never finished it. I was just playing around and I realised that it can be used to solve your problem.

It's been a while since I've used TypeScript though - can you verify that this output would be suitable for you?

export interface Test {
  a: A;
  b: B;
}

export interface A {
  content: Content;
}

export interface B {
  content: Content;
}

export namespace A {
  export interface Content {
  }
}

export namespace B {
  export interface Content {
  }
}

I've added an option so the namespaces can be controlled dynamically, so this could be fine tuned if desired.

mdechdee commented 8 months ago

@aSemy sorry for late response. I think the interface and namespace should not have naming conflict. Should be something like this

export interface Test {
    a: A;
    b: B;
}

export interface A {
    content: ANamespace.Content;
}

export interface B {
    content: BNamespace.Content;
}

export namespace ANamespace {
    export interface Content {};
}

export namespace BNamespace {
    export interface Content {};
}