react-native-web-serial-api 0.0.3 → 0.2.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.
Files changed (177) hide show
  1. package/README.md +198 -104
  2. package/TESTING.md +542 -0
  3. package/android/build.gradle +16 -2
  4. package/android/src/main/java/dev/webserialapi/NativeUsbSerialModule.java +74 -11
  5. package/android/src/main/java/dev/webserialapi/PortPickerActivity.java +61 -59
  6. package/bin/expose-serial.js +205 -0
  7. package/lib/commonjs/UsbSerial.js +58 -26
  8. package/lib/commonjs/UsbSerial.js.map +1 -1
  9. package/lib/commonjs/WebSerial.js +273 -77
  10. package/lib/commonjs/WebSerial.js.map +1 -1
  11. package/lib/commonjs/index.js +15 -3
  12. package/lib/commonjs/index.js.map +1 -1
  13. package/lib/commonjs/lib/dom-exception.js +176 -0
  14. package/lib/commonjs/lib/dom-exception.js.map +1 -0
  15. package/lib/commonjs/lib/event-target.js +140 -0
  16. package/lib/commonjs/lib/event-target.js.map +1 -0
  17. package/lib/commonjs/lib/promise.js +23 -0
  18. package/lib/commonjs/lib/promise.js.map +1 -0
  19. package/lib/commonjs/lib/web-streams.js +42 -0
  20. package/lib/commonjs/lib/web-streams.js.map +1 -0
  21. package/lib/commonjs/testing/device-fixture.js +70 -0
  22. package/lib/commonjs/testing/device-fixture.js.map +1 -0
  23. package/lib/commonjs/testing/expose.js +91 -0
  24. package/lib/commonjs/testing/expose.js.map +1 -0
  25. package/lib/commonjs/testing/harness.js +98 -0
  26. package/lib/commonjs/testing/harness.js.map +1 -0
  27. package/lib/commonjs/testing/in-memory-serial-transport.js +653 -0
  28. package/lib/commonjs/testing/in-memory-serial-transport.js.map +1 -0
  29. package/lib/commonjs/testing/index.js +153 -0
  30. package/lib/commonjs/testing/index.js.map +1 -0
  31. package/lib/commonjs/testing/install-in-memory-serial-transport.js +54 -0
  32. package/lib/commonjs/testing/install-in-memory-serial-transport.js.map +1 -0
  33. package/lib/commonjs/testing/serial-client.js +277 -0
  34. package/lib/commonjs/testing/serial-client.js.map +1 -0
  35. package/lib/commonjs/testing/simulated-device.js +164 -0
  36. package/lib/commonjs/testing/simulated-device.js.map +1 -0
  37. package/lib/commonjs/testing/test-suite.js +142 -0
  38. package/lib/commonjs/testing/test-suite.js.map +1 -0
  39. package/lib/commonjs/transport.js +61 -0
  40. package/lib/commonjs/transport.js.map +1 -0
  41. package/lib/commonjs/websocket/WebSocketSerialTransport.js +659 -0
  42. package/lib/commonjs/websocket/WebSocketSerialTransport.js.map +1 -0
  43. package/lib/commonjs/websocket/bridge.js +234 -0
  44. package/lib/commonjs/websocket/bridge.js.map +1 -0
  45. package/lib/commonjs/websocket/index.js +33 -0
  46. package/lib/commonjs/websocket/index.js.map +1 -0
  47. package/lib/commonjs/websocket/protocol.js +55 -0
  48. package/lib/commonjs/websocket/protocol.js.map +1 -0
  49. package/lib/commonjs/websocket/serial-device-bridge.js +130 -0
  50. package/lib/commonjs/websocket/serial-device-bridge.js.map +1 -0
  51. package/lib/typescript/src/UsbSerial.d.ts +24 -67
  52. package/lib/typescript/src/UsbSerial.d.ts.map +1 -1
  53. package/lib/typescript/src/WebSerial.d.ts +16 -7
  54. package/lib/typescript/src/WebSerial.d.ts.map +1 -1
  55. package/lib/typescript/src/index.d.ts +3 -1
  56. package/lib/typescript/src/index.d.ts.map +1 -1
  57. package/lib/typescript/src/lib/dom-exception.d.ts +100 -0
  58. package/lib/typescript/src/lib/dom-exception.d.ts.map +1 -0
  59. package/lib/typescript/src/lib/event-target.d.ts +55 -0
  60. package/lib/typescript/src/lib/event-target.d.ts.map +1 -0
  61. package/lib/typescript/src/lib/promise.d.ts +11 -0
  62. package/lib/typescript/src/lib/promise.d.ts.map +1 -0
  63. package/lib/typescript/src/lib/web-streams.d.ts +9 -0
  64. package/lib/typescript/src/lib/web-streams.d.ts.map +1 -0
  65. package/lib/typescript/src/testing/device-fixture.d.ts +70 -0
  66. package/lib/typescript/src/testing/device-fixture.d.ts.map +1 -0
  67. package/lib/typescript/src/testing/expose.d.ts +71 -0
  68. package/lib/typescript/src/testing/expose.d.ts.map +1 -0
  69. package/lib/typescript/src/testing/harness.d.ts +34 -0
  70. package/lib/typescript/src/testing/harness.d.ts.map +1 -0
  71. package/lib/typescript/src/testing/in-memory-serial-transport.d.ts +216 -0
  72. package/lib/typescript/src/testing/in-memory-serial-transport.d.ts.map +1 -0
  73. package/lib/typescript/src/testing/index.d.ts +33 -0
  74. package/lib/typescript/src/testing/index.d.ts.map +1 -0
  75. package/lib/typescript/src/testing/install-in-memory-serial-transport.d.ts +25 -0
  76. package/lib/typescript/src/testing/install-in-memory-serial-transport.d.ts.map +1 -0
  77. package/lib/typescript/src/testing/serial-client.d.ts +62 -0
  78. package/lib/typescript/src/testing/serial-client.d.ts.map +1 -0
  79. package/lib/typescript/src/testing/simulated-device.d.ts +127 -0
  80. package/lib/typescript/src/testing/simulated-device.d.ts.map +1 -0
  81. package/lib/typescript/src/testing/test-suite.d.ts +75 -0
  82. package/lib/typescript/src/testing/test-suite.d.ts.map +1 -0
  83. package/lib/typescript/src/transport.d.ts +131 -0
  84. package/lib/typescript/src/transport.d.ts.map +1 -0
  85. package/lib/typescript/src/websocket/WebSocketSerialTransport.d.ts +111 -0
  86. package/lib/typescript/src/websocket/WebSocketSerialTransport.d.ts.map +1 -0
  87. package/lib/typescript/src/websocket/bridge.d.ts +66 -0
  88. package/lib/typescript/src/websocket/bridge.d.ts.map +1 -0
  89. package/lib/typescript/src/websocket/index.d.ts +19 -0
  90. package/lib/typescript/src/websocket/index.d.ts.map +1 -0
  91. package/lib/typescript/src/websocket/protocol.d.ts +64 -0
  92. package/lib/typescript/src/websocket/protocol.d.ts.map +1 -0
  93. package/lib/typescript/src/websocket/serial-device-bridge.d.ts +32 -0
  94. package/lib/typescript/src/websocket/serial-device-bridge.d.ts.map +1 -0
  95. package/package.json +57 -3
  96. package/src/UsbSerial.ts +65 -90
  97. package/src/WebSerial.ts +351 -113
  98. package/src/index.ts +6 -8
  99. package/src/lib/dom-exception.ts +129 -60
  100. package/src/lib/event-target.ts +58 -21
  101. package/src/lib/promise.ts +7 -7
  102. package/src/lib/web-streams.ts +43 -0
  103. package/src/testing/device-fixture.ts +150 -0
  104. package/src/testing/expose.ts +147 -0
  105. package/src/testing/harness.ts +124 -0
  106. package/src/testing/in-memory-serial-transport.ts +840 -0
  107. package/src/testing/index.ts +90 -0
  108. package/src/testing/install-in-memory-serial-transport.ts +65 -0
  109. package/src/testing/serial-client.ts +313 -0
  110. package/src/testing/simulated-device.ts +193 -0
  111. package/src/testing/test-suite.ts +186 -0
  112. package/src/transport.ts +200 -0
  113. package/src/websocket/WebSocketSerialTransport.ts +796 -0
  114. package/src/websocket/bridge.ts +299 -0
  115. package/src/websocket/index.ts +38 -0
  116. package/src/websocket/protocol.ts +101 -0
  117. package/src/websocket/serial-device-bridge.ts +160 -0
  118. package/babel.config.js +0 -3
  119. package/biome.json +0 -35
  120. package/example/.watchmanconfig +0 -1
  121. package/example/App.tsx +0 -71
  122. package/example/__tests__/App.test.tsx +0 -16
  123. package/example/__tests__/connectEvents.test.tsx +0 -81
  124. package/example/__tests__/getPorts.test.tsx +0 -140
  125. package/example/android/app/build.gradle +0 -120
  126. package/example/android/app/debug.keystore +0 -0
  127. package/example/android/app/proguard-rules.pro +0 -10
  128. package/example/android/app/src/debug/AndroidManifest.xml +0 -9
  129. package/example/android/app/src/main/AndroidManifest.xml +0 -38
  130. package/example/android/app/src/main/java/dev/uzlopak/MainActivity.kt +0 -22
  131. package/example/android/app/src/main/java/dev/uzlopak/MainApplication.kt +0 -41
  132. package/example/android/app/src/main/res/drawable/rn_edit_text_material.xml +0 -37
  133. package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  134. package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  135. package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  136. package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  137. package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  138. package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  139. package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  140. package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  141. package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  142. package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  143. package/example/android/app/src/main/res/values/strings.xml +0 -3
  144. package/example/android/app/src/main/res/values/styles.xml +0 -9
  145. package/example/android/build.gradle +0 -22
  146. package/example/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  147. package/example/android/gradle/wrapper/gradle-wrapper.properties +0 -7
  148. package/example/android/gradle.properties +0 -47
  149. package/example/android/gradlew +0 -252
  150. package/example/android/gradlew.bat +0 -94
  151. package/example/android/settings.gradle +0 -6
  152. package/example/app.json +0 -4
  153. package/example/babel.config.js +0 -21
  154. package/example/biome.json +0 -47
  155. package/example/deploy.sh +0 -11
  156. package/example/index.html +0 -26
  157. package/example/index.js +0 -9
  158. package/example/index.web.js +0 -8
  159. package/example/jest.config.js +0 -12
  160. package/example/metro.config.js +0 -58
  161. package/example/package-lock.json +0 -14510
  162. package/example/package.json +0 -48
  163. package/example/react-native.config.js +0 -17
  164. package/example/src/components/AppBar.tsx +0 -73
  165. package/example/src/components/Menu.tsx +0 -90
  166. package/example/src/components/SingleChoiceDialog.tsx +0 -120
  167. package/example/src/screens/ConnectScreen.tsx +0 -195
  168. package/example/src/screens/DevicesScreen.tsx +0 -252
  169. package/example/src/screens/TerminalScreen.tsx +0 -572
  170. package/example/src/settings.ts +0 -43
  171. package/example/src/theme.ts +0 -19
  172. package/example/src/util/TextUtil.ts +0 -129
  173. package/example/tsconfig.json +0 -10
  174. package/example/vite.config.mjs +0 -55
  175. package/scripts/deploy-release.sh +0 -127
  176. package/tsconfig.build.json +0 -7
  177. package/tsconfig.json +0 -20
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.SinkDevice = exports.SimulatedDevice = exports.LoopbackDevice = exports.LineBufferedDevice = void 0;
7
+ exports.toBytes = toBytes;
8
+ /**
9
+ * SimulatedDevice — author a complete simulated serial peripheral.
10
+ *
11
+ * Extend the class and override the lifecycle hooks to model a real device's
12
+ * whole behaviour (firmware/protocol): react to `open()`, to bytes the host
13
+ * writes, to control-signal changes, and stream data back over time. It is
14
+ * hosted by an {@link InMemorySerialTransport} ({@link ./virtual-serial}) and is
15
+ * free of any `react-native` dependency, so the same device runs under Jest,
16
+ * in a browser, and inside a React Native app on a device/emulator (for E2E).
17
+ *
18
+ * @example
19
+ * class Thermometer extends SimulatedDevice {
20
+ * usbVendorId = 0x0403;
21
+ * usbProductId = 0x6001;
22
+ * #timer?: ReturnType<typeof setInterval>;
23
+ * onOpen() {
24
+ * this.#timer = setInterval(() => this.send(`${20 + Math.random()}C\r\n`), 1000);
25
+ * }
26
+ * onData(bytes) { // host wrote a command
27
+ * if (String.fromCharCode(...bytes).trim() === 'ID?') this.send('ACME-TEMP\r\n');
28
+ * }
29
+ * onClose() { clearInterval(this.#timer); }
30
+ * }
31
+ * transport.addDevice(new Thermometer(), {hasPermission: true});
32
+ */
33
+
34
+ /** The negotiated connection parameters (native parity code: 0 none/1 odd/2 even). */
35
+
36
+ /** Device-asserted input signals — what the host reads via getSignals(). */
37
+
38
+ /** Host-asserted output signals (DTR/RTS/break) the device observes. */
39
+
40
+ /**
41
+ * The handle a {@link SimulatedDevice} uses to talk back to the host. Provided by
42
+ * the transport; you normally use the `protected` helpers on `SimulatedDevice`
43
+ * rather than this directly.
44
+ */
45
+
46
+ /** Coerce a payload into a byte array (string → char codes, & 0xff). */
47
+ function toBytes(data) {
48
+ if (typeof data === 'string') {
49
+ return Array.from(data, c => c.charCodeAt(0) & 0xff);
50
+ }
51
+ if (data instanceof Uint8Array) return Array.from(data);
52
+ return data.map(n => n & 0xff);
53
+ }
54
+
55
+ /**
56
+ * Base class for a simulated serial peripheral. Override the `on*` hooks you
57
+ * care about (all default to no-ops and may be async) and use the `protected`
58
+ * helpers to drive the host.
59
+ */
60
+ class SimulatedDevice {
61
+ /** USB Vendor ID this device reports for enumeration. */
62
+
63
+ /** USB Product ID this device reports for enumeration. */
64
+
65
+ /** Optional USB serial number. */
66
+
67
+ #host = null;
68
+
69
+ /** @internal Bind the transport host (called by InMemorySerialTransport). */
70
+ _bind(host) {
71
+ this.#host = host;
72
+ }
73
+
74
+ /** Send bytes to the host (they appear on `port.readable`). */
75
+ send(data) {
76
+ this.#host?.send(toBytes(data));
77
+ }
78
+
79
+ /**
80
+ * Raise a typed read error on the host's readable stream. `name` is the W3C
81
+ * error type, e.g. "BreakError", "BufferOverrunError", "FramingError",
82
+ * "ParityError" (defaults to "NetworkError").
83
+ */
84
+ raiseError(message, name) {
85
+ this.#host?.raiseError(message, name);
86
+ }
87
+
88
+ /** Set device-asserted input signals (DCD/CTS/RI/DSR) the host can read. */
89
+ setSignals(signals) {
90
+ this.#host?.setSignals(signals);
91
+ }
92
+
93
+ /** The parameters the host opened the port with, or null when closed. */
94
+ get openOptions() {
95
+ return this.#host?.openOptions ?? null;
96
+ }
97
+ get deviceId() {
98
+ return this.#host?.deviceId ?? -1;
99
+ }
100
+ get portNumber() {
101
+ return this.#host?.portNumber ?? 0;
102
+ }
103
+
104
+ /** The host opened the port. */
105
+ onOpen(_options) {}
106
+ /** The host wrote bytes to the device. */
107
+ onData(_data) {}
108
+ /** The host changed DTR/RTS/break. */
109
+ onHostSignals(_signals) {}
110
+ /** The host closed the port. */
111
+ onClose() {}
112
+ }
113
+
114
+ /** Optional USB identity for built-in devices. */
115
+ exports.SimulatedDevice = SimulatedDevice;
116
+ /** A loopback device: every byte written is echoed straight back. */
117
+ class LoopbackDevice extends SimulatedDevice {
118
+ constructor(identity = {}) {
119
+ super();
120
+ this.usbVendorId = identity.usbVendorId ?? 0x0403;
121
+ this.usbProductId = identity.usbProductId ?? 0x6001;
122
+ this.serialNumber = identity.serialNumber;
123
+ }
124
+ onData(data) {
125
+ this.send(data);
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Base for a line-oriented command/response device: buffers incoming bytes and
131
+ * calls {@link onLine} for each `\n`-terminated line (trailing CR/LF stripped).
132
+ */
133
+ exports.LoopbackDevice = LoopbackDevice;
134
+ class LineBufferedDevice extends SimulatedDevice {
135
+ #buffer = '';
136
+
137
+ /** Handle one line received from the host. */
138
+
139
+ onData(data) {
140
+ for (let i = 0; i < data.length; i++) {
141
+ this.#buffer += String.fromCharCode(data[i]);
142
+ }
143
+ let nl = this.#buffer.indexOf('\n');
144
+ while (nl >= 0) {
145
+ const line = this.#buffer.slice(0, nl).replace(/\r$/, '');
146
+ this.#buffer = this.#buffer.slice(nl + 1);
147
+ void this.onLine(line);
148
+ nl = this.#buffer.indexOf('\n');
149
+ }
150
+ }
151
+ }
152
+
153
+ /** A device that accepts writes but never sends anything back. */
154
+ exports.LineBufferedDevice = LineBufferedDevice;
155
+ class SinkDevice extends SimulatedDevice {
156
+ constructor(identity = {}) {
157
+ super();
158
+ this.usbVendorId = identity.usbVendorId ?? 0x0403;
159
+ this.usbProductId = identity.usbProductId ?? 0x6001;
160
+ this.serialNumber = identity.serialNumber;
161
+ }
162
+ }
163
+ exports.SinkDevice = SinkDevice;
164
+ //# sourceMappingURL=simulated-device.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["toBytes","data","Array","from","c","charCodeAt","Uint8Array","map","n","SimulatedDevice","host","_bind","send","raiseError","message","name","setSignals","signals","openOptions","deviceId","portNumber","onOpen","_options","onData","_data","onHostSignals","_signals","onClose","exports","LoopbackDevice","constructor","identity","usbVendorId","usbProductId","serialNumber","LineBufferedDevice","buffer","i","length","String","fromCharCode","nl","indexOf","line","slice","replace","onLine","SinkDevice"],"sourceRoot":"../../../src","sources":["testing/simulated-device.ts"],"mappings":";;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA;;AAGA;;AAQA;;AAOA;AACA;AACA;AACA;AACA;;AAWA;AACO,SAASA,OAAOA,CAACC,IAAoC,EAAY;EACtE,IAAI,OAAOA,IAAI,KAAK,QAAQ,EAAE;IAC5B,OAAOC,KAAK,CAACC,IAAI,CAACF,IAAI,EAAEG,CAAC,IAAIA,CAAC,CAACC,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;EACtD;EACA,IAAIJ,IAAI,YAAYK,UAAU,EAAE,OAAOJ,KAAK,CAACC,IAAI,CAACF,IAAI,CAAC;EACvD,OAAOA,IAAI,CAACM,GAAG,CAACC,CAAC,IAAIA,CAAC,GAAG,IAAI,CAAC;AAChC;;AAEA;AACA;AACA;AACA;AACA;AACO,MAAeC,eAAe,CAAC;EACpC;;EAEA;;EAEA;;EAGA,CAACC,IAAI,GAA+B,IAAI;;EAExC;EACAC,KAAKA,CAACD,IAAyB,EAAQ;IACrC,IAAI,CAAC,CAACA,IAAI,GAAGA,IAAI;EACnB;;EAEA;EACUE,IAAIA,CAACX,IAAoC,EAAQ;IACzD,IAAI,CAAC,CAACS,IAAI,EAAEE,IAAI,CAACZ,OAAO,CAACC,IAAI,CAAC,CAAC;EACjC;;EAEA;AACF;AACA;AACA;AACA;EACYY,UAAUA,CAACC,OAAe,EAAEC,IAAa,EAAQ;IACzD,IAAI,CAAC,CAACL,IAAI,EAAEG,UAAU,CAACC,OAAO,EAAEC,IAAI,CAAC;EACvC;;EAEA;EACUC,UAAUA,CAACC,OAA2B,EAAQ;IACtD,IAAI,CAAC,CAACP,IAAI,EAAEM,UAAU,CAACC,OAAO,CAAC;EACjC;;EAEA;EACA,IAAcC,WAAWA,CAAA,EAAsC;IAC7D,OAAO,IAAI,CAAC,CAACR,IAAI,EAAEQ,WAAW,IAAI,IAAI;EACxC;EAEA,IAAcC,QAAQA,CAAA,EAAW;IAC/B,OAAO,IAAI,CAAC,CAACT,IAAI,EAAES,QAAQ,IAAI,CAAC,CAAC;EACnC;EAEA,IAAcC,UAAUA,CAAA,EAAW;IACjC,OAAO,IAAI,CAAC,CAACV,IAAI,EAAEU,UAAU,IAAI,CAAC;EACpC;;EAEA;EACAC,MAAMA,CAACC,QAAoC,EAAwB,CAAC;EACpE;EACAC,MAAMA,CAACC,KAAiB,EAAwB,CAAC;EACjD;EACAC,aAAaA,CAACC,QAAqB,EAAwB,CAAC;EAC5D;EACAC,OAAOA,CAAA,EAAyB,CAAC;AACnC;;AAEA;AAAAC,OAAA,CAAAnB,eAAA,GAAAA,eAAA;AAOA;AACO,MAAMoB,cAAc,SAASpB,eAAe,CAAC;EAKlDqB,WAAWA,CAACC,QAAiC,GAAG,CAAC,CAAC,EAAE;IAClD,KAAK,CAAC,CAAC;IACP,IAAI,CAACC,WAAW,GAAGD,QAAQ,CAACC,WAAW,IAAI,MAAM;IACjD,IAAI,CAACC,YAAY,GAAGF,QAAQ,CAACE,YAAY,IAAI,MAAM;IACnD,IAAI,CAACC,YAAY,GAAGH,QAAQ,CAACG,YAAY;EAC3C;EAEAX,MAAMA,CAACtB,IAAgB,EAAQ;IAC7B,IAAI,CAACW,IAAI,CAACX,IAAI,CAAC;EACjB;AACF;;AAEA;AACA;AACA;AACA;AAHA2B,OAAA,CAAAC,cAAA,GAAAA,cAAA;AAIO,MAAeM,kBAAkB,SAAS1B,eAAe,CAAC;EAC/D,CAAC2B,MAAM,GAAG,EAAE;;EAEZ;;EAGAb,MAAMA,CAACtB,IAAgB,EAAQ;IAC7B,KAAK,IAAIoC,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGpC,IAAI,CAACqC,MAAM,EAAED,CAAC,EAAE,EAAE;MACpC,IAAI,CAAC,CAACD,MAAM,IAAIG,MAAM,CAACC,YAAY,CAACvC,IAAI,CAACoC,CAAC,CAAC,CAAC;IAC9C;IACA,IAAII,EAAE,GAAG,IAAI,CAAC,CAACL,MAAM,CAACM,OAAO,CAAC,IAAI,CAAC;IACnC,OAAOD,EAAE,IAAI,CAAC,EAAE;MACd,MAAME,IAAI,GAAG,IAAI,CAAC,CAACP,MAAM,CAACQ,KAAK,CAAC,CAAC,EAAEH,EAAE,CAAC,CAACI,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;MACzD,IAAI,CAAC,CAACT,MAAM,GAAG,IAAI,CAAC,CAACA,MAAM,CAACQ,KAAK,CAACH,EAAE,GAAG,CAAC,CAAC;MACzC,KAAK,IAAI,CAACK,MAAM,CAACH,IAAI,CAAC;MACtBF,EAAE,GAAG,IAAI,CAAC,CAACL,MAAM,CAACM,OAAO,CAAC,IAAI,CAAC;IACjC;EACF;AACF;;AAEA;AAAAd,OAAA,CAAAO,kBAAA,GAAAA,kBAAA;AACO,MAAMY,UAAU,SAAStC,eAAe,CAAC;EAK9CqB,WAAWA,CAACC,QAAiC,GAAG,CAAC,CAAC,EAAE;IAClD,KAAK,CAAC,CAAC;IACP,IAAI,CAACC,WAAW,GAAGD,QAAQ,CAACC,WAAW,IAAI,MAAM;IACjD,IAAI,CAACC,YAAY,GAAGF,QAAQ,CAACE,YAAY,IAAI,MAAM;IACnD,IAAI,CAACC,YAAY,GAAGH,QAAQ,CAACG,YAAY;EAC3C;AACF;AAACN,OAAA,CAAAmB,UAAA,GAAAA,UAAA","ignoreList":[]}
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.compareTestResults = compareTestResults;
7
+ exports.runTestSuite = runTestSuite;
8
+ var _harness = require("./harness");
9
+ var _serialClient = require("./serial-client");
10
+ /**
11
+ * A runtime-agnostic suite runner for serial device tests. Write a set of
12
+ * `SerialTest`s once and run them anywhere a {@link SerialPort} exists:
13
+ *
14
+ * - in Jest against a {@link DeviceHandle} simulator (in-memory),
15
+ * - on a device / emulator over a real or WebSocket-backed port, and
16
+ * - against BOTH, then {@link compareTestResults} to prove the device matches
17
+ * the simulator case-for-case.
18
+ *
19
+ * Each test receives an opened, host-side {@link SerialClient}; by default one
20
+ * client is shared across the whole suite (open once, close at the end), which
21
+ * matches how a request/response protocol session behaves. Pass `shared: false`
22
+ * to open and close a fresh client per test. The runner never throws — it
23
+ * collects a {@link SerialTestResult} per case — so it is safe to drive an
24
+ * on-device Self-Test screen.
25
+ *
26
+ * @example One suite, two transports, compared
27
+ * const sim = await runTestSuite(myTests, await virtualPort());
28
+ * const dev = await runTestSuite(myTests, realPort);
29
+ * const rows = compareTestResults(sim, dev); // a row passes when both agree
30
+ */
31
+
32
+ /** One test case. `run` receives an already-opened client (typically per the
33
+ * suite's {@link TestClient}; `SerialClient` by default). */
34
+
35
+ /** Progress hooks so a UI can render results live as each test completes. */
36
+
37
+ /**
38
+ * How to build (and tear down) the per-suite client from a port. Provide this to
39
+ * run a higher-level protocol client (e.g. an HCI / NMEA framer built on a
40
+ * {@link SerialClient}) instead of the raw client. `connect` must also open the
41
+ * port; `disconnect` must release it (a `SerialClient.close()` does both).
42
+ */
43
+
44
+ function defaultClientFactory(open) {
45
+ return {
46
+ async connect(port) {
47
+ const client = new _serialClient.SerialClient(port);
48
+ await client.open(open);
49
+ return client;
50
+ },
51
+ disconnect: client => client.close()
52
+ };
53
+ }
54
+
55
+ /**
56
+ * Run `tests` against an already-acquired `port`, collecting one result per
57
+ * case. With the default (shared) client the port is opened once and closed at
58
+ * the end; with `shared: false` each test gets a fresh open/close. Never throws.
59
+ */
60
+ async function runTestSuite(tests, port, options = {}) {
61
+ const factory = options.client ?? defaultClientFactory(options.open);
62
+ const shared = options.shared ?? true;
63
+ const progress = options.progress;
64
+ const results = [];
65
+ let sharedClient = null;
66
+ if (shared) {
67
+ try {
68
+ sharedClient = await factory.connect(port);
69
+ } catch (e) {
70
+ const result = {
71
+ name: 'open serial port',
72
+ passed: false,
73
+ error: (0, _harness.errorMessage)(e),
74
+ durationMs: 0
75
+ };
76
+ progress?.onResult?.(result);
77
+ return [result];
78
+ }
79
+ }
80
+ const total = tests.length;
81
+ try {
82
+ for (let i = 0; i < total; i++) {
83
+ const test = tests[i];
84
+ progress?.onStart?.(test.name, i, total);
85
+ const start = Date.now();
86
+ let perTest = null;
87
+ let result;
88
+ try {
89
+ if (!shared) perTest = await factory.connect(port);
90
+ const client = shared ? sharedClient : perTest;
91
+ await test.run(client);
92
+ result = {
93
+ name: test.name,
94
+ passed: true,
95
+ durationMs: Date.now() - start
96
+ };
97
+ } catch (e) {
98
+ result = {
99
+ name: test.name,
100
+ passed: false,
101
+ error: (0, _harness.errorMessage)(e),
102
+ durationMs: Date.now() - start
103
+ };
104
+ } finally {
105
+ if (perTest) await factory.disconnect(perTest).catch(() => {});
106
+ }
107
+ results.push(result);
108
+ progress?.onResult?.(result);
109
+ }
110
+ } finally {
111
+ if (sharedClient) await factory.disconnect(sharedClient).catch(() => {});
112
+ }
113
+ return results;
114
+ }
115
+
116
+ /**
117
+ * Compare two runs of the same suite case-by-case. A row passes when both runs
118
+ * agree (both passed or both failed), so the `candidate` is judged equivalent to
119
+ * the `reference` rather than judged on its own. Cases the candidate produced
120
+ * that the reference never ran are surfaced as failing `candidate: …` rows.
121
+ */
122
+ function compareTestResults(reference, candidate) {
123
+ const candidateByName = new Map(candidate.map(r => [r.name, r]));
124
+ const candidateOnly = candidate.filter(r => !reference.some(s => s.name === r.name)).map(r => ({
125
+ name: `candidate: ${r.name}`,
126
+ passed: false,
127
+ error: r.error ?? 'candidate produced an unexpected result',
128
+ durationMs: r.durationMs
129
+ }));
130
+ const compared = reference.map(s => {
131
+ const r = candidateByName.get(s.name);
132
+ const identical = !!r && r.passed === s.passed;
133
+ return {
134
+ name: s.name,
135
+ passed: identical,
136
+ error: identical ? undefined : `reference ${s.passed ? 'passed' : 'failed'}, candidate ${r ? r.passed ? 'passed' : 'failed' : 'did not respond'}${r?.error ? `: ${r.error}` : ''}`,
137
+ durationMs: r?.durationMs ?? 0
138
+ };
139
+ });
140
+ return [...candidateOnly, ...compared];
141
+ }
142
+ //# sourceMappingURL=test-suite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_harness","require","_serialClient","defaultClientFactory","open","connect","port","client","SerialClient","disconnect","close","runTestSuite","tests","options","factory","shared","progress","results","sharedClient","e","result","name","passed","error","errorMessage","durationMs","onResult","total","length","i","test","onStart","start","Date","now","perTest","run","catch","push","compareTestResults","reference","candidate","candidateByName","Map","map","r","candidateOnly","filter","some","s","compared","get","identical","undefined"],"sourceRoot":"../../../src","sources":["testing/test-suite.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.StopBits = exports.Parity = exports.DataBits = exports.DEFAULT_OPEN_OPTIONS = void 0;
7
+ /**
8
+ * Hardware-transport abstraction for the Web Serial polyfill.
9
+ *
10
+ * `SerialTransport` is the single interface that the `Serial`/`SerialPort`
11
+ * classes depend on to talk to "the device". The production implementation
12
+ * (`UsbSerialModule`, backed by the `NativeUsbSerial` TurboModule — see
13
+ * {@link ./UsbSerial}) and the in-memory test/dev double
14
+ * (`InMemorySerialTransport` — see {@link ./testing/in-memory-serial-transport}) both
15
+ * implement it.
16
+ *
17
+ * This module is intentionally free of any `react-native` import. That is what
18
+ * lets the virtual transport — and therefore the conformance suite built on top
19
+ * of it — run unchanged under Node/Jest, in a browser, and on a device.
20
+ */
21
+
22
+ // UsbSerialPort.ControlLine enum
23
+
24
+ // UsbSerialPort.FlowControl enum
25
+
26
+ const Parity = exports.Parity = {
27
+ NONE: 0,
28
+ ODD: 1,
29
+ EVEN: 2,
30
+ MARK: 3,
31
+ SPACE: 4
32
+ };
33
+ const DataBits = exports.DataBits = {
34
+ FIVE: 5,
35
+ SIX: 6,
36
+ SEVEN: 7,
37
+ EIGHT: 8
38
+ };
39
+ const StopBits = exports.StopBits = {
40
+ ONE: 1,
41
+ ONE_FIVE: 3,
42
+ TWO: 2
43
+ };
44
+ const DEFAULT_OPEN_OPTIONS = exports.DEFAULT_OPEN_OPTIONS = {
45
+ dataBits: DataBits.EIGHT,
46
+ stopBits: StopBits.ONE,
47
+ parity: Parity.NONE
48
+ };
49
+
50
+ /** Handle returned by the `on*` subscription methods. */
51
+
52
+ /**
53
+ * The contract every serial transport must satisfy. It mirrors the JS-friendly
54
+ * surface of `UsbSerialModule` exactly, so `UsbSerialModule implements
55
+ * SerialTransport` is a faithful 1:1 and any conforming double (e.g.
56
+ * `InMemorySerialTransport`) is a drop-in replacement.
57
+ *
58
+ * Ports are addressed by the pair `(deviceId, portNumber)`. Inbound bytes,
59
+ * read errors and device attach/detach arrive through the `on*` subscriptions.
60
+ */
61
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Parity","exports","NONE","ODD","EVEN","MARK","SPACE","DataBits","FIVE","SIX","SEVEN","EIGHT","StopBits","ONE","ONE_FIVE","TWO","DEFAULT_OPEN_OPTIONS","dataBits","stopBits","parity"],"sourceRoot":"../../src","sources":["transport.ts"],"mappings":";;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAGA;;AA0DO,MAAMA,MAAM,GAAAC,OAAA,CAAAD,MAAA,GAAG;EACpBE,IAAI,EAAE,CAAC;EACPC,GAAG,EAAE,CAAC;EACNC,IAAI,EAAE,CAAC;EACPC,IAAI,EAAE,CAAC;EACPC,KAAK,EAAE;AACT,CAAU;AAEH,MAAMC,QAAQ,GAAAN,OAAA,CAAAM,QAAA,GAAG;EACtBC,IAAI,EAAE,CAAC;EACPC,GAAG,EAAE,CAAC;EACNC,KAAK,EAAE,CAAC;EACRC,KAAK,EAAE;AACT,CAAU;AAEH,MAAMC,QAAQ,GAAAX,OAAA,CAAAW,QAAA,GAAG;EACtBC,GAAG,EAAE,CAAC;EACNC,QAAQ,EAAE,CAAC;EACXC,GAAG,EAAE;AACP,CAAU;AASH,MAAMC,oBAA6D,GAAAf,OAAA,CAAAe,oBAAA,GAAG;EAC3EC,QAAQ,EAAEV,QAAQ,CAACI,KAAK;EACxBO,QAAQ,EAAEN,QAAQ,CAACC,GAAG;EACtBM,MAAM,EAAEnB,MAAM,CAACE;AACjB,CAAC;;AAED;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","ignoreList":[]}