Hi everyone, I'm having issues with `kotlin.Number...
# javascript
o
Hi everyone, I'm having issues with
kotlin.Number
:
Cannot read property 'prototype' of undefined
This is the code (generated JS):
Copy code
BigDecimal.prototype = Object.create(Number_0.prototype)
And
Number_0
:
Copy code
var Number_0 = Kotlin.kotlin.Number;
This are my source sets
Copy code
val jsMain by getting {
  dependsOn(commonMain)
  dependencies {
    implementation(kotlin("stdlib-js"))
  }
}

val jsTest by getting {
  dependsOn(jsMain)

  dependencies {
    implementation(kotlin("test-js"))
  }
}
t
1. Do you have constants on file level? 2. Do you use DCE? 3. Which Kotlin version do you use?
o
Hi Victor: 1. No DCE 2. No global constant 3. Koltin 1.3.72 I found out is really easy to reproduce (I was able to reproduce it in two different projects)
Just adding this
Copy code
class BigDecimal : Number() {
    override fun toByte(): Byte = 0
    override fun toChar(): Char = '0'
    override fun toDouble(): Double = 0.0
    override fun toFloat(): Float = 0f
    override fun toInt(): Int = 0
    override fun toLong(): Long = 0L
    override fun toShort(): Short = 0
}
Removing it works, I added it to another project and it broke it too
r
seems like a bug it fails with kotlin playground as well: https://pl.kotl.in/8AfBGNlku
three years old bug
o
You're right 😢
r
it's still failing with 1.4-M3, so there is nothing else you can do but vote
o
All hope is lost, and the known workaround involves manual editing the generated JS file
t
What is your use case about
BigDecimal
?
r
@Omar Mainegra I've came up with some crazy workaround (just for fun 😉)
1. Add
implementation(npm("webpack-inject-plugin"))
to your dependencies in
build.gradle.kts
2. Put
inject.js
file into your
webpack.config.d
dir with the following content:
Copy code
;(function() {
    const InjectPlugin = require('webpack-inject-plugin').default;

    config.plugins.push(
    new InjectPlugin(function() {
            return "arguments[2]('../../packages_imported/kotlin/1.3.72/kotlin.js').kotlin.Number = Number;"
        })
    );
})();
It works for me
(at least in dev mode 😉)
this is better (works in both dev and production mode):
Copy code
;(function() {
    const InjectPlugin = require('webpack-inject-plugin').default;

    config.plugins.push(
    new InjectPlugin(function() {
            return "require('kotlin').kotlin.Number = Number;"
        })
    );
})();
o
Hi Robert, I'll try your suggestion, thanks for it
Hi @Robert Jaros sadly it doesn't work for me, probably is the
webpack-inject-plugin
, I know the configuration is being applied (it's copied to
karma.conf.js
and prints)
Also editing manually the generated file with your change works
It looks like the plugin is not injecting the code 😢
r
have you added npm dependency?
o
Yes
Sorry, this one
r
have you tried generating final bundle and check if the js file contains this code snippet?
o
Actually I'm just running the tests for now
./gradlew jsBrowserTest
r
perhaps it's not working for tests I haven't tested this
I just tested simple run and browserProductionWebpack
o
Yes, tested that and and I can't find the generated code
Not in the non-dce and the dce version
The plugins is actually loaded
t
dependsOn
are redundant here
👍 1
Do you use
kotlin("multiplatform")
plugin?
o
Yeap
Hi @turansky, do you know if it's possible to hook in the middle of the gradle task (i.e
jsBrowserTest
) so I can patch the generated JS file before runnig the tests/packaging?
t
Simplest way - webpack
Another way - add custom task after compilation
Webpack plugin - more safe option
o
😢 But it didn't work, let me try it again, also this you just sent me
I came up with this simple gradle task to patch
kotlin.js
before running the tests
t
It can be simplified
compileTestKotlinJs
can be finalized with
patch
Also
configure
is redundant,
invoke
call it inside
o
Cool, thanks for the feedback
I have a weird issue with the patch, given my original definition:
Copy code
expect class BigDecimal : Number {
...
}
this fails in JS but passes in JVM and iOS:
Copy code
@Test
fun is_a_Number() {
  assertTrue { BigDecimal(1) is Number }
}
If I force the cast with
BigDecimal(1) as Number
I got:
ClassCastException: Illegal cast
t
My suggestion - it will works in ES6 only
Try this
Copy code
class BigDecimal extends Number {
    constructor(value) {
        super(value)
    }
}
Screenshot 2020-07-27 at 23.48.25.png
o
So I need to write a
BigDecimal
part in JS?
This is the expect class in Kotlin
t
Kotlin
1.3.72
?
o
Yeap
t
KT-31126 - possible root cause
Generated JS check required
o
😢 Not again
the PR is merged, is not in 1.3.72?
t
1.4+ 😞
o
Anyway, thanks a lot
t
In any case generated JS check required
external BigDecimal will work in any Kotlin
o
Sorry, I didn't get these two last comments
t
1.
BigDecimal
as ES6 class works 2. You can fix constructor generated by Kotlin with
jsPatch
task 3. PROFIT
o
Ahh, yes, the class works just fine, all the tests are passing, I just don't know what to do to make the
is Number
expression work in JS
I tried adding a primary constructor as suggested in the PR, like
actual class BigDecimal(private val raw: BigNum) : Number()
but it didn't work
And I'm not a Javascript developer, so IDK what could I try to make it work in JS side
t
You can support
is
check for
BigDecimal
manually 🙂 https://pl.kotl.in/J6Vgadnf0
jsPatch
can do it too
o
Awesome tip, I'm using
jsPatch
to "override"
Kotlin.isNumber
, I added
Copy code
_.isNumber = function (a) { return typeof a == 'number' || a instanceof Kotlin.Long || a.constructor.name == 'BigDecimal'; };
And the test (
assertTrue { BigDecimal(1) is Number }
) is passing
I couldn't use
a instanceof Kotlin.BigDecimal
it was complaining the right side is not an object
t
a instanceof BigDecimal
- my expectation (without
Kotlin.
)
BigDecimal
is your custom class, isn’t it?
o
Yes, but since that's not defined until later (not in kotlin.js) it can't find the symbol yet
ReferenceError: BigDecimal is not defined
Screen Shot 2020-07-28 at 10.12.35 AM.png
t
No function BigDecimal in your js?
o
This is what's generated
Copy code
BigDecimal.prototype = Object.create(Number_0.prototype);
BigDecimal.prototype.constructor = BigDecimal;
And
var Number_0 = Kotlin.kotlin.Number;
t
function BigDecimal
?
o
Yes
Copy code
function BigDecimal(raw) {
  BigDecimal$Companion_getInstance();
  Number_0.call(this);
  this.raw_0 = raw;
}
t
instanceof
must work in that case
o
It's really weird, I got that error
t
o
Wow, that's so good, I didn't even know that was possible
t
Full case must be realized via
jsPatch
in plain js (sideeffect mode)
o
Gotcha, thanks for everything