brighterscript 1.0.0-alpha.5 → 1.0.0-alpha.51

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 (652) hide show
  1. package/README.md +79 -138
  2. package/bsconfig.schema.json +196 -5
  3. package/dist/ActionPipeline.d.ts +10 -0
  4. package/dist/ActionPipeline.js +40 -0
  5. package/dist/ActionPipeline.js.map +1 -0
  6. package/dist/AstValidationSegmenter.d.ts +45 -0
  7. package/dist/AstValidationSegmenter.js +322 -0
  8. package/dist/AstValidationSegmenter.js.map +1 -0
  9. package/dist/BsConfig.d.ts +161 -43
  10. package/dist/BusyStatusTracker.d.ts +61 -0
  11. package/dist/BusyStatusTracker.js +148 -0
  12. package/dist/BusyStatusTracker.js.map +1 -0
  13. package/dist/Cache.d.ts +3 -8
  14. package/dist/Cache.js +9 -14
  15. package/dist/Cache.js.map +1 -1
  16. package/dist/CacheVerifier.d.ts +7 -0
  17. package/dist/CacheVerifier.js +20 -0
  18. package/dist/CacheVerifier.js.map +1 -0
  19. package/dist/CodeActionUtil.d.ts +29 -4
  20. package/dist/CodeActionUtil.js +22 -5
  21. package/dist/CodeActionUtil.js.map +1 -1
  22. package/dist/CommentFlagProcessor.d.ts +20 -15
  23. package/dist/CommentFlagProcessor.js +143 -58
  24. package/dist/CommentFlagProcessor.js.map +1 -1
  25. package/dist/CrossScopeValidator.d.ts +68 -0
  26. package/dist/CrossScopeValidator.js +650 -0
  27. package/dist/CrossScopeValidator.js.map +1 -0
  28. package/dist/DependencyGraph.d.ts +8 -3
  29. package/dist/DependencyGraph.js +49 -16
  30. package/dist/DependencyGraph.js.map +1 -1
  31. package/dist/DiagnosticCollection.d.ts +21 -5
  32. package/dist/DiagnosticCollection.js +77 -24
  33. package/dist/DiagnosticCollection.js.map +1 -1
  34. package/dist/DiagnosticFilterer.d.ts +27 -6
  35. package/dist/DiagnosticFilterer.js +273 -60
  36. package/dist/DiagnosticFilterer.js.map +1 -1
  37. package/dist/DiagnosticManager.d.ts +83 -0
  38. package/dist/DiagnosticManager.js +422 -0
  39. package/dist/DiagnosticManager.js.map +1 -0
  40. package/dist/DiagnosticMessages.d.ts +602 -196
  41. package/dist/DiagnosticMessages.js +926 -342
  42. package/dist/DiagnosticMessages.js.map +1 -1
  43. package/dist/DiagnosticSeverityAdjuster.d.ts +7 -0
  44. package/dist/DiagnosticSeverityAdjuster.js +45 -0
  45. package/dist/DiagnosticSeverityAdjuster.js.map +1 -0
  46. package/dist/FunctionScope.d.ts +28 -0
  47. package/dist/FunctionScope.js +52 -0
  48. package/dist/FunctionScope.js.map +1 -0
  49. package/dist/KeyedThrottler.d.ts +3 -3
  50. package/dist/KeyedThrottler.js +3 -3
  51. package/dist/KeyedThrottler.js.map +1 -1
  52. package/dist/LanguageServer.d.ts +136 -104
  53. package/dist/LanguageServer.js +577 -741
  54. package/dist/LanguageServer.js.map +1 -1
  55. package/dist/Logger.d.ts +17 -13
  56. package/dist/Logger.js +64 -34
  57. package/dist/Logger.js.map +1 -1
  58. package/dist/PluginInterface.d.ts +32 -10
  59. package/dist/PluginInterface.js +117 -7
  60. package/dist/PluginInterface.js.map +1 -1
  61. package/dist/Program.d.ts +302 -98
  62. package/dist/Program.js +1613 -726
  63. package/dist/Program.js.map +1 -1
  64. package/dist/ProgramBuilder.d.ts +39 -22
  65. package/dist/ProgramBuilder.js +245 -179
  66. package/dist/ProgramBuilder.js.map +1 -1
  67. package/dist/Scope.d.ts +227 -106
  68. package/dist/Scope.js +609 -557
  69. package/dist/Scope.js.map +1 -1
  70. package/dist/ScopeNamespaceLookup.d.ts +73 -0
  71. package/dist/ScopeNamespaceLookup.js +242 -0
  72. package/dist/ScopeNamespaceLookup.js.map +1 -0
  73. package/dist/SemanticTokenUtils.js +5 -1
  74. package/dist/SemanticTokenUtils.js.map +1 -1
  75. package/dist/Stopwatch.d.ts +4 -0
  76. package/dist/Stopwatch.js +8 -1
  77. package/dist/Stopwatch.js.map +1 -1
  78. package/dist/SymbolTable.d.ts +145 -26
  79. package/dist/SymbolTable.js +575 -64
  80. package/dist/SymbolTable.js.map +1 -1
  81. package/dist/SymbolTypeFlag.d.ts +9 -0
  82. package/dist/SymbolTypeFlag.js +14 -0
  83. package/dist/SymbolTypeFlag.js.map +1 -0
  84. package/dist/Throttler.d.ts +12 -0
  85. package/dist/Throttler.js +39 -0
  86. package/dist/Throttler.js.map +1 -1
  87. package/dist/Watcher.d.ts +0 -3
  88. package/dist/Watcher.js +0 -3
  89. package/dist/Watcher.js.map +1 -1
  90. package/dist/XmlScope.d.ts +5 -15
  91. package/dist/XmlScope.js +34 -90
  92. package/dist/XmlScope.js.map +1 -1
  93. package/dist/astUtils/CachedLookups.d.ts +50 -0
  94. package/dist/astUtils/CachedLookups.js +337 -0
  95. package/dist/astUtils/CachedLookups.js.map +1 -0
  96. package/dist/astUtils/Editor.d.ts +69 -0
  97. package/dist/astUtils/Editor.js +245 -0
  98. package/dist/astUtils/Editor.js.map +1 -0
  99. package/dist/astUtils/creators.d.ts +54 -19
  100. package/dist/astUtils/creators.js +242 -42
  101. package/dist/astUtils/creators.js.map +1 -1
  102. package/dist/astUtils/reflection.d.ts +199 -85
  103. package/dist/astUtils/reflection.js +518 -145
  104. package/dist/astUtils/reflection.js.map +1 -1
  105. package/dist/astUtils/stackedVisitor.js.map +1 -1
  106. package/dist/astUtils/visitors.d.ts +117 -53
  107. package/dist/astUtils/visitors.js +95 -15
  108. package/dist/astUtils/visitors.js.map +1 -1
  109. package/dist/astUtils/xml.d.ts +9 -8
  110. package/dist/astUtils/xml.js +12 -7
  111. package/dist/astUtils/xml.js.map +1 -1
  112. package/dist/bscPlugin/BscPlugin.d.ts +26 -4
  113. package/dist/bscPlugin/BscPlugin.js +96 -4
  114. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  115. package/dist/bscPlugin/CallExpressionInfo.d.ts +36 -0
  116. package/dist/bscPlugin/CallExpressionInfo.js +142 -0
  117. package/dist/bscPlugin/CallExpressionInfo.js.map +1 -0
  118. package/dist/bscPlugin/FileWriter.d.ts +19 -0
  119. package/dist/bscPlugin/FileWriter.js +79 -0
  120. package/dist/bscPlugin/FileWriter.js.map +1 -0
  121. package/dist/bscPlugin/SignatureHelpUtil.d.ts +10 -0
  122. package/dist/bscPlugin/SignatureHelpUtil.js +137 -0
  123. package/dist/bscPlugin/SignatureHelpUtil.js.map +1 -0
  124. package/dist/bscPlugin/codeActions/CodeActionsProcessor.d.ts +109 -7
  125. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +676 -26
  126. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  127. package/dist/bscPlugin/codeActions/FixAllCodeActionsProcessor.d.ts +17 -0
  128. package/dist/bscPlugin/codeActions/FixAllCodeActionsProcessor.js +66 -0
  129. package/dist/bscPlugin/codeActions/FixAllCodeActionsProcessor.js.map +1 -0
  130. package/dist/bscPlugin/codeActions/codeActionHelpers.d.ts +18 -0
  131. package/dist/bscPlugin/codeActions/codeActionHelpers.js +31 -0
  132. package/dist/bscPlugin/codeActions/codeActionHelpers.js.map +1 -0
  133. package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +65 -0
  134. package/dist/bscPlugin/completions/CompletionsProcessor.js +633 -0
  135. package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -0
  136. package/dist/bscPlugin/definition/DefinitionProvider.d.ts +13 -0
  137. package/dist/bscPlugin/definition/DefinitionProvider.js +220 -0
  138. package/dist/bscPlugin/definition/DefinitionProvider.js.map +1 -0
  139. package/dist/bscPlugin/fileProviders/FileProvider.d.ts +9 -0
  140. package/dist/bscPlugin/fileProviders/FileProvider.js +51 -0
  141. package/dist/bscPlugin/fileProviders/FileProvider.js.map +1 -0
  142. package/dist/bscPlugin/hover/HoverProcessor.d.ts +18 -0
  143. package/dist/bscPlugin/hover/HoverProcessor.js +238 -0
  144. package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -0
  145. package/dist/bscPlugin/references/ReferencesProvider.d.ts +12 -0
  146. package/dist/bscPlugin/references/ReferencesProvider.js +57 -0
  147. package/dist/bscPlugin/references/ReferencesProvider.js.map +1 -0
  148. package/dist/bscPlugin/selectionRanges/SelectionRangesProcessor.d.ts +7 -0
  149. package/dist/bscPlugin/selectionRanges/SelectionRangesProcessor.js +77 -0
  150. package/dist/bscPlugin/selectionRanges/SelectionRangesProcessor.js.map +1 -0
  151. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +14 -0
  152. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +164 -0
  153. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -0
  154. package/dist/bscPlugin/serialize/BslibManager.d.ts +12 -0
  155. package/dist/bscPlugin/serialize/BslibManager.js +46 -0
  156. package/dist/bscPlugin/serialize/BslibManager.js.map +1 -0
  157. package/dist/bscPlugin/serialize/FileSerializer.d.ts +9 -0
  158. package/dist/bscPlugin/serialize/FileSerializer.js +80 -0
  159. package/dist/bscPlugin/serialize/FileSerializer.js.map +1 -0
  160. package/dist/bscPlugin/symbols/DocumentSymbolProcessor.d.ts +7 -0
  161. package/dist/bscPlugin/symbols/DocumentSymbolProcessor.js +22 -0
  162. package/dist/bscPlugin/symbols/DocumentSymbolProcessor.js.map +1 -0
  163. package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.d.ts +7 -0
  164. package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.js +26 -0
  165. package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.js.map +1 -0
  166. package/dist/bscPlugin/symbols/symbolUtils.d.ts +5 -0
  167. package/dist/bscPlugin/symbols/symbolUtils.js +141 -0
  168. package/dist/bscPlugin/symbols/symbolUtils.js.map +1 -0
  169. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.d.ts +34 -0
  170. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js +504 -0
  171. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js.map +1 -0
  172. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.d.ts +12 -0
  173. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js +99 -0
  174. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js.map +1 -0
  175. package/dist/bscPlugin/validation/BrsFileAfterValidator.d.ts +7 -0
  176. package/dist/bscPlugin/validation/BrsFileAfterValidator.js +18 -0
  177. package/dist/bscPlugin/validation/BrsFileAfterValidator.js.map +1 -0
  178. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +51 -0
  179. package/dist/bscPlugin/validation/BrsFileValidator.js +714 -0
  180. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -0
  181. package/dist/bscPlugin/validation/ProgramValidator.d.ts +11 -0
  182. package/dist/bscPlugin/validation/ProgramValidator.js +33 -0
  183. package/dist/bscPlugin/validation/ProgramValidator.js.map +1 -0
  184. package/dist/bscPlugin/validation/ScopeValidator.d.ts +158 -0
  185. package/dist/bscPlugin/validation/ScopeValidator.js +1481 -0
  186. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -0
  187. package/dist/bscPlugin/validation/XmlFileValidator.d.ts +8 -0
  188. package/dist/bscPlugin/validation/XmlFileValidator.js +50 -0
  189. package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -0
  190. package/dist/cli.js +140 -28
  191. package/dist/cli.js.map +1 -1
  192. package/dist/common/Sequencer.d.ts +53 -0
  193. package/dist/common/Sequencer.js +233 -0
  194. package/dist/common/Sequencer.js.map +1 -0
  195. package/dist/deferred.d.ts +5 -3
  196. package/dist/deferred.js +10 -0
  197. package/dist/deferred.js.map +1 -1
  198. package/dist/diagnosticUtils.d.ts +61 -4
  199. package/dist/diagnosticUtils.js +285 -25
  200. package/dist/diagnosticUtils.js.map +1 -1
  201. package/dist/examples/plugins/removePrint.d.ts +2 -2
  202. package/dist/examples/plugins/removePrint.js +8 -12
  203. package/dist/examples/plugins/removePrint.js.map +1 -1
  204. package/dist/files/AssetFile.d.ts +24 -0
  205. package/dist/files/AssetFile.js +25 -0
  206. package/dist/files/AssetFile.js.map +1 -0
  207. package/dist/files/BrsFile.d.ts +161 -87
  208. package/dist/files/BrsFile.js +919 -936
  209. package/dist/files/BrsFile.js.map +1 -1
  210. package/dist/files/BscFile.d.ts +102 -0
  211. package/dist/files/BscFile.js +15 -0
  212. package/dist/files/BscFile.js.map +1 -0
  213. package/dist/files/Factory.d.ts +25 -0
  214. package/dist/files/Factory.js +22 -0
  215. package/dist/files/Factory.js.map +1 -0
  216. package/dist/files/LazyFileData.d.ts +21 -0
  217. package/dist/files/LazyFileData.js +54 -0
  218. package/dist/files/LazyFileData.js.map +1 -0
  219. package/dist/files/XmlFile.d.ts +80 -41
  220. package/dist/files/XmlFile.js +162 -137
  221. package/dist/files/XmlFile.js.map +1 -1
  222. package/dist/globalCallables.d.ts +3 -1
  223. package/dist/globalCallables.js +424 -184
  224. package/dist/globalCallables.js.map +1 -1
  225. package/dist/index.d.ts +32 -4
  226. package/dist/index.js +54 -7
  227. package/dist/index.js.map +1 -1
  228. package/dist/interfaces.d.ts +987 -125
  229. package/dist/interfaces.js +21 -0
  230. package/dist/interfaces.js.map +1 -1
  231. package/dist/lexer/Lexer.d.ts +51 -12
  232. package/dist/lexer/Lexer.js +214 -65
  233. package/dist/lexer/Lexer.js.map +1 -1
  234. package/dist/lexer/Token.d.ts +27 -11
  235. package/dist/lexer/Token.js +10 -2
  236. package/dist/lexer/Token.js.map +1 -1
  237. package/dist/lexer/TokenKind.d.ts +48 -2
  238. package/dist/lexer/TokenKind.js +167 -10
  239. package/dist/lexer/TokenKind.js.map +1 -1
  240. package/dist/logging.d.ts +14 -0
  241. package/dist/logging.js +29 -0
  242. package/dist/logging.js.map +1 -0
  243. package/dist/lsp/ActionQueue.d.ts +35 -0
  244. package/dist/lsp/ActionQueue.js +115 -0
  245. package/dist/lsp/ActionQueue.js.map +1 -0
  246. package/dist/lsp/DocumentManager.d.ts +63 -0
  247. package/dist/lsp/DocumentManager.js +122 -0
  248. package/dist/lsp/DocumentManager.js.map +1 -0
  249. package/dist/lsp/LspProject.d.ts +287 -0
  250. package/dist/lsp/LspProject.js +3 -0
  251. package/dist/lsp/LspProject.js.map +1 -0
  252. package/dist/lsp/PathFilterer.d.ts +75 -0
  253. package/dist/lsp/PathFilterer.js +196 -0
  254. package/dist/lsp/PathFilterer.js.map +1 -0
  255. package/dist/lsp/Project.d.ts +200 -0
  256. package/dist/lsp/Project.js +562 -0
  257. package/dist/lsp/Project.js.map +1 -0
  258. package/dist/lsp/ProjectManager.d.ts +288 -0
  259. package/dist/lsp/ProjectManager.js +967 -0
  260. package/dist/lsp/ProjectManager.js.map +1 -0
  261. package/dist/lsp/ReaderWriterManager.d.ts +21 -0
  262. package/dist/lsp/ReaderWriterManager.js +60 -0
  263. package/dist/lsp/ReaderWriterManager.js.map +1 -0
  264. package/dist/lsp/worker/MessageHandler.d.ts +99 -0
  265. package/dist/lsp/worker/MessageHandler.js +138 -0
  266. package/dist/lsp/worker/MessageHandler.js.map +1 -0
  267. package/dist/lsp/worker/WorkerPool.d.ts +38 -0
  268. package/dist/lsp/worker/WorkerPool.js +78 -0
  269. package/dist/lsp/worker/WorkerPool.js.map +1 -0
  270. package/dist/lsp/worker/WorkerThreadProject.d.ts +168 -0
  271. package/dist/lsp/worker/WorkerThreadProject.js +205 -0
  272. package/dist/lsp/worker/WorkerThreadProject.js.map +1 -0
  273. package/dist/lsp/worker/WorkerThreadProjectRunner.d.ts +15 -0
  274. package/dist/lsp/worker/WorkerThreadProjectRunner.js +58 -0
  275. package/dist/lsp/worker/WorkerThreadProjectRunner.js.map +1 -0
  276. package/dist/lsp/worker/run.js +14 -0
  277. package/dist/lsp/worker/run.js.map +1 -0
  278. package/dist/parser/AstNode.d.ts +205 -0
  279. package/dist/parser/AstNode.js +305 -0
  280. package/dist/parser/AstNode.js.map +1 -0
  281. package/dist/parser/BrightScriptDocParser.d.ts +56 -0
  282. package/dist/parser/BrightScriptDocParser.js +294 -0
  283. package/dist/parser/BrightScriptDocParser.js.map +1 -0
  284. package/dist/parser/BrsTranspileState.d.ts +22 -3
  285. package/dist/parser/BrsTranspileState.js +19 -0
  286. package/dist/parser/BrsTranspileState.js.map +1 -1
  287. package/dist/parser/Expression.d.ts +601 -220
  288. package/dist/parser/Expression.js +1516 -502
  289. package/dist/parser/Expression.js.map +1 -1
  290. package/dist/parser/Parser.d.ts +137 -121
  291. package/dist/parser/Parser.js +1808 -982
  292. package/dist/parser/Parser.js.map +1 -1
  293. package/dist/parser/SGParser.d.ts +30 -13
  294. package/dist/parser/SGParser.js +94 -56
  295. package/dist/parser/SGParser.js.map +1 -1
  296. package/dist/parser/SGTypes.d.ts +134 -46
  297. package/dist/parser/SGTypes.js +206 -115
  298. package/dist/parser/SGTypes.js.map +1 -1
  299. package/dist/parser/Statement.d.ts +854 -267
  300. package/dist/parser/Statement.js +2416 -621
  301. package/dist/parser/Statement.js.map +1 -1
  302. package/dist/parser/TranspileState.d.ts +30 -14
  303. package/dist/parser/TranspileState.js +124 -27
  304. package/dist/parser/TranspileState.js.map +1 -1
  305. package/dist/preprocessor/Manifest.d.ts +6 -6
  306. package/dist/preprocessor/Manifest.js +17 -38
  307. package/dist/preprocessor/Manifest.js.map +1 -1
  308. package/dist/roku-types/data.json +20554 -0
  309. package/dist/roku-types/index.d.ts +5726 -0
  310. package/dist/roku-types/index.js +11 -0
  311. package/dist/roku-types/index.js.map +1 -0
  312. package/dist/types/ArrayType.d.ts +12 -5
  313. package/dist/types/ArrayType.js +95 -25
  314. package/dist/types/ArrayType.js.map +1 -1
  315. package/dist/types/AssociativeArrayType.d.ts +15 -0
  316. package/dist/types/AssociativeArrayType.js +64 -0
  317. package/dist/types/AssociativeArrayType.js.map +1 -0
  318. package/dist/types/BaseFunctionType.d.ts +10 -0
  319. package/dist/types/BaseFunctionType.js +26 -0
  320. package/dist/types/BaseFunctionType.js.map +1 -0
  321. package/dist/types/BooleanType.d.ts +9 -5
  322. package/dist/types/BooleanType.js +19 -8
  323. package/dist/types/BooleanType.js.map +1 -1
  324. package/dist/types/BscType.d.ts +41 -3
  325. package/dist/types/BscType.js +152 -0
  326. package/dist/types/BscType.js.map +1 -1
  327. package/dist/types/BscTypeKind.d.ts +28 -0
  328. package/dist/types/BscTypeKind.js +33 -0
  329. package/dist/types/BscTypeKind.js.map +1 -0
  330. package/dist/types/BuiltInInterfaceAdder.d.ts +28 -0
  331. package/dist/types/BuiltInInterfaceAdder.js +212 -0
  332. package/dist/types/BuiltInInterfaceAdder.js.map +1 -0
  333. package/dist/types/CallFuncableType.d.ts +24 -0
  334. package/dist/types/CallFuncableType.js +91 -0
  335. package/dist/types/CallFuncableType.js.map +1 -0
  336. package/dist/types/ClassType.d.ts +17 -0
  337. package/dist/types/ClassType.js +63 -0
  338. package/dist/types/ClassType.js.map +1 -0
  339. package/dist/types/ComponentType.d.ts +22 -0
  340. package/dist/types/ComponentType.js +110 -0
  341. package/dist/types/ComponentType.js.map +1 -0
  342. package/dist/types/DoubleType.d.ts +10 -5
  343. package/dist/types/DoubleType.js +21 -17
  344. package/dist/types/DoubleType.js.map +1 -1
  345. package/dist/types/DynamicType.d.ts +13 -5
  346. package/dist/types/DynamicType.js +26 -5
  347. package/dist/types/DynamicType.js.map +1 -1
  348. package/dist/types/EnumType.d.ts +42 -0
  349. package/dist/types/EnumType.js +101 -0
  350. package/dist/types/EnumType.js.map +1 -0
  351. package/dist/types/FloatType.d.ts +10 -5
  352. package/dist/types/FloatType.js +21 -17
  353. package/dist/types/FloatType.js.map +1 -1
  354. package/dist/types/FunctionType.d.ts +8 -22
  355. package/dist/types/FunctionType.js +25 -63
  356. package/dist/types/FunctionType.js.map +1 -1
  357. package/dist/types/InheritableType.d.ts +29 -0
  358. package/dist/types/InheritableType.js +173 -0
  359. package/dist/types/InheritableType.js.map +1 -0
  360. package/dist/types/InlineInterfaceType.d.ts +5 -0
  361. package/dist/types/InlineInterfaceType.js +17 -0
  362. package/dist/types/InlineInterfaceType.js.map +1 -0
  363. package/dist/types/IntegerType.d.ts +10 -5
  364. package/dist/types/IntegerType.js +21 -17
  365. package/dist/types/IntegerType.js.map +1 -1
  366. package/dist/types/InterfaceType.d.ts +14 -6
  367. package/dist/types/InterfaceType.js +30 -15
  368. package/dist/types/InterfaceType.js.map +1 -1
  369. package/dist/types/IntersectionType.d.ts +29 -0
  370. package/dist/types/IntersectionType.js +256 -0
  371. package/dist/types/IntersectionType.js.map +1 -0
  372. package/dist/types/InvalidType.d.ts +10 -5
  373. package/dist/types/InvalidType.js +21 -9
  374. package/dist/types/InvalidType.js.map +1 -1
  375. package/dist/types/LongIntegerType.d.ts +10 -5
  376. package/dist/types/LongIntegerType.js +21 -17
  377. package/dist/types/LongIntegerType.js.map +1 -1
  378. package/dist/types/NamespaceType.d.ts +12 -0
  379. package/dist/types/NamespaceType.js +28 -0
  380. package/dist/types/NamespaceType.js.map +1 -0
  381. package/dist/types/ObjectType.d.ts +12 -5
  382. package/dist/types/ObjectType.js +25 -8
  383. package/dist/types/ObjectType.js.map +1 -1
  384. package/dist/types/ReferenceType.d.ts +123 -0
  385. package/dist/types/ReferenceType.js +726 -0
  386. package/dist/types/ReferenceType.js.map +1 -0
  387. package/dist/types/StringType.d.ts +12 -5
  388. package/dist/types/StringType.js +23 -8
  389. package/dist/types/StringType.js.map +1 -1
  390. package/dist/types/TypeStatementType.d.ts +19 -0
  391. package/dist/types/TypeStatementType.js +56 -0
  392. package/dist/types/TypeStatementType.js.map +1 -0
  393. package/dist/types/TypedFunctionType.d.ts +34 -0
  394. package/dist/types/TypedFunctionType.js +157 -0
  395. package/dist/types/TypedFunctionType.js.map +1 -0
  396. package/dist/types/UninitializedType.d.ts +11 -6
  397. package/dist/types/UninitializedType.js +20 -11
  398. package/dist/types/UninitializedType.js.map +1 -1
  399. package/dist/types/UnionType.d.ts +27 -0
  400. package/dist/types/UnionType.js +196 -0
  401. package/dist/types/UnionType.js.map +1 -0
  402. package/dist/types/VoidType.d.ts +11 -5
  403. package/dist/types/VoidType.js +22 -8
  404. package/dist/types/VoidType.js.map +1 -1
  405. package/dist/types/helpers.d.ts +51 -0
  406. package/dist/types/helpers.js +329 -0
  407. package/dist/types/helpers.js.map +1 -0
  408. package/dist/types/index.d.ts +22 -0
  409. package/dist/types/index.js +39 -0
  410. package/dist/types/index.js.map +1 -0
  411. package/dist/types/roFunctionType.d.ts +11 -0
  412. package/dist/types/roFunctionType.js +37 -0
  413. package/dist/types/roFunctionType.js.map +1 -0
  414. package/dist/util.d.ts +325 -185
  415. package/dist/util.js +2135 -568
  416. package/dist/util.js.map +1 -1
  417. package/dist/validators/ClassValidator.d.ts +9 -15
  418. package/dist/validators/ClassValidator.js +93 -138
  419. package/dist/validators/ClassValidator.js.map +1 -1
  420. package/package.json +183 -138
  421. package/CHANGELOG.md +0 -1188
  422. package/dist/astUtils/creators.spec.js +0 -21
  423. package/dist/astUtils/creators.spec.js.map +0 -1
  424. package/dist/astUtils/index.d.ts +0 -7
  425. package/dist/astUtils/index.js +0 -26
  426. package/dist/astUtils/index.js.map +0 -1
  427. package/dist/astUtils/reflection.spec.d.ts +0 -1
  428. package/dist/astUtils/reflection.spec.js +0 -292
  429. package/dist/astUtils/reflection.spec.js.map +0 -1
  430. package/dist/astUtils/stackedVisitor.spec.d.ts +0 -1
  431. package/dist/astUtils/stackedVisitor.spec.js +0 -79
  432. package/dist/astUtils/stackedVisitor.spec.js.map +0 -1
  433. package/dist/astUtils/visitors.spec.d.ts +0 -1
  434. package/dist/astUtils/visitors.spec.js +0 -854
  435. package/dist/astUtils/visitors.spec.js.map +0 -1
  436. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.d.ts +0 -1
  437. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +0 -194
  438. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +0 -1
  439. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.d.ts +0 -7
  440. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.js +0 -63
  441. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.js.map +0 -1
  442. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.spec.d.ts +0 -1
  443. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.spec.js +0 -45
  444. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.spec.js.map +0 -1
  445. package/dist/files/BrsFile.Class.spec.d.ts +0 -1
  446. package/dist/files/BrsFile.Class.spec.js +0 -1081
  447. package/dist/files/BrsFile.Class.spec.js.map +0 -1
  448. package/dist/files/BrsFile.spec.d.ts +0 -1
  449. package/dist/files/BrsFile.spec.js +0 -2524
  450. package/dist/files/BrsFile.spec.js.map +0 -1
  451. package/dist/files/XmlFile.spec.d.ts +0 -1
  452. package/dist/files/XmlFile.spec.js +0 -1065
  453. package/dist/files/XmlFile.spec.js.map +0 -1
  454. package/dist/files/tests/imports.spec.d.ts +0 -1
  455. package/dist/files/tests/imports.spec.js +0 -241
  456. package/dist/files/tests/imports.spec.js.map +0 -1
  457. package/dist/lexer/Character.spec.d.ts +0 -1
  458. package/dist/lexer/Character.spec.js +0 -27
  459. package/dist/lexer/Character.spec.js.map +0 -1
  460. package/dist/lexer/Lexer.spec.d.ts +0 -1
  461. package/dist/lexer/Lexer.spec.js +0 -1101
  462. package/dist/lexer/Lexer.spec.js.map +0 -1
  463. package/dist/lexer/index.d.ts +0 -3
  464. package/dist/lexer/index.js +0 -17
  465. package/dist/lexer/index.js.map +0 -1
  466. package/dist/parser/Parser.Class.spec.d.ts +0 -1
  467. package/dist/parser/Parser.Class.spec.js +0 -390
  468. package/dist/parser/Parser.Class.spec.js.map +0 -1
  469. package/dist/parser/Parser.spec.d.ts +0 -4
  470. package/dist/parser/Parser.spec.js +0 -1216
  471. package/dist/parser/Parser.spec.js.map +0 -1
  472. package/dist/parser/SGParser.spec.d.ts +0 -1
  473. package/dist/parser/SGParser.spec.js +0 -145
  474. package/dist/parser/SGParser.spec.js.map +0 -1
  475. package/dist/parser/SGTypes.spec.d.ts +0 -1
  476. package/dist/parser/SGTypes.spec.js +0 -351
  477. package/dist/parser/SGTypes.spec.js.map +0 -1
  478. package/dist/parser/Statement.spec.d.ts +0 -1
  479. package/dist/parser/Statement.spec.js +0 -94
  480. package/dist/parser/Statement.spec.js.map +0 -1
  481. package/dist/parser/index.d.ts +0 -3
  482. package/dist/parser/index.js +0 -16
  483. package/dist/parser/index.js.map +0 -1
  484. package/dist/parser/tests/Parser.spec.d.ts +0 -18
  485. package/dist/parser/tests/Parser.spec.js +0 -35
  486. package/dist/parser/tests/Parser.spec.js.map +0 -1
  487. package/dist/parser/tests/controlFlow/For.spec.d.ts +0 -1
  488. package/dist/parser/tests/controlFlow/For.spec.js +0 -161
  489. package/dist/parser/tests/controlFlow/For.spec.js.map +0 -1
  490. package/dist/parser/tests/controlFlow/ForEach.spec.d.ts +0 -1
  491. package/dist/parser/tests/controlFlow/ForEach.spec.js +0 -106
  492. package/dist/parser/tests/controlFlow/ForEach.spec.js.map +0 -1
  493. package/dist/parser/tests/controlFlow/If.spec.d.ts +0 -1
  494. package/dist/parser/tests/controlFlow/If.spec.js +0 -551
  495. package/dist/parser/tests/controlFlow/If.spec.js.map +0 -1
  496. package/dist/parser/tests/controlFlow/While.spec.d.ts +0 -1
  497. package/dist/parser/tests/controlFlow/While.spec.js +0 -107
  498. package/dist/parser/tests/controlFlow/While.spec.js.map +0 -1
  499. package/dist/parser/tests/expression/Additive.spec.d.ts +0 -1
  500. package/dist/parser/tests/expression/Additive.spec.js +0 -99
  501. package/dist/parser/tests/expression/Additive.spec.js.map +0 -1
  502. package/dist/parser/tests/expression/ArrayLiterals.spec.d.ts +0 -1
  503. package/dist/parser/tests/expression/ArrayLiterals.spec.js +0 -254
  504. package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +0 -1
  505. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.d.ts +0 -1
  506. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +0 -266
  507. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +0 -1
  508. package/dist/parser/tests/expression/Boolean.spec.d.ts +0 -1
  509. package/dist/parser/tests/expression/Boolean.spec.js +0 -83
  510. package/dist/parser/tests/expression/Boolean.spec.js.map +0 -1
  511. package/dist/parser/tests/expression/Call.spec.d.ts +0 -1
  512. package/dist/parser/tests/expression/Call.spec.js +0 -134
  513. package/dist/parser/tests/expression/Call.spec.js.map +0 -1
  514. package/dist/parser/tests/expression/Exponential.spec.d.ts +0 -1
  515. package/dist/parser/tests/expression/Exponential.spec.js +0 -37
  516. package/dist/parser/tests/expression/Exponential.spec.js.map +0 -1
  517. package/dist/parser/tests/expression/Function.spec.d.ts +0 -1
  518. package/dist/parser/tests/expression/Function.spec.js +0 -403
  519. package/dist/parser/tests/expression/Function.spec.js.map +0 -1
  520. package/dist/parser/tests/expression/Indexing.spec.d.ts +0 -1
  521. package/dist/parser/tests/expression/Indexing.spec.js +0 -219
  522. package/dist/parser/tests/expression/Indexing.spec.js.map +0 -1
  523. package/dist/parser/tests/expression/Multiplicative.spec.d.ts +0 -1
  524. package/dist/parser/tests/expression/Multiplicative.spec.js +0 -67
  525. package/dist/parser/tests/expression/Multiplicative.spec.js.map +0 -1
  526. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.d.ts +0 -1
  527. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +0 -201
  528. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +0 -1
  529. package/dist/parser/tests/expression/PrefixUnary.spec.d.ts +0 -1
  530. package/dist/parser/tests/expression/PrefixUnary.spec.js +0 -105
  531. package/dist/parser/tests/expression/PrefixUnary.spec.js.map +0 -1
  532. package/dist/parser/tests/expression/Primary.spec.d.ts +0 -1
  533. package/dist/parser/tests/expression/Primary.spec.js +0 -149
  534. package/dist/parser/tests/expression/Primary.spec.js.map +0 -1
  535. package/dist/parser/tests/expression/Relational.spec.d.ts +0 -1
  536. package/dist/parser/tests/expression/Relational.spec.js +0 -83
  537. package/dist/parser/tests/expression/Relational.spec.js.map +0 -1
  538. package/dist/parser/tests/expression/SourceLiteralExpression.spec.d.ts +0 -1
  539. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +0 -201
  540. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +0 -1
  541. package/dist/parser/tests/expression/TemplateStringExpression.spec.d.ts +0 -1
  542. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +0 -202
  543. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +0 -1
  544. package/dist/parser/tests/expression/TernaryExpression.spec.d.ts +0 -1
  545. package/dist/parser/tests/expression/TernaryExpression.spec.js +0 -323
  546. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +0 -1
  547. package/dist/parser/tests/statement/AssignmentOperators.spec.d.ts +0 -1
  548. package/dist/parser/tests/statement/AssignmentOperators.spec.js +0 -79
  549. package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +0 -1
  550. package/dist/parser/tests/statement/Declaration.spec.d.ts +0 -1
  551. package/dist/parser/tests/statement/Declaration.spec.js +0 -108
  552. package/dist/parser/tests/statement/Declaration.spec.js.map +0 -1
  553. package/dist/parser/tests/statement/Dim.spec.d.ts +0 -1
  554. package/dist/parser/tests/statement/Dim.spec.js +0 -73
  555. package/dist/parser/tests/statement/Dim.spec.js.map +0 -1
  556. package/dist/parser/tests/statement/Function.spec.d.ts +0 -1
  557. package/dist/parser/tests/statement/Function.spec.js +0 -332
  558. package/dist/parser/tests/statement/Function.spec.js.map +0 -1
  559. package/dist/parser/tests/statement/Goto.spec.d.ts +0 -1
  560. package/dist/parser/tests/statement/Goto.spec.js +0 -50
  561. package/dist/parser/tests/statement/Goto.spec.js.map +0 -1
  562. package/dist/parser/tests/statement/Increment.spec.d.ts +0 -1
  563. package/dist/parser/tests/statement/Increment.spec.js +0 -117
  564. package/dist/parser/tests/statement/Increment.spec.js.map +0 -1
  565. package/dist/parser/tests/statement/LibraryStatement.spec.d.ts +0 -1
  566. package/dist/parser/tests/statement/LibraryStatement.spec.js +0 -74
  567. package/dist/parser/tests/statement/LibraryStatement.spec.js.map +0 -1
  568. package/dist/parser/tests/statement/Misc.spec.d.ts +0 -1
  569. package/dist/parser/tests/statement/Misc.spec.js +0 -333
  570. package/dist/parser/tests/statement/Misc.spec.js.map +0 -1
  571. package/dist/parser/tests/statement/PrintStatement.spec.d.ts +0 -1
  572. package/dist/parser/tests/statement/PrintStatement.spec.js +0 -181
  573. package/dist/parser/tests/statement/PrintStatement.spec.js.map +0 -1
  574. package/dist/parser/tests/statement/ReturnStatement.spec.d.ts +0 -1
  575. package/dist/parser/tests/statement/ReturnStatement.spec.js +0 -94
  576. package/dist/parser/tests/statement/ReturnStatement.spec.js.map +0 -1
  577. package/dist/parser/tests/statement/Set.spec.d.ts +0 -1
  578. package/dist/parser/tests/statement/Set.spec.js +0 -218
  579. package/dist/parser/tests/statement/Set.spec.js.map +0 -1
  580. package/dist/parser/tests/statement/Stop.spec.d.ts +0 -1
  581. package/dist/parser/tests/statement/Stop.spec.js +0 -37
  582. package/dist/parser/tests/statement/Stop.spec.js.map +0 -1
  583. package/dist/parser/tests/statement/Throw.spec.d.ts +0 -1
  584. package/dist/parser/tests/statement/Throw.spec.js +0 -35
  585. package/dist/parser/tests/statement/Throw.spec.js.map +0 -1
  586. package/dist/parser/tests/statement/TryCatch.spec.d.ts +0 -1
  587. package/dist/parser/tests/statement/TryCatch.spec.js +0 -140
  588. package/dist/parser/tests/statement/TryCatch.spec.js.map +0 -1
  589. package/dist/preprocessor/Chunk.d.ts +0 -82
  590. package/dist/preprocessor/Chunk.js +0 -77
  591. package/dist/preprocessor/Chunk.js.map +0 -1
  592. package/dist/preprocessor/Manifest.spec.d.ts +0 -0
  593. package/dist/preprocessor/Manifest.spec.js +0 -105
  594. package/dist/preprocessor/Manifest.spec.js.map +0 -1
  595. package/dist/preprocessor/Preprocessor.d.ts +0 -60
  596. package/dist/preprocessor/Preprocessor.js +0 -156
  597. package/dist/preprocessor/Preprocessor.js.map +0 -1
  598. package/dist/preprocessor/Preprocessor.spec.d.ts +0 -1
  599. package/dist/preprocessor/Preprocessor.spec.js +0 -152
  600. package/dist/preprocessor/Preprocessor.spec.js.map +0 -1
  601. package/dist/preprocessor/PreprocessorParser.d.ts +0 -61
  602. package/dist/preprocessor/PreprocessorParser.js +0 -194
  603. package/dist/preprocessor/PreprocessorParser.js.map +0 -1
  604. package/dist/preprocessor/PreprocessorParser.spec.d.ts +0 -1
  605. package/dist/preprocessor/PreprocessorParser.spec.js +0 -116
  606. package/dist/preprocessor/PreprocessorParser.spec.js.map +0 -1
  607. package/dist/preprocessor/index.d.ts +0 -3
  608. package/dist/preprocessor/index.js +0 -16
  609. package/dist/preprocessor/index.js.map +0 -1
  610. package/dist/types/ArrayType.spec.d.ts +0 -1
  611. package/dist/types/ArrayType.spec.js +0 -30
  612. package/dist/types/ArrayType.spec.js.map +0 -1
  613. package/dist/types/BooleanType.spec.d.ts +0 -1
  614. package/dist/types/BooleanType.spec.js +0 -12
  615. package/dist/types/BooleanType.spec.js.map +0 -1
  616. package/dist/types/CustomType.d.ts +0 -10
  617. package/dist/types/CustomType.js +0 -35
  618. package/dist/types/CustomType.js.map +0 -1
  619. package/dist/types/DoubleType.spec.d.ts +0 -1
  620. package/dist/types/DoubleType.spec.js +0 -12
  621. package/dist/types/DoubleType.spec.js.map +0 -1
  622. package/dist/types/DynamicType.spec.d.ts +0 -1
  623. package/dist/types/DynamicType.spec.js +0 -12
  624. package/dist/types/DynamicType.spec.js.map +0 -1
  625. package/dist/types/FloatType.spec.d.ts +0 -1
  626. package/dist/types/FloatType.spec.js +0 -12
  627. package/dist/types/FloatType.spec.js.map +0 -1
  628. package/dist/types/FunctionType.spec.d.ts +0 -1
  629. package/dist/types/FunctionType.spec.js +0 -29
  630. package/dist/types/FunctionType.spec.js.map +0 -1
  631. package/dist/types/IntegerType.spec.d.ts +0 -1
  632. package/dist/types/IntegerType.spec.js +0 -12
  633. package/dist/types/IntegerType.spec.js.map +0 -1
  634. package/dist/types/InvalidType.spec.d.ts +0 -1
  635. package/dist/types/InvalidType.spec.js +0 -12
  636. package/dist/types/InvalidType.spec.js.map +0 -1
  637. package/dist/types/LazyType.d.ts +0 -15
  638. package/dist/types/LazyType.js +0 -32
  639. package/dist/types/LazyType.js.map +0 -1
  640. package/dist/types/LongIntegerType.spec.d.ts +0 -1
  641. package/dist/types/LongIntegerType.spec.js +0 -12
  642. package/dist/types/LongIntegerType.spec.js.map +0 -1
  643. package/dist/types/ObjectType.spec.d.ts +0 -1
  644. package/dist/types/ObjectType.spec.js +0 -12
  645. package/dist/types/ObjectType.spec.js.map +0 -1
  646. package/dist/types/StringType.spec.d.ts +0 -1
  647. package/dist/types/StringType.spec.js +0 -12
  648. package/dist/types/StringType.spec.js.map +0 -1
  649. package/dist/types/VoidType.spec.d.ts +0 -1
  650. package/dist/types/VoidType.spec.js +0 -12
  651. package/dist/types/VoidType.spec.js.map +0 -1
  652. /package/dist/{astUtils/creators.spec.d.ts → lsp/worker/run.d.ts} +0 -0
