brighterscript 1.0.0-alpha.3 → 1.0.0-alpha.30

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 (605) hide show
  1. package/CHANGELOG.md +1230 -285
  2. package/README.md +61 -131
  3. package/bsconfig.schema.json +68 -2
  4. package/dist/ActionPipeline.d.ts +10 -0
  5. package/dist/ActionPipeline.js +40 -0
  6. package/dist/ActionPipeline.js.map +1 -0
  7. package/dist/AstValidationSegmenter.d.ts +35 -0
  8. package/dist/AstValidationSegmenter.js +209 -0
  9. package/dist/AstValidationSegmenter.js.map +1 -0
  10. package/dist/BsConfig.d.ts +51 -6
  11. package/dist/BusyStatusTracker.d.ts +31 -0
  12. package/dist/BusyStatusTracker.js +83 -0
  13. package/dist/BusyStatusTracker.js.map +1 -0
  14. package/dist/Cache.d.ts +5 -6
  15. package/dist/Cache.js +12 -11
  16. package/dist/Cache.js.map +1 -1
  17. package/dist/CacheVerifier.d.ts +7 -0
  18. package/dist/CacheVerifier.js +20 -0
  19. package/dist/CacheVerifier.js.map +1 -0
  20. package/dist/CodeActionUtil.d.ts +11 -2
  21. package/dist/CodeActionUtil.js +17 -3
  22. package/dist/CodeActionUtil.js.map +1 -1
  23. package/dist/CommentFlagProcessor.d.ts +7 -6
  24. package/dist/CommentFlagProcessor.js +10 -7
  25. package/dist/CommentFlagProcessor.js.map +1 -1
  26. package/dist/DependencyGraph.d.ts +8 -3
  27. package/dist/DependencyGraph.js +49 -16
  28. package/dist/DependencyGraph.js.map +1 -1
  29. package/dist/DiagnosticCollection.d.ts +5 -3
  30. package/dist/DiagnosticCollection.js +18 -16
  31. package/dist/DiagnosticCollection.js.map +1 -1
  32. package/dist/DiagnosticFilterer.d.ts +8 -4
  33. package/dist/DiagnosticFilterer.js +77 -44
  34. package/dist/DiagnosticFilterer.js.map +1 -1
  35. package/dist/DiagnosticManager.d.ts +55 -0
  36. package/dist/DiagnosticManager.js +214 -0
  37. package/dist/DiagnosticManager.js.map +1 -0
  38. package/dist/DiagnosticMessages.d.ts +184 -17
  39. package/dist/DiagnosticMessages.js +242 -24
  40. package/dist/DiagnosticMessages.js.map +1 -1
  41. package/dist/DiagnosticSeverityAdjuster.d.ts +7 -0
  42. package/dist/DiagnosticSeverityAdjuster.js +41 -0
  43. package/dist/DiagnosticSeverityAdjuster.js.map +1 -0
  44. package/dist/FunctionScope.d.ts +28 -0
  45. package/dist/FunctionScope.js +52 -0
  46. package/dist/FunctionScope.js.map +1 -0
  47. package/dist/KeyedThrottler.d.ts +3 -3
  48. package/dist/KeyedThrottler.js +3 -3
  49. package/dist/KeyedThrottler.js.map +1 -1
  50. package/dist/LanguageServer.d.ts +72 -47
  51. package/dist/LanguageServer.js +544 -312
  52. package/dist/LanguageServer.js.map +1 -1
  53. package/dist/Logger.d.ts +9 -10
  54. package/dist/Logger.js +36 -30
  55. package/dist/Logger.js.map +1 -1
  56. package/dist/PluginInterface.d.ts +29 -7
  57. package/dist/PluginInterface.js +90 -7
  58. package/dist/PluginInterface.js.map +1 -1
  59. package/dist/Program.d.ts +204 -99
  60. package/dist/Program.js +1060 -699
  61. package/dist/Program.js.map +1 -1
  62. package/dist/ProgramBuilder.d.ts +29 -18
  63. package/dist/ProgramBuilder.js +170 -132
  64. package/dist/ProgramBuilder.js.map +1 -1
  65. package/dist/Scope.d.ts +144 -109
  66. package/dist/Scope.js +538 -551
  67. package/dist/Scope.js.map +1 -1
  68. package/dist/SemanticTokenUtils.d.ts +14 -0
  69. package/dist/SemanticTokenUtils.js +81 -0
  70. package/dist/SemanticTokenUtils.js.map +1 -0
  71. package/dist/Stopwatch.d.ts +4 -0
  72. package/dist/Stopwatch.js +8 -1
  73. package/dist/Stopwatch.js.map +1 -1
  74. package/dist/SymbolTable.d.ts +91 -24
  75. package/dist/SymbolTable.js +286 -63
  76. package/dist/SymbolTable.js.map +1 -1
  77. package/dist/SymbolTypeFlag.d.ts +8 -0
  78. package/dist/SymbolTypeFlag.js +13 -0
  79. package/dist/SymbolTypeFlag.js.map +1 -0
  80. package/dist/Throttler.d.ts +12 -0
  81. package/dist/Throttler.js +39 -0
  82. package/dist/Throttler.js.map +1 -1
  83. package/dist/Watcher.d.ts +0 -3
  84. package/dist/Watcher.js +0 -3
  85. package/dist/Watcher.js.map +1 -1
  86. package/dist/XmlScope.d.ts +5 -15
  87. package/dist/XmlScope.js +35 -87
  88. package/dist/XmlScope.js.map +1 -1
  89. package/dist/astUtils/CachedLookups.d.ts +49 -0
  90. package/dist/astUtils/CachedLookups.js +324 -0
  91. package/dist/astUtils/CachedLookups.js.map +1 -0
  92. package/dist/astUtils/Editor.d.ts +69 -0
  93. package/dist/astUtils/Editor.js +245 -0
  94. package/dist/astUtils/Editor.js.map +1 -0
  95. package/dist/astUtils/Editor.spec.js +258 -0
  96. package/dist/astUtils/Editor.spec.js.map +1 -0
  97. package/dist/astUtils/creators.d.ts +33 -10
  98. package/dist/astUtils/creators.js +224 -30
  99. package/dist/astUtils/creators.js.map +1 -1
  100. package/dist/astUtils/creators.spec.js +5 -5
  101. package/dist/astUtils/creators.spec.js.map +1 -1
  102. package/dist/astUtils/reflection.d.ts +145 -82
  103. package/dist/astUtils/reflection.js +304 -132
  104. package/dist/astUtils/reflection.js.map +1 -1
  105. package/dist/astUtils/reflection.spec.js +267 -162
  106. package/dist/astUtils/reflection.spec.js.map +1 -1
  107. package/dist/astUtils/stackedVisitor.js.map +1 -1
  108. package/dist/astUtils/stackedVisitor.spec.js +14 -14
  109. package/dist/astUtils/stackedVisitor.spec.js.map +1 -1
  110. package/dist/astUtils/visitors.d.ts +114 -53
  111. package/dist/astUtils/visitors.js +70 -13
  112. package/dist/astUtils/visitors.js.map +1 -1
  113. package/dist/astUtils/visitors.spec.js +465 -51
  114. package/dist/astUtils/visitors.spec.js.map +1 -1
  115. package/dist/astUtils/xml.d.ts +9 -8
  116. package/dist/astUtils/xml.js +10 -5
  117. package/dist/astUtils/xml.js.map +1 -1
  118. package/dist/bscPlugin/BscPlugin.d.ts +22 -1
  119. package/dist/bscPlugin/BscPlugin.js +88 -0
  120. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  121. package/dist/bscPlugin/CallExpressionInfo.d.ts +36 -0
  122. package/dist/bscPlugin/CallExpressionInfo.js +131 -0
  123. package/dist/bscPlugin/CallExpressionInfo.js.map +1 -0
  124. package/dist/bscPlugin/FileWriter.d.ts +6 -0
  125. package/dist/bscPlugin/FileWriter.js +24 -0
  126. package/dist/bscPlugin/FileWriter.js.map +1 -0
  127. package/dist/bscPlugin/SignatureHelpUtil.d.ts +10 -0
  128. package/dist/bscPlugin/SignatureHelpUtil.js +137 -0
  129. package/dist/bscPlugin/SignatureHelpUtil.js.map +1 -0
  130. package/dist/bscPlugin/codeActions/CodeActionsProcessor.d.ts +1 -1
  131. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +26 -17
  132. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  133. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +94 -20
  134. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
  135. package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +60 -0
  136. package/dist/bscPlugin/completions/CompletionsProcessor.js +601 -0
  137. package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -0
  138. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +2139 -0
  139. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -0
  140. package/dist/bscPlugin/definition/DefinitionProvider.d.ts +13 -0
  141. package/dist/bscPlugin/definition/DefinitionProvider.js +210 -0
  142. package/dist/bscPlugin/definition/DefinitionProvider.js.map +1 -0
  143. package/dist/bscPlugin/definition/DefinitionProvider.spec.js +88 -0
  144. package/dist/bscPlugin/definition/DefinitionProvider.spec.js.map +1 -0
  145. package/dist/bscPlugin/fileProviders/FileProvider.d.ts +9 -0
  146. package/dist/bscPlugin/fileProviders/FileProvider.js +51 -0
  147. package/dist/bscPlugin/fileProviders/FileProvider.js.map +1 -0
  148. package/dist/bscPlugin/hover/HoverProcessor.d.ts +18 -0
  149. package/dist/bscPlugin/hover/HoverProcessor.js +218 -0
  150. package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -0
  151. package/dist/bscPlugin/hover/HoverProcessor.spec.d.ts +1 -0
  152. package/dist/bscPlugin/hover/HoverProcessor.spec.js +737 -0
  153. package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -0
  154. package/dist/bscPlugin/references/ReferencesProvider.d.ts +12 -0
  155. package/dist/bscPlugin/references/ReferencesProvider.js +56 -0
  156. package/dist/bscPlugin/references/ReferencesProvider.js.map +1 -0
  157. package/dist/bscPlugin/references/ReferencesProvider.spec.d.ts +1 -0
  158. package/dist/bscPlugin/references/ReferencesProvider.spec.js +51 -0
  159. package/dist/bscPlugin/references/ReferencesProvider.spec.js.map +1 -0
  160. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +14 -0
  161. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +138 -0
  162. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -0
  163. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.d.ts +1 -0
  164. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +491 -0
  165. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -0
  166. package/dist/bscPlugin/serialize/BslibInjector.spec.d.ts +1 -0
  167. package/dist/bscPlugin/serialize/BslibInjector.spec.js +19 -0
  168. package/dist/bscPlugin/serialize/BslibInjector.spec.js.map +1 -0
  169. package/dist/bscPlugin/serialize/BslibManager.d.ts +9 -0
  170. package/dist/bscPlugin/serialize/BslibManager.js +40 -0
  171. package/dist/bscPlugin/serialize/BslibManager.js.map +1 -0
  172. package/dist/bscPlugin/serialize/FileSerializer.d.ts +9 -0
  173. package/dist/bscPlugin/serialize/FileSerializer.js +72 -0
  174. package/dist/bscPlugin/serialize/FileSerializer.js.map +1 -0
  175. package/dist/bscPlugin/symbols/DocumentSymbolProcessor.d.ts +7 -0
  176. package/dist/bscPlugin/symbols/DocumentSymbolProcessor.js +22 -0
  177. package/dist/bscPlugin/symbols/DocumentSymbolProcessor.js.map +1 -0
  178. package/dist/bscPlugin/symbols/DocumentSymbolProcessor.spec.d.ts +1 -0
  179. package/dist/bscPlugin/symbols/DocumentSymbolProcessor.spec.js +291 -0
  180. package/dist/bscPlugin/symbols/DocumentSymbolProcessor.spec.js.map +1 -0
  181. package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.d.ts +7 -0
  182. package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.js +26 -0
  183. package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.js.map +1 -0
  184. package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.spec.d.ts +1 -0
  185. package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.spec.js +245 -0
  186. package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.spec.js.map +1 -0
  187. package/dist/bscPlugin/symbols/symbolUtils.d.ts +5 -0
  188. package/dist/bscPlugin/symbols/symbolUtils.js +140 -0
  189. package/dist/bscPlugin/symbols/symbolUtils.js.map +1 -0
  190. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.d.ts +21 -0
  191. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js +202 -0
  192. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js.map +1 -0
  193. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.d.ts +1 -0
  194. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js +41 -0
  195. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js.map +1 -0
  196. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.d.ts +12 -0
  197. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js +99 -0
  198. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js.map +1 -0
  199. package/dist/bscPlugin/validation/BrsFileAfterValidatior.d.ts +7 -0
  200. package/dist/bscPlugin/validation/BrsFileAfterValidatior.js +18 -0
  201. package/dist/bscPlugin/validation/BrsFileAfterValidatior.js.map +1 -0
  202. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +34 -0
  203. package/dist/bscPlugin/validation/BrsFileValidator.js +462 -0
  204. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -0
  205. package/dist/bscPlugin/validation/BrsFileValidator.spec.d.ts +1 -0
  206. package/dist/bscPlugin/validation/BrsFileValidator.spec.js +758 -0
  207. package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +1 -0
  208. package/dist/bscPlugin/validation/ProgramValidator.d.ts +11 -0
  209. package/dist/bscPlugin/validation/ProgramValidator.js +33 -0
  210. package/dist/bscPlugin/validation/ProgramValidator.js.map +1 -0
  211. package/dist/bscPlugin/validation/ScopeValidator.d.ts +131 -0
  212. package/dist/bscPlugin/validation/ScopeValidator.js +1097 -0
  213. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -0
  214. package/dist/bscPlugin/validation/ScopeValidator.spec.d.ts +1 -0
  215. package/dist/bscPlugin/validation/ScopeValidator.spec.js +2796 -0
  216. package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -0
  217. package/dist/bscPlugin/validation/XmlFileValidator.d.ts +8 -0
  218. package/dist/bscPlugin/validation/XmlFileValidator.js +44 -0
  219. package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -0
  220. package/dist/cli.js +117 -11
  221. package/dist/cli.js.map +1 -1
  222. package/dist/deferred.d.ts +3 -3
  223. package/dist/deferred.js.map +1 -1
  224. package/dist/diagnosticUtils.d.ts +10 -3
  225. package/dist/diagnosticUtils.js +58 -21
  226. package/dist/diagnosticUtils.js.map +1 -1
  227. package/dist/examples/plugins/removePrint.js +8 -12
  228. package/dist/examples/plugins/removePrint.js.map +1 -1
  229. package/dist/files/AssetFile.d.ts +24 -0
  230. package/dist/files/AssetFile.js +25 -0
  231. package/dist/files/AssetFile.js.map +1 -0
  232. package/dist/files/BrsFile.Class.spec.js +858 -153
  233. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  234. package/dist/files/BrsFile.d.ts +144 -82
  235. package/dist/files/BrsFile.js +847 -911
  236. package/dist/files/BrsFile.js.map +1 -1
  237. package/dist/files/BrsFile.spec.js +2928 -834
  238. package/dist/files/BrsFile.spec.js.map +1 -1
  239. package/dist/files/BscFile.d.ts +101 -0
  240. package/dist/files/BscFile.js +15 -0
  241. package/dist/files/BscFile.js.map +1 -0
  242. package/dist/files/Factory.d.ts +25 -0
  243. package/dist/files/Factory.js +22 -0
  244. package/dist/files/Factory.js.map +1 -0
  245. package/dist/files/LazyFileData.d.ts +20 -0
  246. package/dist/files/LazyFileData.js +54 -0
  247. package/dist/files/LazyFileData.js.map +1 -0
  248. package/dist/files/LazyFileData.spec.d.ts +1 -0
  249. package/dist/files/LazyFileData.spec.js +27 -0
  250. package/dist/files/LazyFileData.spec.js.map +1 -0
  251. package/dist/files/XmlFile.d.ts +73 -41
  252. package/dist/files/XmlFile.js +126 -138
  253. package/dist/files/XmlFile.js.map +1 -1
  254. package/dist/files/XmlFile.spec.js +450 -318
  255. package/dist/files/XmlFile.spec.js.map +1 -1
  256. package/dist/files/tests/imports.spec.js +62 -52
  257. package/dist/files/tests/imports.spec.js.map +1 -1
  258. package/dist/files/tests/optionalChaning.spec.d.ts +1 -0
  259. package/dist/files/tests/optionalChaning.spec.js +152 -0
  260. package/dist/files/tests/optionalChaning.spec.js.map +1 -0
  261. package/dist/globalCallables.d.ts +3 -1
  262. package/dist/globalCallables.js +416 -162
  263. package/dist/globalCallables.js.map +1 -1
  264. package/dist/index.d.ts +25 -3
  265. package/dist/index.js +42 -5
  266. package/dist/index.js.map +1 -1
  267. package/dist/interfaces.d.ts +722 -119
  268. package/dist/interfaces.js +31 -0
  269. package/dist/interfaces.js.map +1 -1
  270. package/dist/lexer/Character.spec.js +5 -5
  271. package/dist/lexer/Character.spec.js.map +1 -1
  272. package/dist/lexer/Lexer.d.ts +40 -9
  273. package/dist/lexer/Lexer.js +191 -49
  274. package/dist/lexer/Lexer.js.map +1 -1
  275. package/dist/lexer/Lexer.spec.js +775 -563
  276. package/dist/lexer/Lexer.spec.js.map +1 -1
  277. package/dist/lexer/Token.d.ts +11 -3
  278. package/dist/lexer/Token.js +10 -2
  279. package/dist/lexer/Token.js.map +1 -1
  280. package/dist/lexer/TokenKind.d.ts +27 -1
  281. package/dist/lexer/TokenKind.js +112 -5
  282. package/dist/lexer/TokenKind.js.map +1 -1
  283. package/dist/logging.d.ts +9 -0
  284. package/dist/logging.js +16 -0
  285. package/dist/logging.js.map +1 -0
  286. package/dist/parser/AstNode.d.ts +180 -0
  287. package/dist/parser/AstNode.js +245 -0
  288. package/dist/parser/AstNode.js.map +1 -0
  289. package/dist/parser/AstNode.spec.d.ts +1 -0
  290. package/dist/parser/AstNode.spec.js +165 -0
  291. package/dist/parser/AstNode.spec.js.map +1 -0
  292. package/dist/parser/BrsTranspileState.d.ts +12 -2
  293. package/dist/parser/BrsTranspileState.js +6 -0
  294. package/dist/parser/BrsTranspileState.js.map +1 -1
  295. package/dist/parser/Expression.d.ts +454 -210
  296. package/dist/parser/Expression.js +953 -498
  297. package/dist/parser/Expression.js.map +1 -1
  298. package/dist/parser/Parser.Class.spec.js +200 -95
  299. package/dist/parser/Parser.Class.spec.js.map +1 -1
  300. package/dist/parser/Parser.d.ts +105 -120
  301. package/dist/parser/Parser.js +1406 -912
  302. package/dist/parser/Parser.js.map +1 -1
  303. package/dist/parser/Parser.spec.d.ts +3 -1
  304. package/dist/parser/Parser.spec.js +1383 -456
  305. package/dist/parser/Parser.spec.js.map +1 -1
  306. package/dist/parser/SGParser.d.ts +44 -6
  307. package/dist/parser/SGParser.js +212 -185
  308. package/dist/parser/SGParser.js.map +1 -1
  309. package/dist/parser/SGParser.spec.js +30 -28
  310. package/dist/parser/SGParser.spec.js.map +1 -1
  311. package/dist/parser/SGTypes.d.ts +293 -50
  312. package/dist/parser/SGTypes.js +540 -187
  313. package/dist/parser/SGTypes.js.map +1 -1
  314. package/dist/parser/Statement.d.ts +734 -244
  315. package/dist/parser/Statement.js +1758 -611
  316. package/dist/parser/Statement.js.map +1 -1
  317. package/dist/parser/Statement.spec.js +45 -34
  318. package/dist/parser/Statement.spec.js.map +1 -1
  319. package/dist/parser/TranspileState.d.ts +17 -8
  320. package/dist/parser/TranspileState.js +73 -11
  321. package/dist/parser/TranspileState.js.map +1 -1
  322. package/dist/parser/tests/Parser.spec.d.ts +10 -9
  323. package/dist/parser/tests/Parser.spec.js +18 -14
  324. package/dist/parser/tests/Parser.spec.js.map +1 -1
  325. package/dist/parser/tests/controlFlow/For.spec.js +79 -69
  326. package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
  327. package/dist/parser/tests/controlFlow/ForEach.spec.js +53 -47
  328. package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
  329. package/dist/parser/tests/controlFlow/If.spec.js +217 -196
  330. package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
  331. package/dist/parser/tests/controlFlow/While.spec.js +48 -42
  332. package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
  333. package/dist/parser/tests/expression/Additive.spec.js +31 -31
  334. package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
  335. package/dist/parser/tests/expression/ArrayLiterals.spec.js +157 -120
  336. package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
  337. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +202 -139
  338. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
  339. package/dist/parser/tests/expression/Boolean.spec.js +25 -25
  340. package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
  341. package/dist/parser/tests/expression/Call.spec.js +150 -41
  342. package/dist/parser/tests/expression/Call.spec.js.map +1 -1
  343. package/dist/parser/tests/expression/Exponential.spec.js +18 -18
  344. package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
  345. package/dist/parser/tests/expression/Function.spec.js +257 -257
  346. package/dist/parser/tests/expression/Function.spec.js.map +1 -1
  347. package/dist/parser/tests/expression/Indexing.spec.js +160 -90
  348. package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
  349. package/dist/parser/tests/expression/Multiplicative.spec.js +38 -38
  350. package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
  351. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +196 -98
  352. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  353. package/dist/parser/tests/expression/PrefixUnary.spec.js +42 -42
  354. package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
  355. package/dist/parser/tests/expression/Primary.spec.js +42 -42
  356. package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
  357. package/dist/parser/tests/expression/RegexLiteralExpression.spec.d.ts +1 -0
  358. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +171 -0
  359. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -0
  360. package/dist/parser/tests/expression/Relational.spec.js +44 -44
  361. package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
  362. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +31 -31
  363. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
  364. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +230 -90
  365. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  366. package/dist/parser/tests/expression/TernaryExpression.spec.js +377 -148
  367. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  368. package/dist/parser/tests/expression/TypeExpression.spec.d.ts +1 -0
  369. package/dist/parser/tests/expression/TypeExpression.spec.js +126 -0
  370. package/dist/parser/tests/expression/TypeExpression.spec.js.map +1 -0
  371. package/dist/parser/tests/expression/UnaryExpression.spec.d.ts +1 -0
  372. package/dist/parser/tests/expression/UnaryExpression.spec.js +52 -0
  373. package/dist/parser/tests/expression/UnaryExpression.spec.js.map +1 -0
  374. package/dist/parser/tests/statement/AssignmentOperators.spec.js +37 -37
  375. package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
  376. package/dist/parser/tests/statement/ConstStatement.spec.d.ts +1 -0
  377. package/dist/parser/tests/statement/ConstStatement.spec.js +262 -0
  378. package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -0
  379. package/dist/parser/tests/statement/Continue.spec.d.ts +1 -0
  380. package/dist/parser/tests/statement/Continue.spec.js +119 -0
  381. package/dist/parser/tests/statement/Continue.spec.js.map +1 -0
  382. package/dist/parser/tests/statement/Declaration.spec.js +45 -45
  383. package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
  384. package/dist/parser/tests/statement/Dim.spec.js +22 -22
  385. package/dist/parser/tests/statement/Dim.spec.js.map +1 -1
  386. package/dist/parser/tests/statement/Enum.spec.d.ts +1 -0
  387. package/dist/parser/tests/statement/Enum.spec.js +684 -0
  388. package/dist/parser/tests/statement/Enum.spec.js.map +1 -0
  389. package/dist/parser/tests/statement/For.spec.d.ts +1 -0
  390. package/dist/parser/tests/statement/For.spec.js +45 -0
  391. package/dist/parser/tests/statement/For.spec.js.map +1 -0
  392. package/dist/parser/tests/statement/ForEach.spec.d.ts +1 -0
  393. package/dist/parser/tests/statement/ForEach.spec.js +36 -0
  394. package/dist/parser/tests/statement/ForEach.spec.js.map +1 -0
  395. package/dist/parser/tests/statement/Function.spec.js +208 -198
  396. package/dist/parser/tests/statement/Function.spec.js.map +1 -1
  397. package/dist/parser/tests/statement/Goto.spec.js +16 -15
  398. package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
  399. package/dist/parser/tests/statement/Increment.spec.js +51 -51
  400. package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
  401. package/dist/parser/tests/statement/InterfaceStatement.spec.d.ts +1 -0
  402. package/dist/parser/tests/statement/InterfaceStatement.spec.js +109 -0
  403. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -0
  404. package/dist/parser/tests/statement/LibraryStatement.spec.js +18 -18
  405. package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
  406. package/dist/parser/tests/statement/Misc.spec.js +123 -163
  407. package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
  408. package/dist/parser/tests/statement/PrintStatement.spec.js +125 -108
  409. package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
  410. package/dist/parser/tests/statement/ReturnStatement.spec.js +51 -49
  411. package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
  412. package/dist/parser/tests/statement/Set.spec.js +110 -97
  413. package/dist/parser/tests/statement/Set.spec.js.map +1 -1
  414. package/dist/parser/tests/statement/Stop.spec.js +13 -12
  415. package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
  416. package/dist/parser/tests/statement/Throw.spec.js +6 -6
  417. package/dist/parser/tests/statement/Throw.spec.js.map +1 -1
  418. package/dist/parser/tests/statement/TryCatch.spec.js +26 -15
  419. package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
  420. package/dist/preprocessor/Manifest.d.ts +6 -6
  421. package/dist/preprocessor/Manifest.js +17 -38
  422. package/dist/preprocessor/Manifest.js.map +1 -1
  423. package/dist/preprocessor/Manifest.spec.d.ts +1 -0
  424. package/dist/preprocessor/Manifest.spec.js +78 -103
  425. package/dist/preprocessor/Manifest.spec.js.map +1 -1
  426. package/dist/roku-types/data.json +19351 -0
  427. package/dist/roku-types/index.d.ts +5483 -0
  428. package/dist/roku-types/index.js +11 -0
  429. package/dist/roku-types/index.js.map +1 -0
  430. package/dist/types/ArrayType.d.ts +9 -5
  431. package/dist/types/ArrayType.js +68 -24
  432. package/dist/types/ArrayType.js.map +1 -1
  433. package/dist/types/ArrayType.spec.js +39 -11
  434. package/dist/types/ArrayType.spec.js.map +1 -1
  435. package/dist/types/AssociativeArrayType.d.ts +14 -0
  436. package/dist/types/AssociativeArrayType.js +60 -0
  437. package/dist/types/AssociativeArrayType.js.map +1 -0
  438. package/dist/types/BaseFunctionType.d.ts +9 -0
  439. package/dist/types/BaseFunctionType.js +25 -0
  440. package/dist/types/BaseFunctionType.js.map +1 -0
  441. package/dist/types/BooleanType.d.ts +10 -5
  442. package/dist/types/BooleanType.js +21 -9
  443. package/dist/types/BooleanType.js.map +1 -1
  444. package/dist/types/BooleanType.spec.js +10 -4
  445. package/dist/types/BooleanType.spec.js.map +1 -1
  446. package/dist/types/BscType.d.ts +29 -3
  447. package/dist/types/BscType.js +121 -0
  448. package/dist/types/BscType.js.map +1 -1
  449. package/dist/types/BscTypeKind.d.ts +25 -0
  450. package/dist/types/BscTypeKind.js +30 -0
  451. package/dist/types/BscTypeKind.js.map +1 -0
  452. package/dist/types/BuiltInInterfaceAdder.d.ts +23 -0
  453. package/dist/types/BuiltInInterfaceAdder.js +174 -0
  454. package/dist/types/BuiltInInterfaceAdder.js.map +1 -0
  455. package/dist/types/BuiltInInterfaceAdder.spec.d.ts +1 -0
  456. package/dist/types/BuiltInInterfaceAdder.spec.js +115 -0
  457. package/dist/types/BuiltInInterfaceAdder.spec.js.map +1 -0
  458. package/dist/types/ClassType.d.ts +17 -0
  459. package/dist/types/ClassType.js +58 -0
  460. package/dist/types/ClassType.js.map +1 -0
  461. package/dist/types/ClassType.spec.d.ts +1 -0
  462. package/dist/types/ClassType.spec.js +76 -0
  463. package/dist/types/ClassType.spec.js.map +1 -0
  464. package/dist/types/ComponentType.d.ts +27 -0
  465. package/dist/types/ComponentType.js +83 -0
  466. package/dist/types/ComponentType.js.map +1 -0
  467. package/dist/types/DoubleType.d.ts +10 -5
  468. package/dist/types/DoubleType.js +25 -18
  469. package/dist/types/DoubleType.js.map +1 -1
  470. package/dist/types/DoubleType.spec.js +12 -4
  471. package/dist/types/DoubleType.spec.js.map +1 -1
  472. package/dist/types/DynamicType.d.ts +12 -5
  473. package/dist/types/DynamicType.js +22 -6
  474. package/dist/types/DynamicType.js.map +1 -1
  475. package/dist/types/DynamicType.spec.js +16 -5
  476. package/dist/types/DynamicType.spec.js.map +1 -1
  477. package/dist/types/EnumType.d.ts +40 -0
  478. package/dist/types/EnumType.js +80 -0
  479. package/dist/types/EnumType.js.map +1 -0
  480. package/dist/types/EnumType.spec.d.ts +1 -0
  481. package/dist/types/EnumType.spec.js +33 -0
  482. package/dist/types/EnumType.spec.js.map +1 -0
  483. package/dist/types/FloatType.d.ts +10 -5
  484. package/dist/types/FloatType.js +25 -18
  485. package/dist/types/FloatType.js.map +1 -1
  486. package/dist/types/FloatType.spec.js +4 -4
  487. package/dist/types/FloatType.spec.js.map +1 -1
  488. package/dist/types/FunctionType.d.ts +10 -22
  489. package/dist/types/FunctionType.js +26 -63
  490. package/dist/types/FunctionType.js.map +1 -1
  491. package/dist/types/InheritableType.d.ts +28 -0
  492. package/dist/types/InheritableType.js +157 -0
  493. package/dist/types/InheritableType.js.map +1 -0
  494. package/dist/types/IntegerType.d.ts +10 -5
  495. package/dist/types/IntegerType.js +25 -18
  496. package/dist/types/IntegerType.js.map +1 -1
  497. package/dist/types/IntegerType.spec.js +8 -4
  498. package/dist/types/IntegerType.spec.js.map +1 -1
  499. package/dist/types/InterfaceType.d.ts +14 -6
  500. package/dist/types/InterfaceType.js +26 -15
  501. package/dist/types/InterfaceType.js.map +1 -1
  502. package/dist/types/InterfaceType.spec.d.ts +1 -0
  503. package/dist/types/InterfaceType.spec.js +227 -0
  504. package/dist/types/InterfaceType.spec.js.map +1 -0
  505. package/dist/types/InvalidType.d.ts +9 -5
  506. package/dist/types/InvalidType.js +20 -9
  507. package/dist/types/InvalidType.js.map +1 -1
  508. package/dist/types/InvalidType.spec.js +8 -4
  509. package/dist/types/InvalidType.spec.js.map +1 -1
  510. package/dist/types/LongIntegerType.d.ts +10 -5
  511. package/dist/types/LongIntegerType.js +25 -18
  512. package/dist/types/LongIntegerType.js.map +1 -1
  513. package/dist/types/LongIntegerType.spec.js +10 -4
  514. package/dist/types/LongIntegerType.spec.js.map +1 -1
  515. package/dist/types/NamespaceType.d.ts +12 -0
  516. package/dist/types/NamespaceType.js +28 -0
  517. package/dist/types/NamespaceType.js.map +1 -0
  518. package/dist/types/ObjectType.d.ts +10 -5
  519. package/dist/types/ObjectType.js +23 -9
  520. package/dist/types/ObjectType.js.map +1 -1
  521. package/dist/types/ObjectType.spec.js +3 -3
  522. package/dist/types/ObjectType.spec.js.map +1 -1
  523. package/dist/types/ReferenceType.d.ts +71 -0
  524. package/dist/types/ReferenceType.js +467 -0
  525. package/dist/types/ReferenceType.js.map +1 -0
  526. package/dist/types/ReferenceType.spec.d.ts +1 -0
  527. package/dist/types/ReferenceType.spec.js +151 -0
  528. package/dist/types/ReferenceType.spec.js.map +1 -0
  529. package/dist/types/StringType.d.ts +13 -5
  530. package/dist/types/StringType.js +25 -9
  531. package/dist/types/StringType.js.map +1 -1
  532. package/dist/types/StringType.spec.js +3 -3
  533. package/dist/types/StringType.spec.js.map +1 -1
  534. package/dist/types/TypedFunctionType.d.ts +33 -0
  535. package/dist/types/TypedFunctionType.js +106 -0
  536. package/dist/types/TypedFunctionType.js.map +1 -0
  537. package/dist/types/TypedFunctionType.spec.d.ts +1 -0
  538. package/dist/types/TypedFunctionType.spec.js +122 -0
  539. package/dist/types/TypedFunctionType.spec.js.map +1 -0
  540. package/dist/types/UninitializedType.d.ts +8 -6
  541. package/dist/types/UninitializedType.js +15 -9
  542. package/dist/types/UninitializedType.js.map +1 -1
  543. package/dist/types/UnionType.d.ts +20 -0
  544. package/dist/types/UnionType.js +127 -0
  545. package/dist/types/UnionType.js.map +1 -0
  546. package/dist/types/UnionType.spec.d.ts +1 -0
  547. package/dist/types/UnionType.spec.js +129 -0
  548. package/dist/types/UnionType.spec.js.map +1 -0
  549. package/dist/types/VoidType.d.ts +10 -5
  550. package/dist/types/VoidType.js +20 -9
  551. package/dist/types/VoidType.js.map +1 -1
  552. package/dist/types/VoidType.spec.js +3 -3
  553. package/dist/types/VoidType.spec.js.map +1 -1
  554. package/dist/types/helper.spec.d.ts +1 -0
  555. package/dist/types/helper.spec.js +144 -0
  556. package/dist/types/helper.spec.js.map +1 -0
  557. package/dist/types/helpers.d.ts +24 -0
  558. package/dist/types/helpers.js +178 -0
  559. package/dist/types/helpers.js.map +1 -0
  560. package/dist/types/index.d.ts +22 -0
  561. package/dist/types/index.js +39 -0
  562. package/dist/types/index.js.map +1 -0
  563. package/dist/util.d.ts +216 -106
  564. package/dist/util.js +1289 -319
  565. package/dist/util.js.map +1 -1
  566. package/dist/validators/ClassValidator.d.ts +9 -15
  567. package/dist/validators/ClassValidator.js +81 -134
  568. package/dist/validators/ClassValidator.js.map +1 -1
  569. package/package.json +169 -138
  570. package/dist/astUtils/index.d.ts +0 -7
  571. package/dist/astUtils/index.js +0 -26
  572. package/dist/astUtils/index.js.map +0 -1
  573. package/dist/lexer/index.d.ts +0 -3
  574. package/dist/lexer/index.js +0 -17
  575. package/dist/lexer/index.js.map +0 -1
  576. package/dist/parser/index.d.ts +0 -3
  577. package/dist/parser/index.js +0 -16
  578. package/dist/parser/index.js.map +0 -1
  579. package/dist/preprocessor/Chunk.d.ts +0 -82
  580. package/dist/preprocessor/Chunk.js +0 -77
  581. package/dist/preprocessor/Chunk.js.map +0 -1
  582. package/dist/preprocessor/Preprocessor.d.ts +0 -60
  583. package/dist/preprocessor/Preprocessor.js +0 -156
  584. package/dist/preprocessor/Preprocessor.js.map +0 -1
  585. package/dist/preprocessor/Preprocessor.spec.js +0 -152
  586. package/dist/preprocessor/Preprocessor.spec.js.map +0 -1
  587. package/dist/preprocessor/PreprocessorParser.d.ts +0 -61
  588. package/dist/preprocessor/PreprocessorParser.js +0 -194
  589. package/dist/preprocessor/PreprocessorParser.js.map +0 -1
  590. package/dist/preprocessor/PreprocessorParser.spec.js +0 -116
  591. package/dist/preprocessor/PreprocessorParser.spec.js.map +0 -1
  592. package/dist/preprocessor/index.d.ts +0 -3
  593. package/dist/preprocessor/index.js +0 -16
  594. package/dist/preprocessor/index.js.map +0 -1
  595. package/dist/types/CustomType.d.ts +0 -10
  596. package/dist/types/CustomType.js +0 -35
  597. package/dist/types/CustomType.js.map +0 -1
  598. package/dist/types/FunctionType.spec.js +0 -29
  599. package/dist/types/FunctionType.spec.js.map +0 -1
  600. package/dist/types/LazyType.d.ts +0 -15
  601. package/dist/types/LazyType.js +0 -32
  602. package/dist/types/LazyType.js.map +0 -1
  603. /package/dist/{preprocessor/Preprocessor.spec.d.ts → astUtils/Editor.spec.d.ts} +0 -0
  604. /package/dist/{preprocessor/PreprocessorParser.spec.d.ts → bscPlugin/completions/CompletionsProcessor.spec.d.ts} +0 -0
  605. /package/dist/{types/FunctionType.spec.d.ts → bscPlugin/definition/DefinitionProvider.spec.d.ts} +0 -0
