Skip to content

Commit

Permalink
Basic support for class and interface merging
Browse files Browse the repository at this point in the history
  • Loading branch information
sgrishchenko committed May 5, 2023
1 parent b29b906 commit b0c1796
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 44 deletions.
11 changes: 7 additions & 4 deletions src/converter/plugins/DeclarationMergingPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import ts, {Declaration, InterfaceDeclaration, Node, Program} from "typescript";
import ts, {Declaration, NamedDeclaration, Node, Program} from "typescript";
import {ConverterPlugin} from "../plugin";
import {ConverterContext} from "../context";
import {Render} from "../render";
Expand Down Expand Up @@ -30,11 +30,14 @@ export class DeclarationMergingService {
return false
}

getAllInterfaceMembers(node: InterfaceDeclaration): Declaration[] {
getMembers(node: NamedDeclaration): Declaration[] | undefined {
if (!node.name) return undefined

const typeChecker = this.program.getTypeChecker()
const symbol = typeChecker.getSymbolAtLocation(node.name)
if (!symbol) return Array.from(node.members)
if (!symbol.members) return Array.from(node.members)

if (!symbol) return undefined
if (!symbol.members) return undefined

return Array.from(symbol.members.values())
.map(member => member?.declarations?.[0])
Expand Down
65 changes: 28 additions & 37 deletions src/converter/plugins/convertClassDeclaration.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,27 @@
import ts, {
ClassElement,
ConstructorDeclaration,
GetAccessorDeclaration, IndexSignatureDeclaration,
MethodDeclaration,
PropertyDeclaration, SetAccessorDeclaration,
SyntaxKind
} from "typescript";
import ts, {Declaration, ModifierLike, SyntaxKind} from "typescript";
import {createSimplePlugin} from "../plugin";
import {ifPresent} from "../render";
import {CheckCoverageService, checkCoverageServiceKey} from "./CheckCoveragePlugin";
import {InheritanceModifierService, inheritanceModifierServiceKey} from "./InheritanceModifierPlugin";
import {DeclarationMergingService, declarationMergingServiceKey} from "./DeclarationMergingPlugin";

function extractModifiers(member: Declaration): ModifierLike[] {
if (
ts.isPropertyDeclaration(member)
|| ts.isMethodDeclaration(member)
|| ts.isConstructorDeclaration(member)
|| ts.isGetAccessorDeclaration(member)
|| ts.isSetAccessorDeclaration(member)
|| ts.isIndexSignatureDeclaration(member)
) {
return Array.from(member.modifiers ?? [])
}

return []
}

type SupportedClassElement =
| PropertyDeclaration
| MethodDeclaration
| ConstructorDeclaration
| GetAccessorDeclaration
| SetAccessorDeclaration
| IndexSignatureDeclaration

function filterSupportedMembers(members: readonly ClassElement[]): readonly SupportedClassElement[] {
return members.filter((member): member is SupportedClassElement => {
return (
ts.isPropertyDeclaration(member)
|| ts.isMethodDeclaration(member)
|| ts.isConstructorDeclaration(member)
|| ts.isGetAccessorDeclaration(member)
|| ts.isSetAccessorDeclaration(member)
|| ts.isIndexSignatureDeclaration(member)
)
})
function filterPublicMembers(members: Declaration[]): readonly Declaration[] {
return members.filter(member => extractModifiers(member).every(it => it.kind !== SyntaxKind.PrivateKeyword))
}

export const convertClassDeclaration = createSimplePlugin((node, context, render) => {
Expand All @@ -38,6 +30,8 @@ export const convertClassDeclaration = createSimplePlugin((node, context, render
const checkCoverageService = context.lookupService<CheckCoverageService>(checkCoverageServiceKey)
checkCoverageService?.cover(node)

const declarationMergingService = context.lookupService<DeclarationMergingService>(declarationMergingServiceKey)

const inheritanceModifierService = context.lookupService<InheritanceModifierService>(inheritanceModifierServiceKey)

const exportModifier = node.modifiers?.find(it => it.kind === SyntaxKind.ExportKeyword)
Expand All @@ -58,23 +52,20 @@ export const convertClassDeclaration = createSimplePlugin((node, context, render
?.map(heritageClause => render(heritageClause))
?.join(", ")

const supportedMembers = filterSupportedMembers(node.members)

const publicMembers = supportedMembers
.filter(member => (member.modifiers ?? []).every(it => it.kind !== SyntaxKind.PrivateKeyword))
const mergedMembers = declarationMergingService?.getMembers(node) ?? Array.from(node.members)

// cover private members
supportedMembers
.filter(member => (member.modifiers ?? []).some(it => it.kind === SyntaxKind.PrivateKeyword))
mergedMembers
.filter(member => extractModifiers(member).some(it => it.kind === SyntaxKind.PrivateKeyword))
.forEach(member => checkCoverageService?.cover(member))

const members = publicMembers
.filter(member => (member.modifiers ?? []).every(it => it.kind !== SyntaxKind.StaticKeyword))
const members = filterPublicMembers(mergedMembers)
.map(member => render(member))
.join("\n")

const staticMembers = publicMembers
.filter(member => (member.modifiers ?? []).some(it => it.kind === SyntaxKind.StaticKeyword))
// do not use merging for static members
const staticMembers = filterPublicMembers(Array.from(node.members))
.filter(member => extractModifiers(member).some(it => it.kind === SyntaxKind.StaticKeyword))
.map(member => render(member))
.join("\n")

Expand Down
2 changes: 1 addition & 1 deletion src/converter/plugins/convertInterfaceDeclaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const convertInterfaceDeclaration = createSimplePlugin((node, context, re
?.map(heritageClause => render(heritageClause))
?.join(", ")

const members = (declarationMergingService?.getAllInterfaceMembers(node) ?? node.members)
const members = (declarationMergingService?.getMembers(node) ?? node.members)
.map(member => render(member))
.join("\n")

Expand Down
2 changes: 0 additions & 2 deletions test/sandbox/base/generated/accessor/simple.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ external class Simple {

var property: String


}


Expand All @@ -22,7 +21,6 @@ external class DifferentTypes {

var property: String


}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

@file:JsModule("sandbox-base/declarationMerging/classWithInterfaces")
@file:Suppress(
"NON_EXTERNAL_DECLARATION_IN_INAPPROPRIATE_FILE",
)

package sandbox.base.declarationMerging








external class ExampleClass {

@Suppress("DEPRECATION")
@nativeInvoke
operator fun invoke(param: String): Unit

var a: Double
var b: String
var c: Boolean
}


14 changes: 14 additions & 0 deletions test/sandbox/base/lib/declarationMerging/classWithInterfaces.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
interface ExampleClass {
(param: string): void

a: number
}

interface ExampleClass {
b: string
}

declare class ExampleClass {
a: number
c: boolean
}

0 comments on commit b0c1796

Please sign in to comment.