How to set JsName for property support field in Kotlin?

I played with Kotlin without JavaScript backend support in 1.0.x, and now I'm trying to port my toy project to 1.1.x. These are the simplest bones of a single-page web application that interacts with PouchDB. To add data to PouchDB, you need JavaScript objects with specific properties _idand _rev. They also should not have any other properties starting with _, because they are reserved by PouchDB.

Now, if I create such a class, I can send instances to PouchDB.

class PouchDoc(
        var _id: String
) {
    var _rev: String? = null
}

However, if I do something to make the properties virtual - redefine their interface or open a class and create a subclass that redefines them - the field name _idwill be distorted by something like that _id_mmz446$_0and therefore PouchDB rejects the object. If I applied a property @JsName("_id")to a property that affects only the generated getter and setter, it still leaves a support field with a malformed name.

In addition, for any virtual properties whose names do not begin with _, PouchDB will accept an object, but it only stores support fields with their mutilated names, and not with names that would be named.

So far I can get around everything, making them non-virtual, I think. But I was thinking about exchanging interfaces between the PouchDoc and non-PouchDoc classes in Kotlin, and it seems like I can't do this.

, , Kotlin?

+6
2

, https://youtrack.jetbrains.com/issue/KT-8127

, : https://youtrack.jetbrains.com/issue/KT-17682 https://youtrack.jetbrains.com/issue/KT-17683

, - .

interface PouchDoc1 {
    var id: String
    var _id: String
        get() = id
        set(v) { id = v}

    var rev: String?
    var _rev: String?
        get() = rev
        set(v) { rev = v}
}

class Impl1 : PouchDoc1 {
    override var id = "id0"
    override var rev: String? = "rev0"
}

interface PouchDoc2 {
    var id: String 
        get() = this.asDynamic()["_id"]
        set(v) { this.asDynamic()["_id"] = v}

    var rev: String?
        get() = this.asDynamic()["_rev"]
        set(v) { this.asDynamic()["_rev"] = v}
}

class Impl2 : PouchDoc2 {
    init {
        id = "id1"
        rev = "rev1"
    }
}

external interface PouchDoc3 { // marker interface 
}

var PouchDoc3.id: String 
    get() = this.asDynamic()["_id"]
    set(v) { this.asDynamic()["_id"] = v}

var PouchDoc3.rev: String?
    get() = this.asDynamic()["_rev"]
    set(v) { this.asDynamic()["_rev"] = v}

class Impl3 : PouchDoc3 {
    init {
        id = "id1"
        rev = "rev1"
    }
}

fun keys(a: Any) = js("Object").getOwnPropertyNames(a)

fun printKeys(a: Any) {
    println(a::class.simpleName)
    println(" instance keys: " + keys(a).toString())
    println("__proto__ keys: " + keys(a.asDynamic().__proto__).toString())
    println()
}

fun main(args: Array<String>) {
    printKeys(Impl1())
    printKeys(Impl2())
    printKeys(Impl3())
}
+2

JetBrains, , JetBrains https://discuss.kotlinlang.org/t/controlling-the-jsname-of-fields-for-pouchdb-interop/2531/. , @bashor.

, @bashor , , .

class JSMapDelegate<T>(
        val jsobject: dynamic
) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return jsobject[property.name]
    }
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        jsobject[property.name] = value
    }
}

external interface PouchDoc4 {
    var _id: String
    var _rev: String
}

class Impl4() : PouchDoc4 {
    override var _id: String by JSMapDelegate<String>(this)
    override var _rev: String by JSMapDelegate<String>(this)

    constructor(_id: String) : this() {
        this._id = _id
    }
}

jsobject[property.name] = value set , ...

( , , , getter/setter, , , @bashor PouchDoc2.)

Alexey Kotlin : " ( ) ( ): / JS, ". , JavaScript, getters/seters, Kotlin . , , , , , .

external interface PouchDoc5 {
    var _id: String
    var _rev: String
}

external class Impl5 : PouchDoc5 {
    override var _id: String
    override var _rev: String
}

fun <T> create(): T = js("{ return {}; }")
fun Impl5(_id: String): Impl5 {
    return create<Impl5>().apply {
        this._id = _id
    }
}

keys

null
 instance keys: _id
__proto__ keys: toSource,toString,toLocaleString,valueOf,watch,unwatch,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,__defineGetter__,__defineSetter__,__lookupGetter__,__lookupSetter__,__proto__,constructor

. -,

fun <T> create(): T = js("{}")

( Kotlin 1.1),

function jsobject() {
}

undefined. , , .

-,

fun Impl5(_id: String): Impl5 {
    return (js("{}") as Impl5).apply {
        this._id = _id
    }
}

Impl5, ReferenceError: Impl5 is not defined ( , Firefox). . , , , , .

, create inline, : -)

0

Source: https://habr.com/ru/post/1016880/


All Articles