@@ -6,39 +6,31 @@ 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;
10
- require("array-flat-polyfill");
11
- const glob = require("glob");
9
+ exports.NotificationName = exports.CustomCommands = exports.LanguageServer = void 0;
12
10
  const path = require("path");
13
- const rokuDeploy = require("roku-deploy");
11
+ require("array-flat-polyfill");
14
12
  const node_1 = require("vscode-languageserver/node");
15
13
  const vscode_uri_1 = require("vscode-uri");
16
14
  const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument");
17
- const deferred_1 = require("./deferred");
18
- const DiagnosticMessages_1 = require("./DiagnosticMessages");
19
- const ProgramBuilder_1 = require("./ProgramBuilder");
20
15
  const util_1 = require("./util");
21
- const Logger_1 = require("./Logger");
22
- const Throttler_1 = require("./Throttler");
23
- const KeyedThrottler_1 = require("./KeyedThrottler");
24
16
  const DiagnosticCollection_1 = require("./DiagnosticCollection");
25
- const reflection_1 = require("./astUtils/reflection");
26
17
  const SemanticTokenUtils_1 = require("./SemanticTokenUtils");
18
+ const logging_1 = require("./logging");
19
+ const ignore_1 = require("ignore");
20
+ const micromatch = require("micromatch");
21
+ const PathFilterer_1 = require("./lsp/PathFilterer");
22
+ const ProjectManager_1 = require("./lsp/ProjectManager");
23
+ const fsExtra = require("fs-extra");
24
+ const deferred_1 = require("./deferred");
25
+ const WorkerThreadProject_1 = require("./lsp/worker/WorkerThreadProject");
26
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
27
+ const isEqual = require("lodash.isequal");
27
28
  class LanguageServer {
28
29
  constructor() {
29
- this.connection = undefined;
30
- this.workspaces = [];
31
30
  /**
32
- * The number of milliseconds that should be used for language server typing debouncing
31
+ * The language server protocol connection, used to send and receive all requests and responses
33
32
  */
34
- this.debounceTimeout = 150;
35
- /**
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.
39
- * Also, they should only be created when the file is opened, and destroyed when the file is closed.
40
- */
41
- this.standaloneFileWorkspaces = {};
33
+ this.connection = undefined;
42
34
  this.hasConfigurationCapability = false;
43
35
  /**
44
36
  * Indicates whether the client supports workspace folders
@@ -49,77 +41,84 @@ class LanguageServer {
49
41
  * The text document manager supports full document sync only
50
42
  */
51
43
  this.documents = new node_1.TextDocuments(vscode_languageserver_textdocument_1.TextDocument);
52
- this.keyedThrottler = new KeyedThrottler_1.KeyedThrottler(this.debounceTimeout);
53
- this.validateThrottler = new Throttler_1.Throttler(0);
54
- this.boundValidateAll = this.validateAll.bind(this);
44
+ this.logger = (0, logging_1.createLogger)({
45
+ logLevel: logging_1.LogLevel.log
46
+ });
47
+ /**
48
+ * Pending file changes waiting to be flushed after the debounce period
49
+ */
50
+ this.pendingFileChanges = [];
51
+ /**
52
+ * How long to wait (in ms) after the last file change event before processing the batch.
53
+ * This prevents excessive revalidation during bulk operations like `git checkout` or package installs.
54
+ */
55
+ this.fileChangeDebounceDelay = 300;
56
+ this.workspaceConfigsCache = new Map();
57
+ this.busyStatusIndex = -1;
58
+ this.pathFiltererDisposables = [];
55
59
  this.diagnosticCollection = new DiagnosticCollection_1.DiagnosticCollection();
56
- }
57
- createConnection() {
58
- return node_1.createConnection(node_1.ProposedFeatures.all);
59
- }
60
- validateAllThrottled() {
61
- return this.validateThrottler.run(this.boundValidateAll);
60
+ (0, logging_1.setLspLoggerProps)();
61
+ //replace the workerPool logger with our own so logging info can be synced
62
+ WorkerThreadProject_1.workerPool.logger = this.logger.createLogger();
63
+ this.pathFilterer = new PathFilterer_1.PathFilterer({ logger: this.logger });
64
+ this.projectManager = new ProjectManager_1.ProjectManager({
65
+ pathFilterer: this.pathFilterer,
66
+ logger: this.logger.createLogger()
67
+ });
68
+ //anytime a project emits a collection of diagnostics, send them to the client
69
+ this.projectManager.on('diagnostics', (event) => {
70
+ this.logger.debug(`Received ${event.diagnostics.length} diagnostics from project ${event.project.projectNumber}`);
71
+ this.sendDiagnostics(event).catch(logAndIgnoreError);
72
+ });
73
+ // Send all open document changes whenever a project is activated. This is necessary because at project startup, the project loads files from disk
74
+ // and may not have the latest unsaved file changes. Any existing projects that already use these files will just ignore the changes
75
+ // because the file contents haven't changed.
76
+ this.projectManager.on('project-activate', (event) => {
77
+ //keep logLevel in sync with the most verbose log level found across all projects
78
+ this.syncLogLevel().catch(logAndIgnoreError);
79
+ //resend all open document changes
80
+ const documents = [...this.documents.all()];
81
+ if (documents.length > 0) {
82
+ this.logger.log(`[${util_1.util.getProjectLogName(event.project)}] loaded or changed. Resending all open document changes.`, documents.map(x => x.uri));
83
+ for (const document of this.documents.all()) {
84
+ this.onTextDocumentDidChangeContent({
85
+ document: document
86
+ }).catch(logAndIgnoreError);
87
+ }
88
+ }
89
+ });
90
+ this.projectManager.busyStatusTracker.on('active-runs-change', (event) => {
91
+ this.sendBusyStatus();
92
+ });
62
93
  }
63
94
  //run the server
64
95
  run() {
96
+ var _a;
65
97
  // Create a connection for the server. The connection uses Node's IPC as a transport.
66
- // Also include all preview / proposed LSP features.
67
- this.connection = this.createConnection();
98
+ this.connection = this.establishConnection();
99
+ //disable logger colors when running in LSP mode
100
+ logging_1.logger.enableColor = false;
68
101
  //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);
102
+ this.loggerSubscription = logging_1.logger.subscribe((message) => {
103
+ this.connection.tracer.log(message.argsText);
71
104
  });
72
- this.connection.onInitialize(this.onInitialize.bind(this));
73
- this.connection.onInitialized(this.onInitialized.bind(this)); //eslint-disable-line
74
- this.connection.onDidChangeConfiguration(this.onDidChangeConfiguration.bind(this)); //eslint-disable-line
75
- this.connection.onDidChangeWatchedFiles(this.onDidChangeWatchedFiles.bind(this)); //eslint-disable-line
105
+ //bind all our on* methods that share the same name from connection
106
+ for (const name of Object.getOwnPropertyNames(LanguageServer.prototype)) {
107
+ if (/on+/.test(name) && typeof ((_a = this.connection) === null || _a === void 0 ? void 0 : _a[name]) === 'function') {
108
+ this.connection[name](this[name].bind(this));
109
+ }
110
+ }
111
+ //Register semantic token requests. TODO switch to a more specific connection function call once they actually add it
112
+ this.connection.onRequest(node_1.SemanticTokensRequest.method, this.onFullSemanticTokens.bind(this));
113
+ //file-operation requests live under connection.workspace, so they aren't picked up by the on* auto-bind loop above
114
+ this.connection.workspace.onWillRenameFiles(this.onWillRenameFiles.bind(this));
76
115
  // The content of a text document has changed. This event is emitted
77
116
  // when the text document is first opened, when its content has changed,
78
117
  // or when document is closed without saving (original contents are sent as a change)
79
118
  //
80
- this.documents.onDidChangeContent(async (change) => {
81
- await this.validateTextDocument(change.document);
82
- });
119
+ this.documents.onDidChangeContent(this.onTextDocumentDidChangeContent.bind(this));
83
120
  //whenever a document gets closed
84
- this.documents.onDidClose(async (change) => {
85
- await this.onDocumentClose(change.document);
86
- });
87
- // 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
- });
91
- // This handler resolves additional information for the item selected in
92
- // the completion list.
93
- this.connection.onCompletionResolve(this.onCompletionResolve.bind(this));
94
- this.connection.onHover(this.onHover.bind(this));
95
- this.connection.onExecuteCommand(this.onExecuteCommand.bind(this));
96
- this.connection.onDefinition(this.onDefinition.bind(this));
97
- this.connection.onDocumentSymbol(this.onDocumentSymbol.bind(this));
98
- this.connection.onWorkspaceSymbol(this.onWorkspaceSymbol.bind(this));
99
- this.connection.onSignatureHelp(this.onSignatureHelp.bind(this));
100
- this.connection.onReferences(this.onReferences.bind(this));
101
- this.connection.onCodeAction(this.onCodeAction.bind(this));
102
- //TODO switch to a more specific connection function call once they actually add it
103
- this.connection.onRequest(node_1.SemanticTokensRequest.method, this.onFullSemanticTokens.bind(this));
104
- /*
105
- this.connection.onDidOpenTextDocument((params) => {
106
- // A text document got opened in VSCode.
107
- // params.uri uniquely identifies the document. For documents stored on disk this is a file URI.
108
- // params.text the initial full content of the document.
109
- this.connection.console.log(`${params.textDocument.uri} opened.`);
110
- });
111
- this.connection.onDidChangeTextDocument((params) => {
112
- // The content of a text document did change in VSCode.
113
- // params.uri uniquely identifies the document.
114
- // params.contentChanges describe the content changes to the document.
115
- this.connection.console.log(`${params.textDocument.uri} changed: ${JSON.stringify(params.contentChanges)}`);
116
- });
117
- this.connection.onDidCloseTextDocument((params) => {
118
- // A text document got closed in VSCode.
119
- // params.uri uniquely identifies the document.
120
- this.connection.console.log(`${params.textDocument.uri} closed.`);
121
- });
122
- */
121
+ this.documents.onDidClose(this.onDocumentClose.bind(this));
123
122
  // listen for open, change and close text document events
