Bernhard
07/24/2024, 10:09 AMprivate class SetterProxy
@Suppress("UNCHECKED_CAST")
fun <D : Document> buildUpdate(block: D.() -> Unit): Record<String, Any?> {
val setterProxy = SetterProxy() as D
setterProxy.block()
return setterProxy.toUpdates()
}
Solved this using Js ProxiesCLOVIS
07/24/2024, 1:00 PMclass Foo {
private val data = HashMap<String, Any?>()
val property2: String by data
val property3: Int by data
}
Now, if you use property2 = "foo"
, it writes that into the mapBernhard
07/24/2024, 1:00 PMCLOVIS
07/24/2024, 1:01 PMval
for each of them. That's required to be type-safe.Bernhard
07/24/2024, 1:53 PMval isProxy = Symbol("isProxy")
private class Handler(
private val currentPath: String = "",
private val updates: HashMap<String, Any?>,
) {
private fun buildPath(p: String) = if (currentPath.isEmpty()) p else "$currentPath.$p"
fun set(target: dynamic, p: PropertyKey, value: dynamic, receiver: Any) {
if (value[isProxy] === true) throw IllegalArgumentException("You are assigning an attribute to a proxy. Did you mean to assign a value instead?")
updates[buildPath("$p")] = value
}
fun get(target: Any, p: PropertyKey, receiver: Any): Any {
if (p === isProxy) return true
return Handler(buildPath("$p"), updates)
.asProxy(jso())
}
fun asProxy(target: Any): Proxy<Any> {
@Suppress("UNCHECKED_CAST")
val binding = recordOf("set" to ::set, "get" to ::get) as ProxyHandler<Any>
return Proxy(target, binding)
}
}
/**
* Allows you to assign partial updates in a typesafe manner, e.g.:
* pf2eActor.typeSafeUpdate {
* name = "test",
* system.details.level.value = 3
* }.await()
*
* will produce {'name': 'test', 'system.details.level.value': 3}
*
* Note that you *must not* assign a property to itself, e.g.
* * pf2eActor.typeSafeUpdate {
* * name = "test",
* * system.details.level.value = system.details.level.value
* * }.await()
*/
@Suppress("UNCHECKED_CAST")
fun <D : Document> D.typeSafeUpdate(block: D.() -> Unit): Promise<D> {
val result = HashMap<String, Any?>()
val proxy = Handler(updates = result)
.asProxy(this) as D
proxy.block()
return update(result.toRecord()) as Promise<D>
}
Bernhard
07/24/2024, 1:53 PM