diff --git a/js/js.libraries/src/core/char.kt b/js/js.libraries/src/core/char.kt index 22f7c70d9ee..b6aab56c24a 100644 --- a/js/js.libraries/src/core/char.kt +++ b/js/js.libraries/src/core/char.kt @@ -18,3 +18,7 @@ package kotlin.js // actually \s is enough to match all whitespace, but \xA0 added because of different regexp behavior of Rhino used in Selenium tests public fun Char.isWhitespace(): Boolean = toString().matches("[\\s\\xA0]") + +native public fun Char.toLowerCase(): Char = noImpl + +native public fun Char.toUpperCase(): Char = noImpl diff --git a/js/js.libraries/src/core/string.kt b/js/js.libraries/src/core/string.kt index 74b2e9aaeeb..dae143b03b6 100644 --- a/js/js.libraries/src/core/string.kt +++ b/js/js.libraries/src/core/string.kt @@ -1,28 +1,20 @@ package kotlin.js -native public fun String.startsWith(s: String): Boolean = noImpl -native public fun String.endsWith(s: String): Boolean = noImpl -native public fun String.contains(s: String): Boolean = noImpl - -native public fun String.startsWith(char: Char): Boolean = noImpl -native public fun String.endsWith(char: Char): Boolean = noImpl -native public fun String.contains(char: Char): Boolean = noImpl - native public fun String.toUpperCase() : String = noImpl native public fun String.toLowerCase() : String = noImpl -native public fun String.indexOf(str : String) : Int = noImpl -native public fun String.indexOf(str : String, fromIndex : Int) : Int = noImpl +native("indexOf") +public fun String.nativeIndexOf(str : String, fromIndex : Int) : Int = noImpl -native public fun String.lastIndexOf(str: String) : Int = noImpl -native public fun String.lastIndexOf(str : String, fromIndex : Int) : Int = noImpl +native("lastIndexOf") +public fun String.nativeLastIndexOf(str : String, fromIndex : Int) : Int = noImpl library("splitString") -public fun String.split(regex: String): Array = noImpl +public fun String.splitByRegex(regex: String): Array = noImpl library("splitString") -public fun String.split(regex: String, limit: Int): Array = noImpl +public fun String.splitByRegex(regex: String, limit: Int): Array = noImpl native public fun String.substring(beginIndex : Int) : String = noImpl native public fun String.substring(beginIndex : Int, endIndex : Int) : String = noImpl diff --git a/js/js.libraries/src/core/stringsCode.kt b/js/js.libraries/src/core/stringsCode.kt index 706f448b1b9..68dc1d15afe 100644 --- a/js/js.libraries/src/core/stringsCode.kt +++ b/js/js.libraries/src/core/stringsCode.kt @@ -1,16 +1,50 @@ package kotlin.js -public inline fun String.lastIndexOf(ch : Char, fromIndex : Int) : Int = lastIndexOf(ch.toString(), fromIndex) -public inline fun String.lastIndexOf(ch: Char) : Int = lastIndexOf(ch.toString()) +public inline fun String.nativeIndexOf(ch : Char, fromIndex : Int) : Int = nativeIndexOf(ch.toString(), fromIndex) +public inline fun String.nativeLastIndexOf(ch : Char, fromIndex : Int) : Int = nativeLastIndexOf(ch.toString(), fromIndex) + +/** + * Returns `true` if this string starts with the specified prefix. + */ +public fun String.startsWith(prefix: String, ignoreCase: Boolean = false): Boolean = + regionMatches(0, prefix, 0, prefix.length(), ignoreCase) + +/** + * Returns `true` if a substring of this string starting at the specified offset [thisOffset] starts with the specified prefix. + */ +public fun String.startsWith(prefix: String, thisOffset: Int, ignoreCase: Boolean = false): Boolean = + regionMatches(thisOffset, prefix, 0, prefix.length(), ignoreCase) + +/** + * Returns `true` if this string ends with the specified suffix. + */ +public fun String.endsWith(suffix: String, ignoreCase: Boolean = false): Boolean = + regionMatches(length() - suffix.length(), suffix, 0, suffix.length(), ignoreCase = true) + -public inline fun String.indexOf(ch : Char) : Int = indexOf(ch.toString()) -public inline fun String.indexOf(ch : Char, fromIndex : Int) : Int = indexOf(ch.toString(), fromIndex) public inline fun String.matches(regex : String) : Boolean { val result = this.match(regex) return result != null && result.size() > 0 } +public fun String.equals(anotherString: String, ignoreCase: Boolean = false): Boolean = + if (!ignoreCase) + this == anotherString + else + this.toLowerCase() == anotherString.toLowerCase() + + +public fun String.regionMatches(thisOffset: Int, other: String, otherOffset: Int, length: Int, ignoreCase: Boolean = false): Boolean { + if ((otherOffset < 0) || (thisOffset < 0) || (thisOffset > length() - length) + || (otherOffset > other.length() - length)) { + return false; + } + + return substring(thisOffset, thisOffset + length).equals(other.substring(otherOffset, otherOffset + length), ignoreCase) +} + + /** * Returns a copy of this string capitalised if it is not empty or already starting with an uppper case letter, otherwise returns this * diff --git a/js/js.translator/testData/kotlin_lib.js b/js/js.translator/testData/kotlin_lib.js index c3e4f3b1d0d..1027621d12e 100644 --- a/js/js.translator/testData/kotlin_lib.js +++ b/js/js.translator/testData/kotlin_lib.js @@ -17,19 +17,6 @@ (function (Kotlin) { "use strict"; - // Shims for String - String.prototype.startsWith = function (s) { - return this.indexOf(s) === 0; - }; - - String.prototype.endsWith = function (s) { - return this.indexOf(s, this.length - s.length) !== -1; - }; - - String.prototype.contains = function (s) { - return this.indexOf(s) !== -1; - }; - // Kotlin stdlib Kotlin.equals = function (obj1, obj2) {