@exodus/bytes 1.8.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,7 +13,7 @@ export const assertEncoding = (encoding) => {
13
13
 
14
14
  const r = 0xff_fd
15
15
 
16
- function getEncoding(encoding) {
16
+ export function getEncoding(encoding) {
17
17
  assertEncoding(encoding)
18
18
  if (encoding === xUserDefined) return Array.from({ length: 128 }, (_, i) => 0xf7_80 + i)
19
19
  if (encoding === iso8i) encoding = 'iso-8859-8'
package/fallback/utf16.js CHANGED
@@ -12,45 +12,48 @@ const to16 = (a) => new Uint16Array(a.buffer, a.byteOffset, a.byteLength / 2) //
12
12
  export function to16input(u8, le) {
13
13
  // Assume even number of bytes
14
14
  if (le === isLE) return to16(u8.byteOffset % 2 === 0 ? u8 : Uint8Array.from(u8))
15
+ return to16(swap16(Uint8Array.from(u8)))
16
+ }
17
+
18
+ export const decode = (u16, loose = false, checked = false) => {
19
+ if (checked || isWellFormed(u16)) return decodeUCS2(u16)
20
+ if (!loose) throw new TypeError(E_STRICT)
21
+ return decodeUCS2(toWellFormed(Uint16Array.from(u16))) // cloned for replacement
22
+ }
23
+
24
+ export function encode(str, loose = false, checked = false, swapped = false) {
25
+ const arr = new Uint16Array(str.length)
26
+ if (checked) return swapped ? encodeCheckedSwapped(str, arr) : encodeChecked(str, arr)
27
+ return swapped ? encodeUncheckedSwapped(str, arr, loose) : encodeUnchecked(str, arr, loose)
28
+ }
15
29
 
16
- const res = new Uint8Array(u8.length)
30
+ /* eslint-disable @exodus/mutable/no-param-reassign-prop-only */
17
31
 
32
+ // Assumes checked length % 2 === 0, otherwise does not swap tail
33
+ function swap16(u8) {
18
34
  let i = 0
19
35
  for (const last3 = u8.length - 3; i < last3; i += 4) {
20
36
  const x0 = u8[i]
21
37
  const x1 = u8[i + 1]
22
38
  const x2 = u8[i + 2]
23
39
  const x3 = u8[i + 3]
24
- res[i] = x1
25
- res[i + 1] = x0
26
- res[i + 2] = x3
27
- res[i + 3] = x2
40
+ u8[i] = x1
41
+ u8[i + 1] = x0
42
+ u8[i + 2] = x3
43
+ u8[i + 3] = x2
28
44
  }
29
45
 
30
46
  for (const last = u8.length - 1; i < last; i += 2) {
31
47
  const x0 = u8[i]
32
48
  const x1 = u8[i + 1]
33
- res[i] = x1
34
- res[i + 1] = x0
49
+ u8[i] = x1
50
+ u8[i + 1] = x0
35
51
  }
36
52
 
37
- return to16(res)
38
- }
39
-
40
- export const decode = (u16, loose = false, checked = false) => {
41
- if (checked || isWellFormed(u16)) return decodeUCS2(u16)
42
- if (!loose) throw new TypeError(E_STRICT)
43
- return decodeUCS2(toWellFormed(Uint16Array.from(u16))) // cloned for replacement
44
- }
45
-
46
- export function encode(str, loose = false, checked = false, swapped = false) {
47
- const arr = new Uint16Array(str.length)
48
- if (checked) return swapped ? encodeCheckedSwapped(str, arr) : encodeChecked(str, arr)
49
- return swapped ? encodeUncheckedSwapped(str, arr, loose) : encodeUnchecked(str, arr, loose)
53
+ return u8
50
54
  }
51
55
 
52
56
  // Splitting paths into small functions helps (at least on SpiderMonkey)
53
- /* eslint-disable @exodus/mutable/no-param-reassign-prop-only */
54
57
 
55
58
  const encodeChecked = (str, arr) => encodeCharcodes(str, arr) // Same as encodeLatin1, but with Uint16Array
56
59
 
@@ -121,6 +124,7 @@ function encodeUncheckedSwapped(str, arr, loose = false) {
121
124
  return arr
122
125
  }
123
126
 
127
+ // Only needed on Hermes, everything else has native impl
124
128
  export function toWellFormed(u16) {
125
129
  const length = u16.length
126
130
  for (let i = 0; i < length; i++) {
@@ -143,10 +147,15 @@ export function toWellFormed(u16) {
143
147
  return u16
144
148
  }
145
149
 
150
+ // Only needed on Hermes, everything else has native impl
146
151
  export function isWellFormed(u16) {
147
152
  const length = u16.length
148
153
  let i = 0
149
154
 
155
+ const m = 0x80_00_80_00
156
+ const l = 0xd8_00
157
+ const h = 0xe0_00
158
+
150
159
  // Speedup with u32, by skipping to the first surrogate
151
160
  // Only implemented for aligned input for now, but almost all input is aligned (pooled Buffer or 0 offset)
152
161
  if (length > 32 && u16.byteOffset % 4 === 0) {
@@ -158,21 +167,31 @@ export function isWellFormed(u16) {
158
167
  const b = u32[i + 1]
159
168
  const c = u32[i + 2]
160
169
  const d = u32[i + 3]
161
- if (a & 0x80_00_80_00 || b & 0x80_00_80_00 || c & 0x80_00_80_00 || d & 0x80_00_80_00) break
170
+ if (a & m || b & m || c & m || d & m) break // bitwise OR does not make this faster on Hermes
162
171
  }
163
172
 
164
- for (; i < u32length; i++) if (u32[i] & 0x80_00_80_00) break
173
+ for (; i < u32length; i++) if (u32[i] & m) break
165
174
  i *= 2
166
175
  }
167
176
 
177
+ // An extra loop gives ~30-40% speedup e.g. on English text without surrogates but with other symbols above 0x80_00
178
+ for (const last3 = length - 3; ; i += 4) {
179
+ if (i >= last3) break
180
+ const a = u16[i]
181
+ const b = u16[i + 1]
182
+ const c = u16[i + 2]
183
+ const d = u16[i + 3]
184
+ if ((a >= l && a < h) || (b >= l && b < h) || (c >= l && c < h) || (d >= l && d < h)) break
185
+ }
186
+
168
187
  for (; i < length; i++) {
169
188
  const code = u16[i]
170
- if (code >= 0xd8_00 && code < 0xe0_00) {
189
+ if (code >= l && code < h) {
171
190
  // An unexpected trail or a lead at the very end of input
172
- if (code > 0xdb_ff || i + 1 >= length) return false
191
+ if (code >= 0xdc_00 || i + 1 >= length) return false
173
192
  i++ // consume next
174
193
  const next = u16[i] // Process valid pairs immediately
175
- if (next < 0xdc_00 || next >= 0xe0_00) return false
194
+ if (next < 0xdc_00 || next >= h) return false
176
195
  }
177
196
  }
178
197
 
package/fallback/utf8.js CHANGED
@@ -191,7 +191,7 @@ export function encode(string, loose) {
191
191
 
192
192
  if (small) {
193
193
  // TODO: use resizable array buffers? will have to return a non-resizeable one
194
- if (p !== i) throw new Error('Unreachable') // Here, p === i (only when small is still true)
194
+ if (p !== i) /* c8 ignore next */ throw new Error('Unreachable') // Here, p === i (only when small is still true)
195
195
  const bytesNew = new Uint8Array(p + (length - i) * 3) // maximium can be 3x of the string length in charcodes
196
196
  bytesNew.set(bytes)
197
197
  bytes = bytesNew
package/hex.d.ts CHANGED
@@ -19,4 +19,3 @@ export function toHex(arr: Uint8ArrayBuffer): string;
19
19
  export function fromHex(str: string, format?: 'uint8'): Uint8ArrayBuffer;
20
20
  export function fromHex(str: string, format: 'buffer'): Buffer;
21
21
  export function fromHex(str: string, format?: OutputFormat): Uint8ArrayBuffer | Buffer;
22
-
package/index.d.ts ADDED
@@ -0,0 +1,43 @@
1
+ /**
2
+ * ### The `@exodus/bytes` package consists of submodules, there is no single export.
3
+ * Import specific submodules instead.
4
+ *
5
+ * See [README](https://github.com/ExodusOSS/bytes/blob/main/README.md).
6
+ *
7
+ * Example:
8
+ * ```js
9
+ * import { fromHex, toHex } from '@exodus/bytes/hex.js'
10
+ * import { fromBase64, toBase64, fromBase64url, toBase64url, fromBase64any } from '@exodus/bytes/base64.js'
11
+ * import { fromBase32, toBase32, fromBase32hex, toBase32hex } from '@exodus/bytes/base32.js'
12
+ * import { fromBase58, toBase58, fromBase58xrp, toBase58xrp } from '@exodus/bytes/base58.js'
13
+ * import { fromBech32, toBech32, fromBech32m, toBech32m, getPrefix } from '@exodus/bytes/bech32.js'
14
+ * import { fromBigInt, toBigInt } from '@exodus/bytes/bigint.js'
15
+ *
16
+ * import { utf8fromString, utf8toString, utf8fromStringLoose, utf8toStringLoose } from '@exodus/bytes/utf8.js'
17
+ * import { utf16fromString, utf16toString, utf16fromStringLoose, utf16toStringLoose } from '@exodus/bytes/utf16.js'
18
+ * import {
19
+ * createSinglebyteDecoder, createSinglebyteEncoder,
20
+ * windows1252toString, windows1252fromString,
21
+ * latin1toString, latin1fromString } from '@exodus/bytes/single-byte.js'
22
+ * import { createMultibyteDecoder, createMultibyteEncoder } from '@exodus/bytes/multi-byte.js'
23
+ *
24
+ * import {
25
+ * fromBase58check, toBase58check,
26
+ * fromBase58checkSync, toBase58checkSync,
27
+ * makeBase58check } from '@exodus/bytes/base58check.js'
28
+ * import { fromWifString, toWifString, fromWifStringSync, toWifStringSync } from '@exodus/bytes/wif.js'
29
+ *
30
+ * // All encodings from the WHATWG Encoding spec
31
+ * import { TextDecoder, TextEncoder, TextDecoderStream, TextEncoderStream } from '@exodus/bytes/encoding.js'
32
+ * import { getBOMEncoding, legacyHookDecode, labelToName, normalizeEncoding } from '@exodus/bytes/encoding.js'
33
+ *
34
+ * // Omits legacy multi-byte decoders to save bundle size
35
+ * import { TextDecoder, TextEncoder, TextDecoderStream, TextEncoderStream } from '@exodus/bytes/encoding-lite.js'
36
+ * import { getBOMEncoding, legacyHookDecode, labelToName, normalizeEncoding } from '@exodus/bytes/encoding-lite.js'
37
+ *
38
+ * // In browser bundles, uses built-in TextDecoder / TextEncoder to save bundle size
39
+ * import { TextDecoder, TextEncoder, TextDecoderStream, TextEncoderStream } from '@exodus/bytes/encoding-browser.js'
40
+ * import { getBOMEncoding, legacyHookDecode, labelToName, normalizeEncoding } from '@exodus/bytes/encoding-browser.js'
41
+ * ```
42
+ */
43
+ declare module "@exodus/bytes" {}
package/index.js ADDED
@@ -0,0 +1,5 @@
1
+ throw new Error(
2
+ `This package consists of submodules, there is no single export. Import specific submodules instead.
3
+ See README: https://github.com/ExodusOSS/bytes/blob/main/README.md
4
+ `
5
+ )
package/multi-byte.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { assertUint8 } from './assert.js'
2
- import { multibyteDecoder } from './fallback/multi-byte.js'
2
+ import { multibyteDecoder, multibyteEncoder } from './fallback/multi-byte.js'
3
3
 
4
4
  export function createMultibyteDecoder(encoding, loose = false) {
5
5
  const jsDecoder = multibyteDecoder(encoding, loose) // asserts
@@ -11,3 +11,9 @@ export function createMultibyteDecoder(encoding, loose = false) {
11
11
  return jsDecoder(arr, stream)
12
12
  }
13
13
  }
14
+
15
+ export function createMultibyteEncoder(encoding, { mode = 'fatal' } = {}) {
16
+ // TODO: replacement, truncate (replacement will need varying length)
17
+ if (mode !== 'fatal') throw new Error('Unsupported mode')
18
+ return multibyteEncoder(encoding) // asserts
19
+ }
@@ -1,6 +1,6 @@
1
1
  import { assertUint8 } from './assert.js'
2
2
  import { isDeno, toBuf } from './fallback/_utils.js'
3
- import { isAsciiSuperset, multibyteDecoder } from './fallback/multi-byte.js'
3
+ import { isAsciiSuperset, multibyteDecoder, multibyteEncoder } from './fallback/multi-byte.js'
4
4
  import { isAscii } from 'node:buffer'
5
5
 
6
6
  export function createMultibyteDecoder(encoding, loose = false) {
@@ -21,3 +21,9 @@ export function createMultibyteDecoder(encoding, loose = false) {
21
21
  return jsDecoder(arr, stream)
22
22
  }
23
23
  }
24
+
25
+ export function createMultibyteEncoder(encoding, { mode = 'fatal' } = {}) {
26
+ // TODO: replacement, truncate (replacement will need varying length)
27
+ if (mode !== 'fatal') throw new Error('Unsupported mode')
28
+ return multibyteEncoder(encoding) // asserts
29
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/bytes",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "description": "Various operations on Uint8Array data",
5
5
  "scripts": {
6
6
  "lint": "eslint .",
@@ -23,6 +23,7 @@
23
23
  "test:firefox:playwright": "exodus-test --engine=firefox:playwright",
24
24
  "test:servo:bundle": "exodus-test --engine=servo:bundle",
25
25
  "test": "exodus-test",
26
+ "size": "esbuild --minify --bundle",
26
27
  "jsvu": "jsvu",
27
28
  "playwright": "exodus-test --playwright",
28
29
  "benchmark": "exodus-test --concurrency=1 benchmarks/*.bench.js",
@@ -48,6 +49,7 @@
48
49
  "/fallback/base58check.js",
49
50
  "/fallback/base64.js",
50
51
  "/fallback/encoding.js",
52
+ "/fallback/encoding.api.js",
51
53
  "/fallback/encoding.labels.js",
52
54
  "/fallback/encoding.util.js",
53
55
  "/fallback/hex.js",
@@ -71,6 +73,10 @@
71
73
  "/base64.d.ts",
72
74
  "/bech32.js",
73
75
  "/bigint.js",
76
+ "/encoding-browser.js",
77
+ "/encoding-browser.browser.js",
78
+ "/encoding-browser.native.js",
79
+ "/encoding-browser.d.ts",
74
80
  "/encoding.js",
75
81
  "/encoding.d.ts",
76
82
  "/encoding-lite.js",
@@ -78,6 +84,8 @@
78
84
  "/hex.js",
79
85
  "/hex.d.ts",
80
86
  "/hex.node.js",
87
+ "/index.js",
88
+ "/index.d.ts",
81
89
  "/multi-byte.js",
82
90
  "/multi-byte.node.js",
83
91
  "/single-byte.js",
@@ -89,7 +97,14 @@
89
97
  "/utf8.node.js",
90
98
  "/wif.js"
91
99
  ],
100
+ "main": "index.js",
101
+ "module": "index.js",
102
+ "types": "index.d.ts",
92
103
  "exports": {
104
+ ".": {
105
+ "types": "./index.d.ts",
106
+ "default": "./index.js"
107
+ },
93
108
  "./array.js": {
94
109
  "types": "./array.d.ts",
95
110
  "default": "./array.js"
@@ -127,6 +142,13 @@
127
142
  "types": "./encoding-lite.d.ts",
128
143
  "default": "./encoding-lite.js"
129
144
  },
145
+ "./encoding-browser.js": {
146
+ "types": "./encoding-browser.d.ts",
147
+ "node": "./encoding-browser.js",
148
+ "react-native": "./encoding-browser.native.js",
149
+ "browser": "./encoding-browser.browser.js",
150
+ "default": "./encoding-browser.js"
151
+ },
130
152
  "./utf16.js": {
131
153
  "node": "./utf16.node.js",
132
154
  "default": "./utf16.js"
@@ -138,11 +160,14 @@
138
160
  },
139
161
  "./wif.js": "./wif.js"
140
162
  },
163
+ "react-native": {
164
+ "./encoding-browser.js": "./encoding-browser.native.js"
165
+ },
141
166
  "peerDependencies": {
142
- "@exodus/crypto": "^1.0.0-rc.4"
167
+ "@noble/hashes": "^1.8.0 || ^2.0.0"
143
168
  },
144
169
  "peerDependenciesMeta": {
145
- "@exodus/crypto": {
170
+ "@noble/hashes": {
146
171
  "optional": true
147
172
  }
148
173
  },
@@ -153,6 +178,7 @@
153
178
  "@exodus/prettier": "^1.0.0",
154
179
  "@exodus/test": "^1.0.0-rc.109",
155
180
  "@noble/hashes": "^2.0.1",
181
+ "@oslojs/encoding": "^1.1.0",
156
182
  "@petamoriken/float16": "^3.9.3",
157
183
  "@scure/base": "^1.2.6",
158
184
  "@stablelib/base64": "^2.0.1",
@@ -167,9 +193,11 @@
167
193
  "bs58check": "^4.0.0",
168
194
  "bstring": "^0.3.9",
169
195
  "buffer": "^6.0.3",
196
+ "c8": "^10.1.3",
170
197
  "decode-utf8": "^1.0.1",
171
198
  "electron": "36.5.0",
172
199
  "encode-utf8": "^2.0.0",
200
+ "esbuild": "^0.27.2",
173
201
  "eslint": "^8.44.0",
174
202
  "fast-base64-decode": "^2.0.0",
175
203
  "fast-base64-encode": "^1.0.0",
@@ -177,6 +205,7 @@
177
205
  "hi-base32": "^0.5.1",
178
206
  "iconv-lite": "^0.7.0",
179
207
  "jsvu": "^3.0.3",
208
+ "punycode": "^2.3.1",
180
209
  "text-encoding": "^0.7.0",
181
210
  "typescript": "^5.9.3",
182
211
  "uint8array-tools": "^0.0.9",
package/single-byte.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { assertUint8 } from './assert.js'
2
- import { canDecoders, nativeEncoder, isHermes, skipWeb, E_STRING } from './fallback/_utils.js'
2
+ import { canDecoders, nativeEncoder, skipWeb, E_STRING } from './fallback/_utils.js'
3
3
  import { encodeAscii, encodeAsciiPrefix, encodeLatin1 } from './fallback/latin1.js'
4
4
  import { assertEncoding, encodingDecoder, encodeMap, E_STRICT } from './fallback/single-byte.js'
5
5
 
@@ -66,17 +66,15 @@ function encode(s, m) {
66
66
  const x = new Uint8Array(len)
67
67
  let i = nativeEncoder ? 0 : encodeAsciiPrefix(x, s)
68
68
 
69
- if (!isHermes) {
70
- for (const len3 = len - 3; i < len3; i += 4) {
71
- const x0 = s.charCodeAt(i), x1 = s.charCodeAt(i + 1), x2 = s.charCodeAt(i + 2), x3 = s.charCodeAt(i + 3) // prettier-ignore
72
- const c0 = m[x0], c1 = m[x1], c2 = m[x2], c3 = m[x3] // prettier-ignore
73
- if ((!c0 && x0) || (!c1 && x1) || (!c2 && x2) || (!c3 && x3)) throw new TypeError(E_STRICT)
69
+ for (const len3 = len - 3; i < len3; i += 4) {
70
+ const x0 = s.charCodeAt(i), x1 = s.charCodeAt(i + 1), x2 = s.charCodeAt(i + 2), x3 = s.charCodeAt(i + 3) // prettier-ignore
71
+ const c0 = m[x0], c1 = m[x1], c2 = m[x2], c3 = m[x3] // prettier-ignore
72
+ if ((!c0 && x0) || (!c1 && x1) || (!c2 && x2) || (!c3 && x3)) return null
74
73
 
75
- x[i] = c0
76
- x[i + 1] = c1
77
- x[i + 2] = c2
78
- x[i + 3] = c3
79
- }
74
+ x[i] = c0
75
+ x[i + 1] = c1
76
+ x[i + 2] = c2
77
+ x[i + 3] = c3
80
78
  }
81
79
 
82
80
  for (; i < len; i++) {
@@ -61,6 +61,32 @@ export function createSinglebyteDecoder(encoding, loose = false) {
61
61
 
62
62
  const NON_LATIN = /[^\x00-\xFF]/ // eslint-disable-line no-control-regex
63
63
 
64
+ function encode(s, m) {
65
+ const len = s.length
66
+ let i = 0
67
+ const b = Buffer.from(s, 'utf-16le') // aligned
68
+ if (!isLE) b.swap16()
69
+ const x = new Uint16Array(b.buffer, b.byteOffset, b.byteLength / 2)
70
+ for (const len3 = len - 3; i < len3; i += 4) {
71
+ const x0 = x[i], x1 = x[i + 1], x2 = x[i + 2], x3 = x[i + 3] // prettier-ignore
72
+ const c0 = m[x0], c1 = m[x1], c2 = m[x2], c3 = m[x3] // prettier-ignore
73
+ if (!(c0 && c1 && c2 && c3) && ((!c0 && x0) || (!c1 && x1) || (!c2 && x2) || (!c3 && x3))) return null // prettier-ignore
74
+ x[i] = c0
75
+ x[i + 1] = c1
76
+ x[i + 2] = c2
77
+ x[i + 3] = c3
78
+ }
79
+
80
+ for (; i < len; i++) {
81
+ const x0 = x[i]
82
+ const c0 = m[x0]
83
+ if (!c0 && x0) return null
84
+ x[i] = c0
85
+ }
86
+
87
+ return new Uint8Array(x)
88
+ }
89
+
64
90
  export function createSinglebyteEncoder(encoding, { mode = 'fatal' } = {}) {
65
91
  // TODO: replacement, truncate (replacement will need varying length)
66
92
  if (mode !== 'fatal') throw new Error('Unsupported mode')
@@ -82,32 +108,9 @@ export function createSinglebyteEncoder(encoding, { mode = 'fatal' } = {}) {
82
108
  if (b.length === s.length) return new Uint8Array(b.buffer, b.byteOffset, b.byteLength)
83
109
  }
84
110
 
85
- const len = s.length
86
- let i = 0
87
- const b = Buffer.from(s, 'utf-16le') // aligned
88
- if (!isLE) b.swap16()
89
- const x = new Uint16Array(b.buffer, b.byteOffset, b.byteLength / 2)
90
- for (const len3 = len - 3; i < len3; i += 4) {
91
- const x0 = x[i], x1 = x[i + 1], x2 = x[i + 2], x3 = x[i + 3] // prettier-ignore
92
- const c0 = m[x0], c1 = m[x1], c2 = m[x2], c3 = m[x3] // prettier-ignore
93
- if (!(c0 && c1 && c2 && c3) && ((!c0 && x0) || (!c1 && x1) || (!c2 && x2) || (!c3 && x3))) {
94
- throw new TypeError(E_STRICT)
95
- }
96
-
97
- x[i] = c0
98
- x[i + 1] = c1
99
- x[i + 2] = c2
100
- x[i + 3] = c3
101
- }
102
-
103
- for (; i < len; i++) {
104
- const x0 = x[i]
105
- const c0 = m[x0]
106
- if (!c0 && x0) throw new TypeError(E_STRICT)
107
- x[i] = c0
108
- }
109
-
110
- return new Uint8Array(x)
111
+ const res = encode(s, m)
112
+ if (!res) throw new TypeError(E_STRICT)
113
+ return res
111
114
  }
112
115
  }
113
116
 
package/utf16.js CHANGED
@@ -34,6 +34,7 @@ function encode(str, loose = false, format = 'uint16') {
34
34
 
35
35
  if (format === 'uint8-le' || format === 'uint8-be') return to8(u16) // Already swapped
36
36
  if (format === 'uint16') return u16
37
+ /* c8 ignore next */
37
38
  throw new Error('Unreachable')
38
39
  }
39
40
 
package/utf16.node.js CHANGED
@@ -30,11 +30,15 @@ function encode(str, loose = false, format = 'uint16') {
30
30
  return new Uint16Array(b.buffer, b.byteOffset, b.byteLength / 2)
31
31
  }
32
32
 
33
+ /* c8 ignore next */
33
34
  throw new Error('Unreachable')
34
35
  }
35
36
 
36
- const swapped = (x, swap) =>
37
- swap ? Buffer.from(x).swap16() : Buffer.from(x.buffer, x.byteOffset, x.byteLength)
37
+ // Convert to Buffer view or a swapped Buffer copy
38
+ const swapped = (x, swap) => {
39
+ const b = Buffer.from(x.buffer, x.byteOffset, x.byteLength)
40
+ return swap ? Buffer.from(b).swap16() : b
41
+ }
38
42
 
39
43
  // We skip TextDecoder on Node.js, as it's is somewhy significantly slower than Buffer for utf16
40
44
  // Also, it incorrectly misses replacements with Node.js is built without ICU, we fix that