@kaeawc/auto-mobile 0.0.88 → 0.0.90

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.
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: auto-mobile-usage
3
+ description: How to drive Android and iOS devices with AutoMobile MCP tools. Use before acquiring a device, observing a screen, or acting on one, and when a call fails with device_owned_by_other_session, device_service_disabled or capacity_exhausted.
4
+ ---
5
+
6
+ # Driving devices with AutoMobile
7
+
8
+ ## 1. Get a session first
9
+
10
+ - Acquire a device with `getAndroid` or `getApple`. It finds or boots one and returns a `sessionUuid`.
11
+ - A connection that acquired a device is bound to it, so later calls route to that session without repeating it. A different connection, or a CLI call, passes `sessionUuid` on every call.
12
+ - A device that a session holds takes control calls only from that session (`device_owned_by_other_session` otherwise). Naming someone else's `sessionUuid` never takes the device over.
13
+ - `setActiveDevice` and acquisition are the only calls that change which session an untargeted call uses. With several sessions, pass `sessionUuid` or `deviceId` (`ambiguous_session_selector`).
14
+ - `session_ownership_lost` and `no_active_device_session` are permanent for that session: acquire a new one.
15
+
16
+ ## 2. Observe before you act
17
+
18
+ - Call `observe` before the first action and again after each action that can change the screen. Coordinates and Android synthetic `s2-` element ids are valid only for the observation that returned them.
19
+ - Act on what `observe` returned: `tapOn` takes a `selector` (`text`, `elementId`, `testTag`), `swipeOn` scrolls the screen or a container (`lookFor` scrolls until an element appears), `tapAt` takes coordinates, `sendKeys` types into the focused field. Do not guess coordinates.
20
+ - `skeleton` lists only rows you can act on. Static text (a status label, a validation error, a result message) is in `context`; read it there to verify a result. `waitFor` with `text` or `textAny`, or `for: "appear"`/`"textEquals"` with only `text`, matches text in either array.
21
+ - Ask `observe` for a screenshot only when the hierarchy is not enough; images are the largest part of a result.
22
+
23
+ ## 3. Resources versus tools
24
+
25
+ - Tools act or run a computation. Resources (`automobile:` URIs) are cheap read-only state: `automobile:tools` lists every tool and whether it is enabled, `automobile:devices/booted` lists booted devices, `automobile:observation/latest` is the latest observation.
26
+ - Read a resource instead of calling a tool when you only need state. A sessionless read never takes a held device.
27
+ - A tool that is gated off does not appear in `tools/list`. Enable it with `setToolEnabled` or the `enableTools` argument of `getAndroid` and `getApple`.
28
+
29
+ ## 4. Long operations and Tasks
30
+
31
+ - `executePlan`, `installApp` and `videoRecording` with `action: "stop"` can run as a task when your client declares the Tasks extension. You get a task handle, poll it with `tasks/get`, and cancel with `tasks/cancel`; the work survives a client reconnect.
32
+ - Do not wrap short interaction calls (`tapOn`, `sendKeys`, `pressButton`) in tasks. Without Tasks support the same calls simply block until done.
33
+
34
+ ## 5. Typed errors
35
+
36
+ An error result carries a stable `code`. Read `code` and `retryable` instead of the message text.
37
+
38
+ | Code | Meaning and next step |
39
+ | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
40
+ | `capacity_exhausted` | The platform is at its booted-device limit. Retryable: wait `retryAfterMs`, or shut down a device you hold, then repeat the acquisition. Do not loop faster than `retryAfterMs`. |
41
+ | `device_service_disabled` | A simulator service the tool needs is switched off. Not retryable until you act: follow `howToEnable` in the error (enable it with `setDeviceResources`) or start the simulator without it. |
42
+ | `device_owned_by_other_session` | Another session holds the device. Acquire your own device or pass the right `sessionUuid`. |
43
+ | `plan_execution_in_progress` | A plan is running on the session. Retry when it finishes; reads stay allowed. |
44
+
45
+ Release a device you no longer need so other sessions can use it.
@@ -1,9 +1,9 @@
1
- The MIT License (MIT)
2
-
3
- Copyright © 2025 Borewit
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
-
7
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
-
9
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ The MIT License (MIT)
2
+
3
+ Copyright © 2025 Borewit
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,87 +1,87 @@
1
- [![CI](https://github.com/Borewit/text-codec/actions/workflows/ci.yml/badge.svg)](https://github.com/Borewit/text-codec/actions/workflows/ci.yml)
2
- [![npm version](https://img.shields.io/npm/v/%40borewit%2Ftext-codec.svg)](https://www.npmjs.com/package/@borewit/text-codec)
3
- [![npm downloads](http://img.shields.io/npm/dm/@borewit/text-codec.svg)](https://npmcharts.com/compare/@borewit/text-codec?interval=30)
4
- ![bundlejs](https://deno.bundlejs.com/?q=@borewit/text-codec&badge)
5
- [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg?logo=open-source-initiative&logoColor=white)](LICENSE.txt)
6
-
7
- # `@borewit/text-codec`
8
-
9
- A **lightweight polyfill for text encoders and decoders** covering a small set of commonly used encodings.
10
-
11
- Some JavaScript runtimes provide limited or inconsistent encoding support through `TextEncoder` and `TextDecoder`.
12
- Examples include environments like **Hermes (React Native)** or certain **Node.js builds with limited ICU support**.
13
-
14
- This module provides **reliable encode/decode support for a small set of encodings that may be missing or unreliable in those environments**.
15
-
16
- - If a native UTF-8 `TextEncoder` / `TextDecoder` is available, it is used.
17
- - All other encodings are implemented by this library.
18
-
19
- ## Supported encodings
20
-
21
- - `utf-8` / `utf8`
22
- - `utf-16le`
23
- - `ascii`
24
- - `latin1` / `iso-8859-1`
25
- - `windows-1252`
26
-
27
- These encodings are commonly encountered in metadata formats and legacy text data.
28
-
29
- ## ✨ Features
30
-
31
- - Encoding and decoding utilities
32
- - Lightweight
33
- - Typed API
34
-
35
- ## 📦 Installation
36
-
37
- ```sh
38
- npm install @borewit/text-codec
39
- ```
40
-
41
- # 📚 API Documentation
42
-
43
- ## `textDecode(bytes, encoding): string`
44
-
45
- Decodes binary data into a JavaScript string.
46
-
47
- **Parameters**
48
- - `bytes` (`Uint8Array`) — The binary data to decode.
49
- - `encoding` (`SupportedEncoding`, optional) — Encoding type. Defaults to `"utf-8"`.
50
-
51
- **Returns**
52
- - `string` — The decoded text.
53
-
54
- **Example**
55
- ```js
56
- import { textDecode } from "@borewit/text-codec";
57
-
58
- const bytes = new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f]);
59
- const text = textDecode(bytes, "ascii");
60
- console.log(text); // "Hello"
61
- ```
62
-
63
- ## `textEncode(input, encoding): Uint8Array`
64
-
65
- Encodes a JavaScript string into binary form using the specified encoding.
66
-
67
- **Parameters**
68
-
69
- - `input` (`string`) — The string to encode.
70
- - `encoding` (`SupportedEncoding`, optional) — Encoding type. Defaults to `"utf-8"`.
71
-
72
- **Returns**
73
-
74
- `Uint8Array` — The encoded binary data.
75
-
76
- Example:
77
- ```js
78
- import { textEncode } from "@borewit/text-codec";
79
-
80
- const bytes = textEncode("Hello", "utf-16le");
81
- console.log(bytes); // Uint8Array([...])
82
- ```
83
-
84
- ## 📜 Licence
85
-
86
- This project is licensed under the [MIT License](LICENSE.txt). Feel free to use, modify, and distribute as needed.
1
+ [![CI](https://github.com/Borewit/text-codec/actions/workflows/ci.yml/badge.svg)](https://github.com/Borewit/text-codec/actions/workflows/ci.yml)
2
+ [![npm version](https://img.shields.io/npm/v/%40borewit%2Ftext-codec.svg)](https://www.npmjs.com/package/@borewit/text-codec)
3
+ [![npm downloads](http://img.shields.io/npm/dm/@borewit/text-codec.svg)](https://npmcharts.com/compare/@borewit/text-codec?interval=30)
4
+ ![bundlejs](https://deno.bundlejs.com/?q=@borewit/text-codec&badge)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg?logo=open-source-initiative&logoColor=white)](LICENSE.txt)
6
+
7
+ # `@borewit/text-codec`
8
+
9
+ A **lightweight polyfill for text encoders and decoders** covering a small set of commonly used encodings.
10
+
11
+ Some JavaScript runtimes provide limited or inconsistent encoding support through `TextEncoder` and `TextDecoder`.
12
+ Examples include environments like **Hermes (React Native)** or certain **Node.js builds with limited ICU support**.
13
+
14
+ This module provides **reliable encode/decode support for a small set of encodings that may be missing or unreliable in those environments**.
15
+
16
+ - If a native UTF-8 `TextEncoder` / `TextDecoder` is available, it is used.
17
+ - All other encodings are implemented by this library.
18
+
19
+ ## Supported encodings
20
+
21
+ - `utf-8` / `utf8`
22
+ - `utf-16le`
23
+ - `ascii`
24
+ - `latin1` / `iso-8859-1`
25
+ - `windows-1252`
26
+
27
+ These encodings are commonly encountered in metadata formats and legacy text data.
28
+
29
+ ## ✨ Features
30
+
31
+ - Encoding and decoding utilities
32
+ - Lightweight
33
+ - Typed API
34
+
35
+ ## 📦 Installation
36
+
37
+ ```sh
38
+ npm install @borewit/text-codec
39
+ ```
40
+
41
+ # 📚 API Documentation
42
+
43
+ ## `textDecode(bytes, encoding): string`
44
+
45
+ Decodes binary data into a JavaScript string.
46
+
47
+ **Parameters**
48
+ - `bytes` (`Uint8Array`) — The binary data to decode.
49
+ - `encoding` (`SupportedEncoding`, optional) — Encoding type. Defaults to `"utf-8"`.
50
+
51
+ **Returns**
52
+ - `string` — The decoded text.
53
+
54
+ **Example**
55
+ ```js
56
+ import { textDecode } from "@borewit/text-codec";
57
+
58
+ const bytes = new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f]);
59
+ const text = textDecode(bytes, "ascii");
60
+ console.log(text); // "Hello"
61
+ ```
62
+
63
+ ## `textEncode(input, encoding): Uint8Array`
64
+
65
+ Encodes a JavaScript string into binary form using the specified encoding.
66
+
67
+ **Parameters**
68
+
69
+ - `input` (`string`) — The string to encode.
70
+ - `encoding` (`SupportedEncoding`, optional) — Encoding type. Defaults to `"utf-8"`.
71
+
72
+ **Returns**
73
+
74
+ `Uint8Array` — The encoded binary data.
75
+
76
+ Example:
77
+ ```js
78
+ import { textEncode } from "@borewit/text-codec";
79
+
80
+ const bytes = textEncode("Hello", "utf-16le");
81
+ console.log(bytes); // Uint8Array([...])
82
+ ```
83
+
84
+ ## 📜 Licence
85
+
86
+ This project is licensed under the [MIT License](LICENSE.txt). Feel free to use, modify, and distribute as needed.
87
87
 
@@ -1,9 +1,31 @@
1
1
  const WINDOWS_1252_EXTRA = {
2
- 0x80: "€", 0x82: "‚", 0x83: "ƒ", 0x84: "„", 0x85: "…", 0x86: "†",
3
- 0x87: "‡", 0x88: "ˆ", 0x89: "‰", 0x8a: "Š", 0x8b: "‹", 0x8c: "Œ",
4
- 0x8e: "Ž", 0x91: "‘", 0x92: "’", 0x93: "“", 0x94: "”", 0x95: "•",
5
- 0x96: "–", 0x97: "—", 0x98: "˜", 0x99: "™", 0x9a: "š", 0x9b: "›",
6
- 0x9c: "œ", 0x9e: "ž", 0x9f: "Ÿ",
2
+ 0x80: '€',
3
+ 0x82: '‚',
4
+ 0x83: 'ƒ',
5
+ 0x84: '„',
6
+ 0x85: '…',
7
+ 0x86: '†',
8
+ 0x87: '‡',
9
+ 0x88: 'ˆ',
10
+ 0x89: '‰',
11
+ 0x8a: 'Š',
12
+ 0x8b: '‹',
13
+ 0x8c: 'Œ',
14
+ 0x8e: 'Ž',
15
+ 0x91: '‘',
16
+ 0x92: '’',
17
+ 0x93: '“',
18
+ 0x94: '”',
19
+ 0x95: '•',
20
+ 0x96: '–',
21
+ 0x97: '—',
22
+ 0x98: '˜',
23
+ 0x99: '™',
24
+ 0x9a: 'š',
25
+ 0x9b: '›',
26
+ 0x9c: 'œ',
27
+ 0x9e: 'ž',
28
+ 0x9f: 'Ÿ'
7
29
  };
8
30
  const WINDOWS_1252_REVERSE = {};
9
31
  for (const [code, char] of Object.entries(WINDOWS_1252_EXTRA)) {
@@ -12,80 +34,86 @@ for (const [code, char] of Object.entries(WINDOWS_1252_EXTRA)) {
12
34
  let _utf8Decoder;
13
35
  let _utf8Encoder;
14
36
  function utf8Decoder() {
15
- if (typeof globalThis.TextDecoder === "undefined")
16
- return undefined;
17
- return (_utf8Decoder !== null && _utf8Decoder !== void 0 ? _utf8Decoder : (_utf8Decoder = new globalThis.TextDecoder("utf-8")));
37
+ if (_utf8Decoder === undefined) {
38
+ try {
39
+ _utf8Decoder = typeof globalThis.TextDecoder === 'undefined' ? null : new globalThis.TextDecoder('utf-8');
40
+ }
41
+ catch {
42
+ _utf8Decoder = null;
43
+ }
44
+ }
45
+ return _utf8Decoder !== null && _utf8Decoder !== void 0 ? _utf8Decoder : undefined;
18
46
  }
19
47
  function utf8Encoder() {
20
- if (typeof globalThis.TextEncoder === "undefined")
21
- return undefined;
22
- return (_utf8Encoder !== null && _utf8Encoder !== void 0 ? _utf8Encoder : (_utf8Encoder = new globalThis.TextEncoder()));
48
+ if (_utf8Encoder === undefined) {
49
+ try {
50
+ _utf8Encoder = typeof globalThis.TextEncoder === 'undefined' ? null : new globalThis.TextEncoder();
51
+ }
52
+ catch {
53
+ _utf8Encoder = null;
54
+ }
55
+ }
56
+ return _utf8Encoder !== null && _utf8Encoder !== void 0 ? _utf8Encoder : undefined;
23
57
  }
24
58
  const CHUNK = 32 * 1024;
25
59
  const REPLACEMENT = 0xfffd;
26
60
  /**
27
61
  * Decode text from binary data
28
62
  */
29
- export function textDecode(bytes, encoding = "utf-8") {
63
+ export function textDecode(bytes, encoding = 'utf-8') {
30
64
  switch (encoding.toLowerCase()) {
31
- case "utf-8":
32
- case "utf8": {
65
+ case 'utf-8':
66
+ case 'utf8': {
33
67
  const dec = utf8Decoder();
34
68
  return dec ? dec.decode(bytes) : decodeUTF8(bytes);
35
69
  }
36
- case "utf-16le":
70
+ case 'utf-16le':
37
71
  return decodeUTF16LE(bytes);
38
- case "us-ascii":
39
- case "ascii":
72
+ case 'us-ascii':
73
+ case 'ascii':
40
74
  return decodeASCII(bytes);
41
- case "latin1":
42
- case "iso-8859-1":
75
+ case 'latin1':
76
+ case 'iso-8859-1':
43
77
  return decodeLatin1(bytes);
44
- case "windows-1252":
78
+ case 'windows-1252':
45
79
  return decodeWindows1252(bytes);
46
80
  default:
47
81
  throw new RangeError(`Encoding '${encoding}' not supported`);
48
82
  }
49
83
  }
50
- export function textEncode(input = "", encoding = "utf-8") {
84
+ export function textEncode(input = '', encoding = 'utf-8') {
51
85
  switch (encoding.toLowerCase()) {
52
- case "utf-8":
53
- case "utf8": {
86
+ case 'utf-8':
87
+ case 'utf8': {
54
88
  const enc = utf8Encoder();
55
89
  return enc ? enc.encode(input) : encodeUTF8(input);
56
90
  }
57
- case "utf-16le":
91
+ case 'utf-16le':
58
92
  return encodeUTF16LE(input);
59
- case "us-ascii":
60
- case "ascii":
93
+ case 'us-ascii':
94
+ case 'ascii':
61
95
  return encodeASCII(input);
62
- case "latin1":
63
- case "iso-8859-1":
96
+ case 'latin1':
97
+ case 'iso-8859-1':
64
98
  return encodeLatin1(input);
65
- case "windows-1252":
99
+ case 'windows-1252':
66
100
  return encodeWindows1252(input);
67
101
  default:
68
102
  throw new RangeError(`Encoding '${encoding}' not supported`);
69
103
  }
70
104
  }
71
- function appendCodePoint(out, cp) {
72
- if (cp <= 0xffff) {
73
- out.push(String.fromCharCode(cp));
74
- return;
75
- }
76
- cp -= 0x10000;
77
- out.push(String.fromCharCode(0xd800 + (cp >> 10), 0xdc00 + (cp & 0x3ff)));
78
- }
79
105
  function flushChunk(parts, chunk) {
80
- if (chunk.length === 0)
106
+ if (chunk.length === 0) {
81
107
  return;
108
+ }
82
109
  parts.push(String.fromCharCode.apply(null, chunk));
83
110
  chunk.length = 0;
84
111
  }
85
112
  function pushCodeUnit(parts, chunk, codeUnit) {
86
113
  chunk.push(codeUnit);
87
- if (chunk.length >= CHUNK)
114
+ if (chunk.length >= CHUNK) {
88
115
  flushChunk(parts, chunk);
116
+ }
89
117
  }
90
118
  function pushCodePoint(parts, chunk, cp) {
91
119
  if (cp <= 0xffff) {
@@ -101,10 +129,7 @@ function decodeUTF8(bytes) {
101
129
  const chunk = [];
102
130
  let i = 0;
103
131
  // Match TextDecoder("utf-8") default BOM handling
104
- if (bytes.length >= 3 &&
105
- bytes[0] === 0xef &&
106
- bytes[1] === 0xbb &&
107
- bytes[2] === 0xbf) {
132
+ if (bytes.length >= 3 && bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf) {
108
133
  i = 3;
109
134
  }
110
135
  while (i < bytes.length) {
@@ -120,83 +145,38 @@ function decodeUTF8(bytes) {
120
145
  i++;
121
146
  continue;
122
147
  }
123
- // 2-byte sequence
124
- if (b1 <= 0xdf) {
125
- if (i + 1 >= bytes.length) {
126
- pushCodeUnit(parts, chunk, REPLACEMENT);
127
- i++;
128
- continue;
129
- }
130
- const b2 = bytes[i + 1];
131
- if ((b2 & 0xc0) !== 0x80) {
132
- pushCodeUnit(parts, chunk, REPLACEMENT);
133
- i++;
134
- continue;
135
- }
136
- const cp = ((b1 & 0x1f) << 6) | (b2 & 0x3f);
137
- pushCodeUnit(parts, chunk, cp);
138
- i += 2;
139
- continue;
140
- }
141
- // 3-byte sequence
142
- if (b1 <= 0xef) {
143
- if (i + 2 >= bytes.length) {
144
- pushCodeUnit(parts, chunk, REPLACEMENT);
145
- i++;
146
- continue;
148
+ const length = b1 <= 0xdf ? 2 : b1 <= 0xef ? 3 : 4;
149
+ let cp = b1 & (0x7f >> length);
150
+ let lower = b1 === 0xe0 ? 0xa0 : b1 === 0xf0 ? 0x90 : 0x80;
151
+ let upper = b1 === 0xed ? 0x9f : b1 === 0xf4 ? 0x8f : 0xbf;
152
+ let consumed = 1;
153
+ i++;
154
+ // Consume only the valid prefix. An interrupting byte starts a new sequence.
155
+ while (consumed < length && i < bytes.length) {
156
+ const next = bytes[i];
157
+ if (next < lower || next > upper) {
158
+ break;
147
159
  }
148
- const b2 = bytes[i + 1];
149
- const b3 = bytes[i + 2];
150
- const valid = (b2 & 0xc0) === 0x80 &&
151
- (b3 & 0xc0) === 0x80 &&
152
- !(b1 === 0xe0 && b2 < 0xa0) && // overlong
153
- !(b1 === 0xed && b2 >= 0xa0); // surrogate range
154
- if (!valid) {
155
- pushCodeUnit(parts, chunk, REPLACEMENT);
156
- i++;
157
- continue;
158
- }
159
- const cp = ((b1 & 0x0f) << 12) |
160
- ((b2 & 0x3f) << 6) |
161
- (b3 & 0x3f);
162
- pushCodeUnit(parts, chunk, cp);
163
- i += 3;
164
- continue;
165
- }
166
- // 4-byte sequence
167
- if (i + 3 >= bytes.length) {
168
- pushCodeUnit(parts, chunk, REPLACEMENT);
169
- i++;
170
- continue;
171
- }
172
- const b2 = bytes[i + 1];
173
- const b3 = bytes[i + 2];
174
- const b4 = bytes[i + 3];
175
- const valid = (b2 & 0xc0) === 0x80 &&
176
- (b3 & 0xc0) === 0x80 &&
177
- (b4 & 0xc0) === 0x80 &&
178
- !(b1 === 0xf0 && b2 < 0x90) && // overlong
179
- !(b1 === 0xf4 && b2 > 0x8f); // > U+10FFFF
180
- if (!valid) {
181
- pushCodeUnit(parts, chunk, REPLACEMENT);
160
+ cp = (cp << 6) | (next & 0x3f);
161
+ consumed++;
182
162
  i++;
183
- continue;
163
+ lower = 0x80;
164
+ upper = 0xbf;
184
165
  }
185
- const cp = ((b1 & 0x07) << 18) |
186
- ((b2 & 0x3f) << 12) |
187
- ((b3 & 0x3f) << 6) |
188
- (b4 & 0x3f);
189
- pushCodePoint(parts, chunk, cp);
190
- i += 4;
166
+ pushCodePoint(parts, chunk, consumed === length ? cp : REPLACEMENT);
191
167
  }
192
168
  flushChunk(parts, chunk);
193
- return parts.join("");
169
+ return parts.join('');
194
170
  }
195
171
  function decodeUTF16LE(bytes) {
196
172
  const parts = [];
197
173
  const chunk = [];
198
174
  const len = bytes.length;
199
175
  let i = 0;
176
+ // Match TextDecoder("utf-16le") default BOM handling
177
+ if (len >= 2 && bytes[0] === 0xff && bytes[1] === 0xfe) {
178
+ i = 2;
179
+ }
200
180
  while (i + 1 < len) {
201
181
  const u1 = bytes[i] | (bytes[i + 1] << 8);
202
182
  i += 2;
@@ -230,7 +210,7 @@ function decodeUTF16LE(bytes) {
230
210
  pushCodeUnit(parts, chunk, REPLACEMENT);
231
211
  }
232
212
  flushChunk(parts, chunk);
233
- return parts.join("");
213
+ return parts.join('');
234
214
  }
235
215
  function decodeASCII(bytes) {
236
216
  const parts = [];
@@ -242,7 +222,7 @@ function decodeASCII(bytes) {
242
222
  }
243
223
  parts.push(String.fromCharCode.apply(null, codes));
244
224
  }
245
- return parts.join("");
225
+ return parts.join('');
246
226
  }
247
227
  function decodeLatin1(bytes) {
248
228
  const parts = [];
@@ -254,23 +234,24 @@ function decodeLatin1(bytes) {
254
234
  }
255
235
  parts.push(String.fromCharCode.apply(null, codes));
256
236
  }
257
- return parts.join("");
237
+ return parts.join('');
258
238
  }
259
239
  function decodeWindows1252(bytes) {
260
240
  const parts = [];
261
- let out = "";
241
+ let out = '';
262
242
  for (let i = 0; i < bytes.length; i++) {
263
243
  const b = bytes[i];
264
244
  const extra = b >= 0x80 && b <= 0x9f ? WINDOWS_1252_EXTRA[b] : undefined;
265
245
  out += extra !== null && extra !== void 0 ? extra : String.fromCharCode(b);
266
246
  if (out.length >= CHUNK) {
267
247
  parts.push(out);
268
- out = "";
248
+ out = '';
269
249
  }
270
250
  }
271
- if (out)
251
+ if (out) {
272
252
  parts.push(out);
273
- return parts.join("");
253
+ }
254
+ return parts.join('');
274
255
  }
275
256
  function encodeUTF8(str) {
276
257
  const out = [];
@@ -350,14 +331,16 @@ function encodeUTF16LE(str) {
350
331
  }
351
332
  function encodeASCII(str) {
352
333
  const out = new Uint8Array(str.length);
353
- for (let i = 0; i < str.length; i++)
334
+ for (let i = 0; i < str.length; i++) {
354
335
  out[i] = str.charCodeAt(i) & 0x7f;
336
+ }
355
337
  return out;
356
338
  }
357
339
  function encodeLatin1(str) {
358
340
  const out = new Uint8Array(str.length);
359
- for (let i = 0; i < str.length; i++)
341
+ for (let i = 0; i < str.length; i++) {
360
342
  out[i] = str.charCodeAt(i) & 0xff;
343
+ }
361
344
  return out;
362
345
  }
363
346
  function encodeWindows1252(str) {
@@ -369,8 +352,7 @@ function encodeWindows1252(str) {
369
352
  out[i] = WINDOWS_1252_REVERSE[ch];
370
353
  continue;
371
354
  }
372
- if ((code >= 0x00 && code <= 0x7f) ||
373
- (code >= 0xa0 && code <= 0xff)) {
355
+ if ((code >= 0x00 && code <= 0x7f) || (code >= 0xa0 && code <= 0xff)) {
374
356
  out[i] = code;
375
357
  continue;
376
358
  }