124
123
  this.documents.listen(this.connection);
125
124
  // Listen on the connection
@@ -127,7 +126,6 @@ class LanguageServer {
127
126
  }
128
127
  /**
129
128
  * Called when the client starts initialization
130
- * @param params
131
129
  */
132
130
  onInitialize(params) {
133
131
  let clientCapabilities = params.capabilities;
@@ -141,7 +139,7 @@ class LanguageServer {
141
139
  textDocumentSync: node_1.TextDocumentSyncKind.Full,
142
140
  // Tell the client that the server supports code completion
143
141
  completionProvider: {
144
- resolveProvider: true,
142
+ resolveProvider: false,
145
143
  //anytime the user types a period, auto-show the completion results
146
144
  triggerCharacters: ['.'],
147
145
  allCommitCharacters: ['.', '@']
@@ -154,58 +152,68 @@ class LanguageServer {
154
152
  },
155
153
  referencesProvider: true,
156
154
  codeActionProvider: {
157
- codeActionKinds: [node_1.CodeActionKind.Refactor]
155
+ codeActionKinds: [
156
+ node_1.CodeActionKind.QuickFix,
157
+ node_1.CodeActionKind.Refactor,
158
+ node_1.CodeActionKind.SourceFixAll
159
+ ]
158
160
  },
159
161
  signatureHelpProvider: {
160
162
  triggerCharacters: ['(', ',']
161
163
  },
162
164
  definitionProvider: true,
163
165
  hoverProvider: true,
166
+ selectionRangeProvider: true,
164
167
  executeCommandProvider: {
165
168
  commands: [
166
169
  CustomCommands.TranspileFile
167
170
  ]
171
+ },
172
+ workspace: {
173
+ fileOperations: {
174
+ willRename: {
175
+ filters: [{
176
+ pattern: {
177
+ glob: '**/*.{bs,brs,xml}',
178
+ matches: 'file'
179
+ }
180
+ }]
181
+ }
182
+ }
168
183
  }
169
184
  }
170
185
  };
171
186
  }
