11import { assertUint8 } from './assert.js'
22import { typedView } from './array.js'
3- import { isHermes , nativeDecoder , nativeEncoder , E_STRING } from './fallback/_utils.js'
4- import { asciiPrefix , decodeLatin1 } from './fallback/latin1.js'
3+ import { nativeDecoder , nativeEncoder , E_STRING , E_STRICT_UNICODE } from './fallback/_utils.js'
54import * as js from './fallback/utf8.js'
65
7- const { TextDecoder, decodeURIComponent , escape } = globalThis // Buffer is optional
6+ const { TextDecoder } = globalThis
87// ignoreBOM: true means that BOM will be left as-is, i.e. will be present in the output
98// We don't want to strip anything unexpectedly
109const decoderLoose = nativeDecoder
@@ -13,10 +12,6 @@ const decoderFatal = nativeDecoder
1312 : null
1413const { isWellFormed } = String . prototype
1514
16- const { E_STRICT , E_STRICT_UNICODE } = js
17-
18- const shouldUseEscapePath = isHermes // faster only on Hermes, js path beats it on normal engines
19-
2015function deLoose ( str , loose , res ) {
2116 if ( loose || str . length === res . length ) return res // length is equal only for ascii, which is automatically fine
2217 if ( isWellFormed ) {
@@ -51,32 +46,19 @@ function deLoose(str, loose, res) {
5146function encode ( str , loose = false ) {
5247 if ( typeof str !== 'string' ) throw new TypeError ( E_STRING )
5348 if ( str . length === 0 ) return new Uint8Array ( ) // faster than Uint8Array.of
54- if ( nativeEncoder ) return deLoose ( str , loose , nativeEncoder . encode ( str ) )
49+ if ( nativeEncoder || ! js . encode ) return deLoose ( str , loose , nativeEncoder . encode ( str ) )
5550 // No reason to use unescape + encodeURIComponent: it's slower than JS on normal engines, and modern Hermes already has TextEncoder
5651 return js . encode ( str , loose )
5752}
5853
5954function decode ( arr , loose = false ) {
6055 assertUint8 ( arr )
6156 if ( arr . byteLength === 0 ) return ''
62- if ( nativeDecoder ) return loose ? decoderLoose . decode ( arr ) : decoderFatal . decode ( arr ) // Node.js and browsers
63-
64- // Fast path for ASCII prefix, this is faster than all alternatives below
65- const prefix = decodeLatin1 ( arr , 0 , asciiPrefix ( arr ) ) // No native decoder to use, so decodeAscii is useless here
66- if ( prefix . length === arr . length ) return prefix
67-
68- // This codepath gives a ~3x perf boost on Hermes
69- if ( shouldUseEscapePath && escape && decodeURIComponent ) {
70- const o = escape ( decodeLatin1 ( arr , prefix . length , arr . length ) )
71- try {
72- return prefix + decodeURIComponent ( o ) // Latin1 to utf8
73- } catch {
74- if ( ! loose ) throw new TypeError ( E_STRICT )
75- // Ok, we have to use manual implementation for loose decoder
76- }
57+ if ( nativeDecoder || ! js . decodeFast ) {
58+ return loose ? decoderLoose . decode ( arr ) : decoderFatal . decode ( arr ) // Node.js and browsers
7759 }
7860
79- return prefix + js . decode ( arr , loose , prefix . length )
61+ return js . decodeFast ( arr , loose )
8062}
8163
8264export const utf8fromString = ( str , format = 'uint8' ) => typedView ( encode ( str , false ) , format )
0 commit comments