Is it expected or a bug, that `@JsPlainObject` ign...
# javascript
v
Is it expected or a bug, that
@JsPlainObject
ignores
@Deprecated
annotations? I wanted to have one property with level
HIDDEN
to have two methods, one that sets it to
false
and one that sets it to
true
as that changes what the handled JS lib returns and thus needs a different return type. But with the
invoke
and
copy
methods by
@JsPlainObject
I can just freely use the property and get not even a deprecation warning.
t
Looks like deprecated extension property is what you need 🙂
v
What's that? I'd expect js-plain-objects to copy the deprecation annotation from the fields it replicates. If I don't use js-plain-objects but
jso { ... }
it works exactly like intended
t
Does it work like you described with data classes?
v
Iirc, yes, but I'd need to test to be sure
Hm, with a data class I at least see the deprecated annotation in the quickdoc of intellij, but indeed neither the constructor nor the copy method complains when using with level
ERROR
or is hidden with
HIDDEN
. Wtf?
.... o_O Ok, seems my mental model is greatly incorrect. Even on data and also on normal classes, the constructor parameter can be used just fine. Just when then then accessing the property otherwise the
@Deprecated
kicks in. 😕
So what is that "deprecated extension" you mentioned?
Otherwise I need to make one option class for the user-facing side, and one option class as
external
and then translate from one to the other
t
Copy code
@Deprecated
var MyOptions.prop: String?
    get() = asDynamic().prop
    set(value) { asDynamic().prop = value }
v
Ah, I see, that doesn't work out though in my case. The
ncc
has two modes. If you give
watch = false
(the default) you get a
Promise
returned. If you give
watch = true
you instead get an object returned on which you can register two types of handlers and can close the watcher. I always used the
Promise
version so just left out the
watch
parameter. Now that I looked into your comments, I've seen again this situation and thought I try to implement it in my PR too. So I need two separate functions with same parameters but different return type and for one
watch
is fixed
true
, for the other
false
. So I though I add
watch
with deprecated hidden and just set it from the two separate methods, so the extension property wouldn't work here I think. I probably have to go with two versions of the interface unless you have another great idea for me. 🙂
t
We have multiple pills for different cases
Do you have link on described API?
t
In this case separate function
nccWatch
is what I expect
watch
property - internal extension property
It's not single option, but it's probably simplest
v
Ah, as internal extension property, that could maybe do, yeah. I tried internal val first but that didn't compile
t
Also
watch
type can be type parameter
It's more flexible (I like it more)
But checks required
v
you mean as reified type parameter and then checking that?
How would that work with different return types?
Or did I get you wrong again?
t
Copy code
@JsName("true")
external object Watch

@JsPlainObject
external interface NccOptions<W: Watch?> {
    val watch: W
}

external fun ncc(options: NccOptions<Nothing?>): Promise<CompileResult>

external fun ncc(options: NccOptions<Watch>): WatchResult
v
Oh, that looks interesting, I'll give that a try, thanks
t
NccOptions<out W: Watch?>
-
out
should help also
v
Hm, almost there. If I set
watch = null
it uses the one, if I use
watch = Watch
it uses the other. But I have to set either explicitly
I guess I just did something wrong still
t
Looks like best solution for start
v
With needing to give
watch
explicitly? 😕
That somehow feels wrong, but if you say so
t
It's interop cost :(
👌 1
Somehow you should say which mode you want
Will it request
watch
if you will declare type parameter?
ncc(NccOptions<Void>())
?
New favourite, without additional parameters:
Copy code
@JsName("true")
external object Watch

@JsPlainObject
external interface NccOptions {
    // all options except `watch`
}

@JsPlainObject
external interface NccBuildOptions: NccOptions

@JsPlainObject
external interface NccWatchOptions {
    val watch: Watch
}

external fun ncc(options: NccBuildOptions): Promise<BuildResult>

external fun ncc(options: NccWatchOptions): WatchResult
This variant is better, because in "watch" mode you can have additional options.
v
Will it request
watch
if you will declare type parameter?
ncc(NccOptions<Void>())
Yes, requires to give
watch = null
. And
NccOptions<Watch>
requires to give
watch = Watch
New favourite, without additional parameters:
But this would then still require to declare twice that you want to watch, doesn't it? Because you will have to do
NccWatchOptions(watch = Watch)
.
So I think I'm back to
ncc()
and
nccWatched()
, but now have a good way (I hope) to implement it thanks, you'll see the result in the PR. Two more questions about the hardest part in software engineering, naming. Maybe you have a better idea than me, I'm feeling a bit uncreative right now. For the non-watched mode, an
NccResult
is returned which has non-null
code
and nullable
map
and
assets
. For the watched mode the watch handler you can register gets something similar. It is documented as having the same three fields, plus additionally
err
where errors will be supplied. Actually, in reality you either get an object that has only
err
set, or one that is set like the result of non-watched execution. Right now I have named the class
NccResultWithError
, with the same fields as
NccResult
, just all nullable (thus not subclass) and additionally
err
nullable. Do you have a better idea how to handle it or how to name it? And the second thing is the thing you get returned in watched mode. Right now I called it
NccHandlerRegistry
, as you can register one watch handler and one rebuild handler. But you can (and need to) also call
close()
on it to close the watcher that is created internally. So the
NccHandlerRegistry
name does not fully apply.
t
I see 2 modes:
build
and
watch
NccBuildOptions -> NccBuildResult
NccWatchOptions -> NccWatchResult
v
Hm, well, both build and do exactly the same, just the result handling is different, but I think I get the point maybe
t
So I think I'm back to
ncc()
and
nccWatched()
This variant will be hard in support, when more watch options will be added
From Vite experience: 1. Build options are common 2. Watch options = build options + additional options
Separate options for build required only for safe
ncc
call
More examples
*Options
->
*Result
you can find in TanStack projects - like here
v
Ah, I think now we are getting somewhere good finally. Now I can do
ncc()
or
ncc(NccOptions(...))
or
ncc(NccWatchOptions(...))
without a consumer-facing
watch
property. 🙂
Was the
NccWatchResult
for the thing with
err
, or for the thing where you register the handlers and close the watcher? I guess for the former one, any idea for the latter?
t
Copy code
interface NccBuildResult {
    val err?
}

interface NccBuildSuccessResult :
    NccBuildResult {
    val code
    val map
    val assets
}

interface NccBuildErrorResult :
    NccBuildResult {
    val err
}
v
How would you use that? You cannot check
is
, can you?
And the non-watched does never get
err
. The non-watched call always gets
code
,
map?
,
assets?
. The handler you can register for the watched call is documented to get
err
,
code
,
map
,
assets
but actually is either getting
err
or
code
,
map?
,
assets?
Wait a moment, I can update the PR with the current state