1import Protocol from 'devtools-protocol';
2
3import { CdpMessage, DebuggerRequest, DeviceResponse, InspectorHandler } from './types';
4import { ExpoDebuggerInfo } from '../device';
5
6/**
7 * Vscode doesn't seem to work nicely with missing `description` fields on `RemoteObject` instances.
8 * It also tries to invoke `Runtime.callFunctionOn` on `Symbol` types, which crashes Hermes.
9 * This handler tries to compensate for these two separate issues.
10 *
11 * @see https://github.com/facebook/hermes/issues/114
12 * @see https://github.com/microsoft/vscode-js-debug/issues/1583
13 */
14export class VscodeRuntimeGetPropertiesHandler implements InspectorHandler {
15  /** Keep track of `Runtime.getProperties` responses to intercept, by request id */
16  interceptGetProperties = new Set<number>();
17
18  onDebuggerMessage(
19    message: DebuggerRequest<RuntimeGetProperties>,
20    { debuggerType }: ExpoDebuggerInfo
21  ): boolean {
22    if (debuggerType === 'vscode' && message.method === 'Runtime.getProperties') {
23      this.interceptGetProperties.add(message.id);
24    }
25
26    // Do not block propagation of this message
27    return false;
28  }
29
30  onDeviceMessage(
31    message: DeviceResponse<RuntimeGetProperties>,
32    { debuggerType }: ExpoDebuggerInfo
33  ) {
34    if (
35      debuggerType === 'vscode' &&
36      'id' in message &&
37      this.interceptGetProperties.has(message.id)
38    ) {
39      this.interceptGetProperties.delete(message.id);
40
41      for (const item of message.result.result ?? []) {
42        // Force-fully format the properties description to be an empty string
43        if (item.value) {
44          item.value.description = item.value.description ?? '';
45        }
46
47        // Avoid passing the `objectId` for symbol types.
48        // When collapsing in vscode, it will fetch information about the symbol using the `objectId`.
49        // The `Runtime.getProperties` request of the symbol hard-crashes Hermes.
50        if (item.value?.type === 'symbol' && item.value.objectId) {
51          delete item.value.objectId;
52        }
53      }
54    }
55
56    // Do not block propagation of this message
57    return false;
58  }
59}
60
61/** @see https://chromedevtools.github.io/devtools-protocol/v8/Runtime/#method-getProperties */
62export type RuntimeGetProperties = CdpMessage<
63  'Runtime.getProperties',
64  Protocol.Runtime.GetPropertiesRequest,
65  Protocol.Runtime.GetPropertiesResponse
66>;
67