@@ -6,39 +6,40 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  return c > 3 && r && Object.defineProperty(target, key, r), r;
7
7
  };
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.CustomCommands = exports.LanguageServer = void 0;
9
+ exports.NotificationName = exports.CustomCommands = exports.LanguageServer = void 0;
10
10
  require("array-flat-polyfill");
11
- const glob = require("glob");
11
+ const fastGlob = require("fast-glob");
12
12
  const path = require("path");
13
- const rokuDeploy = require("roku-deploy");
14
- const vscode_languageserver_1 = require("vscode-languageserver");
13
+ const roku_deploy_1 = require("roku-deploy");
14
+ const node_1 = require("vscode-languageserver/node");
15
15
  const vscode_uri_1 = require("vscode-uri");
16
16
  const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument");
17
17
  const deferred_1 = require("./deferred");
18
18
  const DiagnosticMessages_1 = require("./DiagnosticMessages");
19
19
  const ProgramBuilder_1 = require("./ProgramBuilder");
20
20
  const util_1 = require("./util");
21
- const Logger_1 = require("./Logger");
22
21
  const Throttler_1 = require("./Throttler");
23
22
  const KeyedThrottler_1 = require("./KeyedThrottler");
24
23
  const DiagnosticCollection_1 = require("./DiagnosticCollection");
