[K/JS] Fix collections interop iterables for Map#keys ^KT-69928 Fixed
diff --git a/js/js.translator/testData/typescript-export/common.tsconfig.json b/js/js.translator/testData/typescript-export/common.tsconfig.json
index 84be715..0eea504 100644
--- a/js/js.translator/testData/typescript-export/common.tsconfig.json
+++ b/js/js.translator/testData/typescript-export/common.tsconfig.json
@@ -2,6 +2,7 @@
"compilerOptions": {
"target": "es5",
"strict": true,
+ "downlevelIteration": true,
"newLine": "lf",
"lib": ["es2015", "dom"]
}
diff --git a/js/js.translator/testData/typescript-export/js/collections-in-exported-file/collections__main.ts b/js/js.translator/testData/typescript-export/js/collections-in-exported-file/collections__main.ts
index b2f6ea7..0ebc971 100644
--- a/js/js.translator/testData/typescript-export/js/collections-in-exported-file/collections__main.ts
+++ b/js/js.translator/testData/typescript-export/js/collections-in-exported-file/collections__main.ts
@@ -25,8 +25,8 @@
function assertThrow(fn: () => void, message: string) {
try {
- fn();
- throw message;
+ fn();
+ throw message;
} catch (e) {}
}
@@ -173,6 +173,8 @@
assert(mapReadonlyView.has("a"), "Problem with accessing element in map readonly view")
assert(mapReadonlyView.get("a") == 1, "Problem with accessing element in map readonly view")
assert(joinSetOrMap(mapReadonlyView) == "[a:1][b:2][c:3]", "Problem with map readonly view iterator")
+ assert(joinMapKeys(mapReadonlyView) == "[a][b][c]", "Problem with map readonly view keys function")
+ assert(joinMapValues(mapReadonlyView) == "[1][2][3]", "Problem with map readonly view values function")
assert(consumeMap(map), "Problem with consumption of a Kotlin map")
assertThrow(() => { (mapReadonlyView as Map<string, number>).set("d", 4) }, "Map readonly view have ability to mutate the map by 'set'")
assertThrow(() => { (mapReadonlyView as Map<string, number>).delete("a") }, "Map readonly view have ability to mutate the map by 'delete'")
@@ -188,9 +190,13 @@
assert(mutableMapReadonlyView.has("d"), "Problem with accessing element in mutable map readonly view")
assert(mutableMapReadonlyView.get("d") == 4, "Problem with accessing element in mutable map readonly view")
assert(joinSetOrMap(mutableMapReadonlyView) == "[d:4][e:5][f:6]", "Problem with mutable map readonly view")
+ assert(joinMapKeys(mutableMapReadonlyView) == "[d][e][f]", "Problem with mutable map readonly view keys function")
+ assert(joinMapValues(mutableMapReadonlyView) == "[4][5][6]", "Problem with mutable map readonly view values function")
assert(!consumeMap(mutableMap), "Problem with consumption of a Kotlin mutable map as a map")
assert(consumeMutableMap(mutableMap), "Problem with consumption of a Kotlin mutable map as a mutable map")
assert(joinSetOrMap(mutableMapReadonlyView) == "[d:4][e:5][f:6][g:7]", "Problem with mutable map readonly view after original map is mutated")
+ assert(joinMapKeys(mutableMapReadonlyView) == "[d][e][f][g]", "Problem with mutable map readonly view keys function after original map is mutated")
+ assert(joinMapValues(mutableMapReadonlyView) == "[4][5][6][7]", "Problem with mutable map readonly view values function after original map is mutated")
assertThrow(() => { (mutableMapReadonlyView as Map<string, number>).set("d", 4) }, "Mutable map readonly view have ability to mutate the map by 'set'")
assertThrow(() => { (mutableMapReadonlyView as Map<string, number>).delete("a") }, "Mutable map readonly view have ability to mutate the map by 'delete'")
assertThrow(() => { (mutableMapReadonlyView as Map<string, number>).clear() }, "Mutable map readonly view have ability to mutate the map by 'clear'")
@@ -202,16 +208,24 @@
assert(mutableMapView.has("d"), "Problem with accessing element in mutable map view")
assert(mutableMapView.get("d") == 4, "Problem with accessing element in mutable map view")
assert(joinSetOrMap(mutableMapView) == "[d:4][e:5][f:6]", "Problem with mutable map view")
+ assert(joinMapKeys(mutableMapView) == "[d][e][f]", "Problem with mutable map view keys function")
+ assert(joinMapValues(mutableMapView) == "[4][5][6]", "Problem with mutable map view values function")
assert(consumeMutableMap(mutableMap), "Problem with consumption of a Kotlin mutable map as a mutable map")
assert(joinSetOrMap(mutableMapView) == "[d:4][e:5][f:6][g:7]", "Problem with mutable map view after original map is mutated")
+ assert(joinMapKeys(mutableMapView) == "[d][e][f][g]", "Problem with mutable map view keys function after original map is mutated")
+ assert(joinMapValues(mutableMapView) == "[4][5][6][7]", "Problem with mutable map view values function after original map is mutated")
mutableMapView.set("h", 8)
assert(joinSetOrMap(mutableMapView) == "[d:4][e:5][f:6][g:7][h:8]", "Problem with mutable map view after the view is mutated")
+ assert(joinMapKeys(mutableMapView) == "[d][e][f][g][h]", "Problem with mutable map view keys function after the view is mutated")
+ assert(joinMapValues(mutableMapView) == "[4][5][6][7][8]", "Problem with mutable map view values function after the view is mutated")
mutableMapView.clear()
assert(joinSetOrMap(mutableMapView) == "", "Problem with mutable map view after the view is mutated")
+ assert(joinMapKeys(mutableMapView) == "", "Problem with mutable map view keys function after the view is mutated")
+ assert(joinMapValues(mutableMapView) == "", "Problem with mutable map view values function after the view is mutated")
assert(consumeMap(KtMutableMap.fromJsMap(new Map([["a", 1], ["b", 2], ["c", 3]]))), "Problem with map to map conversion for Kotlin mutable map")
assert(consumeMutableMap(KtMutableMap.fromJsMap(new Map([["d", 4], ["e", 5], ["f", 6]]))), "Problem with map to mutable map conversion for Kotlin mutable map")
@@ -231,4 +245,24 @@
}
return result
-}
\ No newline at end of file
+}
+
+function joinMapKeys(map: ReadonlyMap<string, number>): string {
+ let result = ""
+
+ for (const key of map.keys()) {
+ result += `[${key}]`
+ }
+
+ return result
+}
+
+function joinMapValues(map: ReadonlyMap<string, number>): string {
+ let result = ""
+
+ for (const value of map.values()) {
+ result += `[${value}]`
+ }
+
+ return result
+}
diff --git a/js/js.translator/testData/typescript-export/js/collections/collections__main.ts b/js/js.translator/testData/typescript-export/js/collections/collections__main.ts
index b2f6ea7..0611b93 100644
--- a/js/js.translator/testData/typescript-export/js/collections/collections__main.ts
+++ b/js/js.translator/testData/typescript-export/js/collections/collections__main.ts
@@ -173,6 +173,8 @@
assert(mapReadonlyView.has("a"), "Problem with accessing element in map readonly view")
assert(mapReadonlyView.get("a") == 1, "Problem with accessing element in map readonly view")
assert(joinSetOrMap(mapReadonlyView) == "[a:1][b:2][c:3]", "Problem with map readonly view iterator")
+ assert(joinMapKeys(mapReadonlyView) == "[a][b][c]", "Problem with map readonly view keys function")
+ assert(joinMapValues(mapReadonlyView) == "[1][2][3]", "Problem with map readonly view values function")
assert(consumeMap(map), "Problem with consumption of a Kotlin map")
assertThrow(() => { (mapReadonlyView as Map<string, number>).set("d", 4) }, "Map readonly view have ability to mutate the map by 'set'")
assertThrow(() => { (mapReadonlyView as Map<string, number>).delete("a") }, "Map readonly view have ability to mutate the map by 'delete'")
@@ -188,9 +190,13 @@
assert(mutableMapReadonlyView.has("d"), "Problem with accessing element in mutable map readonly view")
assert(mutableMapReadonlyView.get("d") == 4, "Problem with accessing element in mutable map readonly view")
assert(joinSetOrMap(mutableMapReadonlyView) == "[d:4][e:5][f:6]", "Problem with mutable map readonly view")
+ assert(joinMapKeys(mutableMapReadonlyView) == "[d][e][f]", "Problem with mutable map readonly view keys function")
+ assert(joinMapValues(mutableMapReadonlyView) == "[4][5][6]", "Problem with mutable map readonly view values function")
assert(!consumeMap(mutableMap), "Problem with consumption of a Kotlin mutable map as a map")
assert(consumeMutableMap(mutableMap), "Problem with consumption of a Kotlin mutable map as a mutable map")
assert(joinSetOrMap(mutableMapReadonlyView) == "[d:4][e:5][f:6][g:7]", "Problem with mutable map readonly view after original map is mutated")
+ assert(joinMapKeys(mutableMapReadonlyView) == "[d][e][f][g]", "Problem with mutable map readonly view keys function after original map is mutated")
+ assert(joinMapValues(mutableMapReadonlyView) == "[4][5][6][7]", "Problem with mutable map readonly view values function after original map is mutated")
assertThrow(() => { (mutableMapReadonlyView as Map<string, number>).set("d", 4) }, "Mutable map readonly view have ability to mutate the map by 'set'")
assertThrow(() => { (mutableMapReadonlyView as Map<string, number>).delete("a") }, "Mutable map readonly view have ability to mutate the map by 'delete'")
assertThrow(() => { (mutableMapReadonlyView as Map<string, number>).clear() }, "Mutable map readonly view have ability to mutate the map by 'clear'")
@@ -202,16 +208,24 @@
assert(mutableMapView.has("d"), "Problem with accessing element in mutable map view")
assert(mutableMapView.get("d") == 4, "Problem with accessing element in mutable map view")
assert(joinSetOrMap(mutableMapView) == "[d:4][e:5][f:6]", "Problem with mutable map view")
+ assert(joinMapKeys(mutableMapView) == "[d][e][f]", "Problem with mutable map view keys function")
+ assert(joinMapValues(mutableMapView) == "[4][5][6]", "Problem with mutable map view values function")
assert(consumeMutableMap(mutableMap), "Problem with consumption of a Kotlin mutable map as a mutable map")
assert(joinSetOrMap(mutableMapView) == "[d:4][e:5][f:6][g:7]", "Problem with mutable map view after original map is mutated")
+ assert(joinMapKeys(mutableMapView) == "[d][e][f][g]", "Problem with mutable map view keys function after original map is mutated")
+ assert(joinMapValues(mutableMapView) == "[4][5][6][7]", "Problem with mutable map view values function after original map is mutated")
mutableMapView.set("h", 8)
assert(joinSetOrMap(mutableMapView) == "[d:4][e:5][f:6][g:7][h:8]", "Problem with mutable map view after the view is mutated")
+ assert(joinMapKeys(mutableMapView) == "[d][e][f][g][h]", "Problem with mutable map view keys function after the view is mutated")
+ assert(joinMapValues(mutableMapView) == "[4][5][6][7][8]", "Problem with mutable map view values function after the view is mutated")
mutableMapView.clear()
assert(joinSetOrMap(mutableMapView) == "", "Problem with mutable map view after the view is mutated")
+ assert(joinMapKeys(mutableMapView) == "", "Problem with mutable map view keys function after the view is mutated")
+ assert(joinMapValues(mutableMapView) == "", "Problem with mutable map view values function after the view is mutated")
assert(consumeMap(KtMutableMap.fromJsMap(new Map([["a", 1], ["b", 2], ["c", 3]]))), "Problem with map to map conversion for Kotlin mutable map")
assert(consumeMutableMap(KtMutableMap.fromJsMap(new Map([["d", 4], ["e", 5], ["f", 6]]))), "Problem with map to mutable map conversion for Kotlin mutable map")
@@ -231,4 +245,24 @@
}
return result
-}
\ No newline at end of file
+}
+
+function joinMapKeys(map: ReadonlyMap<string, number>): string {
+ let result = ""
+
+ for (const key of map.keys()) {
+ result += `[${key}]`
+ }
+
+ return result
+}
+
+function joinMapValues(map: ReadonlyMap<string, number>): string {
+ let result = ""
+
+ for (const value of map.values()) {
+ result += `[${value}]`
+ }
+
+ return result
+}
diff --git a/libraries/stdlib/js/runtime/collectionsInterop.kt b/libraries/stdlib/js/runtime/collectionsInterop.kt
index 33f4eb9..4052cf4 100644
--- a/libraries/stdlib/js/runtime/collectionsInterop.kt
+++ b/libraries/stdlib/js/runtime/collectionsInterop.kt
@@ -200,7 +200,7 @@
forEach: (dynamic, dynamic) -> Unit,
): dynamic {
val mapView = objectCreate<JsMapView<K, V>>().also {
- js("it[Symbol.iterator] = entriesIterator")
+ js("it[typeof Symbol !== \"undefined\" ? Symbol.iterator : null] = entriesIterator")
defineProp(it, "size", mapSize, VOID)
}
@@ -211,7 +211,7 @@
'delete': mapRemove,
clear: mapClear,
has: mapContains,
- keys: valuesIterator,
+ keys: keysIterator,
values: valuesIterator,
entries: entriesIterator,
forEach: function (cb, thisArg) { forEach(cb, thisArg || mapView) }
@@ -223,13 +223,17 @@
private fun <T> createJsIteratorFrom(iterator: Iterator<T>, transform: (T) -> dynamic = { it }): dynamic {
val iteratorNext = { iterator.next() }
val iteratorHasNext = { iterator.hasNext() }
- return js("""{
+ val jsIterator = js("""{
next: function() {
var result = { done: !iteratorHasNext() };
if (!result.done) result.value = transform(iteratorNext());
return result;
- }
+ },
}""")
+
+ js("jsIterator[typeof Symbol !== \"undefined\" ? Symbol.iterator : null] = function() { return jsIterator }")
+
+ return jsIterator
}
private fun forEach(cb: (dynamic, dynamic, dynamic) -> Unit, thisArg: dynamic) {