@@ -29,6 +29,11 @@ public func jsIndexOf(_ s: String, _ sub: String) -> Double {
2929/// JavaScript truthiness for the values translated code tests.
3030public func jsTruthy ( _ value : Any ? ) -> Bool { jsIsTruthy ( value ) }
3131
32+ // A typed value's truthiness, chosen over `Any?`'s by overload resolution: no box, and no casts to find its type.
33+ @ inlinable public func jsTruthy ( _ value : Double ) -> Bool { value != 0 && ! value . isNaN }
34+ @ inlinable public func jsTruthy ( _ value : String ) -> Bool { ! value . isEmpty }
35+ @ inlinable public func jsTruthy ( _ value : Bool ) -> Bool { value }
36+
3237/// `a.slice(start, end)`: negative indexes count from the end; out-of-range clamps.
3338public func jsSlice < T > ( _ a : [ T ] , _ start : Double = 0 , _ end : Double ? = nil ) -> [ T ] {
3439 let ( lo , hi ) = jsRange ( a . count , start , end )
@@ -37,19 +42,19 @@ public func jsSlice<T>(_ a: [T], _ start: Double = 0, _ end: Double? = nil) -> [
3742
3843/// `s.slice(start, end)` in UTF-16 units, as JavaScript indexes strings.
3944public func jsSlice ( _ s : String , _ start : Double = 0 , _ end : Double ? = nil ) -> String {
40- let units = Array ( s . utf16 )
41- let ( lo , hi ) = jsRange ( units . count , start , end )
42- return lo < hi ? String ( decoding : units [ lo ..< hi ] , as : UTF16 . self ) : " "
45+ jsUnitSlice ( s ) { count in
46+ let ( lo , hi ) = jsRange ( count , start , end )
47+ return lo < hi ? lo ..< hi : 0 ..< 0
48+ }
4349}
4450
4551private func jsRange ( _ count : Int , _ start : Double , _ end : Double ? ) -> ( Int , Int ) {
4652 ( jsRelativeIndex ( start , count ) , end . map { jsRelativeIndex ( $0 , count ) } ?? count )
4753}
4854
4955public func jsCharAt ( _ s : String , _ index : Double ) -> String {
50- let i = jsToIntegerOrInfinity ( index ) , u = s . utf16
51- guard i >= 0 , i < Double ( u . count ) else { return " " }
52- return String ( decoding : CollectionOfOne ( u [ u . index ( u . startIndex , offsetBy : Int ( i ) ) ] ) , as : UTF16 . self )
56+ let i = jsToIntegerOrInfinity ( index )
57+ return jsUnitSlice ( s ) { count in i >= 0 && i < Double ( count ) ? Int ( i ) ..< ( Int ( i ) + 1 ) : 0 ..< 0 }
5358}
5459
5560/// `s[index]`: undefined unless the index is one of the string's.
@@ -59,12 +64,12 @@ public func jsCharAtOrUndefined(_ s: String, _ index: Double) -> String? {
5964
6065/// `s.replace(a, b)` with a string pattern replaces the first match only, found by UTF-16 units.
6166public func jsReplace ( _ s : String , _ pattern : String , _ replacement : String ) -> String {
62- let u = Array ( s . utf16 ) , p = Array ( pattern . utf16 )
67+ let u = jsUnits ( s ) , p = jsUnits ( pattern )
6368 guard let at = jsUnitsIndex ( u , p , from : 0 ) else { return s }
6469 var out = Array ( u [ ..< at ] )
6570 out += jsSubstitution ( replacement , matched : pattern , at : at , in : s , captures : [ pattern ] , groups : nil ) . utf16
6671 out += u [ ( at + p . count ) ... ]
67- return String ( decoding : out , as : UTF16 . self )
72+ return jsString ( utf16 : out )
6873}
6974
7075/// Where `p` first occurs in `u` at or after `from`.
0 commit comments