25
24
  const reflection_1 = require("./astUtils/reflection");
25
+ const SemanticTokenUtils_1 = require("./SemanticTokenUtils");
26
+ const BusyStatusTracker_1 = require("./BusyStatusTracker");
27
+ const logging_1 = require("./logging");
26
28
  class LanguageServer {
27
29
  constructor() {
28
- //cast undefined as any to get around strictNullChecks...it's ok in this case
29
30
  this.connection = undefined;
30
- this.workspaces = [];
31
+ this.projects = [];
31
32
  /**
32
33
  * The number of milliseconds that should be used for language server typing debouncing
33
34
  */
34
35
  this.debounceTimeout = 150;
35
36
  /**
36
- * These workspaces are created on the fly whenever a file is opened that is not included
37
- * in any of the workspace projects.
38
- * Basically these are single-file workspaces to at least get parsing for standalone files.
37
+ * These projects are created on the fly whenever a file is opened that is not included
38
+ * in any of the workspace-based projects.
39
+ * Basically these are single-file projects to at least get parsing for standalone files.
39
40
  * Also, they should only be created when the file is opened, and destroyed when the file is closed.
40
41
  */
41
- this.standaloneFileWorkspaces = {};
42
+ this.standaloneFileProjects = {};
42
43
  this.hasConfigurationCapability = false;
43
44
  /**
44
45
  * Indicates whether the client supports workspace folders
@@ -48,14 +49,21 @@ class LanguageServer {
48
49
  * Create a simple text document manager.
49
50
  * The text document manager supports full document sync only
50
51
  */
51
- this.documents = new vscode_languageserver_1.TextDocuments(vscode_languageserver_textdocument_1.TextDocument);
52
+ this.documents = new node_1.TextDocuments(vscode_languageserver_textdocument_1.TextDocument);
52
53
  this.keyedThrottler = new KeyedThrottler_1.KeyedThrottler(this.debounceTimeout);
53
54
  this.validateThrottler = new Throttler_1.Throttler(0);
55
+ this.sendDiagnosticsThrottler = new Throttler_1.Throttler(0);
54
56
  this.boundValidateAll = this.validateAll.bind(this);
57
+ this.busyStatusTracker = new BusyStatusTracker_1.BusyStatusTracker();
58
+ this.busyStatusIndex = -1;
59
+ /**
60
+ * A unique project counter to help distinguish log entries in lsp mode
61
+ */
62
+ this.projectCounter = 0;
55
63
  this.diagnosticCollection = new DiagnosticCollection_1.DiagnosticCollection();
56
64
  }
57
65
  createConnection() {
58
- return vscode_languageserver_1.createConnection(vscode_languageserver_1.ProposedFeatures.all);
66
+ return (0, node_1.createConnection)(node_1.ProposedFeatures.all);
59
67
  }
60
68
  validateAllThrottled() {
61
69
  return this.validateThrottler.run(this.boundValidateAll);
@@ -65,9 +73,15 @@ class LanguageServer {
65
73
  // Create a connection for the server. The connection uses Node's IPC as a transport.
66
74
  // Also include all preview / proposed LSP features.
67
75
  this.connection = this.createConnection();
76
+ // Send the current status of the busyStatusTracker anytime it changes
77
+ this.busyStatusTracker.on('change', (status) => {
78
+ void this.sendBusyStatus(status);
79
+ });
80
+ //disable logger colors when running in LSP mode
81
+ logging_1.logger.enableColor = false;
68
82
  //listen to all of the output log events and pipe them into the debug channel in the extension
69
- this.loggerSubscription = Logger_1.Logger.subscribe((text) => {
70
- this.connection.tracer.log(text);
83
+ this.loggerSubscription = logging_1.logger.subscribe((message) => {
84
+ this.connection.tracer.log(message.argsText);
71
85
  });
72
86
  this.connection.onInitialize(this.onInitialize.bind(this));
73
87
  this.connection.onInitialized(this.onInitialized.bind(this)); //eslint-disable-line
@@ -77,17 +91,11 @@ class LanguageServer {
77
91
  // when the text document is first opened, when its content has changed,
78
92
  // or when document is closed without saving (original contents are sent as a change)
79
93
  //
80
- this.documents.onDidChangeContent(async (change) => {
81
- await this.validateTextDocument(change.document);
82
- });
94
+ this.documents.onDidChangeContent(this.validateTextDocument.bind(this));
83
95
  //whenever a document gets closed
84
- this.documents.onDidClose(async (change) => {
85
- await this.onDocumentClose(change.document);
86
- });
96
+ this.documents.onDidClose(this.onDocumentClose.bind(this));
87
97
  // This handler provides the initial list of the completion items.
88
- this.connection.onCompletion(async (params) => {
89
- return this.onCompletion(params.textDocument.uri, params.position);
90
- });
98
+ this.connection.onCompletion(this.onCompletion.bind(this));
91
99
  // This handler resolves additional information for the item selected in
92
100
  // the completion list.
93
101
  this.connection.onCompletionResolve(this.onCompletionResolve.bind(this));
@@ -99,6 +107,8 @@ class LanguageServer {
99
107
  this.connection.onSignatureHelp(this.onSignatureHelp.bind(this));
100
108
  this.connection.onReferences(this.onReferences.bind(this));
101
109
  this.connection.onCodeAction(this.onCodeAction.bind(this));
110
+ //TODO switch to a more specific connection function call once they actually add it
111
+ this.connection.onRequest(node_1.SemanticTokensRequest.method, this.onFullSemanticTokens.bind(this));
102
112
  /*
103
113
  this.connection.onDidOpenTextDocument((params) => {
104
114
  // A text document got opened in VSCode.
@@ -123,9 +133,17 @@ class LanguageServer {
123
133
  // Listen on the connection
124
134
  this.connection.listen();
125
135
  }
136
+ async sendBusyStatus(status) {
137
+ this.busyStatusIndex = ++this.busyStatusIndex <= 0 ? 0 : this.busyStatusIndex;
138
+ await this.connection.sendNotification(NotificationName.busyStatus, {
139
+ status: status,
140
+ timestamp: Date.now(),
141
+ index: this.busyStatusIndex,
142
+ activeRuns: [...this.busyStatusTracker.activeRuns]
143
+ });
144
+ }
126
145
  /**
127
146
  * Called when the client starts initialization
128
- * @param params
129
147
  */
130
148
  onInitialize(params) {
131
149
  let clientCapabilities = params.capabilities;
@@ -136,7 +154,7 @@ class LanguageServer {
136
154
  //return the capabilities of the server
137
155
  return {
138
156
  capabilities: {
139
- textDocumentSync: vscode_languageserver_1.TextDocumentSyncKind.Full,
157
+ textDocumentSync: node_1.TextDocumentSyncKind.Full,
140
158
  // Tell the client that the server supports code completion
141
159
  completionProvider: {
142
160
  resolveProvider: true,
@@ -146,9 +164,13 @@ class LanguageServer {
146
164
  },
147
165
  documentSymbolProvider: true,
148
166
  workspaceSymbolProvider: true,
167
+ semanticTokensProvider: {
168
+ legend: SemanticTokenUtils_1.semanticTokensLegend,
169
+ full: true
170
+ },
149
171
  referencesProvider: true,
150
172
  codeActionProvider: {
151
- codeActionKinds: [vscode_languageserver_1.CodeActionKind.Refactor]
173
+ codeActionKinds: [node_1.CodeActionKind.Refactor]
152
174
  },
153
175
  signatureHelpProvider: {
154
176
  triggerCharacters: ['(', ',']
@@ -163,46 +185,146 @@ class LanguageServer {
163
185
  }
164
186
  };
165
187
  }
188
+ /**
189
+ * Ask the client for the list of `files.exclude` patterns. Useful when determining if we should process a file
190
+ */
191
+ async getWorkspaceExcludeGlobs(workspaceFolder) {
192
+ var _a;
193
+ let config = {
194
+ exclude: {}
195
+ };
196
+ //if supported, ask vscode for the `files.exclude` configuration
197
+ if (this.hasConfigurationCapability) {
198
+ //get any `files.exclude` globs to use to filter
199
+ config = await this.connection.workspace.getConfiguration({
200
+ scopeUri: workspaceFolder,
201
+ section: 'files'
202
+ });
203
+ }
204
+ return Object
205
+ .keys((_a = config === null || config === void 0 ? void 0 : config.exclude) !== null && _a !== void 0 ? _a : {})
206
+ .filter(x => { var _a; return (_a = config === null || config === void 0 ? void 0 : config.exclude) === null || _a === void 0 ? void 0 : _a[x]; })
207
+ //vscode files.exclude patterns support ignoring folders without needing to add `**/*`. So for our purposes, we need to
208
+ //append **/* to everything without a file extension or magic at the end
209
+ .map(pattern => [
210
+ //send the pattern as-is (this handles weird cases and exact file matches)
211
+ pattern,
212
+ //treat the pattern as a directory (no harm in doing this because if it's a file, the pattern will just never match anything)
213
+ `${pattern}/**/*`
214
+ ])
215
+ .flat(1)
216
+ .concat([
217
+ //always ignore projects from node_modules
218
+ '**/node_modules/**/*'
219
+ ]);
220
+ }
221
+ /**
222
+ * Scan the workspace for all `bsconfig.json` files. If at least one is found, then only folders who have bsconfig.json are returned.
223
+ * If none are found, then the workspaceFolder itself is treated as a project
224
+ */
225
+ async getProjectPaths(workspaceFolder) {
226
+ const excludes = (await this.getWorkspaceExcludeGlobs(workspaceFolder)).map(x => (0, util_1.standardizePath) `!${x}`);
227
+ const files = await roku_deploy_1.rokuDeploy.getFilePaths([
228
+ '**/bsconfig.json',
229
+ //exclude all files found in `files.exclude`
230
+ ...excludes
231
+ ], workspaceFolder);
232
+ //if we found at least one bsconfig.json, then ALL projects must have a bsconfig.json.
233
+ if (files.length > 0) {
234
+ return files.map(file => (0, util_1.standardizePath) `${path.dirname(file.src)}`);
235
+ }
236
+ //look for roku project folders
237
+ const rokuLikeDirs = (await Promise.all(
238
+ //find all folders containing a `manifest` file
239
+ (await roku_deploy_1.rokuDeploy.getFilePaths([
240
+ '**/manifest',
241
+ ...excludes
242
+ //is there at least one .bs|.brs file under the `/source` folder?
243
+ ], workspaceFolder)).map(async (manifestEntry) => {
244
+ const manifestDir = path.dirname(manifestEntry.src);
245
+ const files = await roku_deploy_1.rokuDeploy.getFilePaths([
246
+ 'source/**/*.{brs,bs}',
247
+ ...excludes
248
+ ], manifestDir);
249
+ if (files.length > 0) {
250
+ return manifestDir;
251
+ }
252
+ })
253
+ //throw out nulls
254
+ )).filter(x => !!x);
255
+ if (rokuLikeDirs.length > 0) {
256
+ return rokuLikeDirs;
257
+ }
258
+ //treat the workspace folder as a brightscript project itself
259
+ return [workspaceFolder];
260
+ }
261
+ /**
262
+ * Find all folders with bsconfig.json files in them, and treat each as a project.
263
+ * Treat workspaces that don't have a bsconfig.json as a project.
264
+ * Handle situations where bsconfig.json files were added or removed (to elevate/lower workspaceFolder projects accordingly)
265
+ * Leave existing projects alone if they are not affected by these changes
266
+ */
267
+ async syncProjects() {
268
+ const workspacePaths = await this.getWorkspacePaths();
269
+ let projectPaths = (await Promise.all(workspacePaths.map(async (workspacePath) => {
270
+ const projectPaths = await this.getProjectPaths(workspacePath);
271
+ return projectPaths.map(projectPath => ({
272
+ projectPath: projectPath,
273
+ workspacePath: workspacePath
274
+ }));
275
+ }))).flat(1);
276
+ //delete projects not represented in the list
277
+ for (const project of this.getProjects()) {
278
+ if (!projectPaths.find(x => x.projectPath === project.projectPath)) {
279
+ this.removeProject(project);
280
+ }
281
+ }
282
+ //exclude paths to projects we already have
283
+ projectPaths = projectPaths.filter(x => {
284
+ //only keep this project path if there's not a project with that path
285
+ return !this.projects.find(project => project.projectPath === x.projectPath);
286
+ });
287
+ //dedupe by project path
288
+ projectPaths = [
289
+ ...projectPaths.reduce((acc, x) => acc.set(x.projectPath, x), new Map()).values()
290
+ ];
291
+ //create missing projects
292
+ await Promise.all(projectPaths.map(x => this.createProject(x.projectPath, x.workspacePath)));
293
+ //flush diagnostics
294
+ await this.sendDiagnostics();
295
+ }
296
+ /**
297
+ * Get all workspace paths from the client
298
+ */
299
+ async getWorkspacePaths() {
300
+ var _a;
301
+ let workspaceFolders = (_a = await this.connection.workspace.getWorkspaceFolders()) !== null && _a !== void 0 ? _a : [];
302
+ return workspaceFolders.map((x) => {
303
+ return util_1.util.uriToPath(x.uri);
304
+ });
305
+ }
166
306
  /**
167
307
  * Called when the client has finished initializing
168
- * @param params
169
308
  */
170
309
  async onInitialized() {
171
- var _a;
172
- let workspaceCreatedDeferred = new deferred_1.Deferred();
173
- this.initialWorkspacesCreated = workspaceCreatedDeferred.promise;
310
+ let projectCreatedDeferred = new deferred_1.Deferred();
311
+ this.initialProjectsCreated = projectCreatedDeferred.promise;
174
312
  try {
175
313
  if (this.hasConfigurationCapability) {
176
314
  // Register for all configuration changes.
177
- await this.connection.client.register(vscode_languageserver_1.DidChangeConfigurationNotification.type, undefined);
315
+ await this.connection.client.register(node_1.DidChangeConfigurationNotification.type, undefined);
178
316
  }
179
- //ask the client for all workspace folders
180
- let workspaceFolders = (_a = await this.connection.workspace.getWorkspaceFolders()) !== null && _a !== void 0 ? _a : [];
181
- let workspacePaths = workspaceFolders.map((x) => {
182
- return util_1.util.uriToPath(x.uri);
183
- });
184
- await this.createWorkspaces(workspacePaths);
317
+ await this.syncProjects();
185
318
  if (this.clientHasWorkspaceFolderCapability) {
186
319
  this.connection.workspace.onDidChangeWorkspaceFolders(async (evt) => {
187
- //remove programs for removed workspace folders
188
- for (let removed of evt.removed) {
189
- let workspacePath = util_1.util.uriToPath(removed.uri);
190
- let workspace = this.workspaces.find((x) => x.workspacePath === workspacePath);
191
- if (workspace) {
192
- workspace.builder.dispose();
193
- this.workspaces.splice(this.workspaces.indexOf(workspace), 1);
194
- }
195
- }
196
- //create programs for new workspace folders
197
- await this.createWorkspaces(evt.added.map((x) => util_1.util.uriToPath(x.uri)));
320
+ await this.syncProjects();
198
321
  });
199
322
  }
200
- await this.waitAllProgramFirstRuns(false);
201
- workspaceCreatedDeferred.resolve();
202
- await this.sendDiagnostics();
323
+ await this.waitAllProjectFirstRuns(false);
324
+ projectCreatedDeferred.resolve();
203
325
  }
204
326
  catch (e) {
205
- this.sendCriticalFailure(`Critical failure during BrighterScript language server startup.
327
+ await this.sendCriticalFailure(`Critical failure during BrighterScript language server startup.
206
328
  Please file a github issue and include the contents of the 'BrighterScript Language Server' output channel.
207
329
 
208
330
  Error message: ${e.message}`);
@@ -212,39 +334,28 @@ class LanguageServer {
212
334
  /**
213
335
  * Send a critical failure notification to the client, which should show a notification of some kind
214
336
  */
215
- sendCriticalFailure(message) {
216
- this.connection.sendNotification('critical-failure', message);
337
+ async sendCriticalFailure(message) {
338
+ await this.connection.sendNotification('critical-failure', message);
217
339
  }
218
340
  /**
219
341
  * Wait for all programs' first run to complete
220
342
  */
221
- async waitAllProgramFirstRuns(waitForFirstWorkSpace = true) {
222
- if (waitForFirstWorkSpace) {
223
- await this.initialWorkspacesCreated;
343
+ async waitAllProjectFirstRuns(waitForFirstProject = true) {
344
+ if (waitForFirstProject) {
345
+ await this.initialProjectsCreated;
224
346
  }
225
- let status;
226
- let workspaces = this.getWorkspaces();
227
- for (let workspace of workspaces) {
347
+ for (let project of this.getProjects()) {
228
348
  try {
229
- await workspace.firstRunPromise;
349
+ await project.firstRunPromise;
230
350
  }
231
351
  catch (e) {
232
352
  status = 'critical-error';
233
353
  //the first run failed...that won't change unless we reload the workspace, so replace with resolved promise
234
354
  //so we don't show this error again
235
- workspace.firstRunPromise = Promise.resolve();
236
- this.sendCriticalFailure(`BrighterScript language server failed to start: \n${e.message}`);
355
+ project.firstRunPromise = Promise.resolve();
356
+ await this.sendCriticalFailure(`BrighterScript language server failed to start: \n${e.message}`);
237
357
  }
238
358
  }
239
- this.connection.sendNotification('build-status', status ? status : 'success');
240
- }
241
- /**
242
- * Create project for each new workspace. If the workspace is already known,
243
- * it is skipped.
244
- * @param workspaceFolders
245
- */
246
- async createWorkspaces(workspacePaths) {
247
- return Promise.all(workspacePaths.map(async (workspacePath) => this.createWorkspace(workspacePath)));
248
359
  }
249
360
  /**
250
361
  * Event handler for when the program wants to load file contents.
@@ -265,11 +376,16 @@ class LanguageServer {
265
376
  else {
266
377
  scopeUri = vscode_uri_1.URI.file(workspacePath).toString();
267
378
  }
268
- //look for config group called "brightscript"
269
- let config = await this.connection.workspace.getConfiguration({
270
- scopeUri: scopeUri,
271
- section: 'brightscript'
272
- });
379
+ let config = {
380
+ configFile: undefined
381
+ };
382
+ //if the client supports configuration, look for config group called "brightscript"
383
+ if (this.hasConfigurationCapability) {
384
+ config = await this.connection.workspace.getConfiguration({
385
+ scopeUri: scopeUri,
386
+ section: 'brightscript'
387
+ });
388
+ }
273
389
  let configFilePath;
274
390
  //if there's a setting, we need to find the file or show error if it can't be found
275
391
  if (config === null || config === void 0 ? void 0 : config.configFile) {
@@ -278,7 +394,7 @@ class LanguageServer {
278
394
  return configFilePath;
279
395
  }
280
396
  else {
281
- this.sendCriticalFailure(`Cannot find config file specified in user/workspace settings at '${configFilePath}'`);
397
+ await this.sendCriticalFailure(`Cannot find config file specified in user / workspace settings at '${configFilePath}'`);
282
398
  }
283
399
  }
284
400
  //default to config file path found in the root of the workspace
@@ -294,19 +410,35 @@ class LanguageServer {
294
410
  //no config file could be found
295
411
  return undefined;
296
412
  }
297
- async createWorkspace(workspacePath) {
298
- let workspace = this.workspaces.find((x) => x.workspacePath === workspacePath);
299
- //skip this workspace if we already have it
300
- if (workspace) {
413
+ /**
414
+ * @param projectPath path to the project
415
+ * @param workspacePath path to the workspace in which all project should reside or are referenced by
416
+ * @param projectNumber an optional project number to assign to the project. Used when reloading projects that should keep the same number
417
+ */
418
+ async createProject(projectPath, workspacePath = projectPath, projectNumber) {
419
+ workspacePath !== null && workspacePath !== void 0 ? workspacePath : (workspacePath = projectPath);
420
+ let project = this.projects.find((x) => x.projectPath === projectPath);
421
+ //skip this project if we already have it
422
+ if (project) {
301
423
  return;
302
424
  }
303
425
  let builder = new ProgramBuilder_1.ProgramBuilder();
426
+ projectNumber !== null && projectNumber !== void 0 ? projectNumber : (projectNumber = this.projectCounter++);
427
+ builder.logger.prefix = `[prj${projectNumber}]`;
428
+ builder.logger.log(`Created project #${projectNumber} for: "${projectPath}"`);
429
+ //flush diagnostics every time the program finishes validating
430
+ builder.plugins.add({
431
+ name: 'bsc-language-server',
432
+ afterProgramValidate: () => {
433
+ void this.sendDiagnostics();
434
+ }
435
+ });
304
436
  //prevent clearing the console on run...this isn't the CLI so we want to keep a full log of everything
305
437
  builder.allowConsoleClearing = false;
306
438
  //look for files in our in-memory cache before going to the file system
307
439
  builder.addFileResolver(this.documentFileResolver.bind(this));
308
- let configFilePath = await this.getConfigFilePath(workspacePath);
309
- let cwd = workspacePath;
440
+ let configFilePath = await this.getConfigFilePath(projectPath);
441
+ let cwd = projectPath;
310
442
  //if the config file exists, use it and its folder as cwd
311
443
  if (configFilePath && await util_1.util.pathExists(configFilePath)) {
312
444
  cwd = path.dirname(configFilePath);
@@ -315,49 +447,49 @@ class LanguageServer {
315
447
  //config file doesn't exist...let `brighterscript` resolve the default way
316
448
  configFilePath = undefined;
317
449
  }
318
- let firstRunPromise = builder.run({
319
- cwd: cwd,
320
- project: configFilePath,
321
- watch: false,
322
- createPackage: false,
323
- deploy: false,
324
- copyToStaging: false,
325
- showDiagnosticsInConsole: false
326
- });
327
- firstRunPromise.catch((err) => {
328
- console.error(err);
329
- });
330
- let newWorkspace = {
450
+ const firstRunDeferred = new deferred_1.Deferred();
451
+ let newProject = {
452
+ projectNumber: projectNumber,
331
453
  builder: builder,
332
- firstRunPromise: firstRunPromise,
454
+ firstRunPromise: firstRunDeferred.promise,
455
+ projectPath: projectPath,
333
456
  workspacePath: workspacePath,
334
457
  isFirstRunComplete: false,
335
458
  isFirstRunSuccessful: false,
336
459
  configFilePath: configFilePath,
337
- isStandaloneFileWorkspace: false
460
+ isStandaloneFileProject: false
338
461
  };
339
- this.workspaces.push(newWorkspace);
340
- await firstRunPromise.then(() => {
341
- newWorkspace.isFirstRunComplete = true;
342
- newWorkspace.isFirstRunSuccessful = true;
343
- }).catch(() => {
344
- newWorkspace.isFirstRunComplete = true;
345
- newWorkspace.isFirstRunSuccessful = false;
346
- }).then(() => {
347
- //if we found a deprecated brsconfig.json, add a diagnostic warning the user
348
- if (configFilePath && path.basename(configFilePath) === 'brsconfig.json') {
349
- builder.addDiagnostic(configFilePath, Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.brsConfigJsonIsDeprecated()), { range: util_1.util.createRange(0, 0, 0, 0) }));
350
- return this.sendDiagnostics();
351
- }
352
- });
462
+ this.projects.push(newProject);
463
+ try {
464
+ await builder.run({
465
+ cwd: cwd,
466
+ project: configFilePath,
467
+ watch: false,
468
+ createPackage: false,
469
+ deploy: false,
470
+ copyToStaging: false,
471
+ showDiagnosticsInConsole: false
472
+ });
473
+ newProject.isFirstRunComplete = true;
474
+ newProject.isFirstRunSuccessful = true;
475
+ firstRunDeferred.resolve();
476
+ }
477
+ catch (e) {
478
+ builder.logger.error(e);
479
+ firstRunDeferred.reject(e);
480
+ newProject.isFirstRunComplete = true;
481
+ newProject.isFirstRunSuccessful = false;
482
+ }
483
+ //if we found a deprecated brsconfig.json, add a diagnostic warning the user
484
+ if (configFilePath && path.basename(configFilePath) === 'brsconfig.json') {
485
+ builder.addDiagnostic(configFilePath, Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.brsConfigJsonIsDeprecated()), { range: util_1.util.createRange(0, 0, 0, 0) }));
486
+ return this.sendDiagnostics();
487
+ }
353
488
  }
354
- /**
355
- * @param srcPath The absolute path to the source file on disk
356
- */
357
- async createStandaloneFileWorkspace(srcPath) {
489
+ async createStandaloneFileProject(srcPath) {
358
490
  //skip this workspace if we already have it
359
- if (this.standaloneFileWorkspaces[srcPath]) {
360
- return this.standaloneFileWorkspaces[srcPath];
491
+ if (this.standaloneFileProjects[srcPath]) {
492
+ return this.standaloneFileProjects[srcPath];
361
493
  }
362
494
  let builder = new ProgramBuilder_1.ProgramBuilder();
363
495
  //prevent clearing the console on run...this isn't the CLI so we want to keep a full log of everything
@@ -384,53 +516,61 @@ class LanguageServer {
384
516
  ] })).catch((err) => {
385
517
  console.error(err);
386
518
  });
387
- let newWorkspace = {
519
+ let newProject = {
520
+ projectNumber: this.projectCounter++,
388
521
  builder: builder,
389
522
  firstRunPromise: firstRunPromise,
523
+ projectPath: srcPath,
390
524
  workspacePath: srcPath,
391
525
  isFirstRunComplete: false,
392
526
  isFirstRunSuccessful: false,
393
527
  configFilePath: configFilePath,
394
- isStandaloneFileWorkspace: true
528
+ isStandaloneFileProject: true
395
529
  };
396
- this.standaloneFileWorkspaces[srcPath] = newWorkspace;
530
+ this.standaloneFileProjects[srcPath] = newProject;
397
531
  await firstRunPromise.then(() => {
398
- newWorkspace.isFirstRunComplete = true;
399
- newWorkspace.isFirstRunSuccessful = true;
532
+ newProject.isFirstRunComplete = true;
533
+ newProject.isFirstRunSuccessful = true;
400
534
  }).catch(() => {
401
- newWorkspace.isFirstRunComplete = true;
402
- newWorkspace.isFirstRunSuccessful = false;
535
+ newProject.isFirstRunComplete = true;
536
+ newProject.isFirstRunSuccessful = false;
403
537
  });
404
- return newWorkspace;
538
+ return newProject;
405
539
  }
406
- getWorkspaces() {
407
- let workspaces = this.workspaces.slice();
408
- for (let key in this.standaloneFileWorkspaces) {
409
- workspaces.push(this.standaloneFileWorkspaces[key]);
540
+ getProjects() {
541
+ let projects = this.projects.slice();
542
+ for (let key in this.standaloneFileProjects) {
543
+ projects.push(this.standaloneFileProjects[key]);
410
544
  }
411
- return workspaces;
545
+ return projects;
412
546
  }
413
547
  /**
414
548
  * Provide a list of completion items based on the current cursor position
415
- * @param textDocumentPosition
416
549
  */
417
- async onCompletion(uri, position) {
550
+ async onCompletion(params) {
418
551
  //ensure programs are initialized
419
- await this.waitAllProgramFirstRuns();
420
- let filePath = util_1.util.uriToPath(uri);
552
+ await this.waitAllProjectFirstRuns();
553
+ let filePath = util_1.util.uriToPath(params.textDocument.uri);
421
554
  //wait until the file has settled
422
555
  await this.keyedThrottler.onIdleOnce(filePath, true);
556
+ // make sure validation is complete
557
+ await this.validateAllThrottled();
558
+ //wait for the validation cycle to settle
559
+ await this.onValidateSettled();
423
560
  let completions = this
424
- .getWorkspaces()
425
- .flatMap(workspace => workspace.builder.program.getCompletions(filePath, position));
561
+ .getProjects()
562
+ .flatMap(workspace => workspace.builder.program.getCompletions(filePath, params.position));
563
+ //only send one completion if name and type are the same
564
+ let completionsMap = new Map();
426
565
  for (let completion of completions) {
427
566
  completion.commitCharacters = ['.'];
567
+ let key = `${completion.sortText}-${completion.label}-${completion.kind}`;
568
+ completionsMap.set(key, completion);
428
569
  }
429
- return completions;
570
+ return [...completionsMap.values()];
430
571
  }
431
572
  /**
432
573
  * Provide a full completion item from the selection
433
- * @param item
434
574
  */
435
575
  onCompletionResolve(item) {
436
576
  if (item.data === 1) {
@@ -444,57 +584,62 @@ class LanguageServer {
444
584
  return item;
445
585
  }
446
586
  async onCodeAction(params) {
587
+ var _a;
447
588
  //ensure programs are initialized
448
- await this.waitAllProgramFirstRuns();
589
+ await this.waitAllProjectFirstRuns();
449
590
  let srcPath = util_1.util.uriToPath(params.textDocument.uri);
450
591
  //wait until the file has settled
451
592
  await this.keyedThrottler.onIdleOnce(srcPath, true);
452
593
  const codeActions = this
453
- .getWorkspaces()
594
+ .getProjects()
454
595
  //skip programs that don't have this file
455
596
  .filter(x => { var _a, _b; return (_b = (_a = x.builder) === null || _a === void 0 ? void 0 : _a.program) === null || _b === void 0 ? void 0 : _b.hasFile(srcPath); })
456
597
  .flatMap(workspace => workspace.builder.program.getCodeActions(srcPath, params.range));
457
598
  //clone the diagnostics for each code action, since certain diagnostics can have circular reference properties that kill the language server if serialized
458
599
  for (const codeAction of codeActions) {
459
600
  if (codeAction.diagnostics) {
460
- codeAction.diagnostics = codeAction.diagnostics.map(x => util_1.util.toDiagnostic(x));
601
+ codeAction.diagnostics = (_a = codeAction.diagnostics) === null || _a === void 0 ? void 0 : _a.map(x => util_1.util.toDiagnostic(x, params.textDocument.uri));
461
602
  }
462
603
  }
463
604
  return codeActions;
464
605
  }
465
606
  /**
466
- * Reload all specified workspaces, or all workspaces if no workspaces are specified
607
+ * Remove a project from the language server
608
+ */
609
+ removeProject(project) {
610
+ var _a;
611
+ const idx = this.projects.indexOf(project);
612
+ if (idx > -1) {
613
+ this.projects.splice(idx, 1);
614
+ }
615
+ (_a = project === null || project === void 0 ? void 0 : project.builder) === null || _a === void 0 ? void 0 : _a.dispose();
616
+ }
617
+ /**
618
+ * Reload each of the specified workspaces
467
619
  */
468
- async reloadWorkspaces(workspaces) {
469
- workspaces = workspaces ? workspaces : this.getWorkspaces();
470
- await Promise.all(workspaces.map(async (workspace) => {
620
+ async reloadProjects(projects) {
621
+ await Promise.all(projects.map(async (project) => {
471
622
  //ensure the workspace has finished starting up
472
623
  try {
473
- await workspace.firstRunPromise;
624
+ await project.firstRunPromise;
474
625
  }
475
626
  catch (e) { }
476
627
  //handle standard workspace
477
- if (workspace.isStandaloneFileWorkspace === false) {
478
- let idx = this.workspaces.indexOf(workspace);
479
- if (idx > -1) {
480
- //remove this workspace
481
- this.workspaces.splice(idx, 1);
482
- //dispose this workspace's resources
483
- workspace.builder.dispose();
484
- }
628
+ if (project.isStandaloneFileProject === false) {
629
+ this.removeProject(project);
485
630
  //create a new workspace/brs program
486
- await this.createWorkspace(workspace.workspacePath);
631
+ await this.createProject(project.projectPath, project.workspacePath, project.projectNumber);
487
632
  //handle temp workspace
488
633
  }
489
634
  else {
490
- workspace.builder.dispose();
491
- delete this.standaloneFileWorkspaces[workspace.workspacePath];
492
- await this.createStandaloneFileWorkspace(workspace.workspacePath);
635
+ project.builder.dispose();
636
+ delete this.standaloneFileProjects[project.projectPath];
637
+ await this.createStandaloneFileProject(project.projectPath);
493
638
  }
494
639
  }));
495
- if (workspaces.length > 0) {
640
+ if (projects.length > 0) {
496
641
  //wait for all of the programs to finish starting up
497
- await this.waitAllProgramFirstRuns();
642
+ await this.waitAllProjectFirstRuns();
498
643
  // valdiate all workspaces
499
644
  this.validateAllThrottled(); //eslint-disable-line
500
645
  }
@@ -511,42 +656,42 @@ class LanguageServer {
511
656
  *
512
657
  * Sometimes files that used to be included are now excluded, so those open files need to be re-processed as standalone
513
658
  */
514
- async synchronizeStandaloneWorkspaces() {
659
+ async synchronizeStandaloneProjects() {
515
660
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
516
661
  //remove standalone workspaces that are now included in projects
517
- for (let standaloneFilePath in this.standaloneFileWorkspaces) {
518
- let standaloneWorkspace = this.standaloneFileWorkspaces[standaloneFilePath];
519
- for (let workspace of this.workspaces) {
520
- await standaloneWorkspace.firstRunPromise;
521
- let dest = rokuDeploy.getDestPath(standaloneFilePath, (_d = (_c = (_b = (_a = workspace === null || workspace === void 0 ? void 0 : workspace.builder) === null || _a === void 0 ? void 0 : _a.program) === null || _b === void 0 ? void 0 : _b.options) === null || _c === void 0 ? void 0 : _c.files) !== null && _d !== void 0 ? _d : [], this.getRootDir(workspace));
662
+ for (let standaloneFilePath in this.standaloneFileProjects) {
663
+ let standaloneProject = this.standaloneFileProjects[standaloneFilePath];
664
+ for (let project of this.projects) {
665
+ await standaloneProject.firstRunPromise;
666
+ let dest = roku_deploy_1.rokuDeploy.getDestPath(standaloneFilePath, (_d = (_c = (_b = (_a = project === null || project === void 0 ? void 0 : project.builder) === null || _a === void 0 ? void 0 : _a.program) === null || _b === void 0 ? void 0 : _b.options) === null || _c === void 0 ? void 0 : _c.files) !== null && _d !== void 0 ? _d : [], this.getRootDir(project));
522
667
  //destroy this standalone workspace because the file has now been included in an actual workspace,
523
668
  //or if the workspace wants the file
524
- if (((_f = (_e = workspace === null || workspace === void 0 ? void 0 : workspace.builder) === null || _e === void 0 ? void 0 : _e.program) === null || _f === void 0 ? void 0 : _f.hasFile(standaloneFilePath)) || dest) {
525
- standaloneWorkspace.builder.dispose();
526
- delete this.standaloneFileWorkspaces[standaloneFilePath];
669
+ if (((_f = (_e = project === null || project === void 0 ? void 0 : project.builder) === null || _e === void 0 ? void 0 : _e.program) === null || _f === void 0 ? void 0 : _f.hasFile(standaloneFilePath)) || dest) {
670
+ standaloneProject.builder.dispose();
671
+ delete this.standaloneFileProjects[standaloneFilePath];
527
672
  }
528
673
  }
529
674
  }
530
- //create standalone workspaces for open files that no longer have a project
675
+ //create standalone projects for open files that no longer have a project
531
676
  let textDocuments = this.documents.all();
532
677
  outer: for (let textDocument of textDocuments) {
533
678
  let filePath = vscode_uri_1.URI.parse(textDocument.uri).fsPath;
534
- let workspaces = this.getWorkspaces();
535
- for (let workspace of workspaces) {
536
- let dest = rokuDeploy.getDestPath(filePath, (_k = (_j = (_h = (_g = workspace === null || workspace === void 0 ? void 0 : workspace.builder) === null || _g === void 0 ? void 0 : _g.program) === null || _h === void 0 ? void 0 : _h.options) === null || _j === void 0 ? void 0 : _j.files) !== null && _k !== void 0 ? _k : [], this.getRootDir(workspace));
537
- //if this workspace has the file, or it wants the file, do NOT make a standalone workspace for this file
538
- if (((_m = (_l = workspace === null || workspace === void 0 ? void 0 : workspace.builder) === null || _l === void 0 ? void 0 : _l.program) === null || _m === void 0 ? void 0 : _m.hasFile(filePath)) || dest) {
679
+ for (let project of this.getProjects()) {
680
+ let dest = roku_deploy_1.rokuDeploy.getDestPath(filePath, (_k = (_j = (_h = (_g = project === null || project === void 0 ? void 0 : project.builder) === null || _g === void 0 ? void 0 : _g.program) === null || _h === void 0 ? void 0 : _h.options) === null || _j === void 0 ? void 0 : _j.files) !== null && _k !== void 0 ? _k : [], this.getRootDir(project));
681
+ //if this project has the file, or it wants the file, do NOT make a standaloneProject for this file
682
+ if (((_m = (_l = project === null || project === void 0 ? void 0 : project.builder) === null || _l === void 0 ? void 0 : _l.program) === null || _m === void 0 ? void 0 : _m.hasFile(filePath)) || dest) {
539
683
  continue outer;
540
684
  }
541
685
  }
542
686
  //if we got here, no workspace has this file, so make a standalone file workspace
543
- let workspace = await this.createStandaloneFileWorkspace(filePath);
544
- await workspace.firstRunPromise;
687
+ let project = await this.createStandaloneFileProject(filePath);
688
+ await project.firstRunPromise;
545
689
  }
546
690
  }
547
691
  async onDidChangeConfiguration() {
548
692
  if (this.hasConfigurationCapability) {
549
- await this.reloadWorkspaces();
693
+ //if the user changes any config value, just mass-reload all projects
694
+ await this.reloadProjects(this.getProjects());
550
695
  // Reset all cached document settings
551
696
  }
552
697
  else {
@@ -560,18 +705,16 @@ class LanguageServer {
560
705
  * The CLIENT is in charge of what files to watch, so all client
561
706
  * implementations should ensure that all valid project
562
707
  * file types are watched (.brs,.bs,.xml,manifest, and any json/text/image files)
563
- * @param params
564
708
  */
565
709
  async onDidChangeWatchedFiles(params) {
566
710
  //ensure programs are initialized
567
- await this.waitAllProgramFirstRuns();
568
- this.connection.sendNotification('build-status', 'building');
569
- let workspaces = this.getWorkspaces();
711
+ await this.waitAllProjectFirstRuns();
712
+ let projects = this.getProjects();
570
713
  //convert all file paths to absolute paths
571
714
  let changes = params.changes.map(x => {
572
715
  return {
573
716
  type: x.type,
574
- srcPath: util_1.standardizePath `${vscode_uri_1.URI.parse(x.uri).fsPath}`
717
+ srcPath: (0, util_1.standardizePath) `${vscode_uri_1.URI.parse(x.uri).fsPath}`
575
718
  };
576
719
  });
577
720
  let keys = changes.map(x => x.srcPath);
@@ -579,28 +722,32 @@ class LanguageServer {
579
722
  changes = changes.filter(x => keys.includes(x.srcPath));
580
723
  //if we have changes to work with
581
724
  if (changes.length > 0) {
725
+ //if any bsconfig files were added or deleted, re-sync all projects instead of the more specific approach below
726
+ if (changes.find(x => (x.type === node_1.FileChangeType.Created || x.type === node_1.FileChangeType.Deleted) && path.basename(x.srcPath).toLowerCase() === 'bsconfig.json')) {
727
+ return this.syncProjects();
728
+ }
582
729
  //reload any workspace whose bsconfig.json file has changed
583
730
  {
584
- let workspacesToReload = [];
731
+ let projectsToReload = [];
585
732
  //get the file paths as a string array
586
733
  let filePaths = changes.map((x) => x.srcPath);
587
- for (let workspace of workspaces) {
588
- if (workspace.configFilePath && filePaths.includes(workspace.configFilePath)) {
589
- workspacesToReload.push(workspace);
734
+ for (let project of projects) {
735
+ if (project.configFilePath && filePaths.includes(project.configFilePath)) {
736
+ projectsToReload.push(project);
590
737
  }
591
738
  }
592
- if (workspacesToReload.length > 0) {
593
- //vsc can generate a ton of these changes, for vsc system files, so we need to bail if there's no work to do on any of our actual workspace files
594
- //reload any workspaces that need to be reloaded
595
- await this.reloadWorkspaces(workspacesToReload);
739
+ if (projectsToReload.length > 0) {
740
+ //vsc can generate a ton of these changes, for vsc system files, so we need to bail if there's no work to do on any of our actual project files
741
+ //reload any projects that need to be reloaded
742
+ await this.reloadProjects(projectsToReload);
596
743
  }
597
- //set the list of workspaces to non-reloaded workspaces
598
- workspaces = workspaces.filter(x => !workspacesToReload.includes(x));
744
+ //reassign `projects` to the non-reloaded projects
745
+ projects = projects.filter(x => !projectsToReload.includes(x));
599
746
  }
600
747
  //convert created folders into a list of files of their contents
601
748
  const directoryChanges = changes
602
749
  //get only creation items
603
- .filter(change => change.type === vscode_languageserver_1.FileChangeType.Created)
750
+ .filter(change => change.type === node_1.FileChangeType.Created)
604
751
  //keep only the directories
605
752
  .filter(change => util_1.util.isDirectorySync(change.srcPath));
606
753
  //remove the created directories from the changes array (we will add back each of their files next)
@@ -613,56 +760,50 @@ class LanguageServer {
613
760
  .filter(dirPath => !dirPath.includes('.roku-deploy-staging'))
614
761
  //get the files for each folder recursively
615
762
  .flatMap(dirPath => {
616
- //create a glob pattern to match all files
617
- let pattern = rokuDeploy.util.toForwardSlashes(`${dirPath}/**/*`);
618
- let files = glob.sync(pattern, {
619
- absolute: true
763
+ //look up all files
764
+ let files = fastGlob.sync('**/*', {
765
+ absolute: true,
766
+ cwd: roku_deploy_1.util.toForwardSlashes(dirPath)
620
767
  });
621
768
  return files.map(x => {
622
769
  return {
623
- type: vscode_languageserver_1.FileChangeType.Created,
624
- srcPath: util_1.standardizePath `${x}`
770
+ type: node_1.FileChangeType.Created,
771
+ srcPath: (0, util_1.standardizePath) `${x}`
625
772
  };
626
773
  });
627
774
  });
628
775
  //add the new file changes to the changes array.
629
776
  changes.push(...newFileChanges);
630
777
  //give every workspace the chance to handle file changes
631
- await Promise.all(workspaces.map((workspace) => this.handleFileChanges(workspace, changes)));
778
+ await Promise.all(projects.map((project) => this.handleFileChanges(project, changes)));
632
779
  }
633
- this.connection.sendNotification('build-status', 'success');
634
780
  }
635
781
  /**
636
782
  * This only operates on files that match the specified files globs, so it is safe to throw
637
783
  * any file changes you receive with no unexpected side-effects
638
- * @param changes
639
784
  */
640
- async handleFileChanges(workspace, changes) {
785
+ async handleFileChanges(project, changes) {
641
786
  //this loop assumes paths are both file paths and folder paths, which eliminates the need to detect.
642
787
  //All functions below can handle being given a file path AND a folder path, and will only operate on the one they are looking for
643
- let consumeCount = 0;
644
788
  await Promise.all(changes.map(async (change) => {
645
789
  await this.keyedThrottler.run(change.srcPath, async () => {
646
- consumeCount += await this.handleFileChange(workspace, change) ? 1 : 0;
790
+ if (await this.handleFileChange(project, change)) {
791
+ await this.validateAllThrottled();
792
+ }
647
793
  });
648
794
  }));
649
- if (consumeCount > 0) {
650
- await this.validateAllThrottled();
651
- }
652
795
  }
653
796
  /**
654
797
  * This only operates on files that match the specified files globs, so it is safe to throw
655
798
  * any file changes you receive with no unexpected side-effects
656
- * @param changes
799
+ * @returns true if the file was handled by this project, false if it was not
657
800
  */
658
- async handleFileChange(workspace, change) {
659
- const program = workspace.builder.program;
660
- const options = workspace.builder.options;
661
- const rootDir = workspace.builder.rootDir;
801
+ async handleFileChange(project, change) {
802
+ const { program, options, rootDir } = project.builder;
662
803
  //deleted
663
- if (change.type === vscode_languageserver_1.FileChangeType.Deleted) {
804
+ if (change.type === node_1.FileChangeType.Deleted) {
664
805
  //try to act on this path as a directory
665
- workspace.builder.program.removeFilesInFolder(change.srcPath);
806
+ project.builder.removeFilesInFolder(change.srcPath);
666
807
  //if this is a file loaded in the program, remove it
667
808
  if (program.hasFile(change.srcPath)) {
668
809
  program.removeFile(change.srcPath);
@@ -673,16 +814,16 @@ class LanguageServer {
673
814
  }
674
815
  //created
675
816
  }
676
- else if (change.type === vscode_languageserver_1.FileChangeType.Created) {
817
+ else if (change.type === node_1.FileChangeType.Created) {
677
818
  // thanks to `onDidChangeWatchedFiles`, we can safely assume that all "Created" changes are file paths, (not directories)
678
819
  //get the dest path for this file.
679
- let destPath = rokuDeploy.getDestPath(change.srcPath, options.files, rootDir);
820
+ let destPath = roku_deploy_1.rokuDeploy.getDestPath(change.srcPath, options.files, rootDir);
680
821
  //if we got a dest path, then the program wants this file
681
822
  if (destPath) {
682
823
  program.setFile({
683
824
  src: change.srcPath,
684
- dest: rokuDeploy.getDestPath(change.srcPath, options.files, rootDir)
685
- }, await workspace.builder.getFileContents(change.srcPath));
825
+ dest: roku_deploy_1.rokuDeploy.getDestPath(change.srcPath, options.files, rootDir)
826
+ }, await project.builder.getFileContents(change.srcPath));
686
827
  return true;
687
828
  }
688
829
  else {
@@ -697,8 +838,8 @@ class LanguageServer {
697
838
  if (await util_1.util.pathExists(change.srcPath)) {
698
839
  program.setFile({
699
840
  src: change.srcPath,
700
- dest: rokuDeploy.getDestPath(change.srcPath, options.files, rootDir)
701
- }, await workspace.builder.getFileContents(change.srcPath));
841
+ dest: roku_deploy_1.rokuDeploy.getDestPath(change.srcPath, options.files, rootDir)
842
+ }, await project.builder.getFileContents(change.srcPath));
702
843
  }
703
844
  else {
704
845
  program.removeFile(change.srcPath);
@@ -707,85 +848,100 @@ class LanguageServer {
707
848
  }
708
849
  }
709
850
  async onHover(params) {
851
+ var _a;
710
852
  //ensure programs are initialized
711
- await this.waitAllProgramFirstRuns();
712
- let srcPath = util_1.util.uriToPath(params.textDocument.uri);
713
- let workspaces = this.getWorkspaces();
714
- let hovers = await Promise.all(Array.prototype.concat.call([], workspaces.map(async (x) => x.builder.program.getHover(srcPath, params.position))));
715
- //return the first non-falsey hover. TODO is there a way to handle multiple hover results?
716
- let hover = hovers.filter((x) => !!x)[0];
717
- //TODO improve this to support more than just .brs files
718
- if (hover === null || hover === void 0 ? void 0 : hover.contents) {
719
- //create fenced code block to get colorization
720
- hover.contents = {
721
- //TODO - make the program.getHover call figure out what language this is for
722
- language: 'brightscript',
723
- value: hover.contents
853
+ await this.waitAllProjectFirstRuns();
854
+ const srcPath = util_1.util.uriToPath(params.textDocument.uri);
855
+ let projects = this.getProjects();
856
+ let hovers = projects
857
+ //get hovers from all projects
858
+ .map((x) => x.builder.program.getHover(srcPath, params.position))
859
+ //flatten to a single list
860
+ .flat();
861
+ const contents = [
862
+ ...(hovers !== null && hovers !== void 0 ? hovers : [])
863
+ //pull all hover contents out into a flag array of strings
864
+ .map(x => {
865
+ return Array.isArray(x === null || x === void 0 ? void 0 : x.contents) ? x === null || x === void 0 ? void 0 : x.contents : [x === null || x === void 0 ? void 0 : x.contents];
866
+ }).flat()
867
+ //remove nulls
868
+ .filter(x => !!x)
869
+ //dedupe hovers across all projects
870
+ .reduce((set, content) => set.add(content), new Set()).values()
871
+ ];
872
+ if (contents.length > 0) {
873
+ let hover = {
874
+ //use the range from the first hover
875
+ range: (_a = hovers[0]) === null || _a === void 0 ? void 0 : _a.range,
876
+ //the contents of all hovers
877
+ contents: contents
724
878
  };
879
+ return hover;
725
880
  }
726
- return hover;
727
881
  }
728
- async onDocumentClose(textDocument) {
729
- let filePath = vscode_uri_1.URI.parse(textDocument.uri).fsPath;
730
- let standaloneFileWorkspace = this.standaloneFileWorkspaces[filePath];
882
+ async onDocumentClose(event) {
883
+ const { document } = event;
884
+ let filePath = vscode_uri_1.URI.parse(document.uri).fsPath;
885
+ let standaloneFileProject = this.standaloneFileProjects[filePath];
731
886
  //if this was a temp file, close it
732
- if (standaloneFileWorkspace) {
733
- await standaloneFileWorkspace.firstRunPromise;
734
- standaloneFileWorkspace.builder.dispose();
735
- delete this.standaloneFileWorkspaces[filePath];
887
+ if (standaloneFileProject) {
888
+ await standaloneFileProject.firstRunPromise;
889
+ standaloneFileProject.builder.dispose();
890
+ delete this.standaloneFileProjects[filePath];
736
891
  await this.sendDiagnostics();
737
892
  }
738
893
  }
739
- async validateTextDocument(textDocument) {
894
+ async validateTextDocument(event) {
895
+ const { document } = event;
740
896
  //ensure programs are initialized
741
- await this.waitAllProgramFirstRuns();
742
- let filePath = vscode_uri_1.URI.parse(textDocument.uri).fsPath;
897
+ await this.waitAllProjectFirstRuns();
898
+ let filePath = vscode_uri_1.URI.parse(document.uri).fsPath;
743
899
  try {
744
900
  //throttle file processing. first call is run immediately, and then the last call is processed.
745
901
  await this.keyedThrottler.run(filePath, () => {
746
902
  var _a;
747
- this.connection.sendNotification('build-status', 'building');
748
- let documentText = textDocument.getText();
749
- for (const workspace of this.getWorkspaces()) {
903
+ let documentText = document.getText();
904
+ for (const project of this.getProjects()) {
750
905
  //only add or replace existing files. All of the files in the project should
751
906
  //have already been loaded by other means
752
- if (workspace.builder.program.hasFile(filePath)) {
753
- let rootDir = (_a = workspace.builder.program.options.rootDir) !== null && _a !== void 0 ? _a : workspace.builder.program.options.cwd;
754
- let dest = rokuDeploy.getDestPath(filePath, workspace.builder.program.options.files, rootDir);
755
- workspace.builder.program.setFile({
907
+ if (project.builder.program.hasFile(filePath)) {
908
+ let rootDir = (_a = project.builder.program.options.rootDir) !== null && _a !== void 0 ? _a : project.builder.program.options.cwd;
909
+ let dest = roku_deploy_1.rokuDeploy.getDestPath(filePath, project.builder.program.options.files, rootDir);
910
+ project.builder.program.setFile({
756
911
  src: filePath,
757
912
  dest: dest
758
913
  }, documentText);
759
914
  }
760
915
  }
761
916
  });
762
- // validate all workspaces
917
+ // validate all projects
763
918
  await this.validateAllThrottled();
764
919
  }
765
920
  catch (e) {
766
- this.sendCriticalFailure(`Critical error parsing/ validating ${filePath}: ${e.message}`);
921
+ await this.sendCriticalFailure(`Critical error parsing/validating ${filePath}: ${e.message}`);
767
922
  }
768
923
  }
769
924
  async validateAll() {
770
925
  var _a;
771
926
  try {
772
927
  //synchronize parsing for open files that were included/excluded from projects
773
- await this.synchronizeStandaloneWorkspaces();
774
- let workspaces = this.getWorkspaces();
928
+ await this.synchronizeStandaloneProjects();
929
+ let projects = this.getProjects();
775
930
  //validate all programs
776
- await Promise.all(workspaces.map((x) => x.builder.program.validate()));
777
- await this.sendDiagnostics();
931
+ await Promise.all(projects.map((project) => {
932
+ project.builder.program.validate();
933
+ return project;
934
+ }));
778
935
  }
779
936
  catch (e) {
780
937
  this.connection.console.error(e);
781
- this.sendCriticalFailure(`Critical error validating workspace: ${e.message}${(_a = e.stack) !== null && _a !== void 0 ? _a : ''}`);
938
+ await this.sendCriticalFailure(`Critical error validating project: ${e.message}${(_a = e.stack) !== null && _a !== void 0 ? _a : ''}`);
782
939
  }
783
- this.connection.sendNotification('build-status', 'success');
784
940
  }
785
941
  async onWorkspaceSymbol(params) {
786
- await this.waitAllProgramFirstRuns();
787
- const results = util_1.util.flatMap(await Promise.all(this.getWorkspaces().map(workspace => {
788
- return workspace.builder.program.getWorkspaceSymbols();
942
+ await this.waitAllProjectFirstRuns();
943
+ const results = util_1.util.flatMap(await Promise.all(this.getProjects().map(project => {
944
+ return project.builder.program.getWorkspaceSymbols();
789
945
  })), c => c);
790
946
  // Remove duplicates
791
947
  const allSymbols = Object.values(results.reduce((map, symbol) => {
@@ -796,33 +952,33 @@ class LanguageServer {
796
952
  return allSymbols;
797
953
  }
798
954
  async onDocumentSymbol(params) {
799
- await this.waitAllProgramFirstRuns();
955
+ await this.waitAllProjectFirstRuns();
800
956
  await this.keyedThrottler.onIdleOnce(util_1.util.uriToPath(params.textDocument.uri), true);
801
957
  const srcPath = util_1.util.uriToPath(params.textDocument.uri);
802
- for (const workspace of this.getWorkspaces()) {
803
- const file = workspace.builder.program.getFile(srcPath);
804
- if (reflection_1.isBrsFile(file)) {
958
+ for (const project of this.getProjects()) {
959
+ const file = project.builder.program.getFile(srcPath);
960
+ if ((0, reflection_1.isBrsFile)(file)) {
805
961
  return file.getDocumentSymbols();
806
962
  }
807
963
  }
808
964
  }
809
965
  async onDefinition(params) {
810
- await this.waitAllProgramFirstRuns();
966
+ await this.waitAllProjectFirstRuns();
811
967
  const srcPath = util_1.util.uriToPath(params.textDocument.uri);
812
- const results = util_1.util.flatMap(await Promise.all(this.getWorkspaces().map(workspace => {
813
- return workspace.builder.program.getDefinition(srcPath, params.position);
968
+ const results = util_1.util.flatMap(await Promise.all(this.getProjects().map(project => {
969
+ return project.builder.program.getDefinition(srcPath, params.position);
814
970
  })), c => c);
815
971
  return results;
816
972
  }
817
973
  async onSignatureHelp(params) {
818
974
  var _a, _b, _c;
819
- await this.waitAllProgramFirstRuns();
975
+ await this.waitAllProjectFirstRuns();
820
976
  const filepath = util_1.util.uriToPath(params.textDocument.uri);
821
977
  await this.keyedThrottler.onIdleOnce(filepath, true);
822
978
  try {
823
- const signatures = util_1.util.flatMap(await Promise.all(this.getWorkspaces().map(workspace => workspace.builder.program.getSignatureHelp(filepath, params.position))), c => c);
979
+ const signatures = util_1.util.flatMap(await Promise.all(this.getProjects().map(project => project.builder.program.getSignatureHelp(filepath, params.position))), c => c);
824
980
  const activeSignature = signatures.length > 0 ? 0 : null;
825
- const activeParameter = activeSignature >= 0 ? (_a = signatures[activeSignature]) === null || _a === void 0 ? void 0 : _a.index : null;
981
+ const activeParameter = activeSignature !== null ? (_a = signatures[activeSignature]) === null || _a === void 0 ? void 0 : _a.index : null;
826
982
  let results = {
827
983
  signatures: signatures.map((s) => s.signature),
828
984
  activeSignature: activeSignature,
@@ -840,42 +996,75 @@ class LanguageServer {
840
996
  }
841
997
  }
842
998
  async onReferences(params) {
843
- await this.waitAllProgramFirstRuns();
999
+ await this.waitAllProjectFirstRuns();
844
1000
  const position = params.position;
845
1001
  const srcPath = util_1.util.uriToPath(params.textDocument.uri);
846
- const results = util_1.util.flatMap(await Promise.all(this.getWorkspaces().map(workspace => {
847
- return workspace.builder.program.getReferences(srcPath, position);
848
- })), c => c);
1002
+ const results = util_1.util.flatMap(await Promise.all(this.getProjects().map(project => {
1003
+ return project.builder.program.getReferences(srcPath, position);
1004
+ })), c => c !== null && c !== void 0 ? c : []);
849
1005
  return results.filter((r) => r);
850
1006
  }
851
- async sendDiagnostics() {
852
- //Get only the changes to diagnostics since the last time we sent them to the client
853
- const patch = await this.diagnosticCollection.getPatch(this.workspaces);
854
- for (let filePath in patch) {
855
- const diagnostics = patch[filePath].map(d => util_1.util.toDiagnostic(d));
856
- this.connection.sendDiagnostics({
857
- uri: vscode_uri_1.URI.file(filePath).toString(),
858
- diagnostics: diagnostics
859
- });
1007
+ onValidateSettled() {
1008
+ return Promise.all([
1009
+ //wait for the validator to start running (or timeout if it never did)
1010
+ this.validateThrottler.onRunOnce(100),
1011
+ //wait for the validator to stop running (or resolve immediately if it's already idle)
1012
+ this.validateThrottler.onIdleOnce(true)
1013
+ ]);
1014
+ }
1015
+ async onFullSemanticTokens(params) {
1016
+ await this.waitAllProjectFirstRuns();
1017
+ //wait for the file to settle (in case there are multiple file changes in quick succession)
1018
+ await this.keyedThrottler.onIdleOnce(util_1.util.uriToPath(params.textDocument.uri), true);
1019
+ // make sure validation is complete
1020
+ await this.validateAllThrottled();
1021
+ //wait for the validation cycle to settle
1022
+ await this.onValidateSettled();
1023
+ const srcPath = util_1.util.uriToPath(params.textDocument.uri);
1024
+ for (const project of this.projects) {
1025
+ //find the first program that has this file, since it would be incredibly inefficient to generate semantic tokens for the same file multiple times.
1026
+ if (project.builder.program.hasFile(srcPath)) {
1027
+ let semanticTokens = project.builder.program.getSemanticTokens(srcPath);
1028
+ if (semanticTokens !== undefined) {
1029
+ return {
1030
+ data: (0, SemanticTokenUtils_1.encodeSemanticTokens)(semanticTokens)
1031
+ };
1032
+ }
1033
+ }
860
1034
  }
861
1035
  }
1036
+ async sendDiagnostics() {
1037
+ await this.sendDiagnosticsThrottler.run(async () => {
1038
+ //wait for all programs to finish running. This ensures the `Program` exists.
1039
+ await Promise.all(this.projects.map(x => x.firstRunPromise));
1040
+ //Get only the changes to diagnostics since the last time we sent them to the client
1041
+ const patch = this.diagnosticCollection.getPatch(this.projects);
1042
+ for (let filePath in patch) {
1043
+ const uri = vscode_uri_1.URI.file(filePath).toString();
1044
+ const diagnostics = patch[filePath].map(d => util_1.util.toDiagnostic(d, uri));
1045
+ await this.connection.sendDiagnostics({
1046
+ uri: uri,
1047
+ diagnostics: diagnostics
1048
+ });
1049
+ }
1050
+ });
1051
+ }
862
1052
  async onExecuteCommand(params) {
863
- await this.waitAllProgramFirstRuns();
1053
+ await this.waitAllProjectFirstRuns();
864
1054
  if (params.command === CustomCommands.TranspileFile) {
865
- return this.transpileFile(params.arguments[0]);
1055
+ const result = await this.transpileFile(params.arguments[0]);
1056
+ //back-compat: include `pathAbsolute` property so older vscode versions still work
1057
+ result.pathAbsolute = result.srcPath;
1058
+ return result;
866
1059
  }
867
1060
  }
868
- /**
869
- * @param srcPath The absolute path to the source file on disk
870
- */
871
1061
  async transpileFile(srcPath) {
872
1062
  //wait all program first runs
873
- await this.waitAllProgramFirstRuns();
874
- let workspaces = this.getWorkspaces();
875
- //find the first workspace that has this file
876
- for (let workspace of workspaces) {
877
- if (workspace.builder.program.hasFile(srcPath)) {
878
- return workspace.builder.program.getTranspiledFileContents(srcPath);
1063
+ await this.waitAllProjectFirstRuns();
1064
+ //find the first project that has this file
1065
+ for (let project of this.getProjects()) {
1066
+ if (project.builder.program.hasFile(srcPath)) {
1067
+ return project.builder.program.getTranspiledFileContents(srcPath);
879
1068
  }
880
1069
  }
881
1070
  }
@@ -889,22 +1078,35 @@ __decorate([
889
1078
  AddStackToErrorMessage
890
1079
  ], LanguageServer.prototype, "onInitialize", null);
891
1080
  __decorate([
892
- AddStackToErrorMessage
1081
+ TrackBusyStatus
1082
+ ], LanguageServer.prototype, "getProjectPaths", null);
1083
+ __decorate([
1084
+ TrackBusyStatus
1085
+ ], LanguageServer.prototype, "syncProjects", null);
1086
+ __decorate([
1087
+ AddStackToErrorMessage,
1088
+ TrackBusyStatus
893
1089
  ], LanguageServer.prototype, "onInitialized", null);
894
1090
  __decorate([
895
- AddStackToErrorMessage
1091
+ TrackBusyStatus
1092
+ ], LanguageServer.prototype, "createProject", null);
1093
+ __decorate([
1094
+ AddStackToErrorMessage,
1095
+ TrackBusyStatus
896
1096
  ], LanguageServer.prototype, "onCompletion", null);
897
1097
  __decorate([
898
1098
  AddStackToErrorMessage
899
1099
  ], LanguageServer.prototype, "onCompletionResolve", null);
900
1100
  __decorate([
901
- AddStackToErrorMessage
1101
+ AddStackToErrorMessage,
1102
+ TrackBusyStatus
902
1103
  ], LanguageServer.prototype, "onCodeAction", null);
903
1104
  __decorate([
904
1105
  AddStackToErrorMessage
905
1106
  ], LanguageServer.prototype, "onDidChangeConfiguration", null);
906
1107
  __decorate([
907
- AddStackToErrorMessage
1108
+ AddStackToErrorMessage,
1109
+ TrackBusyStatus
908
1110
  ], LanguageServer.prototype, "onDidChangeWatchedFiles", null);
909
1111
  __decorate([
910
1112
  AddStackToErrorMessage
@@ -913,31 +1115,49 @@ __decorate([
913
1115
  AddStackToErrorMessage
914
1116
  ], LanguageServer.prototype, "onDocumentClose", null);
915
1117
  __decorate([
916
- AddStackToErrorMessage
1118
+ AddStackToErrorMessage,
1119
+ TrackBusyStatus
917
1120
  ], LanguageServer.prototype, "validateTextDocument", null);
918
1121
  __decorate([
919
- AddStackToErrorMessage
1122
+ TrackBusyStatus
1123
+ ], LanguageServer.prototype, "validateAll", null);
1124
+ __decorate([
1125
+ AddStackToErrorMessage,
1126
+ TrackBusyStatus
920
1127
  ], LanguageServer.prototype, "onWorkspaceSymbol", null);
921
1128
  __decorate([
922
- AddStackToErrorMessage
1129
+ AddStackToErrorMessage,
1130
+ TrackBusyStatus
923
1131
  ], LanguageServer.prototype, "onDocumentSymbol", null);
924
1132
  __decorate([
925
- AddStackToErrorMessage
1133
+ AddStackToErrorMessage,
1134
+ TrackBusyStatus
926
1135
  ], LanguageServer.prototype, "onDefinition", null);
927
1136
  __decorate([
928
- AddStackToErrorMessage
1137
+ AddStackToErrorMessage,
1138
+ TrackBusyStatus
929
1139
  ], LanguageServer.prototype, "onSignatureHelp", null);
930
1140
  __decorate([
931
- AddStackToErrorMessage
1141
+ AddStackToErrorMessage,
1142
+ TrackBusyStatus
932
1143
  ], LanguageServer.prototype, "onReferences", null);
933
1144
  __decorate([
934
- AddStackToErrorMessage
1145
+ AddStackToErrorMessage,
1146
+ TrackBusyStatus
1147
+ ], LanguageServer.prototype, "onFullSemanticTokens", null);
1148
+ __decorate([
1149
+ AddStackToErrorMessage,
1150
+ TrackBusyStatus
935
1151
  ], LanguageServer.prototype, "onExecuteCommand", null);
936
1152
  exports.LanguageServer = LanguageServer;
937
1153
  var CustomCommands;
938
1154
  (function (CustomCommands) {
939
1155
  CustomCommands["TranspileFile"] = "TranspileFile";
940
1156
  })(CustomCommands = exports.CustomCommands || (exports.CustomCommands = {}));
1157
+ var NotificationName;
1158
+ (function (NotificationName) {
1159
+ NotificationName["busyStatus"] = "busyStatus";
1160
+ })(NotificationName = exports.NotificationName || (exports.NotificationName = {}));
941
1161
  /**
942
1162
  * Wraps a method. If there's an error (either sync or via a promise),
943
1163
  * this appends the error's stack trace at the end of the error message so that the connection will
@@ -969,4 +1189,16 @@ function AddStackToErrorMessage(target, propertyKey, descriptor) {
969
1189
  }
970
1190
  };
971
1191
  }
1192
+ /**
1193
+ * An annotation used to wrap the method in a busyStatus tracking call
1194
+ */
1195
+ function TrackBusyStatus(target, propertyKey, descriptor) {
1196
+ let originalMethod = descriptor.value;
1197
+ //wrapping the original method
1198
+ descriptor.value = function value(...args) {
1199
+ return this.busyStatusTracker.run(() => {
1200
+ return originalMethod.apply(this, args);
1201
+ }, originalMethod.name);
1202
+ };
1203
+ }
972
1204
  //# sourceMappingURL=LanguageServer.js.map