roku-debug 0.21.16 → 0.21.18

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 (263) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/LaunchConfiguration.d.ts +22 -0
  3. package/dist/RendezvousTracker.d.ts +1 -1
  4. package/dist/RendezvousTracker.js +5 -4
  5. package/dist/RendezvousTracker.js.map +1 -1
  6. package/dist/adapters/DebugProtocolAdapter.d.ts +12 -4
  7. package/dist/adapters/DebugProtocolAdapter.js +47 -6
  8. package/dist/adapters/DebugProtocolAdapter.js.map +1 -1
  9. package/dist/adapters/TelnetAdapter.d.ts +2 -13
  10. package/dist/adapters/TelnetAdapter.js +13 -10
  11. package/dist/adapters/TelnetAdapter.js.map +1 -1
  12. package/dist/adapters/customVariableUtils.d.ts +4 -0
  13. package/dist/adapters/customVariableUtils.js +398 -26
  14. package/dist/adapters/customVariableUtils.js.map +1 -1
  15. package/dist/adapters/customVariables/ifAppInfo.d.ts +2 -0
  16. package/dist/adapters/customVariables/ifAppInfo.js +50 -0
  17. package/dist/adapters/customVariables/ifAppInfo.js.map +1 -0
  18. package/dist/adapters/customVariables/ifAppManager.d.ts +2 -0
  19. package/dist/adapters/customVariables/ifAppManager.js +34 -0
  20. package/dist/adapters/customVariables/ifAppManager.js.map +1 -0
  21. package/dist/adapters/customVariables/ifAppMemoryMonitor.d.ts +2 -0
  22. package/dist/adapters/customVariables/ifAppMemoryMonitor.js +34 -0
  23. package/dist/adapters/customVariables/ifAppMemoryMonitor.js.map +1 -0
  24. package/dist/adapters/customVariables/ifArray.d.ts +2 -0
  25. package/dist/adapters/customVariables/ifArray.js +18 -0
  26. package/dist/adapters/customVariables/ifArray.js.map +1 -0
  27. package/dist/adapters/customVariables/ifAudioMetadata.d.ts +2 -0
  28. package/dist/adapters/customVariables/ifAudioMetadata.js +33 -0
  29. package/dist/adapters/customVariables/ifAudioMetadata.js.map +1 -0
  30. package/dist/adapters/customVariables/ifAudioResource.d.ts +2 -0
  31. package/dist/adapters/customVariables/ifAudioResource.js +34 -0
  32. package/dist/adapters/customVariables/ifAudioResource.js.map +1 -0
  33. package/dist/adapters/customVariables/ifByteArray.d.ts +2 -0
  34. package/dist/adapters/customVariables/ifByteArray.js +50 -0
  35. package/dist/adapters/customVariables/ifByteArray.js.map +1 -0
  36. package/dist/adapters/customVariables/ifCECStatus.d.ts +2 -0
  37. package/dist/adapters/customVariables/ifCECStatus.js +18 -0
  38. package/dist/adapters/customVariables/ifCECStatus.js.map +1 -0
  39. package/dist/adapters/customVariables/ifChannelStore.d.ts +2 -0
  40. package/dist/adapters/customVariables/ifChannelStore.js +34 -0
  41. package/dist/adapters/customVariables/ifChannelStore.js.map +1 -0
  42. package/dist/adapters/customVariables/ifDateTime.d.ts +2 -0
  43. package/dist/adapters/customVariables/ifDateTime.js +146 -0
  44. package/dist/adapters/customVariables/ifDateTime.js.map +1 -0
  45. package/dist/adapters/customVariables/ifDeviceInfo.d.ts +2 -0
  46. package/dist/adapters/customVariables/ifDeviceInfo.js +346 -0
  47. package/dist/adapters/customVariables/ifDeviceInfo.js.map +1 -0
  48. package/dist/adapters/customVariables/ifDraw2d.d.ts +2 -0
  49. package/dist/adapters/customVariables/ifDraw2d.js +34 -0
  50. package/dist/adapters/customVariables/ifDraw2d.js.map +1 -0
  51. package/dist/adapters/customVariables/ifEnum.d.ts +2 -0
  52. package/dist/adapters/customVariables/ifEnum.js +26 -0
  53. package/dist/adapters/customVariables/ifEnum.js.map +1 -0
  54. package/dist/adapters/customVariables/ifFileSystem.d.ts +2 -0
  55. package/dist/adapters/customVariables/ifFileSystem.js +18 -0
  56. package/dist/adapters/customVariables/ifFileSystem.js.map +1 -0
  57. package/dist/adapters/customVariables/ifFont.d.ts +2 -0
  58. package/dist/adapters/customVariables/ifFont.js +42 -0
  59. package/dist/adapters/customVariables/ifFont.js.map +1 -0
  60. package/dist/adapters/customVariables/ifFontRegistry.d.ts +2 -0
  61. package/dist/adapters/customVariables/ifFontRegistry.js +34 -0
  62. package/dist/adapters/customVariables/ifFontRegistry.js.map +1 -0
  63. package/dist/adapters/customVariables/ifGetMessagePort.d.ts +2 -0
  64. package/dist/adapters/customVariables/ifGetMessagePort.js +17 -0
  65. package/dist/adapters/customVariables/ifGetMessagePort.js.map +1 -0
  66. package/dist/adapters/customVariables/ifHdmiStatus.d.ts +2 -0
  67. package/dist/adapters/customVariables/ifHdmiStatus.js +42 -0
  68. package/dist/adapters/customVariables/ifHdmiStatus.js.map +1 -0
  69. package/dist/adapters/customVariables/ifHttpAgent.d.ts +2 -0
  70. package/dist/adapters/customVariables/ifHttpAgent.js +8 -0
  71. package/dist/adapters/customVariables/ifHttpAgent.js.map +1 -0
  72. package/dist/adapters/customVariables/ifImageMetadata.d.ts +2 -0
  73. package/dist/adapters/customVariables/ifImageMetadata.js +34 -0
  74. package/dist/adapters/customVariables/ifImageMetadata.js.map +1 -0
  75. package/dist/adapters/customVariables/ifInput.d.ts +2 -0
  76. package/dist/adapters/customVariables/ifInput.js +18 -0
  77. package/dist/adapters/customVariables/ifInput.js.map +1 -0
  78. package/dist/adapters/customVariables/ifList.d.ts +2 -0
  79. package/dist/adapters/customVariables/ifList.js +34 -0
  80. package/dist/adapters/customVariables/ifList.js.map +1 -0
  81. package/dist/adapters/customVariables/ifListToArray.d.ts +2 -0
  82. package/dist/adapters/customVariables/ifListToArray.js +18 -0
  83. package/dist/adapters/customVariables/ifListToArray.js.map +1 -0
  84. package/dist/adapters/customVariables/ifMessagePort.d.ts +2 -0
  85. package/dist/adapters/customVariables/ifMessagePort.js +18 -0
  86. package/dist/adapters/customVariables/ifMessagePort.js.map +1 -0
  87. package/dist/adapters/customVariables/ifMicrophone.d.ts +2 -0
  88. package/dist/adapters/customVariables/ifMicrophone.js +18 -0
  89. package/dist/adapters/customVariables/ifMicrophone.js.map +1 -0
  90. package/dist/adapters/customVariables/ifPath.d.ts +2 -0
  91. package/dist/adapters/customVariables/ifPath.js +26 -0
  92. package/dist/adapters/customVariables/ifPath.js.map +1 -0
  93. package/dist/adapters/customVariables/ifProgramGuide.d.ts +2 -0
  94. package/dist/adapters/customVariables/ifProgramGuide.js +18 -0
  95. package/dist/adapters/customVariables/ifProgramGuide.js.map +1 -0
  96. package/dist/adapters/customVariables/ifRegion.d.ts +2 -0
  97. package/dist/adapters/customVariables/ifRegion.js +98 -0
  98. package/dist/adapters/customVariables/ifRegion.js.map +1 -0
  99. package/dist/adapters/customVariables/ifRegistry.d.ts +2 -0
  100. package/dist/adapters/customVariables/ifRegistry.js +26 -0
  101. package/dist/adapters/customVariables/ifRegistry.js.map +1 -0
  102. package/dist/adapters/customVariables/ifRegistrySection.d.ts +2 -0
  103. package/dist/adapters/customVariables/ifRegistrySection.js +18 -0
  104. package/dist/adapters/customVariables/ifRegistrySection.js.map +1 -0
  105. package/dist/adapters/customVariables/ifSGNodeBoundingRect.d.ts +2 -0
  106. package/dist/adapters/customVariables/ifSGNodeBoundingRect.js +34 -0
  107. package/dist/adapters/customVariables/ifSGNodeBoundingRect.js.map +1 -0
  108. package/dist/adapters/customVariables/ifSGNodeChildren.d.ts +2 -0
  109. package/dist/adapters/customVariables/ifSGNodeChildren.js +74 -0
  110. package/dist/adapters/customVariables/ifSGNodeChildren.js.map +1 -0
  111. package/dist/adapters/customVariables/ifSGNodeDict.d.ts +2 -0
  112. package/dist/adapters/customVariables/ifSGNodeDict.js +18 -0
  113. package/dist/adapters/customVariables/ifSGNodeDict.js.map +1 -0
  114. package/dist/adapters/customVariables/ifSGNodeField.d.ts +2 -0
  115. package/dist/adapters/customVariables/ifSGNodeField.js +26 -0
  116. package/dist/adapters/customVariables/ifSGNodeField.js.map +1 -0
  117. package/dist/adapters/customVariables/ifSGNodeFocus.d.ts +2 -0
  118. package/dist/adapters/customVariables/ifSGNodeFocus.js +26 -0
  119. package/dist/adapters/customVariables/ifSGNodeFocus.js.map +1 -0
  120. package/dist/adapters/customVariables/ifSGNodeHttpAgentAccess.d.ts +2 -0
  121. package/dist/adapters/customVariables/ifSGNodeHttpAgentAccess.js +17 -0
  122. package/dist/adapters/customVariables/ifSGNodeHttpAgentAccess.js.map +1 -0
  123. package/dist/adapters/customVariables/ifSGScreen.d.ts +2 -0
  124. package/dist/adapters/customVariables/ifSGScreen.js +34 -0
  125. package/dist/adapters/customVariables/ifSGScreen.js.map +1 -0
  126. package/dist/adapters/customVariables/ifSocket.d.ts +2 -0
  127. package/dist/adapters/customVariables/ifSocket.js +58 -0
  128. package/dist/adapters/customVariables/ifSocket.js.map +1 -0
  129. package/dist/adapters/customVariables/ifSocketAddress.d.ts +2 -0
  130. package/dist/adapters/customVariables/ifSocketAddress.js +42 -0
  131. package/dist/adapters/customVariables/ifSocketAddress.js.map +1 -0
  132. package/dist/adapters/customVariables/ifSocketAsync.d.ts +2 -0
  133. package/dist/adapters/customVariables/ifSocketAsync.js +42 -0
  134. package/dist/adapters/customVariables/ifSocketAsync.js.map +1 -0
  135. package/dist/adapters/customVariables/ifSocketCastOption.d.ts +2 -0
  136. package/dist/adapters/customVariables/ifSocketCastOption.js +42 -0
  137. package/dist/adapters/customVariables/ifSocketCastOption.js.map +1 -0
  138. package/dist/adapters/customVariables/ifSocketConnection.d.ts +2 -0
  139. package/dist/adapters/customVariables/ifSocketConnection.js +26 -0
  140. package/dist/adapters/customVariables/ifSocketConnection.js.map +1 -0
  141. package/dist/adapters/customVariables/ifSocketConnectionOption.d.ts +2 -0
  142. package/dist/adapters/customVariables/ifSocketConnectionOption.js +42 -0
  143. package/dist/adapters/customVariables/ifSocketConnectionOption.js.map +1 -0
  144. package/dist/adapters/customVariables/ifSocketConnectionStatus.d.ts +2 -0
  145. package/dist/adapters/customVariables/ifSocketConnectionStatus.js +50 -0
  146. package/dist/adapters/customVariables/ifSocketConnectionStatus.js.map +1 -0
  147. package/dist/adapters/customVariables/ifSocketOption.d.ts +2 -0
  148. package/dist/adapters/customVariables/ifSocketOption.js +66 -0
  149. package/dist/adapters/customVariables/ifSocketOption.js.map +1 -0
  150. package/dist/adapters/customVariables/ifSocketStatus.d.ts +2 -0
  151. package/dist/adapters/customVariables/ifSocketStatus.js +90 -0
  152. package/dist/adapters/customVariables/ifSocketStatus.js.map +1 -0
  153. package/dist/adapters/customVariables/ifSourceIdentity.d.ts +2 -0
  154. package/dist/adapters/customVariables/ifSourceIdentity.js +18 -0
  155. package/dist/adapters/customVariables/ifSourceIdentity.js.map +1 -0
  156. package/dist/adapters/customVariables/ifSprite.d.ts +2 -0
  157. package/dist/adapters/customVariables/ifSprite.js +90 -0
  158. package/dist/adapters/customVariables/ifSprite.js.map +1 -0
  159. package/dist/adapters/customVariables/ifString.d.ts +2 -0
  160. package/dist/adapters/customVariables/ifString.js +26 -0
  161. package/dist/adapters/customVariables/ifString.js.map +1 -0
  162. package/dist/adapters/customVariables/ifStringOps.d.ts +2 -0
  163. package/dist/adapters/customVariables/ifStringOps.js +98 -0
  164. package/dist/adapters/customVariables/ifStringOps.js.map +1 -0
  165. package/dist/adapters/customVariables/ifTextToSpeech.d.ts +2 -0
  166. package/dist/adapters/customVariables/ifTextToSpeech.js +74 -0
  167. package/dist/adapters/customVariables/ifTextToSpeech.js.map +1 -0
  168. package/dist/adapters/customVariables/ifTextureRequest.d.ts +2 -0
  169. package/dist/adapters/customVariables/ifTextureRequest.js +26 -0
  170. package/dist/adapters/customVariables/ifTextureRequest.js.map +1 -0
  171. package/dist/adapters/customVariables/ifTimeSpan.d.ts +2 -0
  172. package/dist/adapters/customVariables/ifTimeSpan.js +34 -0
  173. package/dist/adapters/customVariables/ifTimeSpan.js.map +1 -0
  174. package/dist/adapters/customVariables/ifToStr.d.ts +2 -0
  175. package/dist/adapters/customVariables/ifToStr.js +18 -0
  176. package/dist/adapters/customVariables/ifToStr.js.map +1 -0
  177. package/dist/adapters/customVariables/ifUrlTransfer.d.ts +2 -0
  178. package/dist/adapters/customVariables/ifUrlTransfer.js +50 -0
  179. package/dist/adapters/customVariables/ifUrlTransfer.js.map +1 -0
  180. package/dist/adapters/customVariables/ifVideoPlayer.d.ts +2 -0
  181. package/dist/adapters/customVariables/ifVideoPlayer.js +34 -0
  182. package/dist/adapters/customVariables/ifVideoPlayer.js.map +1 -0
  183. package/dist/adapters/customVariables/ifXMLElement.d.ts +2 -0
  184. package/dist/adapters/customVariables/ifXMLElement.js +58 -0
  185. package/dist/adapters/customVariables/ifXMLElement.js.map +1 -0
  186. package/dist/adapters/customVariables/ifXMLList.d.ts +2 -0
  187. package/dist/adapters/customVariables/ifXMLList.js +34 -0
  188. package/dist/adapters/customVariables/ifXMLList.js.map +1 -0
  189. package/dist/adapters/customVariables/index.d.ts +78 -0
  190. package/dist/adapters/customVariables/index.js +159 -0
  191. package/dist/adapters/customVariables/index.js.map +1 -0
  192. package/dist/adapters/customVariables/roAppMemoryNotificationEvent.d.ts +2 -0
  193. package/dist/adapters/customVariables/roAppMemoryNotificationEvent.js +18 -0
  194. package/dist/adapters/customVariables/roAppMemoryNotificationEvent.js.map +1 -0
  195. package/dist/adapters/customVariables/roAudioPlayerEvent.d.ts +2 -0
  196. package/dist/adapters/customVariables/roAudioPlayerEvent.js +138 -0
  197. package/dist/adapters/customVariables/roAudioPlayerEvent.js.map +1 -0
  198. package/dist/adapters/customVariables/roCECStatusEvent.d.ts +2 -0
  199. package/dist/adapters/customVariables/roCECStatusEvent.js +34 -0
  200. package/dist/adapters/customVariables/roCECStatusEvent.js.map +1 -0
  201. package/dist/adapters/customVariables/roChannelStoreEvent.d.ts +2 -0
  202. package/dist/adapters/customVariables/roChannelStoreEvent.js +58 -0
  203. package/dist/adapters/customVariables/roChannelStoreEvent.js.map +1 -0
  204. package/dist/adapters/customVariables/roDeviceInfoEvent.d.ts +2 -0
  205. package/dist/adapters/customVariables/roDeviceInfoEvent.js +34 -0
  206. package/dist/adapters/customVariables/roDeviceInfoEvent.js.map +1 -0
  207. package/dist/adapters/customVariables/roFileSystemEvent.d.ts +2 -0
  208. package/dist/adapters/customVariables/roFileSystemEvent.js +34 -0
  209. package/dist/adapters/customVariables/roFileSystemEvent.js.map +1 -0
  210. package/dist/adapters/customVariables/roHdmiStatusEvent.d.ts +2 -0
  211. package/dist/adapters/customVariables/roHdmiStatusEvent.js +42 -0
  212. package/dist/adapters/customVariables/roHdmiStatusEvent.js.map +1 -0
  213. package/dist/adapters/customVariables/roInputEvent.d.ts +2 -0
  214. package/dist/adapters/customVariables/roInputEvent.js +26 -0
  215. package/dist/adapters/customVariables/roInputEvent.js.map +1 -0
  216. package/dist/adapters/customVariables/roMicrophoneEvent.d.ts +2 -0
  217. package/dist/adapters/customVariables/roMicrophoneEvent.js +34 -0
  218. package/dist/adapters/customVariables/roMicrophoneEvent.js.map +1 -0
  219. package/dist/adapters/customVariables/roSGNodeEvent.d.ts +2 -0
  220. package/dist/adapters/customVariables/roSGNodeEvent.js +50 -0
  221. package/dist/adapters/customVariables/roSGNodeEvent.js.map +1 -0
  222. package/dist/adapters/customVariables/roSGScreenEvent.d.ts +2 -0
  223. package/dist/adapters/customVariables/roSGScreenEvent.js +18 -0
  224. package/dist/adapters/customVariables/roSGScreenEvent.js.map +1 -0
  225. package/dist/adapters/customVariables/roSocketEvent.d.ts +2 -0
  226. package/dist/adapters/customVariables/roSocketEvent.js +18 -0
  227. package/dist/adapters/customVariables/roSocketEvent.js.map +1 -0
  228. package/dist/adapters/customVariables/roSystemLogEvent.d.ts +2 -0
  229. package/dist/adapters/customVariables/roSystemLogEvent.js +18 -0
  230. package/dist/adapters/customVariables/roSystemLogEvent.js.map +1 -0
  231. package/dist/adapters/customVariables/roTextToSpeechEvent.d.ts +2 -0
  232. package/dist/adapters/customVariables/roTextToSpeechEvent.js +34 -0
  233. package/dist/adapters/customVariables/roTextToSpeechEvent.js.map +1 -0
  234. package/dist/adapters/customVariables/roTextureRequestEvent.d.ts +2 -0
  235. package/dist/adapters/customVariables/roTextureRequestEvent.js +42 -0
  236. package/dist/adapters/customVariables/roTextureRequestEvent.js.map +1 -0
  237. package/dist/adapters/customVariables/roUniversalControlEvent.d.ts +2 -0
  238. package/dist/adapters/customVariables/roUniversalControlEvent.js +58 -0
  239. package/dist/adapters/customVariables/roUniversalControlEvent.js.map +1 -0
  240. package/dist/adapters/customVariables/roUrlEvent.d.ts +2 -0
  241. package/dist/adapters/customVariables/roUrlEvent.js +66 -0
  242. package/dist/adapters/customVariables/roUrlEvent.js.map +1 -0
  243. package/dist/adapters/customVariables/roVideoPlayerEvent.d.ts +2 -0
  244. package/dist/adapters/customVariables/roVideoPlayerEvent.js +154 -0
  245. package/dist/adapters/customVariables/roVideoPlayerEvent.js.map +1 -0
  246. package/dist/adapters/customVariables/utils.d.ts +6 -0
  247. package/dist/adapters/customVariables/utils.js +32 -0
  248. package/dist/adapters/customVariables/utils.js.map +1 -0
  249. package/dist/debugSession/BrightScriptDebugSession.d.ts +28 -0
  250. package/dist/debugSession/BrightScriptDebugSession.js +420 -76
  251. package/dist/debugSession/BrightScriptDebugSession.js.map +1 -1
  252. package/dist/interfaces.d.ts +1 -0
  253. package/dist/managers/ProjectManager.d.ts +2 -1
  254. package/dist/managers/ProjectManager.js +4 -3
  255. package/dist/managers/ProjectManager.js.map +1 -1
  256. package/dist/managers/SourceMapManager.d.ts +3 -0
  257. package/dist/managers/SourceMapManager.js +46 -29
  258. package/dist/managers/SourceMapManager.js.map +1 -1
  259. package/dist/util.js +1 -2
  260. package/dist/util.js.map +1 -1
  261. package/package.json +1 -1
  262. package/roku-debug-0.21.18.tgz +0 -0
  263. package/roku-debug-0.21.16.tgz +0 -0