172
187
  /**
173
188
  * Called when the client has finished initializing
174
- * @param params
175
189
  */
176
190
  async onInitialized() {
177
- var _a;
178
- let workspaceCreatedDeferred = new deferred_1.Deferred();
179
- this.initialWorkspacesCreated = workspaceCreatedDeferred.promise;
191
+ this.logger.log('onInitialized');
192
+ //cache a copy of all workspace configurations to use for comparison later
193
+ this.workspaceConfigsCache = new Map((await this.getWorkspaceConfigs()).map(x => [x.workspaceFolder, x]));
194
+ //set our logger to the most verbose logLevel found across any project
195
+ await this.syncLogLevel();
196
+ this.syncProjectActivationConcurrencyLimit();
180
197
  try {
181
198
  if (this.hasConfigurationCapability) {
182
- // Register for all configuration changes.
183
- await this.connection.client.register(node_1.DidChangeConfigurationNotification.type, undefined);
199
+ // register for when the user changes workspace or user settings
200
+ await this.connection.client.register(node_1.DidChangeConfigurationNotification.type, {
201
+ //we only care about when these settings sections change
202
+ section: [
203
+ 'brightscript',
204
+ 'files'
205
+ ]
206
+ });
184
207
  }
185
- //ask the client for all workspace folders
186
- let workspaceFolders = (_a = await this.connection.workspace.getWorkspaceFolders()) !== null && _a !== void 0 ? _a : [];
187
- let workspacePaths = workspaceFolders.map((x) => {
188
- return util_1.util.uriToPath(x.uri);
189
- });
190
- await this.createWorkspaces(workspacePaths);
208
+ //populate the path filterer with the client's include/exclude lists
209
+ await this.rebuildPathFilterer();
210
+ await this.syncProjects();
191
211
  if (this.clientHasWorkspaceFolderCapability) {
212
+ //if the client changes their workspaces, we need to get our projects in sync
192
213
  this.connection.workspace.onDidChangeWorkspaceFolders(async (evt) => {
193
- //remove programs for removed workspace folders
194
- for (let removed of evt.removed) {
195
- let workspacePath = util_1.util.uriToPath(removed.uri);
196
- let workspace = this.workspaces.find((x) => x.workspacePath === workspacePath);
197
- if (workspace) {
198
- workspace.builder.dispose();
199
- this.workspaces.splice(this.workspaces.indexOf(workspace), 1);
200
- }
201
- }
202
- //create programs for new workspace folders
203
- await this.createWorkspaces(evt.added.map((x) => util_1.util.uriToPath(x.uri)));
214
+ await this.syncProjects();
204
215
  });
205
216
  }
206
- await this.waitAllProgramFirstRuns(false);
207
- workspaceCreatedDeferred.resolve();
208
- await this.sendDiagnostics();
209
217
  }
210
218
  catch (e) {
211
219
  this.sendCriticalFailure(`Critical failure during BrighterScript language server startup.
@@ -216,695 +224,510 @@ class LanguageServer {
216
224
  }
217
225
  }
218
226
  /**
219
- * Send a critical failure notification to the client, which should show a notification of some kind
227
+ * Set our logLevel to the most verbose log level found across all projects and workspaces
220
228
  */
221
- sendCriticalFailure(message) {
222
- this.connection.sendNotification('critical-failure', message);
223
- }
224
- /**
225
- * Wait for all programs' first run to complete
226
- */
227
- async waitAllProgramFirstRuns(waitForFirstWorkSpace = true) {
228
- if (waitForFirstWorkSpace) {
229
- await this.initialWorkspacesCreated;
230
- }
231
- let status;
232
- let workspaces = this.getWorkspaces();
233
- for (let workspace of workspaces) {
234
- try {
235
- await workspace.firstRunPromise;
236
- }
237
- catch (e) {
238
- status = 'critical-error';
239
- //the first run failed...that won't change unless we reload the workspace, so replace with resolved promise
240
- //so we don't show this error again
241
- workspace.firstRunPromise = Promise.resolve();
242
- this.sendCriticalFailure(`BrighterScript language server failed to start: \n${e.message}`);
229
+ async syncLogLevel() {
230
+ var _a, _b;
231
+ /**
232
+ * helper to get the logLevel from a list of items and return the item and level (if found), or undefined if not
233
+ */
234
+ const getLogLevel = async (items, fetcher) => {
235
+ const logLevels = await Promise.all(items.map(async (item) => {
236
+ let value = await fetcher(item);
237
+ //force string values to lower case (so we can support things like 'log' or 'Log' or 'LOG')
238
+ if (typeof value === 'string') {
239
+ value = value.toLowerCase();
240
+ }
241
+ const logLevelNumeric = this.logger.getLogLevelNumeric(value);
242
+ if (typeof logLevelNumeric === 'number') {
243
+ return logLevelNumeric;
244
+ }
245
+ else {
246
+ return -1;
247
+ }
248
+ }));
249
+ let idx = logLevels.findIndex(x => x > -1);
250
+ if (idx > -1) {
251
+ const mostVerboseLogLevel = Math.max(...logLevels);
252
+ return {
253
+ logLevel: mostVerboseLogLevel,
254
+ logLevelText: this.logger.getLogLevelText(mostVerboseLogLevel),
255
+ //find the first item having the most verbose logLevel
256
+ item: items[logLevels.findIndex(x => x === mostVerboseLogLevel)]
257
+ };
243
258
  }
259
+ };
260
+ const workspaces = await this.getWorkspaceConfigs();
261
+ let workspaceResult = await getLogLevel(workspaces, workspace => { var _a; return (_a = workspace === null || workspace === void 0 ? void 0 : workspace.languageServer) === null || _a === void 0 ? void 0 : _a.logLevel; });
262
+ if (workspaceResult) {
263
+ this.logger.info(`Setting global logLevel to '${workspaceResult.logLevelText}' based on configuration from workspace '${(_a = workspaceResult === null || workspaceResult === void 0 ? void 0 : workspaceResult.item) === null || _a === void 0 ? void 0 : _a.workspaceFolder}'`);
264
+ this.logger.logLevel = workspaceResult.logLevel;
265
+ return;
266
+ }
267
+ let projectResult = await getLogLevel(this.projectManager.projects, (project) => project.logger.logLevel);
268
+ if (projectResult) {
269
+ this.logger.info(`Setting global logLevel to '${projectResult.logLevelText}' based on project #${(_b = projectResult === null || projectResult === void 0 ? void 0 : projectResult.item) === null || _b === void 0 ? void 0 : _b.projectNumber}`);
270
+ this.logger.logLevel = projectResult.logLevel;
271
+ return;
244
272
  }
245
- this.connection.sendNotification('build-status', status ? status : 'success');
273
+ //use a default level if no other level was found
274
+ this.logger.logLevel = logging_1.LogLevel.log;
246
275
  }
247
276
  /**
248
- * Create project for each new workspace. If the workspace is already known,
249
- * it is skipped.
250
- * @param workspaceFolders
277
+ * Get the project activation concurrency limit from all workspaces and set the project manager's concurrency limit to the lowest value found.
278
+ * This ensures that if the user has multiple workspaces open with different limits,
279
+ * we respect the most restrictive limit to avoid overwhelming the user's machine.
251
280
  */
252
- async createWorkspaces(workspacePaths) {
253
- return Promise.all(workspacePaths.map(async (workspacePath) => this.createWorkspace(workspacePath)));
281
+ syncProjectActivationConcurrencyLimit() {
282
+ const limits = [...this.workspaceConfigsCache]
283
+ .map(x => { var _a, _b; return (_b = (_a = x === null || x === void 0 ? void 0 : x[1]) === null || _a === void 0 ? void 0 : _a.languageServer) === null || _b === void 0 ? void 0 : _b.projectActivationConcurrencyLimit; })
284
+ .filter(x => typeof x === 'number');
285
+ //if we don't have any limits defined, use our default value
286
+ if (limits.length === 0) {
287
+ limits.push(LanguageServer.projectActivationConcurrencyLimitDefault);
288
+ }
289
+ let concurrencyLimit = Math.min(...limits);
290
+ //we must always at least support 1 project activating at a time, otherwise no projects would ever activate
291
+ if (!(concurrencyLimit >= 1)) {
292
+ this.logger.log(`projectActivationConcurrencyLimit was set to ${concurrencyLimit}, which is not a valid value. Defaulting to 1.`);
293
+ concurrencyLimit = 1;
294
+ }
295
+ this.projectManager.projectActivationConcurrencyLimit = concurrencyLimit;
296
+ }
297
+ async onTextDocumentDidChangeContent(event) {
298
+ this.logger.debug('onTextDocumentDidChangeContent', event.document.uri);
299
+ await this.projectManager.handleFileChanges([{
300
+ srcPath: vscode_uri_1.URI.parse(event.document.uri).fsPath,
301
+ type: node_1.FileChangeType.Changed,
302
+ fileContents: event.document.getText(),
303
+ allowStandaloneProject: true
304
+ }]);
254
305
  }
255
306
  /**
256
- * Event handler for when the program wants to load file contents.
257
- * anytime the program wants to load a file, check with our in-memory document cache first
307
+ * Called when watched files changed (add/change/delete).
308
+ * The CLIENT is in charge of what files to watch, so all client
309
+ * implementations should ensure that all valid project
310
+ * file types are watched (.brs,.bs,.xml,manifest, and any json/text/image files)
311
+ *
312
+ * File changes are debounced to batch rapid successive events (e.g. during builds or VCS operations)
313
+ * into a single processing pass, reducing redundant work across projects.
258
314
  */
259
- documentFileResolver(srcPath) {
260
- let pathUri = vscode_uri_1.URI.file(srcPath).toString();
261
- let document = this.documents.get(pathUri);
262
- if (document) {
263
- return document.getText();
264
- }
265
- }
266
- async getConfigFilePath(workspacePath) {
267
- let scopeUri;
268
- if (workspacePath.startsWith('file:')) {
269
- scopeUri = vscode_uri_1.URI.parse(workspacePath).toString();
270
- }
271
- else {
272
- scopeUri = vscode_uri_1.URI.file(workspacePath).toString();
273
- }
274
- //look for config group called "brightscript"
275
- let config = await this.connection.workspace.getConfiguration({
276
- scopeUri: scopeUri,
277
- section: 'brightscript'
278
- });
279
- let configFilePath;
280
- //if there's a setting, we need to find the file or show error if it can't be found
281
- if (config === null || config === void 0 ? void 0 : config.configFile) {
282
- configFilePath = path.resolve(workspacePath, config.configFile);
283
- if (await util_1.util.pathExists(configFilePath)) {
284
- return configFilePath;
285
- }
286
- else {
287
- this.sendCriticalFailure(`Cannot find config file specified in user/workspace settings at '${configFilePath}'`);
288
- }
289
- }
290
- //default to config file path found in the root of the workspace
291
- configFilePath = path.resolve(workspacePath, 'bsconfig.json');
292
- if (await util_1.util.pathExists(configFilePath)) {
293
- return configFilePath;
294
- }
295
- //look for the deprecated `brsconfig.json` file
296
- configFilePath = path.resolve(workspacePath, 'brsconfig.json');
297
- if (await util_1.util.pathExists(configFilePath)) {
298
- return configFilePath;
299
- }
300
- //no config file could be found
301
- return undefined;
302
- }
303
- async createWorkspace(workspacePath) {
304
- let workspace = this.workspaces.find((x) => x.workspacePath === workspacePath);
305
- //skip this workspace if we already have it
306
- if (workspace) {
307
- return;
308
- }
309
- let builder = new ProgramBuilder_1.ProgramBuilder();
310
- //prevent clearing the console on run...this isn't the CLI so we want to keep a full log of everything
311
- builder.allowConsoleClearing = false;
312
- //look for files in our in-memory cache before going to the file system
313
- builder.addFileResolver(this.documentFileResolver.bind(this));
314
- let configFilePath = await this.getConfigFilePath(workspacePath);
315
- let cwd = workspacePath;
316
- //if the config file exists, use it and its folder as cwd
317
- if (configFilePath && await util_1.util.pathExists(configFilePath)) {
318
- cwd = path.dirname(configFilePath);
319
- }
320
- else {
321
- //config file doesn't exist...let `brighterscript` resolve the default way
322
- configFilePath = undefined;
323
- }
324
- let firstRunPromise = builder.run({
325
- cwd: cwd,
326
- project: configFilePath,
327
- watch: false,
328
- createPackage: false,
329
- deploy: false,
330
- copyToStaging: false,
331
- showDiagnosticsInConsole: false
332
- });
333
- firstRunPromise.catch((err) => {
334
- console.error(err);
335
- });
336
- let newWorkspace = {
337
- builder: builder,
338
- firstRunPromise: firstRunPromise,
339
- workspacePath: workspacePath,
340
- isFirstRunComplete: false,
341
- isFirstRunSuccessful: false,
342
- configFilePath: configFilePath,
343
- isStandaloneFileWorkspace: false
344
- };
345
- this.workspaces.push(newWorkspace);
346
- await firstRunPromise.then(() => {
347
- newWorkspace.isFirstRunComplete = true;
348
- newWorkspace.isFirstRunSuccessful = true;
349
- }).catch(() => {
350
- newWorkspace.isFirstRunComplete = true;
351
- newWorkspace.isFirstRunSuccessful = false;
352
- }).then(() => {
353
- //if we found a deprecated brsconfig.json, add a diagnostic warning the user
354
- if (configFilePath && path.basename(configFilePath) === 'brsconfig.json') {
355
- builder.addDiagnostic(configFilePath, Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.brsConfigJsonIsDeprecated()), { range: util_1.util.createRange(0, 0, 0, 0) }));
356
- return this.sendDiagnostics();
357
- }
358
- });
315
+ async onDidChangeWatchedFiles(params) {
316
+ const workspacePaths = (await this.connection.workspace.getWorkspaceFolders()).map(x => util_1.util.uriToPath(x.uri));
317
+ const changes = params.changes
318
+ .map(x => ({
319
+ srcPath: util_1.util.uriToPath(x.uri),
320
+ type: x.type,
321
+ //if this is an open document, allow this file to be loaded in a standalone project (if applicable)
322
+ allowStandaloneProject: this.documents.get(x.uri) !== undefined
323
+ }))
324
+ //exclude all explicit top-level workspace folder paths (to fix a weird macos fs watcher bug that emits events for the workspace folder itself)
325
+ .filter(x => !workspacePaths.includes(x.srcPath));
326
+ this.logger.debug('onDidChangeWatchedFiles', changes);
327
+ //accumulate changes into the pending buffer
328
+ this.pendingFileChanges.push(...changes);
329
+ //reset the debounce timer so we batch rapid successive events
330
+ clearTimeout(this.fileChangeDebounceTimer);
331
+ //use a deferred so callers can await the completion of the flush
332
+ if (!this.pendingFileChangesDeferred) {
333
+ this.pendingFileChangesDeferred = new deferred_1.Deferred();
334
+ }
335
+ const deferred = this.pendingFileChangesDeferred;
336
+ this.fileChangeDebounceTimer = setTimeout(() => {
337
+ void this.flushFileChanges().then(() => deferred.resolve(), (err) => deferred.reject(err));
338
+ }, this.fileChangeDebounceDelay);
339
+ return deferred.promise;
359
340
  }
360
341
  /**
361
- * @param srcPath The absolute path to the source file on disk
342
+ * Flush all pending file changes accumulated during the debounce window
362
343
  */
363
- async createStandaloneFileWorkspace(srcPath) {
364
- //skip this workspace if we already have it
365
- if (this.standaloneFileWorkspaces[srcPath]) {
366
- return this.standaloneFileWorkspaces[srcPath];
367
- }
368
- let builder = new ProgramBuilder_1.ProgramBuilder();
369
- //prevent clearing the console on run...this isn't the CLI so we want to keep a full log of everything
370
- builder.allowConsoleClearing = false;
371
- //look for files in our in-memory cache before going to the file system
372
- builder.addFileResolver(this.documentFileResolver.bind(this));
373
- //get the path to the directory where this file resides
374
- let cwd = path.dirname(srcPath);
375
- //get the closest config file and use most of the settings from that
376
- let configFilePath = await util_1.util.findClosestConfigFile(srcPath);
377
- let project = {};
378
- if (configFilePath) {
379
- project = util_1.util.normalizeAndResolveConfig({ project: configFilePath });
380
- }
381
- //override the rootDir and files array
382
- project.rootDir = cwd;
383
- project.files = [{
384
- src: srcPath,
385
- dest: path.basename(srcPath)
386
- }];
387
- let firstRunPromise = builder.run(Object.assign(Object.assign({}, project), { cwd: cwd, project: configFilePath, watch: false, createPackage: false, deploy: false, copyToStaging: false, diagnosticFilters: [
388
- //hide the "file not referenced by any other file" error..that's expected in a standalone file.
389
- 1013
390
- ] })).catch((err) => {
391
- console.error(err);
344
+ async flushFileChanges() {
345
+ //grab all pending changes and clear the buffer, deduping by srcPath (last event wins)
346
+ const deduped = new Map();
347
+ for (const change of this.pendingFileChanges.splice(0, this.pendingFileChanges.length)) {
348
+ deduped.set(change.srcPath, change);
349
+ }
350
+ const changes = [...deduped.values()];
351
+ this.pendingFileChangesDeferred = undefined;
352
+ //if the client changed any files containing include/exclude patterns, rebuild the path filterer before processing these changes
353
+ if (micromatch.some(changes.map(x => x.srcPath), [
354
+ '**/.gitignore',
355
+ '**/.vscode/settings.json',
356
+ '**/*bsconfig*.json'
357
+ ], {
358
+ dot: true
359
+ })) {
360
+ await this.rebuildPathFilterer();
361
+ }
362
+ //handle the file changes
363
+ await this.projectManager.handleFileChanges(changes);
364
+ }
365
+ async onDocumentClose(event) {
366
+ this.logger.debug('onDocumentClose', event.document.uri);
367
+ await this.projectManager.handleFileClose({
368
+ srcPath: util_1.util.uriToPath(event.document.uri)
392
369
  });
393
- let newWorkspace = {
394
- builder: builder,
395
- firstRunPromise: firstRunPromise,
396
- workspacePath: srcPath,
397
- isFirstRunComplete: false,
398
- isFirstRunSuccessful: false,
399
- configFilePath: configFilePath,
400
- isStandaloneFileWorkspace: true
401
- };
402
- this.standaloneFileWorkspaces[srcPath] = newWorkspace;
403
- await firstRunPromise.then(() => {
404
- newWorkspace.isFirstRunComplete = true;
405
- newWorkspace.isFirstRunSuccessful = true;
406
- }).catch(() => {
407
- newWorkspace.isFirstRunComplete = true;
408
- newWorkspace.isFirstRunSuccessful = false;
409
- });
410
- return newWorkspace;
411
- }
412
- getWorkspaces() {
413
- let workspaces = this.workspaces.slice();
414
- for (let key in this.standaloneFileWorkspaces) {
415
- workspaces.push(this.standaloneFileWorkspaces[key]);
416
- }
417
- return workspaces;
418
370
  }
419
371
  /**
420
372
  * Provide a list of completion items based on the current cursor position
421
- * @param textDocumentPosition
422
373
  */
423
- async onCompletion(uri, position) {
424
- //ensure programs are initialized
425
- await this.waitAllProgramFirstRuns();
426
- let filePath = util_1.util.uriToPath(uri);
427
- //wait until the file has settled
428
- await this.keyedThrottler.onIdleOnce(filePath, true);
429
- let completions = this
430
- .getWorkspaces()
431
- .flatMap(workspace => workspace.builder.program.getCompletions(filePath, position));
432
- for (let completion of completions) {
433
- completion.commitCharacters = ['.'];
434
- }
374
+ async onCompletion(params, cancellationToken, workDoneProgress, resultProgress) {
375
+ this.logger.debug('onCompletion', params, cancellationToken);
376
+ const srcPath = util_1.util.uriToPath(params.textDocument.uri);
377
+ const completions = await this.projectManager.getCompletions({
378
+ srcPath: srcPath,
379
+ position: params.position,
380
+ cancellationToken: cancellationToken
381
+ });
435
382
  return completions;
436
383
  }
437
384
  /**
438
- * Provide a full completion item from the selection
439
- * @param item
440
- */
441
- onCompletionResolve(item) {
442
- if (item.data === 1) {
443
- item.detail = 'TypeScript details';
444
- item.documentation = 'TypeScript documentation';
445
- }
446
- else if (item.data === 2) {
447
- item.detail = 'JavaScript details';
448
- item.documentation = 'JavaScript documentation';
449
- }
450
- return item;
451
- }
452
- async onCodeAction(params) {
453
- //ensure programs are initialized
454
- await this.waitAllProgramFirstRuns();
455
- let srcPath = util_1.util.uriToPath(params.textDocument.uri);
456
- //wait until the file has settled
457
- await this.keyedThrottler.onIdleOnce(srcPath, true);
458
- const codeActions = this
459
- .getWorkspaces()
460
- //skip programs that don't have this file
461
- .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); })
462
- .flatMap(workspace => workspace.builder.program.getCodeActions(srcPath, params.range));
463
- //clone the diagnostics for each code action, since certain diagnostics can have circular reference properties that kill the language server if serialized
464
- for (const codeAction of codeActions) {
465
- if (codeAction.diagnostics) {
466
- codeAction.diagnostics = codeAction.diagnostics.map(x => util_1.util.toDiagnostic(x));
467
- }
468
- }
469
- return codeActions;
470
- }
471
- /**
472
- * Reload all specified workspaces, or all workspaces if no workspaces are specified
473
- */
474
- async reloadWorkspaces(workspaces) {
475
- workspaces = workspaces ? workspaces : this.getWorkspaces();
476
- await Promise.all(workspaces.map(async (workspace) => {
477
- //ensure the workspace has finished starting up
478
- try {
479
- await workspace.firstRunPromise;
480
- }
481
- catch (e) { }
482
- //handle standard workspace
483
- if (workspace.isStandaloneFileWorkspace === false) {
484
- let idx = this.workspaces.indexOf(workspace);
485
- if (idx > -1) {
486
- //remove this workspace
487
- this.workspaces.splice(idx, 1);
488
- //dispose this workspace's resources
489
- workspace.builder.dispose();
490
- }
491
- //create a new workspace/brs program
492
- await this.createWorkspace(workspace.workspacePath);
493
- //handle temp workspace
494
- }
495
- else {
496
- workspace.builder.dispose();
497
- delete this.standaloneFileWorkspaces[workspace.workspacePath];
498
- await this.createStandaloneFileWorkspace(workspace.workspacePath);
499
- }
500
- }));
501
- if (workspaces.length > 0) {
502
- //wait for all of the programs to finish starting up
503
- await this.waitAllProgramFirstRuns();
504
- // valdiate all workspaces
505
- this.validateAllThrottled(); //eslint-disable-line
506
- }
507
- }
508
- getRootDir(workspace) {
509
- var _a, _b, _c;
510
- let options = (_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;
511
- return (_c = options === null || options === void 0 ? void 0 : options.rootDir) !== null && _c !== void 0 ? _c : options === null || options === void 0 ? void 0 : options.cwd;
512
- }
513
- /**
514
- * Sometimes users will alter their bsconfig files array, and will include standalone files.
515
- * If this is the case, those standalone workspaces should be removed because the file was
516
- * included in an actual program now.
517
- *
518
- * Sometimes files that used to be included are now excluded, so those open files need to be re-processed as standalone
519
- */
520
- async synchronizeStandaloneWorkspaces() {
521
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
522
- //remove standalone workspaces that are now included in projects
523
- for (let standaloneFilePath in this.standaloneFileWorkspaces) {
524
- let standaloneWorkspace = this.standaloneFileWorkspaces[standaloneFilePath];
525
- for (let workspace of this.workspaces) {
526
- await standaloneWorkspace.firstRunPromise;
527
- 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));
528
- //destroy this standalone workspace because the file has now been included in an actual workspace,
529
- //or if the workspace wants the file
530
- 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) {
531
- standaloneWorkspace.builder.dispose();
532
- delete this.standaloneFileWorkspaces[standaloneFilePath];
533
- }
534
- }
535
- }
536
- //create standalone workspaces for open files that no longer have a project
537
- let textDocuments = this.documents.all();
538
- outer: for (let textDocument of textDocuments) {
539
- let filePath = vscode_uri_1.URI.parse(textDocument.uri).fsPath;
540
- let workspaces = this.getWorkspaces();
541
- for (let workspace of workspaces) {
542
- 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));
543
- //if this workspace has the file, or it wants the file, do NOT make a standalone workspace for this file
544
- 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) {
545
- continue outer;
546
- }
547
- }
548
- //if we got here, no workspace has this file, so make a standalone file workspace
549
- let workspace = await this.createStandaloneFileWorkspace(filePath);
550
- await workspace.firstRunPromise;
551
- }
552
- }
553
- async onDidChangeConfiguration() {
554
- if (this.hasConfigurationCapability) {
555
- await this.reloadWorkspaces();
556
- // Reset all cached document settings
557
- }
558
- else {
559
- // this.globalSettings = <ExampleSettings>(
560
- // (change.settings.languageServerExample || this.defaultSettings)
561
- // );
562
- }
563
- }
564
- /**
565
- * Called when watched files changed (add/change/delete).
566
- * The CLIENT is in charge of what files to watch, so all client
567
- * implementations should ensure that all valid project
568
- * file types are watched (.brs,.bs,.xml,manifest, and any json/text/image files)
569
- * @param params
385
+ * Get a list of workspaces, and their configurations.
386
+ * Get only the settings for the workspace that are relevant to the language server. We do this so we can cache this object for use in change detection in the future.
570
387
  */
