I remember already asking this question somewhere,...
# javascript
a
I remember already asking this question somewhere, but I do not remember the answer. I have a tree-like object (not map of maps, but close to it), now I need this object to be converted to its structure copy represented as
dynamic
to be passed to JS library. What is the easiest way to do it?
a
No, I need it to work other way around: from typed kotlin object to dynamic. For now I just created a map of maps from my object. I will see if it works.
The ideal way would be to create typed wrapper for the library, but I am not sure it is possible, it dispatches input based on field values.
r
Oops, my bad. Well, to my understanding you can always get dynamic empty
js("{}")
and fill it from map or any other source you have. Mapping an object tree to a
Map
can be done via
Mapper
(ooof) from
kotlinx.coroutines
.
a
Yeah, thanks. I will try different approaches as soon as I win the fight with webpack... again
r
I wholeheartedly wish you good luck with that.
a
I am starting to think that just dropping files into
js
directory seems to be the best solution.
s
Could you share an example of your kotlin object (what's close to map of maps 🤔)? Is your JS library public? Maybe it is possible to wrap it
r
The easiest way is to serialize it to String with kotlinx.serialization and parse with js.JSON. It's a one-liner:
Copy code
kotlin.js.JSON.parse(JSON.plain.stringify(serializer, data))
Probably not very optimized solution, but I use it often 🙂
a
@Svyatoslav Kuzmich [JB], this one: https://github.com/altavir/dataforge-core/blob/df8a5509d63f4121b9ac868dbcd6e44bf3fb1aa7/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Meta.kt#L40. Could you elaborate on what do you mean by "wrap". I did not think that there is a zero copy way to do it. I was intended to do it other way around and create an implementation based on dynamic for JS platform, but zero copy wrapper would be of course better.
s
I noticed
my object is expected to be called by
obj.foo
I assumed map uses String keys. Kotlin/JS
Map
can't be directly used for these cases. But there other zero copy approaches and they heavily depend on the context: If set of keys is limited, you could use
external interface/class
where property correspond to entries:
Copy code
external interface M { 
var keyName1: ValueType?, 
var keyName2: ValueType2?, 
... 
}
This will not fly since you use generic strings. Other approach would be to use something similar to "native" JS map instead of Kotlin `Map`:
Copy code
class NativeJsMap<V: Any> {
    operator fun get(key: String): V? = this.asDynamic()[key]
    operator fun set(key: String, value: V) {
        this.asDynamic()[key] = value 
    }
}
This is useful for simple interop cases, but making it a full replacement of
Map
is hard, especially in multiplatform code. From what I see, making copy is the way.
a
OK, thank you very much. For now. performance is not critical and copy should pose no problem. Though I did not fully understand second proposal. I can make easily wrap my structure in an interface which will have just
get(String)
method. Does JS automatically call
A.get("foo")
when asked for
A.foo
?
s
JS doesn't call
A.get(...)
when asked for property.
get
and
set
are purely for
[]
operator overloading on Kotlin level.
this.asDynamic()[key]
does the trick, it accesses native JS property on the object. In Kotlin you can do
A.asDynamic()["foo"] = fooValue;
and then use it in javascript as
A["foo"]
(or equivalent
A.foo
)
a
OK, it explains how to wrap dynamic in kotlin but not how to pass kotlin as dynamic
s
You are right, unless you use it from the get go. Which is probably not feasible in your case. P.S. I'm wondering if
dynamic
is the best term to describe what you mean.
dynamic
is a very general Kotlin type, literally anything can be stored in it. I'm not sure how to name it, but is more like "object-based JS string-maps" 😃.
a
Yeah, I know. The problem is that JS library I am trying to use is badly written. The transported object could have different structure depending on a flag. Maybe it is good idea to create a sealed class and cover all possibilities, but for now I will go with dynamic to save time.