@@ -22,11 +22,13 @@ const BreakpointManager_1 = require("../managers/BreakpointManager");
22
22
  const logging_1 = require("../logging");
23
23
  const VariablesResponse_1 = require("../debugProtocol/events/responses/VariablesResponse");
24
24
  const brighterscript_1 = require("brighterscript");
25
+ const debounce_1 = require("debounce");
25
26
  const diagnosticSource = 'roku-debug';
26
27
  class BrightScriptDebugSession extends debugadapter_1.DebugSession {
27
28
  constructor() {
28
29
  super();
29
30
  this.logger = logging_1.logger.createLogger(`[session]`);
31
+ this.isWindowsPlatform = process.platform.startsWith('win');
30
32
  /**
31
33
  * A sequence used to help identify log statements for requests
32
34
  */
@@ -49,6 +51,10 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
49
51
  */
50
52
  this.COMPILE_ERROR_THREAD_ID = 7777;
51
53
  this.exceptionBreakpoints = [];
54
+ this.pendingSendLogPromise = Promise.resolve();
55
+ this.debounceSendInvalidatedEvent = (0, debounce_1.debounce)((threadId, frameId) => {
56
+ this.sendInvalidatedEvent(threadId, frameId);
57
+ }, 50);
52
58
  this.evaluateRequestPromise = Promise.resolve();
53
59
  this.evaluateVarIndexByFrameId = new Map();
54
60
  /**
@@ -239,7 +245,7 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
239
245
  * @returns
240
246
  */
241
247
  normalizeLaunchConfig(config) {
242
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
248
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
243
249
  (_a = config.cwd) !== null && _a !== void 0 ? _a : (config.cwd = process.cwd());
244
250
  (_b = config.outDir) !== null && _b !== void 0 ? _b : (config.outDir = (0, FileUtils_1.standardizePath) `${config.cwd}/out`);
245
251
  (_c = config.stagingDir) !== null && _c !== void 0 ? _c : (config.stagingDir = (0, FileUtils_1.standardizePath) `${config.outDir}/.roku-deploy-staging`);
@@ -251,6 +257,8 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
251
257
  (_j = config.brightScriptConsolePort) !== null && _j !== void 0 ? _j : (config.brightScriptConsolePort = 8085);
252
258
  (_k = config.stagingDir) !== null && _k !== void 0 ? _k : (config.stagingDir = config.stagingFolderPath);
253
259
  (_l = config.emitChannelPublishedEvent) !== null && _l !== void 0 ? _l : (config.emitChannelPublishedEvent = true);
260
+ (_m = config.rewriteDevicePathsInLogs) !== null && _m !== void 0 ? _m : (config.rewriteDevicePathsInLogs = true);
261
+ (_o = config.autoResolveVirtualVariables) !== null && _o !== void 0 ? _o : (config.autoResolveVirtualVariables = false);
254
262
  return config;
255
263
  }
256
264
  async launchRequest(response, config) {
@@ -301,7 +309,13 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
301
309
  else {
302
310
  util_1.util.log(`Connecting to Roku via telnet at ${this.launchConfiguration.host}:${this.launchConfiguration.brightScriptConsolePort}`);
303
311
  }
304
- await this.initRendezvousTracking();
312
+ //activate rendezvous tracking (if enabled). Log the error and move on if it crashes, this shouldn't bring down the session.
313
+ try {
314
+ await this.initRendezvousTracking();
315
+ }
316
+ catch (e) {
317
+ this.logger.error('Failed to initialize rendezvous tracking', e);
318
+ }
305
319
  this.createRokuAdapter(this.rendezvousTracker);
306
320
  await this.connectRokuAdapter();
307
321
  await this.runAutomaticSceneGraphCommands(this.launchConfiguration.autoRunSgDebugCommands);
@@ -312,12 +326,12 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
312
326
  //pass along the console output
313
327
  if (this.launchConfiguration.consoleOutput === 'full') {
314
328
  this.rokuAdapter.on('console-output', (data) => {
315
- this.sendLogOutput(data);
329
+ void this.sendLogOutput(data);
316
330
  });
317
331
  }
318
332
  else {
319
333
  this.rokuAdapter.on('unhandled-console-output', (data) => {
320
- this.sendLogOutput(data);
334
+ void this.sendLogOutput(data);
321
335
  });
322
336
  }
323
337
  // Send chanperf events to the extension
@@ -543,15 +557,125 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
543
557
  */
544
558
  sendLogOutput(logOutput) {
545
559
  this.fileLoggingManager.writeRokuDeviceLog(logOutput);
546
- const lines = logOutput.split(/\r?\n/g);
547
- for (let i = 0; i < lines.length; i++) {
548
- let line = lines[i];
549
- if (i < lines.length - 1) {
550
- line += '\n';
560
+ this.pendingSendLogPromise = this.pendingSendLogPromise.then(async () => {
561
+ logOutput = await this.convertBacktracePaths(logOutput);
562
+ const lines = logOutput.split(/\r?\n/g);
563
+ for (let i = 0; i < lines.length; i++) {
564
+ let line = lines[i];
565
+ if (i < lines.length - 1) {
566
+ line += '\n';
567
+ }
568
+ if (this.launchConfiguration.rewriteDevicePathsInLogs) {
569
+ let potentialPaths = this.getPotentialPkgPaths(line);
570
+ for (let potentialPath of potentialPaths) {
571
+ let originalLocation = await this.projectManager.getSourceLocation(potentialPath.path, potentialPath.lineNumber, potentialPath.columnNumber);
572
+ if (originalLocation) {
573
+ let replacement;
574
+ replacement = originalLocation.filePath.replaceAll(' ', '%20');
575
+ if (replacement !== originalLocation.filePath) {
576
+ if (this.isWindowsPlatform) {
577
+ replacement = `vscode://file/${replacement}`;
578
+ }
579
+ else {
580
+ replacement = `file://${replacement}`;
581
+ }
582
+ }
583
+ replacement += `:${originalLocation.lineNumber}`;
584
+ if (potentialPath.columnNumber !== undefined) {
585
+ replacement += `:${originalLocation.columnIndex + 1}`;
586
+ }
587
+ line = line.replaceAll(potentialPath.fullMatch, replacement);
588
+ }
589
+ }
590
+ }
591
+ this.sendEvent(new debugadapter_1.OutputEvent(line, 'stdout'));
592
+ this.sendEvent(new Events_1.LogOutputEvent(line));
593
+ }
594
+ });
595
+ return this.pendingSendLogPromise;
596
+ }
597
+ /**
598
+ * Extracts potential package paths from a given line of text.
599
+ *
600
+ * This method uses a regular expression to find matches in the provided line
601
+ * and returns an array of objects containing details about each match.
602
+ *
603
+ * @param input - The line of text to search for potential package paths.
604
+ * @returns An array of objects, each containing:
605
+ * - `fullMatch`: The full matched string.
606
+ * - `path`: The extracted path from the match.
607
+ * - `lineNumber`: The line number extracted from the match.
608
+ * - `columnNumber`: The column number extracted from the match, or `undefined` if not found.
609
+ */
610
+ getPotentialPkgPaths(input) {
611
+ var _a, _b;
612
+ // https://regex101.com/r/ixpQiq/1
613
+ let matches = input.matchAll(/((?:\.\.\.|[A-Za-z_0-9]*pkg\:\/)[A-Za-z_0-9 \/\.]+\.[A-Za-z_0-9 \/]+)(?:(?:\:)(\d+)(?:\:(\d+))?|\((\d+)(?:\:(\d+))?\))/ig);
614
+ let paths = [];
615
+ if (matches) {
616
+ for (let match of matches) {
617
+ let fullMatch = match[0];
618
+ let path = match[1];
619
+ let lineNumber = parseInt((_a = match[2]) !== null && _a !== void 0 ? _a : match[4]);
620
+ let columnNumber = parseInt((_b = match[3]) !== null && _b !== void 0 ? _b : match[5]);
621
+ if (isNaN(columnNumber)) {
622
+ columnNumber = undefined;
623
+ }
624
+ paths.push({
625
+ fullMatch: fullMatch,
626
+ path: path,
627
+ lineNumber: lineNumber,
628
+ columnNumber: columnNumber
629
+ });
630
+ }
631
+ }
632
+ return paths;
633
+ }
634
+ /**
635
+ * Converts the filename property in backtrace objects in the given input string to source paths if found
636
+ */
637
+ async convertBacktracePaths(input) {
638
+ if (!this.launchConfiguration.rewriteDevicePathsInLogs) {
639
+ return input;
640
+ }
641
+ // Why does this not work? It should work, but it doesn't. I'm not sure why.
642
+ // let matches = input.matchAll(this.deviceBacktraceObjectRegex);
643
+ // https://regex101.com/r/y1koaV/2
644
+ let deviceBacktraceObjectRegex = /{\s+filename:\s+"([A-Za-z0-9_\.\/\: ]+)"\s+function\:\s+".+"\s+(line_number\:\s+(\d+))\s+}/gi;
645
+ let matches = [];
646
+ let match = deviceBacktraceObjectRegex.exec(input);
647
+ while (match) {
648
+ matches.push(match);
649
+ match = deviceBacktraceObjectRegex.exec(input);
650
+ }
651
+ if (matches) {
652
+ for (let match of matches) {
653
+ let fullMatch = match[0];
654
+ let filePath = match[1];
655
+ let fullLineNumber = match[2];
656
+ let lineNumber = parseInt(match[3]);
657
+ let originalLocation = await this.projectManager.getSourceLocation(filePath, lineNumber);
658
+ if (originalLocation) {
659
+ let fileReplacement;
660
+ fileReplacement = originalLocation.filePath.replaceAll(' ', '%20');
661
+ if (fileReplacement !== originalLocation.filePath) {
662
+ if (this.isWindowsPlatform) {
663
+ fileReplacement = `vscode://file/${fileReplacement}`;
664
+ }
665
+ else {
666
+ fileReplacement = `file://${fileReplacement}`;
667
+ }
668
+ }
669
+ fileReplacement += `:${originalLocation.lineNumber}`;
670
+ let lineNumberReplacement = fullLineNumber.replace(lineNumber.toString(), originalLocation.lineNumber.toString());
671
+ // replace the full backtrace object with the an updated version so we don't modify other parts of the log output that might contain the same file path
672
+ let completeReplacement = fullMatch.replace(filePath, fileReplacement);
673
+ completeReplacement = completeReplacement.replace(fullLineNumber, lineNumberReplacement);
674
+ input = input.replaceAll(fullMatch, completeReplacement);
675
+ }
551
676
  }
552
- this.sendEvent(new debugadapter_1.OutputEvent(line, 'stdout'));
553
- this.sendEvent(new Events_1.LogOutputEvent(line));
554
677
  }
678
+ return input;
555
679
  }
556
680
  async runAutomaticSceneGraphCommands(commands) {
557
681
  if (commands) {
@@ -855,7 +979,7 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
855
979
  if (!result) {
856
980
  throw new Error(`Could not get scopes`);
857
981
  }
858
- v = this.getVariableFromResult(result, args.frameId);
982
+ v = await this.getVariableFromResult(result, args.frameId);
859
983
  //TODO - testing something, remove later
860
984
  // eslint-disable-next-line camelcase
861
985
  v.request_seq = response.request_seq;
@@ -969,13 +1093,15 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
969
1093
  this.logger.info('[stepBackRequest] end');
970
1094
  }
971
1095
  async variablesRequest(response, args) {
972
- var _a, _b;
1096
+ var _a, _b, _c, _d;
973
1097
  const logger = this.logger.createLogger('[variablesRequest]');
1098
+ let sendInvalidatedEvent = false;
1099
+ let frameId = null;
974
1100
  try {
975
1101
  logger.log('begin', { args });
976
1102
  //ensure the rokuAdapter is loaded
977
1103
  await this.getRokuAdapter();
978
- let childVariables = [];
1104
+ let updatedVariables = [];
979
1105
  //wait for any `evaluate` commands to finish so we have a higher likely hood of being at a debugger prompt
980
1106
  await this.evaluateRequestPromise;
981
1107
  if (((_a = this.rokuAdapter) === null || _a === void 0 ? void 0 : _a.isAtDebuggerPrompt) !== true) {
@@ -993,13 +1119,15 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
993
1119
  for (const varName of vars) {
994
1120
  let { evalArgs } = await this.evaluateExpressionToTempVar({ expression: varName, frameId: -1 }, util_1.util.getVariablePath(varName));
995
1121
  let result = await this.rokuAdapter.getVariable(evalArgs.expression, -1);
996
- let tempVar = this.getVariableFromResult(result, -1);
997
- childVariables.push(tempVar);
1122
+ let tempVar = await this.getVariableFromResult(result, -1);
1123
+ updatedVariables.push(tempVar);
998
1124
  }
999
1125
  }
1000
1126
  else {
1001
- childVariables.push(new debugadapter_1.Variable('variables disabled by launch.json setting', 'enableVariablesPanel: false'));
1127
+ updatedVariables.push(new debugadapter_1.Variable('variables disabled by launch.json setting', 'enableVariablesPanel: false'));
1002
1128
  }
1129
+ this.variables[args.variablesReference] = new debugadapter_1.Variable('', '', args.variablesReference, 0, updatedVariables.length);
1130
+ this.variables[args.variablesReference].childVariables = updatedVariables;
1003
1131
  }
1004
1132
  else {
1005
1133
  //find the variable with this reference
@@ -1010,49 +1138,120 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
1010
1138
  return this.sendResponse(response);
1011
1139
  }
1012
1140
  logger.log('variable', v);
1013
- //query for child vars if we haven't done it yet.
1014
- if (v.childVariables.length === 0) {
1015
- let { evalArgs } = await this.evaluateExpressionToTempVar({ expression: v.evaluateName, frameId: v.frameId }, util_1.util.getVariablePath(v.evaluateName));
1016
- let result = await this.rokuAdapter.getVariable(evalArgs.expression, v.frameId);
1017
- let tempVar = this.getVariableFromResult(result, v.frameId);
1018
- tempVar.frameId = v.frameId;
1019
- v.childVariables = tempVar.childVariables;
1020
- }
1021
- childVariables = v.childVariables;
1022
- }
1023
- //if the variable is an array, send only the requested range
1024
- if (Array.isArray(childVariables) && args.filter === 'indexed') {
1025
- //only send the variable range requested by the debugger
1026
- childVariables = childVariables.slice(args.start, args.start + args.count);
1027
- }
1028
- let filteredChildVariables = this.launchConfiguration.showHiddenVariables !== true ? childVariables.filter((child) => !child.name.startsWith(this.tempVarPrefix)) : childVariables;
1029
- if (this.launchConfiguration.showHiddenVariables !== true) {
1030
- filteredChildVariables = filteredChildVariables.filter((child) => {
1031
- //A transient variable that we show when there is a value
1032
- if (child.name === '__brs_err__' && child.type !== VariablesResponse_1.VariableType.Uninitialized) {
1033
- return true;
1141
+ //query for child vars if we haven't done it yet or DAP is asking to resolve a lazy variable
1142
+ if (v.childVariables.length === 0 || v.isResolved) {
1143
+ let tempVar;
1144
+ if (!v.isResolved) {
1145
+ // Evaluate the variable
1146
+ try {
1147
+ let { evalArgs } = await this.evaluateExpressionToTempVar({ expression: v.evaluateName, frameId: v.frameId }, util_1.util.getVariablePath(v.evaluateName));
1148
+ let result = await this.rokuAdapter.getVariable(evalArgs.expression, v.frameId);
1149
+ tempVar = await this.getVariableFromResult(result, v.frameId);
1150
+ tempVar.frameId = v.frameId;
1151
+ // Determine if the variable has changed
1152
+ sendInvalidatedEvent = v.type !== tempVar.type || v.indexedVariables !== tempVar.indexedVariables;
1153
+ }
1154
+ catch (error) {
1155
+ logger.error('Error getting variables', error);
1156
+ tempVar = new debugadapter_1.Variable('Error', `❌ Error: ${error.message}`);
1157
+ tempVar.type = '';
1158
+ tempVar.childVariables = [];
1159
+ sendInvalidatedEvent = true;
1160
+ response.success = false;
1161
+ response.message = error.message;
1162
+ }
1163
+ // Merge the resulting updates together
1164
+ v.childVariables = tempVar.childVariables;
1165
+ v.value = tempVar.value;
1166
+ v.type = tempVar.type;
1167
+ v.indexedVariables = tempVar.indexedVariables;
1168
+ v.namedVariables = tempVar.namedVariables;
1034
1169
  }
1035
- else if (util_1.util.isTransientVariable(child.name)) {
1036
- return false;
1170
+ frameId = v.frameId;
1171
+ if (((_b = v === null || v === void 0 ? void 0 : v.presentationHint) === null || _b === void 0 ? void 0 : _b.lazy) || v.isResolved) {
1172
+ // If this was a lazy variable we need to respond with the updated variable and not the children
1173
+ if (v.isResolved && v.childVariables.length > 0) {
1174
+ updatedVariables = v.childVariables;
1175
+ }
1176
+ else {
1177
+ updatedVariables = [v];
1178
+ }
1179
+ v.isResolved = true;
1037
1180
  }
1038
1181
  else {
1039
- return true;
1182
+ updatedVariables = v.childVariables;
1040
1183
  }
1041
- });
1184
+ // If the variable has no children, set the reference to 0
1185
+ // so it does not look expandable in the Ui
1186
+ if (v.childVariables.length === 0) {
1187
+ v.variablesReference = 0;
1188
+ }
1189
+ // If the variable was resolve in the past we may not have fetched a new temp var
1190
+ tempVar !== null && tempVar !== void 0 ? tempVar : (tempVar = v);
1191
+ if (v === null || v === void 0 ? void 0 : v.presentationHint) {
1192
+ v.presentationHint.lazy = (_c = tempVar.presentationHint) === null || _c === void 0 ? void 0 : _c.lazy;
1193
+ }
1194
+ else {
1195
+ v.presentationHint = tempVar.presentationHint;
1196
+ }
1197
+ }
1198
+ else {
1199
+ updatedVariables = v.childVariables;
1200
+ }
1042
1201
  }
1043
1202
  response.body = {
1044
- variables: filteredChildVariables
1203
+ variables: this.filterVariablesUpdates(updatedVariables, args, this.variables[args.variablesReference])
1045
1204
  };
1046
1205
  }
1047
1206
  catch (error) {
1048
1207
  logger.error('Error during variablesRequest', error, { args });
1049
1208
  response.success = false;
1050
- response.message = (_b = error === null || error === void 0 ? void 0 : error.message) !== null && _b !== void 0 ? _b : 'Error during variablesRequest';
1209
+ response.message = (_d = error === null || error === void 0 ? void 0 : error.message) !== null && _d !== void 0 ? _d : 'Error during variablesRequest';
1051
1210
  }
1052
1211
  finally {
1053
1212
  logger.info('end', { response });
1054
1213
  }
1055
1214
  this.sendResponse(response);
1215
+ if (sendInvalidatedEvent) {
1216
+ this.debounceSendInvalidatedEvent(null, frameId);
1217
+ }
1218
+ }
1219
+ filterVariablesUpdates(updatedVariables, args, v) {
1220
+ var _a;
1221
+ if (!updatedVariables || !v) {
1222
+ return [];
1223
+ }
1224
+ let start = (_a = args.start) !== null && _a !== void 0 ? _a : 0;
1225
+ //if the variable is an array, send only the requested range
1226
+ if (Array.isArray(updatedVariables) && args.filter === 'indexed') {
1227
+ //only send the variable range requested by the debugger
1228
+ if (!args.count) {
1229
+ updatedVariables = updatedVariables.slice(0, v.indexedVariables);
1230
+ }
1231
+ else {
1232
+ updatedVariables = updatedVariables.slice(start, start + args.count);
1233
+ }
1234
+ }
1235
+ if (Array.isArray(updatedVariables) && args.filter === 'named') {
1236
+ // We currently do not support named variable paging so we always send all named variables
1237
+ updatedVariables = updatedVariables.slice(v.indexedVariables);
1238
+ }
1239
+ let filteredUpdatedVariables = this.launchConfiguration.showHiddenVariables !== true ? updatedVariables.filter((child) => !child.name.startsWith(this.tempVarPrefix)) : updatedVariables;
1240
+ if (this.launchConfiguration.showHiddenVariables !== true) {
1241
+ filteredUpdatedVariables = filteredUpdatedVariables.filter((child) => {
1242
+ //A transient variable that we show when there is a value
1243
+ if (child.name === '__brs_err__' && child.type !== VariablesResponse_1.VariableType.Uninitialized) {
1244
+ return true;
1245
+ }
1246
+ else if (util_1.util.isTransientVariable(child.name)) {
1247
+ return false;
1248
+ }
1249
+ else {
1250
+ return true;
1251
+ }
1252
+ });
1253
+ }
1254
+ return filteredUpdatedVariables;
1056
1255
  }
1057
1256
  getNextVarIndex(frameId) {
1058
1257
  if (!this.evaluateVarIndexByFrameId.has(frameId)) {
@@ -1098,7 +1297,9 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
1098
1297
  }
1099
1298
  //is at debugger prompt
1100
1299
  }
1101
- else {
1300
+ else if (args.expression.trim()) {
1301
+ // We trim and check that the expression is not an empty string so that we do not send empty expressions to the Roku
1302
+ // This happens mostly when hovering over leading whitespace in the editor
1102
1303
  let { evalArgs, variablePath } = await this.evaluateExpressionToTempVar(args, util_1.util.getVariablePath(args.expression));
1103
1304
  //if we found a variable path (e.g. ['a', 'b', 'c']) then do a variable lookup because it's faster and more widely supported than `evaluate`
1104
1305
  if (variablePath) {
@@ -1113,7 +1314,7 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
1113
1314
  if (!result) {
1114
1315
  throw new Error('Error: unable to evaluate expression');
1115
1316
  }
1116
- v = this.getVariableFromResult(result, evalArgs.frameId);
1317
+ v = await this.getVariableFromResult(result, evalArgs.frameId);
1117
1318
  //TODO - testing something, remove later
1118
1319
  // eslint-disable-next-line camelcase
1119
1320
  v.request_seq = response.request_seq;
@@ -1131,14 +1332,20 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
1131
1332
  else {
1132
1333
  let commandResults = await this.rokuAdapter.evaluate(evalArgs.expression, evalArgs.frameId);
1133
1334
  commandResults.message = util_1.util.trimDebugPrompt(commandResults.message);
1134
- if (args.context !== 'watch') {
1135
- //clear variable cache since this action could have side-effects
1335
+ if (args.context === 'repl') {
1336
+ // Clear variable cache since this action could have side-effects
1337
+ // Only do this for REPL requests as hovers and watches should not clear the cache
1136
1338
  this.clearState();
1137
1339
  this.sendInvalidatedEvent(null, evalArgs.frameId);
1138
1340
  }
1139
- //if the adapter captured output (probably only telnet), print it to the vscode debug console
1341
+ // If the adapter captured output (probably only telnet), log the results
1140
1342
  if (typeof commandResults.message === 'string') {
1141
- this.sendEvent(new debugadapter_1.OutputEvent(commandResults.message, commandResults.type === 'error' ? 'stderr' : 'stdio'));
1343
+ this.logger.debug('evaluateRequest', { commandResults });
1344
+ if (args.context === 'repl') {
1345
+ // If the command was a repl command, send the output to the debug console for the developer as well
1346
+ // We limit this to repl only so you don't get extra logs when hovering over variables ro running watches
1347
+ this.sendEvent(new debugadapter_1.OutputEvent(commandResults.message, commandResults.type === 'error' ? 'stderr' : 'stdio'));
1348
+ }
1142
1349
  }
1143
1350
  if (this.enableDebugProtocol || (typeof commandResults.message !== 'string')) {
1144
1351
  response.body = {
@@ -1171,13 +1378,14 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
1171
1378
  if (!variablePath && util_1.util.isAssignableExpression(args.expression)) {
1172
1379
  let varIndex = this.getNextVarIndex(args.frameId);
1173
1380
  let arrayVarName = this.tempVarPrefix + 'eval';
1381
+ let command = '';
1174
1382
  if (varIndex === 0) {
1175
- const response = await this.rokuAdapter.evaluate(`${arrayVarName} = []`, args.frameId);
1176
- console.log(response);
1383
+ command += `if type(${arrayVarName}) = "<uninitialized>" then ${arrayVarName} = []\n`;
1177
1384
  }
1178
1385
  let statement = `${arrayVarName}[${varIndex}] = ${args.expression}`;
1179
1386
  returnVal.evalArgs.expression = `${arrayVarName}[${varIndex}]`;
1180
- let commandResults = await this.rokuAdapter.evaluate(statement, args.frameId);
1387
+ command += statement;
1388
+ let commandResults = await this.rokuAdapter.evaluate(command, args.frameId);
1181
1389
  if (commandResults.type === 'error') {
1182
1390
  throw new Error(commandResults.message);
1183
1391
  }
@@ -1185,6 +1393,49 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
1185
1393
  }
1186
1394
  return returnVal;
1187
1395
  }
1396
+ async bulkEvaluateExpressionToTempVar(frameId, argsArray, variablePathArray) {
1397
+ let results = {
1398
+ evaluations: [],
1399
+ bulkVarName: ''
1400
+ };
1401
+ let storedVariables = [];
1402
+ let command = '';
1403
+ for (let i = 0; i < argsArray.length; i++) {
1404
+ let args = argsArray[i];
1405
+ let variablePath = variablePathArray[i];
1406
+ let returnVal = { evalArgs: args, variablePath };
1407
+ if (!variablePath && util_1.util.isAssignableExpression(args.expression)) {
1408
+ let varIndex = this.getNextVarIndex(frameId);
1409
+ let arrayVarName = this.tempVarPrefix + 'eval';
1410
+ if (varIndex === 0) {
1411
+ command += `if type(${arrayVarName}) = "<uninitialized>" then ${arrayVarName} = []\n`;
1412
+ }
1413
+ let statement = `${arrayVarName}[${varIndex}] = ${args.expression}\n`;
1414
+ returnVal.evalArgs.expression = `${arrayVarName}[${varIndex}]`;
1415
+ command += statement;
1416
+ storedVariables.push(`${arrayVarName}[${varIndex}]`);
1417
+ returnVal.variablePath = [arrayVarName, varIndex.toString()];
1418
+ }
1419
+ results.evaluations[i] = returnVal;
1420
+ }
1421
+ if (command) {
1422
+ // create a bulk container for the command results
1423
+ let varIndex = this.getNextVarIndex(frameId);
1424
+ let arrayVarName = this.tempVarPrefix + 'eval';
1425
+ let bulkContainerStatement = `${arrayVarName}[${varIndex}] = [\n`;
1426
+ for (let storedVariable of storedVariables) {
1427
+ bulkContainerStatement += `${storedVariable},\n`;
1428
+ }
1429
+ bulkContainerStatement += `]`;
1430
+ command += bulkContainerStatement;
1431
+ results.bulkVarName = `${arrayVarName}[${varIndex}]`;
1432
+ let commandResults = await this.rokuAdapter.evaluate(command, frameId);
1433
+ if (commandResults.type === 'error') {
1434
+ throw new Error(commandResults.message);
1435
+ }
1436
+ }
1437
+ return results;
1438
+ }
1188
1439
  /**
1189
1440
  * Called when the host stops debugging
1190
1441
  * @param response
@@ -1304,28 +1555,57 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
1304
1555
  this.clearState();
1305
1556
  return threads;
1306
1557
  }
1307
- getVariableFromResult(result, frameId) {
1308
- var _a, _b, _c, _d, _e;
1558
+ async getVariableFromResult(result, frameId, maxDepth = 1) {
1559
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
1309
1560
  let v;
1310
1561
  if (result) {
1311
1562
  if (this.enableDebugProtocol) {
1312
1563
  let refId = this.getEvaluateRefId(result.evaluateName, frameId);
1564
+ if (result.isCustom && !((_a = result.presentationHint) === null || _a === void 0 ? void 0 : _a.lazy) && result.evaluateNow) {
1565
+ try {
1566
+ // We should not wait to resolve this variable later. Fetch, store, and merge the results right away.
1567
+ let { evalArgs } = await this.evaluateExpressionToTempVar({ expression: result.evaluateName, frameId: frameId }, util_1.util.getVariablePath(result.evaluateName));
1568
+ let newResult = await this.rokuAdapter.getVariable(evalArgs.expression, frameId);
1569
+ this.mergeEvaluateContainers(result, newResult);
1570
+ }
1571
+ catch (error) {
1572
+ logging_1.logger.error('Error getting variables', error);
1573
+ this.mergeEvaluateContainers(result, {
1574
+ name: result.name,
1575
+ evaluateName: result.evaluateName,
1576
+ children: [],
1577
+ value: `❌ Error: ${error.message}`,
1578
+ type: '',
1579
+ highLevelType: undefined,
1580
+ keyType: undefined
1581
+ });
1582
+ }
1583
+ }
1313
1584
  if (result.keyType) {
1585
+ let value = `${(_b = result.value) !== null && _b !== void 0 ? _b : result.type}`;
1586
+ let indexedVariables = result.indexedVariables;
1587
+ let namedVariables = result.namedVariables;
1588
+ if (indexedVariables === undefined || namedVariables === undefined) {
1589
+ // If either indexed or named variables are undefined, we should tell the debugger to ask for everything
1590
+ // by supplying undefined values for both
1591
+ indexedVariables = undefined;
1592
+ namedVariables = undefined;
1593
+ }
1314
1594
  // check to see if this is an dictionary or a list
1315
1595
  if (result.keyType === 'Integer') {
1316
1596
  // list type
1317
- v = new debugadapter_1.Variable(result.name, result.type, refId, result.elementCount, 0);
1318
- this.variables[refId] = v;
1597
+ v = new debugadapter_1.Variable(result.name, value, refId, indexedVariables, namedVariables);
1319
1598
  }
1320
1599
  else if (result.keyType === 'String') {
1321
1600
  // dictionary type
1322
- v = new debugadapter_1.Variable(result.name, result.type, refId, 0, result.elementCount);
1601
+ v = new debugadapter_1.Variable(result.name, value, refId, indexedVariables, namedVariables);
1323
1602
  }
1603
+ v.type = result.type;
1324
1604
  }
1325
1605
  else {
1326
1606
  let value;
1327
1607
  if (result.type === VariablesResponse_1.VariableType.Invalid) {
1328
- value = (_a = result.value) !== null && _a !== void 0 ? _a : 'Invalid';
1608
+ value = (_c = result.value) !== null && _c !== void 0 ? _c : 'Invalid';
1329
1609
  }
1330
1610
  else if (result.type === VariablesResponse_1.VariableType.Uninitialized) {
1331
1611
  value = 'Uninitialized';
@@ -1333,7 +1613,9 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
1333
1613
  else {
1334
1614
  value = `${result.value}`;
1335
1615
  }
1336
- v = new debugadapter_1.Variable(result.name, value);
1616
+ // If the variable is lazy we must assign a refId to inform the system
1617
+ // to request this variable again in the future for value resolution
1618
+ v = new debugadapter_1.Variable(result.name, value, ((_d = result === null || result === void 0 ? void 0 : result.presentationHint) === null || _d === void 0 ? void 0 : _d.lazy) ? refId : 0);
1337
1619
  }
1338
1620
  this.variables[refId] = v;
1339
1621
  }
@@ -1343,45 +1625,101 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
1343
1625
  }
1344
1626
  else if (result.highLevelType === 'array') {
1345
1627
  let refId = this.getEvaluateRefId(result.evaluateName, frameId);
1346
- v = new debugadapter_1.Variable(result.name, result.type, refId, (_c = (_b = result.children) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0, 0);
1628
+ v = new debugadapter_1.Variable(result.name, result.type, refId, (_f = (_e = result.children) === null || _e === void 0 ? void 0 : _e.length) !== null && _f !== void 0 ? _f : 0, 0);
1347
1629
  this.variables[refId] = v;
1348
1630
  }
1349
1631
  else if (result.highLevelType === 'object') {
1350
- let refId = this.getEvaluateRefId(result.evaluateName, frameId);
1351
- v = new debugadapter_1.Variable(result.name, result.type, refId, 0, (_e = (_d = result.children) === null || _d === void 0 ? void 0 : _d.length) !== null && _e !== void 0 ? _e : 0);
1632
+ let refId;
1633
+ //handle collections
1634
+ if (this.rokuAdapter.isScrapableContainObject(result.type)) {
1635
+ refId = this.getEvaluateRefId(result.evaluateName, frameId);
1636
+ }
1637
+ v = new debugadapter_1.Variable(result.name, result.type, refId, 0, (_h = (_g = result.children) === null || _g === void 0 ? void 0 : _g.length) !== null && _h !== void 0 ? _h : 0);
1352
1638
  this.variables[refId] = v;
1353
1639
  }
1354
1640
  else if (result.highLevelType === 'function') {
1355
- v = new debugadapter_1.Variable(result.name, result.value);
1641
+ v = new debugadapter_1.Variable(result.name, `${result.value}`);
1356
1642
  }
1357
1643
  else {
1358
1644
  //all other cases, but mostly for HighLevelType.unknown
1359
- v = new debugadapter_1.Variable(result.name, result.value);
1645
+ v = new debugadapter_1.Variable(result.name, `${result.value}`);
1360
1646
  }
1361
1647
  }
1362
1648
  v.type = result.type;
1363
1649
  v.evaluateName = result.evaluateName;
1364
1650
  v.frameId = frameId;
1365
1651
  v.type = result.type;
1366
- v.presentationHint = result.presentationHint ? { kind: result.presentationHint } : undefined;
1652
+ v.presentationHint = result.presentationHint ? { kind: (_j = result.presentationHint) === null || _j === void 0 ? void 0 : _j.kind, lazy: (_k = result.presentationHint) === null || _k === void 0 ? void 0 : _k.lazy } : undefined;
1367
1653
  if (util_1.util.isTransientVariable(v.name)) {
1368
1654
  v.presentationHint = { kind: 'virtual' };
1369
1655
  }
1370
- if (result.children) {
1371
- let childVariables = [];
1372
- for (let childContainer of result.children) {
1373
- let childVar = this.getVariableFromResult(childContainer, frameId);
1374
- childVariables.push(childVar);
1656
+ if (result.children && maxDepth > 0) {
1657
+ if (!v.childVariables) {
1658
+ v.childVariables = [];
1375
1659
  }
1376
- v.childVariables = childVariables;
1660
+ // Create a mapping of the children to their index so we can evaluate them in bulk
1661
+ let indexMappedChildren = result.children.map((child, index) => {
1662
+ var _a;
1663
+ let remapped = { child: child, index: index, evaluate: !!(child.isCustom && !((_a = child.presentationHint) === null || _a === void 0 ? void 0 : _a.lazy) && child.evaluateNow) };
1664
+ return remapped;
1665
+ });
1666
+ if (this.enableDebugProtocol) {
1667
+ let childrenToEvaluate = indexMappedChildren.filter(x => x.evaluate);
1668
+ let evaluateArgsArray = childrenToEvaluate.map(x => {
1669
+ return { expression: x.child.evaluateName, frameId: frameId };
1670
+ });
1671
+ let variablePathArray = childrenToEvaluate.map(x => {
1672
+ return util_1.util.getVariablePath(x.child.evaluateName);
1673
+ });
1674
+ try {
1675
+ let bulkEvaluations = await this.bulkEvaluateExpressionToTempVar(frameId, evaluateArgsArray, variablePathArray);
1676
+ if (bulkEvaluations.bulkVarName) {
1677
+ let newResults = await this.rokuAdapter.getVariable(bulkEvaluations.bulkVarName, frameId);
1678
+ childrenToEvaluate.map((mappedChild, index) => {
1679
+ let newResult = newResults.children[index];
1680
+ this.mergeEvaluateContainers(mappedChild.child, newResult);
1681
+ mappedChild.child.evaluateNow = false;
1682
+ return mappedChild;
1683
+ });
1684
+ }
1685
+ }
1686
+ catch (error) {
1687
+ this.logger.error('Error getting bulk variables, will fall back to var by var lookups', error);
1688
+ }
1689
+ }
1690
+ // If bulk evaluations failed, there is fall back logic in `getVariableFromResult` to do individual evaluations
1691
+ v.childVariables = await Promise.all(indexMappedChildren.map(async (mappedChild) => {
1692
+ return this.getVariableFromResult(mappedChild.child, frameId, maxDepth - 1);
1693
+ }));
1694
+ }
1695
+ else {
1696
+ v.childVariables = [];
1377
1697
  }
1378
1698
  // if the var is an array and debugProtocol is enabled, include the array size
1379
1699
  if (this.enableDebugProtocol && v.type === VariablesResponse_1.VariableType.Array) {
1380
- v.value = `${v.type}(${result.elementCount})`;
1700
+ if (isNaN(result.indexedVariables)) {
1701
+ v.value = v.type;
1702
+ }
1703
+ else {
1704
+ v.value = `${v.type}(${result.indexedVariables})`;
1705
+ }
1381
1706
  }
1382
1707
  }
1383
1708
  return v;
1384
1709
  }
1710
+ /**
1711
+ * Helper function to merge the results of an evaluate call into an existing EvaluateContainer
1712
+ * Used primarily for custom variables
1713
+ */
1714
+ mergeEvaluateContainers(original, updated) {
1715
+ original.children = updated.children;
1716
+ original.value = updated.value;
1717
+ original.type = updated.type;
1718
+ original.highLevelType = updated.highLevelType;
1719
+ original.keyType = updated.keyType;
1720
+ original.indexedVariables = updated.indexedVariables;
1721
+ original.namedVariables = updated.namedVariables;
1722
+ }
1385
1723
  getEvaluateRefId(expression, frameId) {
1386
1724
  let evaluateRefId = `${expression}-${frameId}`;
1387
1725
  if (!this.evaluateRefIdLookup[evaluateRefId]) {
@@ -1430,13 +1768,19 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
1430
1768
  return this.shutdownPromise;
1431
1769
  }
1432
1770
  async _shutdown(errorMessage, modal = false) {
1433
- var _a, _b, _c, _d, _e, _f, _g;
1771
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
1434
1772
  try {
1435
1773
  (_a = this.componentLibraryServer) === null || _a === void 0 ? void 0 : _a.stop();
1436
1774
  void ((_c = (_b = this.rendezvousTracker) === null || _b === void 0 ? void 0 : _b.destroy) === null || _c === void 0 ? void 0 : _c.call(_b));
1775
+ try {
1776
+ (_e = (_d = this.sourceMapManager) === null || _d === void 0 ? void 0 : _d.destroy) === null || _e === void 0 ? void 0 : _e.call(_d);
1777
+ }
1778
+ catch (e) {
1779
+ this.logger.error(e);
1780
+ }
1437
1781
  //if configured, delete the staging directory
1438
1782
  if (!this.launchConfiguration.retainStagingFolder) {
1439
- const stagingDirs = (_e = (_d = this.projectManager) === null || _d === void 0 ? void 0 : _d.getStagingDirs()) !== null && _e !== void 0 ? _e : [];
1783
+ const stagingDirs = (_g = (_f = this.projectManager) === null || _f === void 0 ? void 0 : _f.getStagingDirs()) !== null && _g !== void 0 ? _g : [];
1440
1784
  this.logger.info('deleting staging folders', stagingDirs);
1441
1785
  for (let stagingDir of stagingDirs) {
1442
1786
  try {
@@ -1454,7 +1798,7 @@ class BrightScriptDebugSession extends debugadapter_1.DebugSession {
1454
1798
  this.showPopupMessage(errorMessage, 'error', modal);
1455
1799
  }
1456
1800
  this.logger.log('Destroy rokuAdapter');
1457
- await ((_g = (_f = this.rokuAdapter) === null || _f === void 0 ? void 0 : _f.destroy) === null || _g === void 0 ? void 0 : _g.call(_f));
1801
+ await ((_j = (_h = this.rokuAdapter) === null || _h === void 0 ? void 0 : _h.destroy) === null || _j === void 0 ? void 0 : _j.call(_h));
1458
1802
  //press the home button to return to the home screen
1459
1803
  try {
1460
1804
  this.logger.log('Press home button');