571
- async onDidChangeWatchedFiles(params) {
572
- //ensure programs are initialized
573
- await this.waitAllProgramFirstRuns();
574
- this.connection.sendNotification('build-status', 'building');
575
- let workspaces = this.getWorkspaces();
576
- //convert all file paths to absolute paths
577
- let changes = params.changes.map(x => {
388
+ async getWorkspaceConfigs() {
389
+ var _a;
390
+ //get all workspace folders (we'll use these to get settings)
391
+ let workspaces = await Promise.all(((_a = await this.connection.workspace.getWorkspaceFolders()) !== null && _a !== void 0 ? _a : []).map(async (x) => {
392
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
393
+ const workspaceFolder = util_1.util.uriToPath(x.uri);
394
+ const brightscriptConfig = await this.getClientConfiguration(x.uri, 'brightscript');
578
395
  return {
579
- type: x.type,
580
- srcPath: util_1.standardizePath `${vscode_uri_1.URI.parse(x.uri).fsPath}`
581
- };
582
- });
583
- let keys = changes.map(x => x.srcPath);
584
- //filter the list of changes to only the ones that made it through the debounce unscathed
585
- changes = changes.filter(x => keys.includes(x.srcPath));
586
- //if we have changes to work with
587
- if (changes.length > 0) {
588
- //reload any workspace whose bsconfig.json file has changed
589
- {
590
- let workspacesToReload = [];
591
- //get the file paths as a string array
592
- let filePaths = changes.map((x) => x.srcPath);
593
- for (let workspace of workspaces) {
594
- if (workspace.configFilePath && filePaths.includes(workspace.configFilePath)) {
595
- workspacesToReload.push(workspace);
596
- }
396
+ workspaceFolder: workspaceFolder,
397
+ excludePatterns: await this.getWorkspaceExcludeGlobs(workspaceFolder),
398
+ projects: this.normalizeProjectPaths(workspaceFolder, brightscriptConfig === null || brightscriptConfig === void 0 ? void 0 : brightscriptConfig.projects),
399
+ languageServer: {
400
+ enableThreading: (_b = (_a = brightscriptConfig === null || brightscriptConfig === void 0 ? void 0 : brightscriptConfig.languageServer) === null || _a === void 0 ? void 0 : _a.enableThreading) !== null && _b !== void 0 ? _b : LanguageServer.enableThreadingDefault,
401
+ enableProjectDiscovery: (_d = (_c = brightscriptConfig === null || brightscriptConfig === void 0 ? void 0 : brightscriptConfig.languageServer) === null || _c === void 0 ? void 0 : _c.enableProjectDiscovery) !== null && _d !== void 0 ? _d : LanguageServer.enableProjectDiscoveryDefault,
402
+ projectDiscoveryMaxDepth: (_f = (_e = brightscriptConfig === null || brightscriptConfig === void 0 ? void 0 : brightscriptConfig.languageServer) === null || _e === void 0 ? void 0 : _e.projectDiscoveryMaxDepth) !== null && _f !== void 0 ? _f : 15,
403
+ projectDiscoveryExclude: (_g = brightscriptConfig === null || brightscriptConfig === void 0 ? void 0 : brightscriptConfig.languageServer) === null || _g === void 0 ? void 0 : _g.projectDiscoveryExclude,
404
+ logLevel: (_h = brightscriptConfig === null || brightscriptConfig === void 0 ? void 0 : brightscriptConfig.languageServer) === null || _h === void 0 ? void 0 : _h.logLevel,
405
+ projectActivationConcurrencyLimit: (_j = brightscriptConfig === null || brightscriptConfig === void 0 ? void 0 : brightscriptConfig.languageServer) === null || _j === void 0 ? void 0 : _j.projectActivationConcurrencyLimit
597
406
  }
598
- if (workspacesToReload.length > 0) {
599
- //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
600
- //reload any workspaces that need to be reloaded
601
- await this.reloadWorkspaces(workspacesToReload);
602
- }
603
- //set the list of workspaces to non-reloaded workspaces
604
- workspaces = workspaces.filter(x => !workspacesToReload.includes(x));
605
- }
606
- //convert created folders into a list of files of their contents
607
- const directoryChanges = changes
608
- //get only creation items
609
- .filter(change => change.type === node_1.FileChangeType.Created)
610
- //keep only the directories
611
- .filter(change => util_1.util.isDirectorySync(change.srcPath));
612
- //remove the created directories from the changes array (we will add back each of their files next)
613
- changes = changes.filter(x => !directoryChanges.includes(x));
614
- //look up every file in each of the newly added directories
615
- const newFileChanges = directoryChanges
616
- //take just the path
617
- .map(x => x.srcPath)
618
- //exclude the roku deploy staging folder
619
- .filter(dirPath => !dirPath.includes('.roku-deploy-staging'))
620
- //get the files for each folder recursively
621
- .flatMap(dirPath => {
622
- //create a glob pattern to match all files
623
- let pattern = rokuDeploy.util.toForwardSlashes(`${dirPath}/**/*`);
624
- let files = glob.sync(pattern, {
625
- absolute: true
626
- });
627
- return files.map(x => {
628
- return {
629
- type: node_1.FileChangeType.Created,
630
- srcPath: util_1.standardizePath `${x}`
631
- };
632
- });
633
- });
634
- //add the new file changes to the changes array.
635
- changes.push(...newFileChanges);
636
- //give every workspace the chance to handle file changes
637
- await Promise.all(workspaces.map((workspace) => this.handleFileChanges(workspace, changes)));
638
- }
639
- this.connection.sendNotification('build-status', 'success');
640
- }
641
- /**
642
- * This only operates on files that match the specified files globs, so it is safe to throw
643
- * any file changes you receive with no unexpected side-effects
644
- * @param changes
645
- */
646
- async handleFileChanges(workspace, changes) {
647
- //this loop assumes paths are both file paths and folder paths, which eliminates the need to detect.
648
- //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
649
- let consumeCount = 0;
650
- await Promise.all(changes.map(async (change) => {
651
- await this.keyedThrottler.run(change.srcPath, async () => {
652
- consumeCount += await this.handleFileChange(workspace, change) ? 1 : 0;
653
- });
407
+ };
654
408
  }));
655
- if (consumeCount > 0) {
656
- await this.validateAllThrottled();
657
- }
409
+ return workspaces;
658
410
  }
659
411
  /**
660
- * This only operates on files that match the specified files globs, so it is safe to throw
661
- * any file changes you receive with no unexpected side-effects
662
- * @param changes
412
+ * Extract project paths from settings' projects list, expanding the workspaceFolder variable if necessary
663
413
  */
664
- async handleFileChange(workspace, change) {
665
- const program = workspace.builder.program;
666
- const options = workspace.builder.options;
667
- const rootDir = workspace.builder.rootDir;
668
- //deleted
669
- if (change.type === node_1.FileChangeType.Deleted) {
670
- //try to act on this path as a directory
671
- workspace.builder.program.removeFilesInFolder(change.srcPath);
672
- //if this is a file loaded in the program, remove it
673
- if (program.hasFile(change.srcPath)) {
674
- program.removeFile(change.srcPath);
675
- return true;
414
+ normalizeProjectPaths(workspaceFolder, projects) {
415
+ return projects === null || projects === void 0 ? void 0 : projects.reduce((acc, project) => {
416
+ if (typeof project === 'string') {
417
+ acc.push({ path: project });
676
418
  }
677
- else {
678
- return false;
419
+ else if (typeof project.path === 'string') {
420
+ acc.push(project);
679
421
  }
680
- //created
681
- }
682
- else if (change.type === node_1.FileChangeType.Created) {
683
- // thanks to `onDidChangeWatchedFiles`, we can safely assume that all "Created" changes are file paths, (not directories)
684
- //get the dest path for this file.
685
- let destPath = rokuDeploy.getDestPath(change.srcPath, options.files, rootDir);
686
- //if we got a dest path, then the program wants this file
687
- if (destPath) {
688
- program.setFile({
689
- src: change.srcPath,
690
- dest: rokuDeploy.getDestPath(change.srcPath, options.files, rootDir)
691
- }, await workspace.builder.getFileContents(change.srcPath));
692
- return true;
693
- }
694
- else {
695
- //no dest path means the program doesn't want this file
696
- return false;
697
- }
698
- //changed
699
- }
700
- else if (program.hasFile(change.srcPath)) {
701
- //sometimes "changed" events are emitted on files that were actually deleted,
702
- //so determine file existance and act accordingly
703
- if (await util_1.util.pathExists(change.srcPath)) {
704
- program.setFile({
705
- src: change.srcPath,
706
- dest: rokuDeploy.getDestPath(change.srcPath, options.files, rootDir)
707
- }, await workspace.builder.getFileContents(change.srcPath));
708
- }
709
- else {
710
- program.removeFile(change.srcPath);
711
- }
712
- return true;
422
+ return acc;
423
+ }, []).map(project => (Object.assign(Object.assign({}, project), {
424
+ // eslint-disable-next-line no-template-curly-in-string
425
+ path: util_1.util.standardizePath(project.path.replace('${workspaceFolder}', workspaceFolder)) })));
426
+ }
427
+ async onDidChangeConfiguration(args) {
428
+ this.logger.log('onDidChangeConfiguration', 'Reloading all projects');
429
+ const configs = new Map((await this.getWorkspaceConfigs()).map(x => [x.workspaceFolder, x]));
430
+ //find any changed configs. This includes newly created workspaces, deleted workspaces, etc.
431
+ //TODO: enhance this to only reload specific projects, depending on the change
432
+ if (!isEqual(configs, this.workspaceConfigsCache)) {
433
+ //now that we've processed any config diffs, update the cached copy of them
434
+ this.workspaceConfigsCache = configs;
435
+ this.syncProjectActivationConcurrencyLimit();
436
+ //if configuration changed, rebuild the path filterer
437
+ await this.rebuildPathFilterer();
438
+ //if the user changes any user/workspace config settings, just mass-reload all projects
439
+ await this.syncProjects(true);
713
440
  }
714
441
  }
715
442
  async onHover(params) {
716
- //ensure programs are initialized
717
- await this.waitAllProgramFirstRuns();
718
- let srcPath = util_1.util.uriToPath(params.textDocument.uri);
719
- let workspaces = this.getWorkspaces();
720
- let hovers = await Promise.all(Array.prototype.concat.call([], workspaces.map(async (x) => x.builder.program.getHover(srcPath, params.position))));
721
- //return the first non-falsey hover. TODO is there a way to handle multiple hover results?
722
- let hover = hovers.filter((x) => !!x)[0];
723
- //TODO improve this to support more than just .brs files
724
- if (hover === null || hover === void 0 ? void 0 : hover.contents) {
725
- //create fenced code block to get colorization
726
- hover.contents = {
727
- //TODO - make the program.getHover call figure out what language this is for
728
- language: 'brightscript',
729
- value: hover.contents
730
- };
731
- }
732
- return hover;
733
- }
734
- async onDocumentClose(textDocument) {
735
- let filePath = vscode_uri_1.URI.parse(textDocument.uri).fsPath;
736
- let standaloneFileWorkspace = this.standaloneFileWorkspaces[filePath];
737
- //if this was a temp file, close it
738
- if (standaloneFileWorkspace) {
739
- await standaloneFileWorkspace.firstRunPromise;
740
- standaloneFileWorkspace.builder.dispose();
741
- delete this.standaloneFileWorkspaces[filePath];
742
- await this.sendDiagnostics();
743
- }
744
- }
745
- async validateTextDocument(textDocument) {
746
- //ensure programs are initialized
747
- await this.waitAllProgramFirstRuns();
748
- let filePath = vscode_uri_1.URI.parse(textDocument.uri).fsPath;
749
- try {
750
- //throttle file processing. first call is run immediately, and then the last call is processed.
751
- await this.keyedThrottler.run(filePath, () => {
752
- var _a;
753
- this.connection.sendNotification('build-status', 'building');
754
- let documentText = textDocument.getText();
755
- for (const workspace of this.getWorkspaces()) {
756
- //only add or replace existing files. All of the files in the project should
757
- //have already been loaded by other means
758
- if (workspace.builder.program.hasFile(filePath)) {
759
- let rootDir = (_a = workspace.builder.program.options.rootDir) !== null && _a !== void 0 ? _a : workspace.builder.program.options.cwd;
760
- let dest = rokuDeploy.getDestPath(filePath, workspace.builder.program.options.files, rootDir);
761
- workspace.builder.program.setFile({
762
- src: filePath,
763
- dest: dest
764
- }, documentText);
765
- }
766
- }
767
- });
768
- // validate all workspaces
769
- await this.validateAllThrottled();
770
- }
771
- catch (e) {
772
- this.sendCriticalFailure(`Critical error parsing/ validating ${filePath}: ${e.message}`);
773
- }
774
- }
775
- async validateAll() {
776
- var _a;
777
- try {
778
- //synchronize parsing for open files that were included/excluded from projects
779
- await this.synchronizeStandaloneWorkspaces();
780
- let workspaces = this.getWorkspaces();
781
- //validate all programs
782
- await Promise.all(workspaces.map((x) => x.builder.program.validate()));
783
- await this.sendDiagnostics();
784
- }
785
- catch (e) {
786
- this.connection.console.error(e);
787
- this.sendCriticalFailure(`Critical error validating workspace: ${e.message}${(_a = e.stack) !== null && _a !== void 0 ? _a : ''}`);
788
- }
789
- this.connection.sendNotification('build-status', 'success');
443
+ this.logger.debug('onHover', params);
444
+ const srcPath = util_1.util.uriToPath(params.textDocument.uri);
445
+ const result = await this.projectManager.getHover({ srcPath: srcPath, position: params.position });
446
+ return result;
790
447
  }
791
448
  async onWorkspaceSymbol(params) {
792
- await this.waitAllProgramFirstRuns();
793
- const results = util_1.util.flatMap(await Promise.all(this.getWorkspaces().map(workspace => {
794
- return workspace.builder.program.getWorkspaceSymbols();
795
- })), c => c);
796
- // Remove duplicates
797
- const allSymbols = Object.values(results.reduce((map, symbol) => {
798
- const key = symbol.location.uri + symbol.name;
799
- map[key] = symbol;
800
- return map;
801
- }, {}));
802
- return allSymbols;
449
+ this.logger.debug('onWorkspaceSymbol', params);
450
+ const result = await this.projectManager.getWorkspaceSymbol();
451
+ return result;
452
+ }
453
+ async onSelectionRanges(params) {
454
+ this.logger.debug('onSelectionRanges', params);
455
+ const srcPath = util_1.util.uriToPath(params.textDocument.uri);
456
+ return this.projectManager.getSelectionRanges({ srcPath: srcPath, positions: params.positions });
803
457
  }
804
458
  async onDocumentSymbol(params) {
805
- await this.waitAllProgramFirstRuns();
806
- await this.keyedThrottler.onIdleOnce(util_1.util.uriToPath(params.textDocument.uri), true);
459
+ this.logger.debug('onDocumentSymbol', params);
807
460
  const srcPath = util_1.util.uriToPath(params.textDocument.uri);
808
- for (const workspace of this.getWorkspaces()) {
809
- const file = workspace.builder.program.getFile(srcPath);
810
- if (reflection_1.isBrsFile(file)) {
811
- return file.getDocumentSymbols();
812
- }
813
- }
461
+ const result = await this.projectManager.getDocumentSymbol({ srcPath: srcPath });
462
+ return result;
814
463
  }
815
464
  async onDefinition(params) {
816
- await this.waitAllProgramFirstRuns();
465
+ this.logger.debug('onDefinition', params);
817
466
  const srcPath = util_1.util.uriToPath(params.textDocument.uri);
818
- const results = util_1.util.flatMap(await Promise.all(this.getWorkspaces().map(workspace => {
819
- return workspace.builder.program.getDefinition(srcPath, params.position);
820
- })), c => c);
821
- return results;
467
+ const result = this.projectManager.getDefinition({ srcPath: srcPath, position: params.position });
468
+ return result;
822
469
  }
823
470
  async onSignatureHelp(params) {
824
- var _a, _b, _c;
825
- await this.waitAllProgramFirstRuns();
826
- const filepath = util_1.util.uriToPath(params.textDocument.uri);
827
- await this.keyedThrottler.onIdleOnce(filepath, true);
828
- try {
829
- const signatures = util_1.util.flatMap(await Promise.all(this.getWorkspaces().map(workspace => workspace.builder.program.getSignatureHelp(filepath, params.position))), c => c);
830
- const activeSignature = signatures.length > 0 ? 0 : null;
831
- const activeParameter = activeSignature >= 0 ? (_a = signatures[activeSignature]) === null || _a === void 0 ? void 0 : _a.index : null;
832
- let results = {
833
- signatures: signatures.map((s) => s.signature),
834
- activeSignature: activeSignature,
835
- activeParameter: activeParameter
836
- };
837
- return results;
471
+ this.logger.debug('onSignatureHelp', params);
472
+ const srcPath = util_1.util.uriToPath(params.textDocument.uri);
473
+ const result = await this.projectManager.getSignatureHelp({ srcPath: srcPath, position: params.position });
474
+ if (result) {
475
+ return result;
838
476
  }
839
- catch (e) {
840
- this.connection.console.error(`error in onSignatureHelp: ${(_c = (_b = e.stack) !== null && _b !== void 0 ? _b : e.message) !== null && _c !== void 0 ? _c : e}`);
477
+ else {
841
478
  return {
842
479
  signatures: [],
843
- activeSignature: 0,
844
- activeParameter: 0
480
+ activeSignature: null,
481
+ activeParameter: null
845
482
  };
846
483
  }
847
484
  }
848
485
  async onReferences(params) {
849
- await this.waitAllProgramFirstRuns();
850
- const position = params.position;
486
+ this.logger.debug('onReferences', params);
851
487
  const srcPath = util_1.util.uriToPath(params.textDocument.uri);
852
- const results = util_1.util.flatMap(await Promise.all(this.getWorkspaces().map(workspace => {
853
- return workspace.builder.program.getReferences(srcPath, position);
854
- })), c => c);
855
- return results.filter((r) => r);
488
+ const result = await this.projectManager.getReferences({ srcPath: srcPath, position: params.position });
489
+ return result !== null && result !== void 0 ? result : [];
490
+ }
491
+ async onWillRenameFiles(params) {
492
+ var _a, _b;
493
+ var _c;
494
+ this.logger.debug('onWillRenameFiles', params);
495
+ const changes = {};
496
+ for (const file of (_a = params.files) !== null && _a !== void 0 ? _a : []) {
497
+ const oldSrcPath = util_1.util.uriToPath(file.oldUri);
498
+ const newSrcPath = util_1.util.uriToPath(file.newUri);
499
+ const edits = await this.projectManager.getFileRenameEdits({ oldSrcPath: oldSrcPath, newSrcPath: newSrcPath });
500
+ for (const edit of edits) {
501
+ ((_b = changes[_c = edit.uri]) !== null && _b !== void 0 ? _b : (changes[_c] = [])).push({
502
+ range: edit.range,
503
+ newText: edit.newText
504
+ });
505
+ }
506
+ }
507
+ if (Object.keys(changes).length === 0) {
508
+ return null;
509
+ }
510
+ return { changes: changes };
856
511
  }
857
512
  async onFullSemanticTokens(params) {
858
- await this.waitAllProgramFirstRuns();
859
- await this.keyedThrottler.onIdleOnce(util_1.util.uriToPath(params.textDocument.uri), true);
513
+ this.logger.debug('onFullSemanticTokens', params);
860
514
  const srcPath = util_1.util.uriToPath(params.textDocument.uri);
861
- for (const workspace of this.workspaces) {
862
- //find the first program that has this file, since it would be incredibly inefficient to generate semantic tokens for the same file multiple times.
863
- if (workspace.builder.program.hasFile(srcPath)) {
864
- let semanticTokens = workspace.builder.program.getSemanticTokens(srcPath);
865
- return {
866
- data: SemanticTokenUtils_1.encodeSemanticTokens(semanticTokens)
867
- };
868
- }
869
- }
515
+ const result = await this.projectManager.getSemanticTokens({ srcPath: srcPath });
516
+ return {
517
+ data: (0, SemanticTokenUtils_1.encodeSemanticTokens)(result)
518
+ };
870
519
  }
871
- async sendDiagnostics() {
872
- //Get only the changes to diagnostics since the last time we sent them to the client
873
- const patch = await this.diagnosticCollection.getPatch(this.workspaces);
874
- for (let filePath in patch) {
875
- const diagnostics = patch[filePath].map(d => util_1.util.toDiagnostic(d));
876
- this.connection.sendDiagnostics({
877
- uri: vscode_uri_1.URI.file(filePath).toString(),
878
- diagnostics: diagnostics
879
- });
880
- }
520
+ async onCodeAction(params) {
521
+ var _a, _b;
522
+ this.logger.debug('onCodeAction', params);
523
+ const srcPath = util_1.util.uriToPath(params.textDocument.uri);
524
+ const requestedKinds = (_b = (_a = params.context) === null || _a === void 0 ? void 0 : _a.only) !== null && _b !== void 0 ? _b : [];
525
+ const wantsAnyKind = requestedKinds.length === 0;
526
+ // Fix-all is opt-in and expensive, so only fetch when the client asks for it.
527
+ const fixAllKind = node_1.CodeActionKind.SourceFixAll;
528
+ const wantsFixAll = wantsAnyKind ||
529
+ requestedKinds.some(kind => kind.startsWith(fixAllKind) || fixAllKind.startsWith(kind));
530
+ // Standard actions (quickfix, refactor, etc.) all come through getCodeActions,
531
+ // so only skip that pipeline when the client explicitly asked for fix-all only.
532
+ const wantsStandardActions = wantsAnyKind ||
533
+ requestedKinds.some(kind => !kind.startsWith(fixAllKind));
534
+ const [standardActions, fixAllActions] = await Promise.all([
535
+ wantsStandardActions ? this.projectManager.getCodeActions({ srcPath: srcPath, range: params.range }) : [],
536
+ wantsFixAll ? this.projectManager.getFixAllCodeActions({ srcPath: srcPath }) : []
537
+ ]);
538
+ const result = [...(standardActions !== null && standardActions !== void 0 ? standardActions : []), ...(fixAllActions !== null && fixAllActions !== void 0 ? fixAllActions : [])];
539
+ // filter out any code actions with a kind that the client did not ask for (if the client specified any kinds at all)
540
+ if (!wantsAnyKind) {
541
+ return result.filter(x => x.kind && requestedKinds.some(only => x.kind === only || x.kind.startsWith(only + '.')));
542
+ }
543
+ return result;
881
544
  }
882
545
  async onExecuteCommand(params) {
883
- await this.waitAllProgramFirstRuns();
546
+ this.logger.debug('onExecuteCommand', params);
884
547
  if (params.command === CustomCommands.TranspileFile) {
885
- return this.transpileFile(params.arguments[0]);
548
+ const args = {
549
+ srcPath: params.arguments[0]
550
+ };
551
+ const result = await this.projectManager.transpileFile(args);
552
+ //back-compat: include `pathAbsolute` property so older vscode versions still work
553
+ result.pathAbsolute = result.srcPath;
554
+ return result;
886
555
  }
887
556
  }
888
557
  /**
889
- * @param srcPath The absolute path to the source file on disk
558
+ * Establish a connection to the client if not already connected
559
+ */
560
+ establishConnection() {
561
+ if (!this.connection) {
562
+ this.connection = (0, node_1.createConnection)(node_1.ProposedFeatures.all);
563
+ }
564
+ return this.connection;
565
+ }
566
+ /**
567
+ * Send a new busy status notification to the client based on the current busy status
568
+ */
569
+ sendBusyStatus() {
570
+ var _a;
571
+ this.busyStatusIndex = ++this.busyStatusIndex <= 0 ? 0 : this.busyStatusIndex;
572
+ (_a = this.connection.sendNotification(NotificationName.busyStatus, {
573
+ status: this.projectManager.busyStatusTracker.status,
574
+ timestamp: Date.now(),
575
+ index: this.busyStatusIndex,
576
+ activeRuns: [
577
+ //extract only specific information from the active run so we know what's going on
578
+ ...this.projectManager.busyStatusTracker.activeRuns.map(x => ({
579
+ scope: util_1.util.getProjectLogName(x.scope),
580
+ label: x.label,
581
+ startTime: x.startTime.getTime()
582
+ }))
583
+ ]
584
+ })) === null || _a === void 0 ? void 0 : _a.catch(logAndIgnoreError);
585
+ }
586
+ /**
587
+ * Populate the path filterer with the client's include/exclude lists and the projects include lists
588
+ * @returns the instance of the path filterer
589
+ */
590
+ async rebuildPathFilterer() {
591
+ var _a;
592
+ //dispose of any previous pathFilterer disposables
593
+ (_a = this.pathFiltererDisposables) === null || _a === void 0 ? void 0 : _a.forEach(dispose => dispose());
594
+ //keep track of all the pathFilterer disposables so we can dispose them later
595
+ this.pathFiltererDisposables = [];
596
+ const workspaceConfigs = await this.getWorkspaceConfigs();
597
+ await Promise.all(workspaceConfigs.map(async (workspaceConfig) => {
598
+ const rootDir = util_1.util.uriToPath(workspaceConfig.workspaceFolder);
599
+ //always exclude everything from these common folders
600
+ this.pathFiltererDisposables.push(this.pathFilterer.registerExcludeList(rootDir, [
601
+ '**/node_modules/**/*',
602
+ '**/.git/**/*',
603
+ 'out/**/*',
604
+ '**/.roku-deploy-staging/**/*'
605
+ ]));
606
+ //get any `files.exclude` patterns from the client from this workspace
607
+ this.pathFiltererDisposables.push(this.pathFilterer.registerExcludeList(rootDir, workspaceConfig.excludePatterns));
608
+ //get any .gitignore patterns from the client from this workspace
609
+ const gitignorePath = path.resolve(rootDir, '.gitignore');
610
+ if (await fsExtra.pathExists(gitignorePath)) {
611
+ const matcher = (0, ignore_1.default)({ ignoreCase: true }).add(fsExtra.readFileSync(gitignorePath).toString());
612
+ this.pathFiltererDisposables.push(this.pathFilterer.registerExcludeMatcher((p) => {
613
+ const relPath = path.relative(rootDir, p);
614
+ if (ignore_1.default.isPathValid(relPath)) {
615
+ return matcher.test(relPath).ignored;
616
+ }
617
+ else {
618
+ //we do not have a valid relative path, so we cannot determine if it is ignored...thus it is NOT ignored
619
+ return false;
620
+ }
621
+ }));
622
+ }
623
+ }));
624
+ this.logger.log('pathFilterer successfully reconstructed');
625
+ return this.pathFilterer;
626
+ }
627
+ /**
628
+ * Ask the client for the list of `files.exclude` and `files.watcherExclude` patterns. Useful when determining if we should process a file
890
629
  */
891
- async transpileFile(srcPath) {
892
- //wait all program first runs
893
- await this.waitAllProgramFirstRuns();
894
- let workspaces = this.getWorkspaces();
895
- //find the first workspace that has this file
896
- for (let workspace of workspaces) {
897
- if (workspace.builder.program.hasFile(srcPath)) {
898
- return workspace.builder.program.getTranspiledFileContents(srcPath);
630
+ async getWorkspaceExcludeGlobs(workspaceFolder) {
631
+ var _a;
632
+ const filesConfig = await this.getClientConfiguration(workspaceFolder, 'files');
633
+ const searchConfig = await this.getClientConfiguration(workspaceFolder, 'search');
634
+ const languageServerConfig = await this.getClientConfiguration(workspaceFolder, 'brightscript');
635
+ return [
636
+ ...this.extractExcludes(filesConfig === null || filesConfig === void 0 ? void 0 : filesConfig.exclude),
637
+ ...this.extractExcludes(filesConfig === null || filesConfig === void 0 ? void 0 : filesConfig.watcherExclude),
638
+ ...this.extractExcludes(searchConfig === null || searchConfig === void 0 ? void 0 : searchConfig.exclude),
639
+ ...this.extractExcludes((_a = languageServerConfig === null || languageServerConfig === void 0 ? void 0 : languageServerConfig.languageServer) === null || _a === void 0 ? void 0 : _a.projectDiscoveryExclude)
640
+ ];
641
+ }
642
+ extractExcludes(exclude) {
643
+ //if the exclude is not defined, return an empty array
644
+ if (!exclude) {
645
+ return [];
646
+ }
647
+ return Object
648
+ .keys(exclude)
649
+ .filter(x => exclude[x])
650
+ //vscode files.exclude patterns support ignoring folders without needing to add `**/*`. So for our purposes, we need to
651
+ //append **/* to everything without a file extension or magic at the end
652
+ .map(pattern => {
653
+ const result = [
654
+ //send the pattern as-is (this handles weird cases and exact file matches)
655
+ pattern
656
+ ];
657
+ //treat the pattern as a directory (no harm in doing this because if it's a file, the pattern will just never match anything)
658
+ if (!pattern.endsWith('/**/*')) {
659
+ result.push(`${pattern}/**/*`);
899
660
  }
661
+ return result;
662
+ })
663
+ .flat(1);
664
+ }
665
+ /**
666
+ * Ask the project manager to sync all projects found within the list of workspaces
667
+ * @param forceReload if true, all projects are discarded and recreated from scratch
668
+ */
669
+ async syncProjects(forceReload = false) {
670
+ const workspaces = await this.getWorkspaceConfigs();
671
+ await this.projectManager.syncProjects(workspaces, forceReload);
672
+ //set our logLevel to the most verbose log level found across all projects and workspaces
673
+ await this.syncLogLevel();
674
+ }
675
+ /**
676
+ * Given a workspaceFolder path, get the specified configuration from the client (if applicable).
677
+ * Be sure to use optional chaining to traverse the result in case that configuration doesn't exist or the client doesn't support `getConfiguration`
678
+ * @param workspaceFolder the folder for the workspace in the client
679
+ */
680
+ async getClientConfiguration(workspaceFolder, section) {
681
+ const scopeUri = util_1.util.pathToUri(workspaceFolder);
682
+ let config = {};
683
+ //if the client supports configuration, look for config group called "brightscript"
684
+ if (this.hasConfigurationCapability) {
685
+ config = await this.connection.workspace.getConfiguration({
686
+ scopeUri: scopeUri,
687
+ section: section
688
+ });
900
689
  }
690
+ return config;
691
+ }
692
+ /**
693
+ * Send a critical failure notification to the client, which should show a notification of some kind
694
+ */
695
+ sendCriticalFailure(message) {
696
+ this.connection.sendNotification('critical-failure', message).catch(logAndIgnoreError);
697
+ }
698
+ /**
699
+ * Send diagnostics to the client
700
+ */
701
+ async sendDiagnostics(options) {
702
+ const patch = this.diagnosticCollection.getPatch(options.project.projectNumber, options.diagnostics);
703
+ await Promise.all(Object.keys(patch).map(async (srcPath) => {
704
+ const uri = vscode_uri_1.URI.file(srcPath).toString();
705
+ const diagnostics = patch[srcPath].map(d => util_1.util.toDiagnostic(d, uri));
706
+ await this.connection.sendDiagnostics({
707
+ uri: uri,
708
+ diagnostics: diagnostics
709
+ });
710
+ }));
901
711
  }
902
712
  dispose() {
903
- var _a;
713
+ var _a, _b, _c;
714
+ clearTimeout(this.fileChangeDebounceTimer);
904
715
  (_a = this.loggerSubscription) === null || _a === void 0 ? void 0 : _a.call(this);
905
- this.validateThrottler.dispose();
716
+ (_c = (_b = this.projectManager) === null || _b === void 0 ? void 0 : _b.dispose) === null || _c === void 0 ? void 0 : _c.call(_b);
906
717
  }
907
718
  }
719
+ /**
720
+ * The default threading setting for the language server. Can be overridden by per-workspace settings
721
+ */
722
+ LanguageServer.enableThreadingDefault = true;
723
+ /**
724
+ * The default project discovery setting for the language server. Can be overridden by per-workspace settings
725
+ */
726
+ LanguageServer.enableProjectDiscoveryDefault = true;
727
+ /**
728
+ * The default number of projects that are permitted to activate concurrently.
729
+ */
730
+ LanguageServer.projectActivationConcurrencyLimitDefault = 3;
908
731
  __decorate([
909
732
  AddStackToErrorMessage
910
733
  ], LanguageServer.prototype, "onInitialize", null);
@@ -913,31 +736,28 @@ __decorate([
913
736
  ], LanguageServer.prototype, "onInitialized", null);
914
737
  __decorate([
915
738
  AddStackToErrorMessage
916
- ], LanguageServer.prototype, "onCompletion", null);
739
+ ], LanguageServer.prototype, "onTextDocumentDidChangeContent", null);
917
740
  __decorate([
918
741
  AddStackToErrorMessage
919
- ], LanguageServer.prototype, "onCompletionResolve", null);
742
+ ], LanguageServer.prototype, "onDidChangeWatchedFiles", null);
920
743
  __decorate([
921
744
  AddStackToErrorMessage
922
- ], LanguageServer.prototype, "onCodeAction", null);
745
+ ], LanguageServer.prototype, "onDocumentClose", null);
923
746
  __decorate([
924
747
  AddStackToErrorMessage
925
- ], LanguageServer.prototype, "onDidChangeConfiguration", null);
748
+ ], LanguageServer.prototype, "onCompletion", null);
926
749
  __decorate([
927
750
  AddStackToErrorMessage
928
- ], LanguageServer.prototype, "onDidChangeWatchedFiles", null);
751
+ ], LanguageServer.prototype, "onDidChangeConfiguration", null);
929
752
  __decorate([
930
753
  AddStackToErrorMessage
931
754
  ], LanguageServer.prototype, "onHover", null);
932
755
  __decorate([
933
756
  AddStackToErrorMessage
934
- ], LanguageServer.prototype, "onDocumentClose", null);
757
+ ], LanguageServer.prototype, "onWorkspaceSymbol", null);
935
758
  __decorate([
936
759
  AddStackToErrorMessage
937
- ], LanguageServer.prototype, "validateTextDocument", null);
938
- __decorate([
939
- AddStackToErrorMessage
940
- ], LanguageServer.prototype, "onWorkspaceSymbol", null);
760
+ ], LanguageServer.prototype, "onSelectionRanges", null);
941
761
  __decorate([
942
762
  AddStackToErrorMessage
943
763
  ], LanguageServer.prototype, "onDocumentSymbol", null);
@@ -950,9 +770,15 @@ __decorate([
950
770
  __decorate([
951
771
  AddStackToErrorMessage
952
772
  ], LanguageServer.prototype, "onReferences", null);
773
+ __decorate([
774
+ AddStackToErrorMessage
775
+ ], LanguageServer.prototype, "onWillRenameFiles", null);
953
776
  __decorate([
954
777
  AddStackToErrorMessage
955
778
  ], LanguageServer.prototype, "onFullSemanticTokens", null);
779
+ __decorate([
780
+ AddStackToErrorMessage
781
+ ], LanguageServer.prototype, "onCodeAction", null);
956
782
  __decorate([
957
783
  AddStackToErrorMessage
958
784
  ], LanguageServer.prototype, "onExecuteCommand", null);
@@ -961,6 +787,10 @@ var CustomCommands;
961
787
  (function (CustomCommands) {
962
788
  CustomCommands["TranspileFile"] = "TranspileFile";
963
789
  })(CustomCommands = exports.CustomCommands || (exports.CustomCommands = {}));
790
+ var NotificationName;
791
+ (function (NotificationName) {
792
+ NotificationName["busyStatus"] = "busyStatus";
793
+ })(NotificationName = exports.NotificationName || (exports.NotificationName = {}));
964
794
  /**
965
795
  * Wraps a method. If there's an error (either sync or via a promise),
966
796
  * this appends the error's stack trace at the end of the error message so that the connection will
@@ -992,4 +822,10 @@ function AddStackToErrorMessage(target, propertyKey, descriptor) {
992
822
  }
993
823
  };
994
824
  }
825
+ function logAndIgnoreError(error) {
826
+ if (error === null || error === void 0 ? void 0 : error.stack) {
827
+ error.message = error.stack;
828
+ }
829
+ console.error(error);
830
+ }
995
831
  //# sourceMappingURL=LanguageServer.js.map