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
package/dist/util.js CHANGED
@@ -5,35 +5,74 @@ const fs = require("fs");
5
5
  const fsExtra = require("fs-extra");
6
6
  const jsonc_parser_1 = require("jsonc-parser");
7
7
  const path = require("path");
8
- const rokuDeploy = require("roku-deploy");
8
+ const roku_deploy_1 = require("roku-deploy");
9
+ const vscode_languageserver_1 = require("vscode-languageserver");
9
10
  const vscode_uri_1 = require("vscode-uri");
10
- const xml2js = require("xml2js");
11
11
  const DiagnosticMessages_1 = require("./DiagnosticMessages");
12
+ const interfaces_1 = require("./interfaces");
12
13
  const BooleanType_1 = require("./types/BooleanType");
13
14
  const DoubleType_1 = require("./types/DoubleType");
14
15
  const DynamicType_1 = require("./types/DynamicType");
15
16
  const FloatType_1 = require("./types/FloatType");
16
- const FunctionType_1 = require("./types/FunctionType");
17
17
  const IntegerType_1 = require("./types/IntegerType");
18
- const InvalidType_1 = require("./types/InvalidType");
19
18
  const LongIntegerType_1 = require("./types/LongIntegerType");
20
19
  const ObjectType_1 = require("./types/ObjectType");
21
20
  const StringType_1 = require("./types/StringType");
22
21
  const VoidType_1 = require("./types/VoidType");
23
22
  const Parser_1 = require("./parser/Parser");
24
- const Logger_1 = require("./Logger");
25
- const lexer_1 = require("./lexer");
26
- const astUtils_1 = require("./astUtils");
27
- const CustomType_1 = require("./types/CustomType");
23
+ const logging_1 = require("./logging");
24
+ const Token_1 = require("./lexer/Token");
25
+ const TokenKind_1 = require("./lexer/TokenKind");
26
+ const reflection_1 = require("./astUtils/reflection");
27
+ const visitors_1 = require("./astUtils/visitors");
28
28
  const source_map_1 = require("source-map");
29
- const SGTypes_1 = require("./parser/SGTypes");
29
+ const requireRelative = require("require-relative");
30
+ const AstNode_1 = require("./parser/AstNode");
31
+ const creators_1 = require("./astUtils/creators");
32
+ const diagnosticUtils_1 = require("./diagnosticUtils");
33
+ const UnionType_1 = require("./types/UnionType");
34
+ const ArrayType_1 = require("./types/ArrayType");
35
+ const ReferenceType_1 = require("./types/ReferenceType");
36
+ const AssociativeArrayType_1 = require("./types/AssociativeArrayType");
37
+ const ComponentType_1 = require("./types/ComponentType");
38
+ const FunctionType_1 = require("./types/FunctionType");
39
+ const helpers_1 = require("./types/helpers");
40
+ const InvalidType_1 = require("./types/InvalidType");
41
+ const types_1 = require("./types");
42
+ const IntersectionType_1 = require("./types/IntersectionType");
30
43
  class Util {
44
+ constructor() {
45
+ this.isWindows = process.platform === 'win32';
46
+ this.standardizePathCache = new Map();
47
+ this.pathToURICache = new Map();
48
+ }
31
49
  clearConsole() {
32
50
  // process.stdout.write('\x1Bc');
33
51
  }
52
+ /**
53
+ * Get the version of brighterscript
54
+ */
55
+ getBrighterScriptVersion() {
56
+ try {
57
+ return fsExtra.readJsonSync(`${__dirname}/../package.json`).version;
58
+ }
59
+ catch (_a) {
60
+ return undefined;
61
+ }
62
+ }
63
+ /**
64
+ * Returns the number of parent directories in the filPath
65
+ */
66
+ getParentDirectoryCount(filePath) {
67
+ if (!filePath) {
68
+ return -1;
69
+ }
70
+ else {
71
+ return filePath.replace(/^pkg:/, '').split(/[\\\/]/).length - 1;
72
+ }
73
+ }
34
74
  /**
35
75
  * Determine if the file exists
36
- * @param filePath
37
76
  */
38
77
  async pathExists(filePath) {
39
78
  if (!filePath) {
@@ -45,7 +84,6 @@ class Util {
45
84
  }
46
85
  /**
47
86
  * Determine if the file exists
48
- * @param filePath
49
87
  */
50
88
  pathExistsSync(filePath) {
51
89
  if (!filePath) {
@@ -59,40 +97,39 @@ class Util {
59
97
  * Determine if this path is a directory
60
98
  */
61
99
  isDirectorySync(dirPath) {
62
- return fs.existsSync(dirPath) && fs.lstatSync(dirPath).isDirectory();
63
- }
64
- /**
65
- * Given a pkg path of any kind, transform it to a roku-specific pkg path (i.e. "pkg:/some/path.brs")
66
- */
67
- sanitizePkgPath(pkgPath) {
68
- pkgPath = pkgPath.replace(/\\/g, '/');
69
- //if there's no protocol, assume it's supposed to start with `pkg:/`
70
- if (!this.startsWithProtocol(pkgPath)) {
71
- pkgPath = 'pkg:/' + pkgPath;
100
+ try {
101
+ return dirPath !== undefined && fs.existsSync(dirPath) && fs.lstatSync(dirPath).isDirectory();
102
+ }
103
+ catch (e) {
104
+ return false;
72
105
  }
73
- return pkgPath;
74
106
  }
75
107
  /**
76
- * Determine if the given path starts with a protocol
108
+ * Read a file from disk. If a failure occurrs, simply return undefined
109
+ * @param filePath path to the file
110
+ * @returns the string contents, or undefined if the file doesn't exist
77
111
  */
78
- startsWithProtocol(path) {
79
- return !!/^[-a-z]+:\//i.exec(path);
112
+ readFileSync(filePath) {
113
+ try {
114
+ return fsExtra.readFileSync(filePath);
115
+ }
116
+ catch (e) {
117
+ return undefined;
118
+ }
80
119
  }
81
120
  /**
82
- * Given a path to a file/directory, replace all path separators with the current system's version.
83
- * @param filePath
121
+ * Given a pkg path of any kind, transform it to a roku-specific pkg path (i.e. "pkg:/some/path.brs")
84
122
  */
85
- pathSepNormalize(filePath, separator) {
86
- if (!filePath) {
87
- return filePath;
88
- }
89
- separator = separator ? separator : path.sep;
90
- return filePath.replace(/[\\/]+/g, separator);
123
+ sanitizePkgPath(pkgPath) {
124
+ //convert all slashes to forwardslash
125
+ pkgPath = pkgPath.replace(/[\/\\]+/g, '/');
126
+ //ensure every path has the leading pkg:/
127
+ return 'pkg:/' + pkgPath.replace(/^pkg:\//i, '');
91
128
  }
92
129
  /**
93
130
  * Find the path to the config file.
94
131
  * If the config file path doesn't exist
95
- * @param configFilePath
132
+ * @param cwd the current working directory where the search for configs should begin
96
133
  */
97
134
  getConfigFilePath(cwd) {
98
135
  cwd = cwd !== null && cwd !== void 0 ? cwd : process.cwd();
@@ -126,15 +163,16 @@ class Util {
126
163
  colIndex++;
127
164
  }
128
165
  }
129
- return this.createRange(lineIndex, colIndex, lineIndex, colIndex + length);
166
+ return exports.util.createRange(lineIndex, colIndex, lineIndex, colIndex + length);
130
167
  }
131
168
  /**
132
169
  * Load the contents of a config file.
133
170
  * If the file extends another config, this will load the base config as well.
134
- * @param configFilePath
135
- * @param parentProjectPaths
171
+ * @param configFilePath the relative or absolute path to a brighterscript config json file
172
+ * @param parentProjectPaths a list of parent config files. This is used by this method to recursively build the config list
136
173
  */
137
174
  loadConfigFile(configFilePath, parentProjectPaths, cwd = process.cwd()) {
175
+ var _a;
138
176
  if (configFilePath) {
139
177
  //if the config file path starts with question mark, then it's optional. return undefined if it doesn't exist
140
178
  if (configFilePath.startsWith('?')) {
@@ -155,16 +193,24 @@ class Util {
155
193
  //load the project file
156
194
  let projectFileContents = fsExtra.readFileSync(configFilePath).toString();
157
195
  let parseErrors = [];
158
- let projectConfig = jsonc_parser_1.parse(projectFileContents, parseErrors);
196
+ let projectConfig = (_a = (0, jsonc_parser_1.parse)(projectFileContents, parseErrors, {
197
+ allowEmptyContent: true,
198
+ allowTrailingComma: true,
199
+ disallowComments: false
200
+ })) !== null && _a !== void 0 ? _a : {};
159
201
  if (parseErrors.length > 0) {
160
202
  let err = parseErrors[0];
161
- let diagnostic = Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.bsConfigJsonHasSyntaxErrors(jsonc_parser_1.printParseErrorCode(parseErrors[0].error))), { file: {
162
- srcPath: configFilePath
163
- }, range: this.getRangeFromOffsetLength(projectFileContents, err.offset, err.length) });
203
+ let diagnostic = Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.syntaxError(`Syntax errors in bsconfig.json: ${(0, jsonc_parser_1.printParseErrorCode)(parseErrors[0].error)}`)), { location: {
204
+ uri: this.pathToUri(configFilePath),
205
+ range: this.getRangeFromOffsetLength(projectFileContents, err.offset, err.length)
206
+ } });
164
207
  throw diagnostic; //eslint-disable-line @typescript-eslint/no-throw-literal
165
208
  }
166
- this.resolvePluginPaths(projectConfig, configFilePath);
167
209
  let projectFileCwd = path.dirname(configFilePath);
210
+ //`plugins` paths should be relative to the current bsconfig
211
+ this.resolvePathsRelativeTo(projectConfig, 'plugins', projectFileCwd);
212
+ //`require` paths should be relative to cwd
213
+ exports.util.resolvePathsRelativeTo(projectConfig, 'require', projectFileCwd);
168
214
  let result;
169
215
  //if the project has a base file, load it
170
216
  if (projectConfig && typeof projectConfig.extends === 'string') {
@@ -179,75 +225,50 @@ class Util {
179
225
  result._ancestors = parentProjectPaths;
180
226
  }
181
227
  //make any paths in the config absolute (relative to the CURRENT config file)
182
- if (result.outFile) {
183
- result.outFile = path.resolve(projectFileCwd, result.outFile);
184
- }
185
228
  if (result.rootDir) {
186
229
  result.rootDir = path.resolve(projectFileCwd, result.rootDir);
187
230
  }
231
+ if (result.outDir) {
232
+ result.outDir = path.resolve(projectFileCwd, result.outDir);
233
+ }
188
234
  if (result.cwd) {
189
235
  result.cwd = path.resolve(projectFileCwd, result.cwd);
190
236
  }
237
+ if (result.sourceRoot && result.resolveSourceRoot) {
238
+ result.sourceRoot = path.resolve(projectFileCwd, result.sourceRoot);
239
+ }
191
240
  return result;
192
241
  }
193
242
  }
194
243
  /**
195
- * Relative paths to scripts in plugins should be resolved relatively to the bsconfig file
196
- * and de-duplicated
197
- * @param config Parsed configuration
198
- * @param configFilePath Path of the configuration file
244
+ * Convert relative paths to absolute paths, relative to the given directory. Also de-dupes the paths. Modifies the array in-place
245
+ * @param collection usually a bsconfig.
246
+ * @param key a key of the config to read paths from (usually this is `'plugins'` or `'require'`)
247
+ * @param relativeDir the path to the folder where the paths should be resolved relative to. This should be an absolute path
199
248
  */
200
- resolvePluginPaths(config, configFilePath) {
249
+ resolvePathsRelativeTo(collection, key, relativeDir) {
201
250
  var _a;
202
- if (((_a = config.plugins) === null || _a === void 0 ? void 0 : _a.length) > 0) {
203
- const relPath = path.dirname(configFilePath);
204
- const exists = {};
205
- config.plugins = config.plugins.map(p => {
206
- return (p === null || p === void 0 ? void 0 : p.startsWith('.')) ? path.resolve(relPath, p) : p;
207
- }).filter(p => {
208
- if (!p || exists[p]) {
209
- return false;
210
- }
211
- exists[p] = true;
212
- return true;
213
- });
214
- }
215
- }
216
- /**
217
- * Do work within the scope of a changed current working directory
218
- * @param targetCwd
219
- * @param callback
220
- */
221
- cwdWork(targetCwd, callback) {
222
- let originalCwd = process.cwd();
223
- if (targetCwd) {
224
- process.chdir(targetCwd);
225
- }
226
- let result;
227
- let err;
228
- try {
229
- result = callback();
230
- }
231
- catch (e) {
232
- err = e;
233
- }
234
- if (targetCwd) {
235
- process.chdir(originalCwd);
251
+ if (!collection[key]) {
252
+ return;
236
253
  }
237
- if (err) {
238
- throw err;
239
- }
240
- else {
241
- return result;
254
+ const result = new Set();
255
+ for (const p of (_a = collection[key]) !== null && _a !== void 0 ? _a : []) {
256
+ if (p) {
257
+ result.add((p === null || p === void 0 ? void 0 : p.startsWith('.')) ? path.resolve(relativeDir, p) : p);
258
+ }
242
259
  }
260
+ collection[key] = [...result];
243
261
  }
244
262
  /**
245
263
  * Given a BsConfig object, start with defaults,
246
264
  * merge with bsconfig.json and the provided options.
247
- * @param config
265
+ * @param config a bsconfig object to use as the baseline for the resulting config
248
266
  */
249
267
  normalizeAndResolveConfig(config) {
250
- let result = this.normalizeConfig({});
268
+ let result = this.normalizeConfig(Object.assign({}, config));
269
+ if (config === null || config === void 0 ? void 0 : config.noProject) {
270
+ return result;
271
+ }
251
272
  //if no options were provided, try to find a bsconfig.json file
252
273
  if (!config || !config.project) {
253
274
  result.project = this.getConfigFilePath(config === null || config === void 0 ? void 0 : config.cwd);
@@ -257,7 +278,7 @@ class Util {
257
278
  result.project = config.project;
258
279
  }
259
280
  if (result.project) {
260
- let configFile = this.loadConfigFile(result.project, null, config === null || config === void 0 ? void 0 : config.cwd);
281
+ let configFile = this.loadConfigFile(result.project, undefined, config === null || config === void 0 ? void 0 : config.cwd);
261
282
  result = Object.assign(result, configFile);
262
283
  }
263
284
  //override the defaults with the specified options
@@ -266,42 +287,81 @@ class Util {
266
287
  }
267
288
  /**
268
289
  * Set defaults for any missing items
269
- * @param config
290
+ * @param config a bsconfig object to use as the baseline for the resulting config
270
291
  */
271
292
  normalizeConfig(config) {
272
- var _a, _b, _c, _d, _e, _f, _g, _h;
273
- config = config || {};
274
- config.deploy = config.deploy === true ? true : false;
275
- //use default options from rokuDeploy
276
- config.files = (_a = config.files) !== null && _a !== void 0 ? _a : rokuDeploy.getOptions().files;
277
- config.createPackage = config.createPackage === false ? false : true;
278
- let rootFolderName = path.basename(process.cwd());
279
- config.outFile = (_b = config.outFile) !== null && _b !== void 0 ? _b : `./out/${rootFolderName}.zip`;
280
- config.sourceMap = config.sourceMap === true;
281
- config.username = (_c = config.username) !== null && _c !== void 0 ? _c : 'rokudev';
282
- config.watch = config.watch === true ? true : false;
283
- config.emitFullPaths = config.emitFullPaths === true ? true : false;
284
- config.retainStagingFolder = config.retainStagingFolder === true ? true : false;
285
- config.copyToStaging = config.copyToStaging === false ? false : true;
286
- config.ignoreErrorCodes = (_d = config.ignoreErrorCodes) !== null && _d !== void 0 ? _d : [];
287
- config.diagnosticFilters = (_e = config.diagnosticFilters) !== null && _e !== void 0 ? _e : [];
288
- config.plugins = (_f = config.plugins) !== null && _f !== void 0 ? _f : [];
289
- config.autoImportComponentScript = config.autoImportComponentScript === true ? true : false;
290
- config.showDiagnosticsInConsole = config.showDiagnosticsInConsole === false ? false : true;
291
- config.sourceRoot = config.sourceRoot ? standardizePath(config.sourceRoot) : undefined;
292
- config.cwd = (_g = config.cwd) !== null && _g !== void 0 ? _g : process.cwd();
293
- config.emitDefinitions = config.emitDefinitions === true ? true : false;
293
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
294
+ config = config !== null && config !== void 0 ? config : {};
295
+ const cwd = (_a = config.cwd) !== null && _a !== void 0 ? _a : process.cwd();
296
+ let logLevel = logging_1.LogLevel.log;
294
297
  if (typeof config.logLevel === 'string') {
295
- config.logLevel = Logger_1.LogLevel[config.logLevel.toLowerCase()];
298
+ logLevel = (_b = logging_1.LogLevel[config.logLevel.toLowerCase()]) !== null && _b !== void 0 ? _b : logging_1.LogLevel.log;
299
+ }
300
+ let bslibDestinationDir = (_c = config.bslibDestinationDir) !== null && _c !== void 0 ? _c : 'source';
301
+ if (bslibDestinationDir !== 'source') {
302
+ // strip leading and trailing slashes
303
+ bslibDestinationDir = bslibDestinationDir.replace(/^(\/*)(.*?)(\/*)$/, '$2');
304
+ }
305
+ let noEmit;
306
+ if ('noEmit' in config) {
307
+ noEmit = config.noEmit;
296
308
  }
297
- config.logLevel = (_h = config.logLevel) !== null && _h !== void 0 ? _h : Logger_1.LogLevel.log;
298
- return config;
309
+ else if ('copyToStaging' in config) {
310
+ noEmit = !config.copyToStaging; //invert the old value
311
+ }
312
+ else {
313
+ noEmit = false; //default case
314
+ }
315
+ let outDir;
316
+ if ('outDir' in config) {
317
+ outDir = (_d = config.outDir) !== null && _d !== void 0 ? _d : './out';
318
+ }
319
+ else if ('stagingFolderPath' in config) {
320
+ outDir = config.stagingFolderPath;
321
+ }
322
+ else if ('stagingDir' in config) {
323
+ outDir = config.stagingDir;
324
+ }
325
+ else {
326
+ outDir = './out'; //default case
327
+ }
328
+ const configWithDefaults = {
329
+ cwd: cwd,
330
+ //use default files array from rokuDeploy
331
+ files: (_e = config.files) !== null && _e !== void 0 ? _e : [...roku_deploy_1.DefaultFiles],
332
+ outDir: outDir,
333
+ sourceMap: config.sourceMap === true,
334
+ relativeSourceMaps: config.relativeSourceMaps === true,
335
+ watch: config.watch === true ? true : false,
336
+ emitFullPaths: config.emitFullPaths === true ? true : false,
337
+ noEmit: noEmit,
338
+ ignoreErrorCodes: (_f = config.ignoreErrorCodes) !== null && _f !== void 0 ? _f : [],
339
+ diagnosticSeverityOverrides: (_g = config.diagnosticSeverityOverrides) !== null && _g !== void 0 ? _g : {},
340
+ diagnosticFilters: (_h = config.diagnosticFilters) !== null && _h !== void 0 ? _h : [],
341
+ diagnosticFiltersV0Compatibility: config.diagnosticFiltersV0Compatibility === true ? true : false,
342
+ plugins: (_j = config.plugins) !== null && _j !== void 0 ? _j : [],
343
+ pruneEmptyCodeFiles: config.pruneEmptyCodeFiles === true ? true : false,
344
+ autoImportComponentScript: config.autoImportComponentScript === true ? true : false,
345
+ showDiagnosticsInConsole: config.showDiagnosticsInConsole === false ? false : true,
346
+ sourceRoot: config.sourceRoot ? standardizePath(config.sourceRoot) : undefined,
347
+ resolveSourceRoot: config.resolveSourceRoot === true ? true : false,
348
+ allowBrighterScriptInBrightScript: config.allowBrighterScriptInBrightScript === true ? true : false,
349
+ emitDefinitions: config.emitDefinitions === true ? true : false,
350
+ removeParameterTypes: config.removeParameterTypes === true ? true : false,
351
+ logLevel: logLevel,
352
+ bslibDestinationDir: bslibDestinationDir,
353
+ legacyCallfuncHandling: config.legacyCallfuncHandling === true ? true : false,
354
+ validate: config.validate === false ? false : true
355
+ };
356
+ //mutate `config` in case anyone is holding a reference to the incomplete one
357
+ const merged = Object.assign(config, configWithDefaults);
358
+ return merged;
299
359
  }
300
360
  /**
301
361
  * Get the root directory from options.
302
362
  * Falls back to options.cwd.
303
363
  * Falls back to process.cwd
304
- * @param options
364
+ * @param options a bsconfig object
305
365
  */
306
366
  getRootDir(options) {
307
367
  if (!options) {
@@ -313,19 +373,8 @@ class Util {
313
373
  rootDir = path.resolve(cwd, rootDir);
314
374
  return rootDir;
315
375
  }
316
- /**
317
- * Format a string with placeholders replaced by argument indexes
318
- * @param subject
319
- * @param params
320
- */
321
- stringFormat(subject, ...args) {
322
- return subject.replace(/{(\d+)}/g, (match, num) => {
323
- return typeof args[num] !== 'undefined' ? args[num] : match;
324
- });
325
- }
326
376
  /**
327
377
  * Given a list of callables as a dictionary indexed by their full name (namespace included, transpiled to underscore-separated.
328
- * @param callables
329
378
  */
330
379
  getCallableContainersByLowerName(callables) {
331
380
  //find duplicate functions
@@ -344,33 +393,34 @@ class Util {
344
393
  return result;
345
394
  }
346
395
  /**
347
- * Split a file by newline characters (LF or CRLF)
348
- * @param text
396
+ * Given an absolute path to a source file, and a target path,
397
+ * compute the pkg path for the target relative to the source file's location
349
398
  */
350
- getLines(text) {
351
- return text.split(/\r?\n/);
352
- }
353
- /**
354
- * Compute the pkg path for the target relative to the source file's location
355
- * @param sourcePkgPath The pkgPath of the file that contains the target path
356
- * @param targetPath a full pkgPath, or a path relative to the containing file
357
- */
358
- getPkgPathFromTarget(sourcePkgPath, targetPath) {
399
+ getPkgPathFromTarget(containingFilePathAbsolute, targetPath) {
359
400
  var _a;
360
- const [protocol] = (_a = /^[-a-z0-9_]+:\/?/i.exec(targetPath)) !== null && _a !== void 0 ? _a : [];
361
- //if the target path is only a file protocol (with or without the trailing slash such as `pkg:` or `pkg:/`), nothing more can be done
362
- if ((targetPath === null || targetPath === void 0 ? void 0 : targetPath.length) === (protocol === null || protocol === void 0 ? void 0 : protocol.length)) {
363
- return null;
401
+ // https://regex101.com/r/w7CG2N/1
402
+ const regexp = /^(?:pkg|libpkg):(\/)?/i;
403
+ const [fullScheme, slash] = (_a = regexp.exec(targetPath)) !== null && _a !== void 0 ? _a : [];
404
+ //if the target starts with 'pkg:' or 'libpkg:' then it's an absolute path. Return as is
405
+ if (slash) {
406
+ targetPath = targetPath.substring(fullScheme.length);
407
+ if (targetPath === '') {
408
+ return null;
409
+ }
410
+ else {
411
+ return path.normalize(targetPath);
412
+ }
364
413
  }
365
- //if the target starts with 'pkg:', return as-is
366
- if (protocol) {
367
- return targetPath;
414
+ //if the path is exactly `pkg:` or `libpkg:`
415
+ if (targetPath === fullScheme && !slash) {
416
+ return null;
368
417
  }
418
+ //remove the filename
419
+ let containingFolder = path.normalize(path.dirname(containingFilePathAbsolute));
369
420
  //start with the containing folder, split by slash
370
- const containingFolder = path.posix.normalize(path.dirname(sourcePkgPath));
371
- let result = containingFolder.split(/[\\/]/);
421
+ let result = containingFolder.split(path.sep);
372
422
  //split on slash
373
- let targetParts = path.posix.normalize(targetPath).split(/[\\/]/);
423
+ let targetParts = path.normalize(targetPath).split(path.sep);
374
424
  for (let part of targetParts) {
375
425
  if (part === '' || part === '.') {
376
426
  //do nothing, it means current directory
@@ -384,19 +434,41 @@ class Util {
384
434
  result.push(part);
385
435
  }
386
436
  }
387
- return result.join('/');
437
+ return result.join(path.sep);
438
+ }
439
+ /**
440
+ * Compute the replacement text for a file-path string (used in `import` statements and XML `<script uri>` attributes)
441
+ * when the target file is being renamed. Preserves the original path style: `pkg:/...` stays `pkg:/...`,
442
+ * relative paths stay relative (recomputed from the containing file's pkg path).
443
+ *
444
+ * @param originalText the path string as it appears in source (no surrounding quotes)
445
+ * @param containingFilePkgPath pkg path of the file containing the reference
446
+ * @param newTargetPkgPath pkg path of the renamed file (path-separator agnostic)
447
+ * @returns the new path string, or `null` if the original style is unsupported
448
+ */
449
+ computeRenamedReferencePath(originalText, containingFilePkgPath, newTargetPkgPath) {
450
+ if (!originalText) {
451
+ return null;
452
+ }
453
+ const newPkgPathForwardSlash = path.normalize(newTargetPkgPath).split(path.sep).join('/');
454
+ const schemeMatch = /^(pkg|libpkg):\//i.exec(originalText);
455
+ if (schemeMatch) {
456
+ return `${schemeMatch[1]}:/${newPkgPathForwardSlash}`;
457
+ }
458
+ const relative = this.getRelativePath(containingFilePkgPath, newTargetPkgPath);
459
+ return relative.split(path.sep).join('/');
388
460
  }
389
461
  /**
390
462
  * Compute the relative path from the source file to the target file
391
- * @param pkgSourcePathAbsolute - the absolute path to the source relative to the package location
392
- * @param pkgTargetPathAbsolute - the absolute path ro the target relative to the package location
463
+ * @param pkgSrcPath - the absolute path to the source, where cwd is the package location
464
+ * @param pkgTargetPath - the absolute path to the target, where cwd is the package location
393
465
  */
394
- getRelativePath(pkgSourcePathAbsolute, pkgTargetPathAbsolute) {
395
- pkgSourcePathAbsolute = path.normalize(pkgSourcePathAbsolute);
396
- pkgTargetPathAbsolute = path.normalize(pkgTargetPathAbsolute);
466
+ getRelativePath(pkgSrcPath, pkgTargetPath) {
467
+ pkgSrcPath = path.normalize(pkgSrcPath);
468
+ pkgTargetPath = path.normalize(pkgTargetPath);
397
469
  //break by path separator
398
- let sourceParts = pkgSourcePathAbsolute.split(path.sep);
399
- let targetParts = pkgTargetPathAbsolute.split(path.sep);
470
+ let sourceParts = pkgSrcPath.split(path.sep);
471
+ let targetParts = pkgTargetPath.split(path.sep);
400
472
  let commonParts = [];
401
473
  //find their common root
402
474
  for (let i = 0; i < targetParts.length; i++) {
@@ -419,16 +491,26 @@ class Util {
419
491
  resultParts = [...resultParts, ...targetParts];
420
492
  return path.join(...resultParts);
421
493
  }
494
+ getImportPackagePath(srcPath, pkgTargetPath) {
495
+ const srcExt = this.getExtension(srcPath);
496
+ const lowerSrcExt = srcExt.toLowerCase();
497
+ const lowerTargetExt = this.getExtension(pkgTargetPath).toLowerCase();
498
+ if (lowerSrcExt === '.bs' && lowerTargetExt === '.brs') {
499
+ // if source is .bs, use that as the import extenstion
500
+ return pkgTargetPath.substring(0, pkgTargetPath.length - lowerTargetExt.length) + srcExt;
501
+ }
502
+ return pkgTargetPath;
503
+ }
422
504
  /**
423
505
  * Walks left in a DottedGetExpression and returns a VariableExpression if found, or undefined if not found
424
506
  */
425
507
  findBeginningVariableExpression(dottedGet) {
426
508
  let left = dottedGet;
427
509
  while (left) {
428
- if (astUtils_1.isVariableExpression(left)) {
510
+ if ((0, reflection_1.isVariableExpression)(left)) {
429
511
  return left;
430
512
  }
431
- else if (astUtils_1.isDottedGetExpression(left)) {
513
+ else if ((0, reflection_1.isDottedGetExpression)(left)) {
432
514
  left = left.obj;
433
515
  }
434
516
  else {
@@ -437,9 +519,19 @@ class Util {
437
519
  }
438
520
  }
439
521
  /**
440
- * Does a touch b in any way?
522
+ * Do `a` and `b` overlap by at least one character. This returns false if they are at the edges. Here's some examples:
523
+ * ```
524
+ * | true | true | true | true | true | false | false | false | false |
525
+ * |------|------|------|------|------|-------|-------|-------|-------|
526
+ * | aa | aaa | aaa | aaa | a | aa | aa | a | a |
527
+ * | bbb | bb | bbb | b | bbb | bb | bb | b | a |
528
+ * ```
441
529
  */
442
530
  rangesIntersect(a, b) {
531
+ //stop if the either range is misisng
532
+ if (!a || !b) {
533
+ return false;
534
+ }
443
535
  // Check if `a` is before `b`
444
536
  if (a.end.line < b.start.line || (a.end.line === b.start.line && a.end.character <= b.start.character)) {
445
537
  return false;
@@ -451,74 +543,159 @@ class Util {
451
543
  // These ranges must intersect
452
544
  return true;
453
545
  }
546
+ /**
547
+ * Do `a` and `b` overlap by at least one character or touch at the edges
548
+ * ```
549
+ * | true | true | true | true | true | true | true | false | false |
550
+ * |------|------|------|------|------|-------|-------|-------|-------|
551
+ * | aa | aaa | aaa | aaa | a | aa | aa | a | a |
552
+ * | bbb | bb | bbb | b | bbb | bb | bb | b | a |
553
+ * ```
554
+ */
555
+ rangesIntersectOrTouch(a, b) {
556
+ //stop if the either range is misisng
557
+ if (!a || !b) {
558
+ return false;
559
+ }
560
+ // Check if `a` is before `b`
561
+ if (a.end.line < b.start.line || (a.end.line === b.start.line && a.end.character < b.start.character)) {
562
+ return false;
563
+ }
564
+ // Check if `b` is before `a`
565
+ if (b.end.line < a.start.line || (b.end.line === a.start.line && b.end.character < a.start.character)) {
566
+ return false;
567
+ }
568
+ // These ranges must intersect
569
+ return true;
570
+ }
454
571
  /**
455
572
  * Test if `position` is in `range`. If the position is at the edges, will return true.
456
573
  * Adapted from core vscode
457
- * @param range
458
- * @param position
459
574
  */
460
575
  rangeContains(range, position) {
461
576
  return this.comparePositionToRange(position, range) === 0;
462
577
  }
463
578
  comparePositionToRange(position, range) {
464
- if (position.line < range.start.line || (position.line === range.start.line && position.character < range.start.character)) {
579
+ //stop if the either range is missng
580
+ if (!position || !range) {
581
+ return 0;
582
+ }
583
+ if (this.comparePosition(position, range.start) < 0) {
584
+ return -1;
585
+ }
586
+ if (this.comparePosition(position, range.end) > 0) {
587
+ return 1;
588
+ }
589
+ return 0;
590
+ }
591
+ comparePosition(a, b) {
592
+ //stop if the either position is missing
593
+ if (!a || !b) {
594
+ return 0;
595
+ }
596
+ if (a.line < b.line || (a.line === b.line && a.character < b.character)) {
465
597
  return -1;
466
598
  }
467
- if (position.line > range.end.line || (position.line === range.end.line && position.character > range.end.character)) {
599
+ if (a.line > b.line || (a.line === b.line && a.character > b.character)) {
468
600
  return 1;
469
601
  }
470
602
  return 0;
471
603
  }
472
604
  /**
473
- * Parse an xml file and get back a javascript object containing its results
474
- * @param text
605
+ * Is the inner range completely enclosed in the outer range
475
606
  */
476
- parseXml(text) {
477
- return new Promise((resolve, reject) => {
478
- xml2js.parseString(text, (err, data) => {
479
- if (err) {
480
- reject(err);
481
- }
482
- else {
483
- resolve(data);
484
- }
485
- });
486
- });
607
+ isRangeInRange(inner, outer) {
608
+ return this.comparePosition(inner.start, outer.start) === 1 &&
609
+ this.comparePosition(inner.end, outer.end) === -1;
487
610
  }
488
- propertyCount(object) {
489
- let count = 0;
490
- for (let key in object) {
491
- if (object.hasOwnProperty(key)) {
492
- count++;
611
+ /**
612
+ * Combine all the documentation for a node - uses the AstNode's leadingTrivia property
613
+ * @param node the node to get the documentation for
614
+ * @param options extra options
615
+ * @param options.prettyPrint if true, will format the comment text for markdown
616
+ * @param options.commentTokens out Array of tokens that match the comment lines
617
+ */
618
+ getNodeDocumentation(node, options = { prettyPrint: true }) {
619
+ var _a, _b, _c, _d;
620
+ if (!node) {
621
+ return '';
622
+ }
623
+ options = options !== null && options !== void 0 ? options : { prettyPrint: true };
624
+ options.commentTokens = (_a = options.commentTokens) !== null && _a !== void 0 ? _a : [];
625
+ const nodeTrivia = (_b = node.leadingTrivia) !== null && _b !== void 0 ? _b : [];
626
+ const leadingTrivia = (0, reflection_1.isStatement)(node)
627
+ ? [...((_d = (_c = node.annotations) === null || _c === void 0 ? void 0 : _c.map(anno => { var _a; return (_a = anno.leadingTrivia) !== null && _a !== void 0 ? _a : []; }).flat()) !== null && _d !== void 0 ? _d : []), ...nodeTrivia]
628
+ : nodeTrivia;
629
+ const tokens = leadingTrivia === null || leadingTrivia === void 0 ? void 0 : leadingTrivia.filter(t => t.kind === TokenKind_1.TokenKind.Newline || t.kind === TokenKind_1.TokenKind.Comment);
630
+ const comments = [];
631
+ let newLinesInRow = 0;
632
+ for (let i = tokens.length - 1; i >= 0; i--) {
633
+ const token = tokens[i];
634
+ //skip whitespace and newline chars
635
+ if (token.kind === TokenKind_1.TokenKind.Comment) {
636
+ comments.push(token);
637
+ newLinesInRow = 0;
638
+ }
639
+ else if (token.kind === TokenKind_1.TokenKind.Newline) {
640
+ //skip these tokens
641
+ newLinesInRow++;
642
+ if (newLinesInRow > 1) {
643
+ // stop processing on empty line.
644
+ break;
645
+ }
646
+ //any other token means there are no more comments
647
+ }
648
+ else {
649
+ break;
493
650
  }
494
651
  }
495
- return count;
496
- }
497
- padLeft(subject, totalLength, char) {
498
- totalLength = totalLength > 1000 ? 1000 : totalLength;
499
- while (subject.length < totalLength) {
500
- subject = char + subject;
652
+ const jsDocCommentBlockLine = /(\/\*{2,}|\*{1,}\/)/i;
653
+ let usesjsDocCommentBlock = false;
654
+ if (comments.length === 0) {
655
+ return '';
501
656
  }
502
- return subject;
657
+ return comments.reverse()
658
+ .map(x => ({ line: x.text.replace(/^('|rem)/i, '').trim(), token: x }))
659
+ .filter(({ line }) => {
660
+ if (jsDocCommentBlockLine.exec(line)) {
661
+ usesjsDocCommentBlock = true;
662
+ return false;
663
+ }
664
+ return true;
665
+ }).map(({ line, token }) => {
666
+ if (usesjsDocCommentBlock) {
667
+ if (line.startsWith('*')) {
668
+ //remove jsDoc leading '*'
669
+ line = line.slice(1).trim();
670
+ }
671
+ }
672
+ if (options.prettyPrint && line.startsWith('@')) {
673
+ // Handle jsdoc/brightscriptdoc tags specially
674
+ // make sure they are on their own markdown line, and add italics
675
+ const firstSpaceIndex = line.indexOf(' ');
676
+ if (firstSpaceIndex === -1) {
677
+ return `\n_${line}_`;
678
+ }
679
+ const firstWord = line.substring(0, firstSpaceIndex);
680
+ return `\n_${firstWord}_ ${line.substring(firstSpaceIndex + 1)}`;
681
+ }
682
+ if (options.commentTokens) {
683
+ options.commentTokens.push(token);
684
+ }
685
+ return line;
686
+ }).join('\n');
503
687
  }
504
688
  /**
505
- * Given a URI, convert that to a regular fs path
506
- * @param uri
689
+ * Prefixes a component name so it can be used as type in the symbol table, without polluting available symbols
690
+ *
691
+ * @param sgNodeName the Name of the component
692
+ * @returns the node name, prefixed with `roSGNode`
507
693
  */
508
- uriToPath(uri) {
509
- let parsedPath = vscode_uri_1.URI.parse(uri).fsPath;
510
- //Uri annoyingly coverts all drive letters to lower case...so this will bring back whatever case it came in as
511
- let match = /\/\/\/([a-z]:)/i.exec(uri);
512
- if (match) {
513
- let originalDriveCasing = match[1];
514
- parsedPath = originalDriveCasing + parsedPath.substring(2);
515
- }
516
- const normalizedPath = path.normalize(parsedPath);
517
- return normalizedPath;
694
+ getSgNodeTypeName(sgNodeName) {
695
+ return 'roSGNode' + sgNodeName;
518
696
  }
519
697
  /**
520
698
  * Force the drive letter to lower case
521
- * @param fullPath
522
699
  */
523
700
  driveLetterToLower(fullPath) {
524
701
  if (fullPath) {
@@ -534,53 +711,72 @@ class Util {
534
711
  return fullPath;
535
712
  }
536
713
  /**
537
- * Determine if two arrays containing primitive values are equal.
538
- * This considers order and compares by equality.
714
+ * Replace the first instance of `search` in `subject` with `replacement`
539
715
  */
540
- areArraysEqual(arr1, arr2) {
541
- if (arr1.length !== arr2.length) {
542
- return false;
716
+ replaceCaseInsensitive(subject, search, replacement) {
717
+ let idx = subject.toLowerCase().indexOf(search.toLowerCase());
718
+ if (idx > -1) {
719
+ let result = subject.substring(0, idx) + replacement + subject.substring(idx + search.length);
720
+ return result;
543
721
  }
544
- for (let i = 0; i < arr1.length; i++) {
545
- if (arr1[i] !== arr2[i]) {
546
- return false;
547
- }
722
+ else {
723
+ return subject;
548
724
  }
549
- return true;
550
725
  }
551
726
  /**
552
- * Given a file path, convert it to a URI string
553
- * @param srcPath The absolute path to the source file on disk
727
+ * Does the string appear to be a uri (i.e. does it start with `file:`)
554
728
  */
555
- pathToUri(srcPath) {
556
- return vscode_uri_1.URI.file(srcPath).toString();
729
+ isUriLike(filePath) {
730
+ return (filePath === null || filePath === void 0 ? void 0 : filePath.indexOf('file:')) === 0; // eslint-disable-line @typescript-eslint/prefer-string-starts-ends-with
557
731
  }
558
732
  /**
559
- * Get the outDir from options, taking into account cwd and absolute outFile paths
560
- * @param options
733
+ * Given a file path, convert it to a URI string
561
734
  */
562
- getOutDir(options) {
563
- options = this.normalizeConfig(options);
564
- let cwd = path.normalize(options.cwd ? options.cwd : process.cwd());
565
- if (path.isAbsolute(options.outFile)) {
566
- return path.dirname(options.outFile);
735
+ pathToUri(filePath) {
736
+ if (!filePath) {
737
+ return filePath;
738
+ }
739
+ else if (this.pathToURICache.has(filePath)) {
740
+ return this.pathToURICache.get(filePath);
741
+ }
742
+ else if (this.isUriLike(filePath)) {
743
+ return filePath;
567
744
  }
568
745
  else {
569
- return path.normalize(path.join(cwd, path.dirname(options.outFile)));
746
+ const uri = vscode_uri_1.URI.file(filePath).toString();
747
+ this.pathToURICache.set(filePath, uri);
748
+ return uri;
749
+ }
750
+ }
751
+ /**
752
+ * Given a URI, convert that to a regular fs path
753
+ */
754
+ uriToPath(uri) {
755
+ //if this doesn't look like a URI, then assume it's already a path
756
+ if (this.isUriLike(uri) === false) {
757
+ return uri;
758
+ }
759
+ let parsedPath = vscode_uri_1.URI.parse(uri).fsPath;
760
+ //Uri annoyingly converts all drive letters to lower case...so this will bring back whatever case it came in as
761
+ let match = /\/\/\/([a-z]:)/i.exec(uri);
762
+ if (match) {
763
+ let originalDriveCasing = match[1];
764
+ parsedPath = originalDriveCasing + parsedPath.substring(2);
570
765
  }
766
+ const normalizedPath = path.normalize(parsedPath);
767
+ return normalizedPath;
571
768
  }
572
769
  /**
573
770
  * Get paths to all files on disc that match this project's source list
574
771
  */
575
772
  async getFilePaths(options) {
576
773
  let rootDir = this.getRootDir(options);
577
- let files = await rokuDeploy.getFilePaths(options.files, rootDir);
774
+ let files = await roku_deploy_1.rokuDeploy.getFilePaths(options.files, rootDir);
578
775
  return files;
579
776
  }
580
777
  /**
581
778
  * Given a path to a brs file, compute the path to a theoretical d.bs file.
582
- * Only `.brs` files can have a typedef, so return undefined for everything else
583
- * @param brsSrcPath The absolute path to the .brs source file on disk
779
+ * Only `.brs` files can have typedef path, so return undefined for everything else
584
780
  */
585
781
  getTypedefPath(brsSrcPath) {
586
782
  const typedefPath = brsSrcPath
@@ -593,51 +789,9 @@ class Util {
593
789
  return undefined;
594
790
  }
595
791
  }
596
- /**
597
- * Determine whether this diagnostic should be supressed or not, based on brs comment-flags
598
- * @param diagnostic
599
- */
600
- diagnosticIsSuppressed(diagnostic) {
601
- var _a, _b;
602
- for (let flag of (_b = (_a = diagnostic.file) === null || _a === void 0 ? void 0 : _a.commentFlags) !== null && _b !== void 0 ? _b : []) {
603
- //this diagnostic is affected by this flag
604
- if (this.rangeContains(flag.affectedRange, diagnostic.range.start)) {
605
- //if the flag acts upon this diagnostic's code
606
- if (flag.codes === null || flag.codes.includes(diagnostic.code)) {
607
- return true;
608
- }
609
- }
610
- }
611
- }
612
- /**
613
- * Walks up the chain
614
- * @param currentPath
615
- */
616
- async findClosestConfigFile(currentPath) {
617
- //make the path absolute
618
- currentPath = path.resolve(path.normalize(currentPath));
619
- let previousPath;
620
- //using ../ on the root of the drive results in the same file path, so that's how we know we reached the top
621
- while (previousPath !== currentPath) {
622
- previousPath = currentPath;
623
- let bsPath = path.join(currentPath, 'bsconfig.json');
624
- let brsPath = path.join(currentPath, 'brsconfig.json');
625
- if (await this.pathExists(bsPath)) {
626
- return bsPath;
627
- }
628
- else if (await this.pathExists(brsPath)) {
629
- return brsPath;
630
- }
631
- else {
632
- //walk upwards one directory
633
- currentPath = path.resolve(path.join(currentPath, '../'));
634
- }
635
- }
636
- //got to the root path, no config file exists
637
- }
638
792
  /**
639
793
  * Set a timeout for the specified milliseconds, and resolve the promise once the timeout is finished.
640
- * @param milliseconds
794
+ * @param milliseconds the minimum number of milliseconds to sleep for
641
795
  */
642
796
  sleep(milliseconds) {
643
797
  return new Promise((resolve) => {
@@ -650,14 +804,6 @@ class Util {
650
804
  }
651
805
  });
652
806
  }
653
- /**
654
- * Given an array, map and then flatten
655
- * @param arr
656
- * @param cb
657
- */
658
- flatMap(array, cb) {
659
- return Array.prototype.concat.apply([], array.map(cb));
660
- }
661
807
  /**
662
808
  * Determines if the position is greater than the range. This means
663
809
  * the position does not touch the range, and has a position greater than the end
@@ -682,56 +828,49 @@ class Util {
682
828
  }
683
829
  }
684
830
  /**
685
- * Get a location object back by extracting location information from other objects that contain location
686
- */
687
- getRange(startObj, endObj) {
688
- return exports.util.createRangeFromPositions(startObj.range.start, endObj.range.end);
689
- }
690
- /**
691
- * If the two items both start on the same line
831
+ * Get a range back from an object that contains (or is) a range
692
832
  */
693
- sameStartLine(first, second) {
694
- if (first && second && first.range.start.line === second.range.start.line) {
695
- return true;
833
+ extractRange(rangeIsh) {
834
+ var _a;
835
+ if (!rangeIsh) {
836
+ return undefined;
837
+ }
838
+ else if ('location' in rangeIsh) {
839
+ return (_a = rangeIsh.location) === null || _a === void 0 ? void 0 : _a.range;
840
+ }
841
+ else if ('range' in rangeIsh) {
842
+ return rangeIsh.range;
843
+ }
844
+ else if (vscode_languageserver_1.Range.is(rangeIsh)) {
845
+ return rangeIsh;
696
846
  }
697
847
  else {
698
- return false;
848
+ return undefined;
699
849
  }
700
850
  }
701
851
  /**
702
852
  * If the two items have lines that touch
703
- * @param first
704
- * @param second
705
853
  */
706
854
  linesTouch(first, second) {
707
- if (first && second && (first.range.start.line === second.range.start.line ||
708
- first.range.start.line === second.range.end.line ||
709
- first.range.end.line === second.range.start.line ||
710
- first.range.end.line === second.range.end.line)) {
855
+ const firstRange = this.extractRange(first);
856
+ const secondRange = this.extractRange(second);
857
+ if (firstRange && secondRange && (firstRange.start.line === secondRange.start.line ||
858
+ firstRange.start.line === secondRange.end.line ||
859
+ firstRange.end.line === secondRange.start.line ||
860
+ firstRange.end.line === secondRange.end.line)) {
711
861
  return true;
712
862
  }
713
863
  else {
714
864
  return false;
715
865
  }
716
866
  }
717
- /**
718
- * Given text with (or without) dots separating text, get the rightmost word.
719
- * (i.e. given "A.B.C", returns "C". or "B" returns "B because there's no dot)
720
- */
721
- getTextAfterFinalDot(name) {
722
- if (name) {
723
- let parts = name.split('.');
724
- if (parts.length > 0) {
725
- return parts[parts.length - 1];
726
- }
727
- }
728
- }
729
867
  /**
730
868
  * Find a script import that the current position touches, or undefined if not found
731
869
  */
732
870
  getScriptImportAtPosition(scriptImports, position) {
733
871
  let scriptImport = scriptImports.find((x) => {
734
- return x.filePathRange.start.line === position.line &&
872
+ return x.filePathRange &&
873
+ x.filePathRange.start.line === position.line &&
735
874
  //column between start and end
736
875
  position.character >= x.filePathRange.start.character &&
737
876
  position.character <= x.filePathRange.end.character;
@@ -775,11 +914,46 @@ class Util {
775
914
  rangeLines.push(lines[i]);
776
915
  }
777
916
  const lastLine = rangeLines.pop();
778
- rangeLines.push(lastLine.substring(0, endCharacter));
917
+ if (lastLine !== undefined) {
918
+ rangeLines.push(lastLine.substring(0, endCharacter));
919
+ }
779
920
  return rangeLines.join('\n');
780
921
  }
781
922
  /**
782
- * Helper for creating `Range` objects. Prefer using this function because vscode-languageserver's `util.createRange()` is significantly slower
923
+ * Helper for creating `Location` objects. Prefer using this function because vscode-languageserver's `Location.create()` is significantly slower at scale
924
+ */
925
+ createLocationFromRange(uri, range) {
926
+ return {
927
+ uri: exports.util.pathToUri(uri),
928
+ range: range
929
+ };
930
+ }
931
+ /**
932
+ * Helper for creating `Location` objects from a file and range
933
+ */
934
+ createLocationFromFileRange(file, range) {
935
+ return this.createLocationFromRange(this.pathToUri(file === null || file === void 0 ? void 0 : file.srcPath), range);
936
+ }
937
+ /**
938
+ * Helper for creating `Location` objects by passing each range value in directly. Prefer using this function because vscode-languageserver's `Location.create()` is significantly slower at scale
939
+ */
940
+ createLocation(startLine, startCharacter, endLine, endCharacter, uri) {
941
+ return {
942
+ uri: exports.util.pathToUri(uri),
943
+ range: {
944
+ start: {
945
+ line: startLine,
946
+ character: startCharacter
947
+ },
948
+ end: {
949
+ line: endLine,
950
+ character: endCharacter
951
+ }
952
+ }
953
+ };
954
+ }
955
+ /**
956
+ * Helper for creating `Range` objects. Prefer using this function because vscode-languageserver's `Range.create()` is significantly slower.
783
957
  */
784
958
  createRange(startLine, startCharacter, endLine, endCharacter) {
785
959
  return {
@@ -797,141 +971,708 @@ class Util {
797
971
  * Create a `Range` from two `Position`s
798
972
  */
799
973
  createRangeFromPositions(startPosition, endPosition) {
800
- return {
801
- start: {
802
- line: startPosition.line,
803
- character: startPosition.character
804
- },
805
- end: {
806
- line: endPosition.line,
807
- character: endPosition.character
808
- }
809
- };
974
+ startPosition = startPosition !== null && startPosition !== void 0 ? startPosition : endPosition;
975
+ endPosition = endPosition !== null && endPosition !== void 0 ? endPosition : startPosition;
976
+ if (!startPosition && !endPosition) {
977
+ return undefined;
978
+ }
979
+ return this.createRange(startPosition.line, startPosition.character, endPosition.line, endPosition.character);
810
980
  }
811
981
  /**
812
- * Given a list of ranges, create a range that starts with the first non-null lefthand range, and ends with the first non-null
813
- * righthand range. Returns undefined if none of the items have a range.
982
+ * Clone a range
814
983
  */
815
- createBoundingRange(...locatables) {
816
- let leftmost;
817
- let rightmost;
818
- for (let i = 0; i < locatables.length; i++) {
819
- //set the leftmost non-null-range item
820
- const left = locatables[i];
821
- if (!leftmost && (left === null || left === void 0 ? void 0 : left.range)) {
822
- leftmost = left;
823
- }
824
- //set the rightmost non-null-range item
825
- const right = locatables[locatables.length - 1 - i];
826
- if (!rightmost && (right === null || right === void 0 ? void 0 : right.range)) {
827
- rightmost = right;
828
- }
829
- //if we have both sides, quit
830
- if (leftmost && rightmost) {
831
- break;
832
- }
833
- }
834
- if (leftmost) {
835
- return this.createRangeFromPositions(leftmost.range.start, rightmost.range.end);
984
+ cloneLocation(location) {
985
+ if (location) {
986
+ return {
987
+ uri: location.uri,
988
+ range: {
989
+ start: {
990
+ line: location.range.start.line,
991
+ character: location.range.start.character
992
+ },
993
+ end: {
994
+ line: location.range.end.line,
995
+ character: location.range.end.character
996
+ }
997
+ }
998
+ };
836
999
  }
837
1000
  else {
838
- return undefined;
1001
+ return location;
839
1002
  }
840
1003
  }
841
1004
  /**
842
- * Create a `Position` object. Prefer this over `Position.create` for performance reasons
1005
+ * Clone every token
843
1006
  */
844
- createPosition(line, character) {
845
- return {
846
- line: line,
847
- character: character
848
- };
849
- }
850
- /**
851
- * Convert a list of tokens into a string, including their leading whitespace
852
- */
853
- tokensToString(tokens) {
854
- let result = '';
855
- //skip iterating the final token
856
- for (let i = 0; i < tokens.length; i++) {
857
- let token = tokens[i];
858
- result += token.leadingWhitespace + token.text;
1007
+ cloneToken(token) {
1008
+ if (token) {
1009
+ const result = {
1010
+ kind: token.kind,
1011
+ location: this.cloneLocation(token.location),
1012
+ text: token.text,
1013
+ isReserved: token.isReserved,
1014
+ leadingWhitespace: token.leadingWhitespace,
1015
+ leadingTrivia: token.leadingTrivia ? token.leadingTrivia.map(x => this.cloneToken(x)) : undefined
1016
+ };
1017
+ //handle those tokens that have charCode
1018
+ if ('charCode' in token) {
1019
+ result.charCode = token.charCode;
1020
+ }
1021
+ return result;
1022
+ }
1023
+ else {
1024
+ return token;
859
1025
  }
860
- return result;
861
1026
  }
862
1027
  /**
863
- * Convert a token into a BscType
1028
+ * Gets the bounding range of a bunch of ranges or objects that have ranges
1029
+ * TODO: this does a full iteration of the args. If the args were guaranteed to be in range order, we could optimize this
864
1030
  */
865
- tokenToBscType(token, allowCustomType = true) {
866
- if (!token) {
867
- return new DynamicType_1.DynamicType();
868
- }
869
- // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
1031
+ createBoundingLocation(...locatables) {
1032
+ var _a, _b;
1033
+ let uri;
1034
+ let startPosition;
1035
+ let endPosition;
1036
+ for (let locatable of locatables) {
1037
+ let range;
1038
+ if (!locatable) {
1039
+ continue;
1040
+ }
1041
+ else if ('location' in locatable) {
1042
+ range = (_a = locatable.location) === null || _a === void 0 ? void 0 : _a.range;
1043
+ if (!uri) {
1044
+ uri = (_b = locatable.location) === null || _b === void 0 ? void 0 : _b.uri;
1045
+ }
1046
+ }
1047
+ else if (vscode_languageserver_1.Location.is(locatable)) {
1048
+ range = locatable.range;
1049
+ if (!uri) {
1050
+ uri = locatable.uri;
1051
+ }
1052
+ }
1053
+ else if ('range' in locatable) {
1054
+ range = locatable.range;
1055
+ }
1056
+ else {
1057
+ range = locatable;
1058
+ }
1059
+ //skip undefined locations or locations without a range
1060
+ if (!range) {
1061
+ continue;
1062
+ }
1063
+ if (!startPosition) {
1064
+ startPosition = range.start;
1065
+ }
1066
+ else if (this.comparePosition(range.start, startPosition) < 0) {
1067
+ startPosition = range.start;
1068
+ }
1069
+ if (!endPosition) {
1070
+ endPosition = range.end;
1071
+ }
1072
+ else if (this.comparePosition(range.end, endPosition) > 0) {
1073
+ endPosition = range.end;
1074
+ }
1075
+ }
1076
+ if (startPosition && endPosition) {
1077
+ return exports.util.createLocation(startPosition.line, startPosition.character, endPosition.line, endPosition.character, uri);
1078
+ }
1079
+ else {
1080
+ return undefined;
1081
+ }
1082
+ }
1083
+ /**
1084
+ * Gets the bounding range of a bunch of ranges or objects that have ranges
1085
+ * TODO: this does a full iteration of the args. If the args were guaranteed to be in range order, we could optimize this
1086
+ */
1087
+ createBoundingRange(...locatables) {
1088
+ var _a;
1089
+ return (_a = this.createBoundingLocation(...locatables)) === null || _a === void 0 ? void 0 : _a.range;
1090
+ }
1091
+ /**
1092
+ * Gets the bounding range of an object that contains a bunch of tokens
1093
+ * @param tokens Object with tokens in it
1094
+ * @returns Range containing all the tokens
1095
+ */
1096
+ createBoundingLocationFromTokens(tokens) {
1097
+ var _a;
1098
+ let uri;
1099
+ let startPosition;
1100
+ let endPosition;
1101
+ for (let key in tokens) {
1102
+ let token = tokens === null || tokens === void 0 ? void 0 : tokens[key];
1103
+ let locatableRange = (_a = token === null || token === void 0 ? void 0 : token.location) === null || _a === void 0 ? void 0 : _a.range;
1104
+ if (!locatableRange) {
1105
+ continue;
1106
+ }
1107
+ if (!startPosition) {
1108
+ startPosition = locatableRange.start;
1109
+ }
1110
+ else if (this.comparePosition(locatableRange.start, startPosition) < 0) {
1111
+ startPosition = locatableRange.start;
1112
+ }
1113
+ if (!endPosition) {
1114
+ endPosition = locatableRange.end;
1115
+ }
1116
+ else if (this.comparePosition(locatableRange.end, endPosition) > 0) {
1117
+ endPosition = locatableRange.end;
1118
+ }
1119
+ if (!uri) {
1120
+ uri = token.location.uri;
1121
+ }
1122
+ }
1123
+ if (startPosition && endPosition) {
1124
+ return this.createLocation(startPosition.line, startPosition.character, endPosition.line, endPosition.character, uri);
1125
+ }
1126
+ else {
1127
+ return undefined;
1128
+ }
1129
+ }
1130
+ /**
1131
+ * Create a `Position` object. Prefer this over `Position.create` for performance reasons.
1132
+ */
1133
+ createPosition(line, character) {
1134
+ return {
1135
+ line: line,
1136
+ character: character
1137
+ };
1138
+ }
1139
+ /**
1140
+ * Convert a token into a BscType
1141
+ */
1142
+ tokenToBscType(token) {
1143
+ // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
870
1144
  switch (token.kind) {
871
- case lexer_1.TokenKind.Boolean:
872
- case lexer_1.TokenKind.True:
873
- case lexer_1.TokenKind.False:
874
- return new BooleanType_1.BooleanType();
875
- case lexer_1.TokenKind.Double:
876
- case lexer_1.TokenKind.DoubleLiteral:
877
- return new DoubleType_1.DoubleType();
878
- case lexer_1.TokenKind.Dynamic:
879
- return new DynamicType_1.DynamicType();
880
- case lexer_1.TokenKind.Float:
881
- case lexer_1.TokenKind.FloatLiteral:
882
- return new FloatType_1.FloatType();
883
- case lexer_1.TokenKind.Function:
884
- //TODO should there be a more generic function type without a signature that's assignable to all other function types?
885
- return new FunctionType_1.FunctionType(new DynamicType_1.DynamicType());
886
- case lexer_1.TokenKind.Integer:
887
- case lexer_1.TokenKind.IntegerLiteral:
888
- return new IntegerType_1.IntegerType();
889
- case lexer_1.TokenKind.Invalid:
890
- return new InvalidType_1.InvalidType();
891
- case lexer_1.TokenKind.LongInteger:
892
- case lexer_1.TokenKind.LongIntegerLiteral:
893
- return new LongIntegerType_1.LongIntegerType();
894
- case lexer_1.TokenKind.Object:
895
- return new ObjectType_1.ObjectType();
896
- case lexer_1.TokenKind.String:
897
- case lexer_1.TokenKind.StringLiteral:
898
- case lexer_1.TokenKind.TemplateStringExpressionBegin:
899
- case lexer_1.TokenKind.TemplateStringExpressionEnd:
900
- case lexer_1.TokenKind.TemplateStringQuasi:
901
- return new StringType_1.StringType();
902
- case lexer_1.TokenKind.Void:
903
- return new VoidType_1.VoidType();
904
- case lexer_1.TokenKind.Identifier:
1145
+ case TokenKind_1.TokenKind.Boolean:
1146
+ return BooleanType_1.BooleanType.instance;
1147
+ case TokenKind_1.TokenKind.True:
1148
+ case TokenKind_1.TokenKind.False:
1149
+ return BooleanType_1.BooleanType.instance;
1150
+ case TokenKind_1.TokenKind.Double:
1151
+ return DoubleType_1.DoubleType.instance;
1152
+ case TokenKind_1.TokenKind.DoubleLiteral:
1153
+ return DoubleType_1.DoubleType.instance;
1154
+ case TokenKind_1.TokenKind.Dynamic:
1155
+ return DynamicType_1.DynamicType.instance;
1156
+ case TokenKind_1.TokenKind.Float:
1157
+ return FloatType_1.FloatType.instance;
1158
+ case TokenKind_1.TokenKind.FloatLiteral:
1159
+ return FloatType_1.FloatType.instance;
1160
+ case TokenKind_1.TokenKind.Function:
1161
+ return FunctionType_1.FunctionType.instance;
1162
+ case TokenKind_1.TokenKind.Integer:
1163
+ return IntegerType_1.IntegerType.instance;
1164
+ case TokenKind_1.TokenKind.IntegerLiteral:
1165
+ return IntegerType_1.IntegerType.instance;
1166
+ case TokenKind_1.TokenKind.Invalid:
1167
+ return InvalidType_1.InvalidType.instance;
1168
+ case TokenKind_1.TokenKind.LongInteger:
1169
+ return LongIntegerType_1.LongIntegerType.instance;
1170
+ case TokenKind_1.TokenKind.LongIntegerLiteral:
1171
+ return LongIntegerType_1.LongIntegerType.instance;
1172
+ case TokenKind_1.TokenKind.Object:
1173
+ return ObjectType_1.ObjectType.instance;
1174
+ case TokenKind_1.TokenKind.String:
1175
+ return StringType_1.StringType.instance;
1176
+ case TokenKind_1.TokenKind.StringLiteral:
1177
+ case TokenKind_1.TokenKind.TemplateStringExpressionBegin:
1178
+ case TokenKind_1.TokenKind.TemplateStringExpressionEnd:
1179
+ case TokenKind_1.TokenKind.TemplateStringQuasi:
1180
+ return StringType_1.StringType.instance;
1181
+ case TokenKind_1.TokenKind.Void:
1182
+ return VoidType_1.VoidType.instance;
1183
+ case TokenKind_1.TokenKind.Identifier:
905
1184
  switch (token.text.toLowerCase()) {
906
1185
  case 'boolean':
907
- return new BooleanType_1.BooleanType();
1186
+ return BooleanType_1.BooleanType.instance;
908
1187
  case 'double':
909
- return new DoubleType_1.DoubleType();
1188
+ return DoubleType_1.DoubleType.instance;
1189
+ case 'dynamic':
1190
+ return DynamicType_1.DynamicType.instance;
910
1191
  case 'float':
911
- return new FloatType_1.FloatType();
1192
+ return FloatType_1.FloatType.instance;
912
1193
  case 'function':
913
- return new FunctionType_1.FunctionType(new DynamicType_1.DynamicType());
1194
+ return FunctionType_1.FunctionType.instance;
914
1195
  case 'integer':
915
- return new IntegerType_1.IntegerType();
1196
+ return IntegerType_1.IntegerType.instance;
916
1197
  case 'invalid':
917
- return new InvalidType_1.InvalidType();
1198
+ return InvalidType_1.InvalidType.instance;
918
1199
  case 'longinteger':
919
- return new LongIntegerType_1.LongIntegerType();
1200
+ return LongIntegerType_1.LongIntegerType.instance;
920
1201
  case 'object':
921
- return new ObjectType_1.ObjectType();
1202
+ return ObjectType_1.ObjectType.instance;
922
1203
  case 'string':
923
- return new StringType_1.StringType();
1204
+ return StringType_1.StringType.instance;
924
1205
  case 'void':
925
- return new VoidType_1.VoidType();
1206
+ return VoidType_1.VoidType.instance;
1207
+ }
1208
+ }
1209
+ }
1210
+ /**
1211
+ * Deciphers the correct types for fields based on docs
1212
+ * https://developer.roku.com/en-ca/docs/references/scenegraph/xml-elements/interface.md
1213
+ * @param typeDescriptor the type descriptor from the docs
1214
+ * @returns {BscType} the known type, or dynamic
1215
+ */
1216
+ getNodeFieldType(typeDescriptor, lookupTable) {
1217
+ let typeDescriptorLower = typeDescriptor.toLowerCase().trim().replace(/\*/g, '');
1218
+ if (typeDescriptorLower.startsWith('as ')) {
1219
+ typeDescriptorLower = typeDescriptorLower.substring(3).trim();
1220
+ }
1221
+ const nodeFilter = (new RegExp(/^\[?(.* node)/, 'i')).exec(typeDescriptorLower);
1222
+ if (nodeFilter === null || nodeFilter === void 0 ? void 0 : nodeFilter[1]) {
1223
+ typeDescriptorLower = nodeFilter[1].trim();
1224
+ }
1225
+ const parensFilter = (new RegExp(/(.*)\(.*\)/, 'gi')).exec(typeDescriptorLower);
1226
+ if (parensFilter === null || parensFilter === void 0 ? void 0 : parensFilter[1]) {
1227
+ typeDescriptorLower = parensFilter[1].trim();
1228
+ }
1229
+ const bscType = this.tokenToBscType((0, creators_1.createToken)(TokenKind_1.TokenKind.Identifier, typeDescriptorLower));
1230
+ if (bscType) {
1231
+ return bscType;
1232
+ }
1233
+ function getRect2dType() {
1234
+ const rect2dType = new AssociativeArrayType_1.AssociativeArrayType();
1235
+ rect2dType.addMember('height', {}, FloatType_1.FloatType.instance, 1 /* SymbolTypeFlag.runtime */);
1236
+ rect2dType.addMember('width', {}, FloatType_1.FloatType.instance, 1 /* SymbolTypeFlag.runtime */);
1237
+ rect2dType.addMember('x', {}, FloatType_1.FloatType.instance, 1 /* SymbolTypeFlag.runtime */);
1238
+ rect2dType.addMember('y', {}, FloatType_1.FloatType.instance, 1 /* SymbolTypeFlag.runtime */);
1239
+ return rect2dType;
1240
+ }
1241
+ function getColorType() {
1242
+ return (0, UnionType_1.unionTypeFactory)([IntegerType_1.IntegerType.instance, StringType_1.StringType.instance]);
1243
+ }
1244
+ //check for uniontypes
1245
+ const multipleTypes = typeDescriptorLower.split(' or ').map(s => s.trim());
1246
+ if (multipleTypes.length > 1) {
1247
+ const individualTypes = multipleTypes.map(t => this.getNodeFieldType(t, lookupTable));
1248
+ return (0, UnionType_1.unionTypeFactory)(individualTypes);
1249
+ }
1250
+ const typeIsArray = typeDescriptorLower.startsWith('array of ') || typeDescriptorLower.startsWith('roarray of ');
1251
+ if (typeIsArray) {
1252
+ const ofSearch = ' of ';
1253
+ const arrayPrefixLength = typeDescriptorLower.indexOf(ofSearch) + ofSearch.length;
1254
+ let arrayOfTypeName = typeDescriptorLower.substring(arrayPrefixLength); //cut off beginnin, eg. 'array of' or 'roarray of'
1255
+ if (arrayOfTypeName.endsWith('s')) {
1256
+ // remove "s" in "floats", etc.
1257
+ arrayOfTypeName = arrayOfTypeName.substring(0, arrayOfTypeName.length - 1);
1258
+ }
1259
+ if (arrayOfTypeName.endsWith('\'')) {
1260
+ // remove "'" in "float's", etc.
1261
+ arrayOfTypeName = arrayOfTypeName.substring(0, arrayOfTypeName.length - 1);
1262
+ }
1263
+ if (arrayOfTypeName === 'rectangle') {
1264
+ arrayOfTypeName = 'rect2d';
1265
+ }
1266
+ let arrayType = this.getNodeFieldType(arrayOfTypeName, lookupTable);
1267
+ return new ArrayType_1.ArrayType(arrayType);
1268
+ }
1269
+ else if (typeDescriptorLower.startsWith('option ')) {
1270
+ const actualTypeName = typeDescriptorLower.substring('option '.length); //cut off beginning 'option '
1271
+ return this.getNodeFieldType(actualTypeName, lookupTable);
1272
+ }
1273
+ else if (typeDescriptorLower.startsWith('value ')) {
1274
+ const actualTypeName = typeDescriptorLower.substring('value '.length); //cut off beginning 'value '
1275
+ return this.getNodeFieldType(actualTypeName, lookupTable);
1276
+ }
1277
+ else if (typeDescriptorLower === 'n/a') {
1278
+ return DynamicType_1.DynamicType.instance;
1279
+ }
1280
+ else if (typeDescriptorLower === 'uri') {
1281
+ return StringType_1.StringType.instance;
1282
+ }
1283
+ else if (typeDescriptorLower === 'color') {
1284
+ return getColorType();
1285
+ }
1286
+ else if (typeDescriptorLower === 'vector2d' || typeDescriptorLower === 'floatarray') {
1287
+ return new ArrayType_1.ArrayType(FloatType_1.FloatType.instance);
1288
+ }
1289
+ else if (typeDescriptorLower === 'vector2darray') {
1290
+ return new ArrayType_1.ArrayType(new ArrayType_1.ArrayType(FloatType_1.FloatType.instance));
1291
+ }
1292
+ else if (typeDescriptorLower === 'intarray') {
1293
+ return new ArrayType_1.ArrayType(IntegerType_1.IntegerType.instance);
1294
+ }
1295
+ else if (typeDescriptorLower === 'colorarray') {
1296
+ return new ArrayType_1.ArrayType(getColorType());
1297
+ }
1298
+ else if (typeDescriptorLower === 'boolarray') {
1299
+ return new ArrayType_1.ArrayType(BooleanType_1.BooleanType.instance);
1300
+ }
1301
+ else if (typeDescriptorLower === 'stringarray' || typeDescriptorLower === 'strarray') {
1302
+ return new ArrayType_1.ArrayType(StringType_1.StringType.instance);
1303
+ }
1304
+ else if (typeDescriptorLower === 'int') {
1305
+ return IntegerType_1.IntegerType.instance;
1306
+ }
1307
+ else if (typeDescriptorLower === 'time') {
1308
+ return DoubleType_1.DoubleType.instance;
1309
+ }
1310
+ else if (typeDescriptorLower === 'str') {
1311
+ return StringType_1.StringType.instance;
1312
+ }
1313
+ else if (typeDescriptorLower === 'bool') {
1314
+ return BooleanType_1.BooleanType.instance;
1315
+ }
1316
+ else if (typeDescriptorLower === 'array' || typeDescriptorLower === 'roarray') {
1317
+ return new ArrayType_1.ArrayType();
1318
+ }
1319
+ else if (typeDescriptorLower === 'assocarray' ||
1320
+ typeDescriptorLower === 'associative array' ||
1321
+ typeDescriptorLower === 'associativearray' ||
1322
+ typeDescriptorLower === 'roassociativearray' ||
1323
+ typeDescriptorLower.startsWith('associative array of') ||
1324
+ typeDescriptorLower.startsWith('associativearray of') ||
1325
+ typeDescriptorLower.startsWith('roassociativearray of')) {
1326
+ return new AssociativeArrayType_1.AssociativeArrayType();
1327
+ }
1328
+ else if (typeDescriptorLower === 'node') {
1329
+ return ComponentType_1.ComponentType.instance;
1330
+ }
1331
+ else if (typeDescriptorLower === 'nodearray') {
1332
+ return new ArrayType_1.ArrayType(ComponentType_1.ComponentType.instance);
1333
+ }
1334
+ else if (typeDescriptorLower === 'rect2d') {
1335
+ return getRect2dType();
1336
+ }
1337
+ else if (typeDescriptorLower === 'rect2darray') {
1338
+ return new ArrayType_1.ArrayType(getRect2dType());
1339
+ }
1340
+ else if (typeDescriptorLower === 'font') {
1341
+ return this.getNodeFieldType('roSGNodeFont', lookupTable);
1342
+ }
1343
+ else if (typeDescriptorLower === 'contentnode') {
1344
+ return this.getNodeFieldType('roSGNodeContentNode', lookupTable);
1345
+ }
1346
+ else if (typeDescriptorLower.endsWith(' node')) {
1347
+ return this.getNodeFieldType('roSgNode' + typeDescriptorLower.substring(0, typeDescriptorLower.length - 5), lookupTable);
1348
+ }
1349
+ else if (lookupTable) {
1350
+ //try doing a lookup
1351
+ return lookupTable.getSymbolType(typeDescriptorLower, {
1352
+ flags: 2 /* SymbolTypeFlag.typetime */,
1353
+ fullName: typeDescriptor,
1354
+ tableProvider: () => lookupTable
1355
+ });
1356
+ }
1357
+ return DynamicType_1.DynamicType.instance;
1358
+ }
1359
+ /**
1360
+ * Return the type of the result of a binary operator
1361
+ * Note: compound assignments (eg. +=) internally use a binary expression, so that's why TokenKind.PlusEqual, etc. are here too
1362
+ */
1363
+ binaryOperatorResultType(leftType, operator, rightType) {
1364
+ if (((0, reflection_1.isAnyReferenceType)(leftType) && !leftType.isResolvable()) ||
1365
+ ((0, reflection_1.isAnyReferenceType)(rightType) && !rightType.isResolvable())) {
1366
+ return new ReferenceType_1.BinaryOperatorReferenceType(leftType, operator, rightType, (lhs, op, rhs) => {
1367
+ return this.binaryOperatorResultType(lhs, op, rhs);
1368
+ });
1369
+ }
1370
+ // Try to find a common value of union type
1371
+ leftType = (0, helpers_1.getUniqueType)([leftType], UnionType_1.unionTypeFactory);
1372
+ rightType = (0, helpers_1.getUniqueType)([rightType], UnionType_1.unionTypeFactory);
1373
+ if ((0, reflection_1.isUnionType)(leftType)) {
1374
+ leftType = this.getHighestPriorityType(leftType.types);
1375
+ }
1376
+ if ((0, reflection_1.isUnionType)(rightType)) {
1377
+ rightType = this.getHighestPriorityType(rightType.types);
1378
+ }
1379
+ if ((0, reflection_1.isVoidType)(leftType) || (0, reflection_1.isVoidType)(rightType) || (0, reflection_1.isUninitializedType)(leftType) || (0, reflection_1.isUninitializedType)(rightType)) {
1380
+ return undefined;
1381
+ }
1382
+ if ((0, reflection_1.isEnumMemberType)(leftType)) {
1383
+ leftType = leftType.underlyingType;
1384
+ }
1385
+ if ((0, reflection_1.isEnumMemberType)(rightType)) {
1386
+ rightType = rightType.underlyingType;
1387
+ }
1388
+ // treat object type like dynamic
1389
+ if ((0, reflection_1.isObjectType)(leftType)) {
1390
+ leftType = DynamicType_1.DynamicType.instance;
1391
+ }
1392
+ if ((0, reflection_1.isObjectType)(rightType)) {
1393
+ rightType = DynamicType_1.DynamicType.instance;
1394
+ }
1395
+ let hasDouble = (0, reflection_1.isDoubleTypeLike)(leftType) || (0, reflection_1.isDoubleTypeLike)(rightType);
1396
+ let hasFloat = (0, reflection_1.isFloatTypeLike)(leftType) || (0, reflection_1.isFloatTypeLike)(rightType);
1397
+ let hasLongInteger = (0, reflection_1.isLongIntegerTypeLike)(leftType) || (0, reflection_1.isLongIntegerTypeLike)(rightType);
1398
+ let hasInvalid = (0, reflection_1.isInvalidTypeLike)(leftType) || (0, reflection_1.isInvalidTypeLike)(rightType);
1399
+ let hasDynamic = (0, reflection_1.isDynamicType)(leftType) || (0, reflection_1.isDynamicType)(rightType);
1400
+ let bothDynamic = (0, reflection_1.isDynamicType)(leftType) && (0, reflection_1.isDynamicType)(rightType);
1401
+ let bothNumbers = (0, reflection_1.isNumberTypeLike)(leftType) && (0, reflection_1.isNumberTypeLike)(rightType);
1402
+ let hasNumber = (0, reflection_1.isNumberTypeLike)(leftType) || (0, reflection_1.isNumberTypeLike)(rightType);
1403
+ let bothStrings = (0, reflection_1.isStringTypeLike)(leftType) && (0, reflection_1.isStringTypeLike)(rightType);
1404
+ let hasString = (0, reflection_1.isStringTypeLike)(leftType) || (0, reflection_1.isStringTypeLike)(rightType);
1405
+ let hasBoolean = (0, reflection_1.isBooleanTypeLike)(leftType) || (0, reflection_1.isBooleanTypeLike)(rightType);
1406
+ let eitherBooleanOrNum = ((0, reflection_1.isNumberTypeLike)(leftType) || (0, reflection_1.isBooleanTypeLike)(leftType)) && ((0, reflection_1.isNumberTypeLike)(rightType) || (0, reflection_1.isBooleanTypeLike)(rightType));
1407
+ let leftIsPrimitive = (0, reflection_1.isPrimitiveType)(leftType);
1408
+ let rightIsPrimitive = (0, reflection_1.isPrimitiveType)(rightType);
1409
+ let hasPrimitive = leftIsPrimitive || rightIsPrimitive;
1410
+ let nonDynamicType;
1411
+ if (hasPrimitive) {
1412
+ nonDynamicType = leftIsPrimitive ? leftType : rightType;
1413
+ }
1414
+ // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
1415
+ switch (operator.kind) {
1416
+ // Math operators
1417
+ case TokenKind_1.TokenKind.Plus:
1418
+ case TokenKind_1.TokenKind.PlusEqual:
1419
+ if (bothStrings) {
1420
+ // "string" + "string" is the only binary expression allowed with strings
1421
+ return StringType_1.StringType.instance;
1422
+ }
1423
+ else if (hasString && hasDynamic) {
1424
+ // assume dynamicValue is a string
1425
+ return StringType_1.StringType.instance;
1426
+ }
1427
+ // eslint-disable-next-line no-fallthrough
1428
+ case TokenKind_1.TokenKind.Minus:
1429
+ case TokenKind_1.TokenKind.MinusEqual:
1430
+ case TokenKind_1.TokenKind.Star:
1431
+ case TokenKind_1.TokenKind.StarEqual:
1432
+ case TokenKind_1.TokenKind.Mod:
1433
+ if (bothNumbers) {
1434
+ if (hasDouble) {
1435
+ return DoubleType_1.DoubleType.instance;
1436
+ }
1437
+ else if (hasFloat) {
1438
+ return FloatType_1.FloatType.instance;
1439
+ }
1440
+ else if (hasLongInteger) {
1441
+ return LongIntegerType_1.LongIntegerType.instance;
1442
+ }
1443
+ return IntegerType_1.IntegerType.instance;
1444
+ }
1445
+ else if (hasNumber && hasDynamic) {
1446
+ // assume dynamic is a number
1447
+ return nonDynamicType;
1448
+ }
1449
+ break;
1450
+ case TokenKind_1.TokenKind.Forwardslash:
1451
+ case TokenKind_1.TokenKind.ForwardslashEqual:
1452
+ if (bothNumbers) {
1453
+ if (hasDouble) {
1454
+ return DoubleType_1.DoubleType.instance;
1455
+ }
1456
+ else if (hasFloat) {
1457
+ return FloatType_1.FloatType.instance;
1458
+ }
1459
+ else if (hasLongInteger) {
1460
+ return LongIntegerType_1.LongIntegerType.instance;
1461
+ }
1462
+ return FloatType_1.FloatType.instance;
1463
+ }
1464
+ else if (hasNumber && hasDynamic) {
1465
+ // assume dynamic is a number
1466
+ return nonDynamicType;
1467
+ }
1468
+ break;
1469
+ case TokenKind_1.TokenKind.Backslash:
1470
+ case TokenKind_1.TokenKind.BackslashEqual:
1471
+ if (bothNumbers) {
1472
+ if (hasLongInteger) {
1473
+ return LongIntegerType_1.LongIntegerType.instance;
1474
+ }
1475
+ return IntegerType_1.IntegerType.instance;
1476
+ }
1477
+ else if (hasNumber && hasDynamic) {
1478
+ // assume dynamic is a number
1479
+ return IntegerType_1.IntegerType.instance;
1480
+ }
1481
+ break;
1482
+ case TokenKind_1.TokenKind.Caret:
1483
+ if (bothNumbers) {
1484
+ if (hasDouble || hasLongInteger) {
1485
+ return DoubleType_1.DoubleType.instance;
1486
+ }
1487
+ else if (hasFloat) {
1488
+ return FloatType_1.FloatType.instance;
1489
+ }
1490
+ return IntegerType_1.IntegerType.instance;
926
1491
  }
927
- if (allowCustomType) {
928
- return new CustomType_1.CustomType(token.text);
1492
+ else if (hasNumber && hasDynamic) {
1493
+ // assume dynamic is a number
1494
+ return IntegerType_1.IntegerType.instance;
929
1495
  }
1496
+ break;
1497
+ // Bitshift operators
1498
+ case TokenKind_1.TokenKind.LeftShift:
1499
+ case TokenKind_1.TokenKind.LeftShiftEqual:
1500
+ case TokenKind_1.TokenKind.RightShift:
1501
+ case TokenKind_1.TokenKind.RightShiftEqual:
1502
+ if (bothNumbers) {
1503
+ if (hasLongInteger) {
1504
+ return LongIntegerType_1.LongIntegerType.instance;
1505
+ }
1506
+ // Bitshifts are allowed with non-integer numerics
1507
+ // but will always truncate to ints
1508
+ return IntegerType_1.IntegerType.instance;
1509
+ }
1510
+ else if (hasNumber && hasDynamic) {
1511
+ // assume dynamic is a number
1512
+ return IntegerType_1.IntegerType.instance;
1513
+ }
1514
+ break;
1515
+ // Comparison operators
1516
+ // All comparison operators result in boolean
1517
+ case TokenKind_1.TokenKind.Equal:
1518
+ case TokenKind_1.TokenKind.LessGreater:
1519
+ // = and <> can accept invalid / dynamic
1520
+ if (hasDynamic || hasInvalid || bothStrings || eitherBooleanOrNum) {
1521
+ return BooleanType_1.BooleanType.instance;
1522
+ }
1523
+ break;
1524
+ case TokenKind_1.TokenKind.Greater:
1525
+ case TokenKind_1.TokenKind.Less:
1526
+ case TokenKind_1.TokenKind.GreaterEqual:
1527
+ case TokenKind_1.TokenKind.LessEqual:
1528
+ if (bothStrings || bothNumbers) {
1529
+ return BooleanType_1.BooleanType.instance;
1530
+ }
1531
+ else if ((hasNumber || hasString) && hasDynamic) {
1532
+ // assume dynamic is a valid type
1533
+ return BooleanType_1.BooleanType.instance;
1534
+ }
1535
+ break;
1536
+ // Logical or bitwise operators
1537
+ case TokenKind_1.TokenKind.Or:
1538
+ case TokenKind_1.TokenKind.And:
1539
+ if (bothNumbers) {
1540
+ // "and"/"or" represent bitwise operators
1541
+ if (hasLongInteger && !hasDouble && !hasFloat) {
1542
+ // 2 long ints or long int and int
1543
+ return LongIntegerType_1.LongIntegerType.instance;
1544
+ }
1545
+ return IntegerType_1.IntegerType.instance;
1546
+ }
1547
+ else if (eitherBooleanOrNum) {
1548
+ // "and"/"or" represent logical operators
1549
+ return BooleanType_1.BooleanType.instance;
1550
+ }
1551
+ else if (hasNumber && hasDynamic) {
1552
+ // assume dynamic is a valid type
1553
+ return IntegerType_1.IntegerType.instance;
1554
+ }
1555
+ else if (hasBoolean && hasDynamic) {
1556
+ // assume dynamic is a valid type
1557
+ return BooleanType_1.BooleanType.instance;
1558
+ }
1559
+ break;
930
1560
  }
1561
+ if (bothDynamic) {
1562
+ return DynamicType_1.DynamicType.instance;
1563
+ }
1564
+ return undefined;
1565
+ }
1566
+ getHighestPriorityType(types, depth = 0) {
1567
+ let result;
1568
+ if (depth > 4) {
1569
+ // shortcut for very complicated types, or self-referencing union types
1570
+ return DynamicType_1.DynamicType.instance;
1571
+ }
1572
+ for (let type of types) {
1573
+ if ((0, reflection_1.isUnionType)(type)) {
1574
+ type = (0, helpers_1.getUniqueType)([type], UnionType_1.unionTypeFactory);
1575
+ if ((0, reflection_1.isUnionType)(type)) {
1576
+ type = this.getHighestPriorityType(type.types, depth + 1);
1577
+ }
1578
+ }
1579
+ if (!result) {
1580
+ result = type;
1581
+ }
1582
+ else {
1583
+ if (type.binaryOpPriorityLevel < result.binaryOpPriorityLevel) {
1584
+ result = type;
1585
+ }
1586
+ else if (type.binaryOpPriorityLevel === result.binaryOpPriorityLevel && !result.isEqual(type)) {
1587
+ // equal priority types, but not equal types, like Boolean and String... just be dynamic at this point
1588
+ result = DynamicType_1.DynamicType.instance;
1589
+ }
1590
+ }
1591
+ if ((0, reflection_1.isUninitializedType)(type)) {
1592
+ return type;
1593
+ }
1594
+ if ((0, reflection_1.isVoidType)(type)) {
1595
+ return type;
1596
+ }
1597
+ if ((0, reflection_1.isInvalidTypeLike)(type)) {
1598
+ return type;
1599
+ }
1600
+ if ((0, reflection_1.isObjectType)(type) && !(0, reflection_1.isDynamicType)(type)) {
1601
+ result = type;
1602
+ }
1603
+ if ((0, reflection_1.isDynamicType)(type)) {
1604
+ result = type;
1605
+ }
1606
+ }
1607
+ return result !== null && result !== void 0 ? result : DynamicType_1.DynamicType.instance;
1608
+ }
1609
+ /**
1610
+ * Return the type of the result of a unary operator
1611
+ */
1612
+ unaryOperatorResultType(operator, exprType) {
1613
+ if ((0, reflection_1.isUnionType)(exprType)) {
1614
+ exprType = this.getHighestPriorityType(exprType.types);
1615
+ }
1616
+ if ((0, reflection_1.isVoidType)(exprType) || (0, reflection_1.isInvalidTypeLike)(exprType) || (0, reflection_1.isUninitializedType)(exprType)) {
1617
+ return undefined;
1618
+ }
1619
+ if ((0, reflection_1.isDynamicType)(exprType) || (0, reflection_1.isObjectType)(exprType)) {
1620
+ return exprType;
1621
+ }
1622
+ // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
1623
+ switch (operator.kind) {
1624
+ // Math operators
1625
+ case TokenKind_1.TokenKind.Plus: // (`num = +num` is valid syntax)
1626
+ case TokenKind_1.TokenKind.Minus:
1627
+ if ((0, reflection_1.isNumberTypeLike)(exprType)) {
1628
+ // a negative number will be the same type, eg, double->double, int->int, etc.
1629
+ return this.getUnboxedType(exprType);
1630
+ }
1631
+ break;
1632
+ case TokenKind_1.TokenKind.Not:
1633
+ if ((0, reflection_1.isBooleanTypeLike)(exprType)) {
1634
+ return BooleanType_1.BooleanType.instance;
1635
+ }
1636
+ else if ((0, reflection_1.isNumberTypeLike)(exprType)) {
1637
+ //numbers can be "notted"
1638
+ // by default they go to ints, except longints, which stay that way
1639
+ if ((0, reflection_1.isLongIntegerTypeLike)(exprType)) {
1640
+ return LongIntegerType_1.LongIntegerType.instance;
1641
+ }
1642
+ return IntegerType_1.IntegerType.instance;
1643
+ }
1644
+ break;
1645
+ }
1646
+ return undefined;
1647
+ }
1648
+ getUnboxedType(boxedType) {
1649
+ if ((0, reflection_1.isIntegerTypeLike)(boxedType)) {
1650
+ return IntegerType_1.IntegerType.instance;
1651
+ }
1652
+ else if ((0, reflection_1.isLongIntegerTypeLike)(boxedType)) {
1653
+ return LongIntegerType_1.LongIntegerType.instance;
1654
+ }
1655
+ else if ((0, reflection_1.isFloatTypeLike)(boxedType)) {
1656
+ return FloatType_1.FloatType.instance;
1657
+ }
1658
+ else if ((0, reflection_1.isDoubleTypeLike)(boxedType)) {
1659
+ return DoubleType_1.DoubleType.instance;
1660
+ }
1661
+ else if ((0, reflection_1.isBooleanTypeLike)(boxedType)) {
1662
+ return BooleanType_1.BooleanType.instance;
1663
+ }
1664
+ else if ((0, reflection_1.isStringTypeLike)(boxedType)) {
1665
+ return StringType_1.StringType.instance;
1666
+ }
1667
+ else if ((0, reflection_1.isInvalidTypeLike)(boxedType)) {
1668
+ return InvalidType_1.InvalidType.instance;
1669
+ }
1670
+ return boxedType;
931
1671
  }
932
1672
  /**
933
1673
  * Get the extension for the given file path. Basically the part after the final dot, except for
934
1674
  * `d.bs` which is treated as single extension
1675
+ * @returns the file extension (i.e. ".d.bs", ".bs", ".brs", ".xml", ".jpg", etc...)
935
1676
  */
936
1677
  getExtension(filePath) {
937
1678
  filePath = filePath.toLowerCase();
@@ -939,21 +1680,18 @@ class Util {
939
1680
  return '.d.bs';
940
1681
  }
941
1682
  else {
942
- const idx = filePath.lastIndexOf('.');
943
- if (idx > -1) {
944
- return filePath.substring(idx);
945
- }
1683
+ return path.extname(filePath).toLowerCase();
946
1684
  }
947
1685
  }
948
1686
  /**
949
1687
  * Load and return the list of plugins
950
1688
  */
951
1689
  loadPlugins(cwd, pathOrModules, onError) {
952
- const logger = new Logger_1.Logger();
1690
+ const logger = (0, logging_1.createLogger)();
953
1691
  return pathOrModules.reduce((acc, pathOrModule) => {
954
1692
  if (typeof pathOrModule === 'string') {
955
1693
  try {
956
- const loaded = this.resolveRequire(cwd, pathOrModule);
1694
+ const loaded = requireRelative(pathOrModule, cwd);
957
1695
  const theExport = loaded.default ? loaded.default : loaded;
958
1696
  let plugin;
959
1697
  // legacy plugins returned a plugin object. If we find that, then add a warning
@@ -963,7 +1701,13 @@ class Util {
963
1701
  // the official plugin format is a factory function that returns a new instance of a plugin.
964
1702
  }
965
1703
  else if (typeof theExport === 'function') {
966
- plugin = theExport();
1704
+ plugin = theExport({
1705
+ version: this.getBrighterScriptVersion()
1706
+ });
1707
+ }
1708
+ else {
1709
+ //this should never happen; somehow an invalid plugin has made it into here
1710
+ throw new Error(`TILT: Encountered an invalid plugin: ${String(plugin)}`);
967
1711
  }
968
1712
  if (!plugin.name) {
969
1713
  plugin.name = pathOrModule;
@@ -982,45 +1726,45 @@ class Util {
982
1726
  return acc;
983
1727
  }, []);
984
1728
  }
985
- resolveRequire(cwd, pathOrModule) {
986
- let target = pathOrModule;
987
- if (!path.isAbsolute(pathOrModule)) {
988
- const localPath = path.resolve(cwd, pathOrModule);
989
- if (fs.existsSync(localPath)) {
990
- target = localPath;
991
- }
992
- else {
993
- const modulePath = path.resolve(cwd, 'node_modules', pathOrModule);
994
- if (fs.existsSync(modulePath)) {
995
- target = modulePath;
996
- }
997
- }
998
- }
999
- // eslint-disable-next-line
1000
- return require(target);
1001
- }
1002
1729
  /**
1003
1730
  * Gathers expressions, variables, and unique names from an expression.
1004
1731
  * This is mostly used for the ternary expression
1005
1732
  */
1006
- getExpressionInfo(expression) {
1733
+ getExpressionInfo(expression, file) {
1007
1734
  const expressions = [expression];
1008
1735
  const variableExpressions = [];
1009
1736
  const uniqueVarNames = new Set();
1010
- // Collect all expressions. Most of these expressions are fairly small so this should be quick!
1011
- // This should only be called during transpile time and only when we actually need it.
1012
- expression === null || expression === void 0 ? void 0 : expression.walk((expression) => {
1013
- if (astUtils_1.isExpression(expression)) {
1737
+ function expressionWalker(expression) {
1738
+ if ((0, reflection_1.isExpression)(expression)) {
1014
1739
  expressions.push(expression);
1015
1740
  }
1016
- if (astUtils_1.isVariableExpression(expression)) {
1741
+ if ((0, reflection_1.isVariableExpression)(expression)) {
1017
1742
  variableExpressions.push(expression);
1018
- uniqueVarNames.add(expression.name.text);
1743
+ uniqueVarNames.add(expression.tokens.name.text);
1019
1744
  }
1020
- }, {
1021
- walkMode: astUtils_1.WalkMode.visitExpressions
1745
+ }
1746
+ // Collect all expressions. Most of these expressions are fairly small so this should be quick!
1747
+ // This should only be called during transpile time and only when we actually need it.
1748
+ expression === null || expression === void 0 ? void 0 : expression.walk(expressionWalker, {
1749
+ walkMode: visitors_1.WalkMode.visitExpressions
1022
1750
  });
1023
- return { expressions: expressions, varExpressions: variableExpressions, uniqueVarNames: [...uniqueVarNames] };
1751
+ //handle the expression itself (for situations when expression is a VariableExpression)
1752
+ expressionWalker(expression);
1753
+ const scope = file.program.getFirstScopeForFile(file);
1754
+ let filteredVarNames = [...uniqueVarNames];
1755
+ if (scope) {
1756
+ filteredVarNames = filteredVarNames.filter((varName) => {
1757
+ const varNameLower = varName.toLowerCase();
1758
+ // TODO: include namespaces in this filter
1759
+ return !scope.getEnumMap().has(varNameLower) &&
1760
+ !scope.getConstMap().has(varNameLower);
1761
+ });
1762
+ }
1763
+ return { expressions: expressions, varExpressions: variableExpressions, uniqueVarNames: filteredVarNames };
1764
+ }
1765
+ concatAnnotationLeadingTrivia(stmt) {
1766
+ var _a, _b;
1767
+ return [...((_b = (_a = stmt.annotations) === null || _a === void 0 ? void 0 : _a.map(anno => { var _a; return (_a = anno.leadingTrivia) !== null && _a !== void 0 ? _a : []; }).flat()) !== null && _b !== void 0 ? _b : []), ...stmt.leadingTrivia];
1024
1768
  }
1025
1769
  /**
1026
1770
  * Create a SourceNode that maps every line to itself. Useful for creating maps for files
@@ -1037,129 +1781,105 @@ class Util {
1037
1781
  return new source_map_1.SourceNode(null, null, source, chunks);
1038
1782
  }
1039
1783
  /**
1040
- * Creates a new SGAttribute object, but keeps the existing Range references (since those should be immutable)
1041
- */
1042
- cloneSGAttribute(attr, value) {
1043
- return new SGTypes_1.SGAttribute({ text: attr.tokens.key.text, range: attr.range }, { text: '=' }, { text: '"' }, { text: value, range: attr.tokens.value.range }, { text: '"' });
1044
- }
1045
- /**
1046
- * Shorthand for creating a new source node
1784
+ * Converts a path into a standardized format (drive letter to lower, remove extra slashes, use single slash type, resolve relative parts, etc...)
1047
1785
  */
1048
- sourceNode(source, locatable, code) {
1049
- if (code !== undefined) {
1050
- const node = new source_map_1.SourceNode(null, null, source, code);
1051
- if (locatable.range) {
1052
- //convert 0-based Range line to 1-based SourceNode line
1053
- node.line = locatable.range.start.line + 1;
1054
- //SourceNode columns are 0-based so no conversion necessary
1055
- node.column = locatable.range.start.character;
1056
- }
1057
- return node;
1786
+ standardizePath(thePath) {
1787
+ //if we have the value in cache already, return it
1788
+ if (this.standardizePathCache.has(thePath)) {
1789
+ return this.standardizePathCache.get(thePath);
1058
1790
  }
1059
- }
1060
- /**
1061
- * Remove leading simple protocols from a path (if present)
1062
- */
1063
- removeProtocol(pkgPath) {
1064
- let match = /^[-a-z_]+:\//.exec(pkgPath);
1065
- if (match) {
1066
- return pkgPath.substring(match[0].length);
1791
+ const originalPath = thePath;
1792
+ if (typeof thePath !== 'string') {
1793
+ return thePath;
1067
1794
  }
1068
- else {
1069
- return pkgPath;
1795
+ //handle `virtual:/` paths specially - just normalize slashes, don't use path.normalize which would mangle the `virtual:` prefix
1796
+ if (/^virtual:[\/\\]/i.test(thePath)) {
1797
+ // Strip the `virtual:` prefix, normalize slashes, then re-add the prefix
1798
+ thePath = 'virtual:/' + thePath.slice(8).replace(/^[\/\\]+/, '').replace(/[\/\\]+/g, '/').toLowerCase();
1799
+ this.standardizePathCache.set(originalPath, thePath);
1800
+ return thePath;
1070
1801
  }
1071
- }
1072
- standardizePath(thePath) {
1073
- return exports.util.driveLetterToLower(rokuDeploy.standardizePath(thePath));
1074
- }
1075
- /*
1076
- * Copy the version of bslib from local node_modules to the staging folder
1077
- */
1078
- async copyBslibToStaging(stagingDir) {
1079
- //copy bslib to the output directory
1080
- await fsExtra.ensureDir(standardizePath(`${stagingDir}/source`));
1081
- // eslint-disable-next-line
1082
- const bslib = require('@rokucommunity/bslib');
1083
- let source = bslib.source;
1084
- //apply the `bslib_` prefix to the functions
1085
- let match;
1086
- const positions = [];
1087
- const regexp = /^(\s*(?:function|sub)\s+)([a-z0-9_]+)/mg;
1088
- // eslint-disable-next-line no-cond-assign
1089
- while (match = regexp.exec(source)) {
1090
- positions.push(match.index + match[1].length);
1802
+ //windows path.normalize will convert all slashes to backslashes and remove duplicates
1803
+ if (this.isWindows) {
1804
+ thePath = path.win32.normalize(thePath);
1091
1805
  }
1092
- for (let i = positions.length - 1; i >= 0; i--) {
1093
- const position = positions[i];
1094
- source = source.slice(0, position) + 'bslib_' + source.slice(position);
1806
+ else {
1807
+ //replace all windows or consecutive slashes with path.sep
1808
+ thePath = thePath.replace(/[\/\\]+/g, '/');
1809
+ // only use path.normalize if dots are present since it's expensive
1810
+ if (thePath.includes('./')) {
1811
+ thePath = path.posix.normalize(thePath);
1812
+ }
1813
+ }
1814
+ // Lowercase drive letter on Windows-like paths (e.g., "C:/...")
1815
+ if (thePath.charCodeAt(1) === 58 /* : */) {
1816
+ // eslint-disable-next-line no-var
1817
+ var firstChar = thePath.charCodeAt(0);
1818
+ if (firstChar >= 65 && firstChar <= 90) {
1819
+ thePath = String.fromCharCode(firstChar + 32) + thePath.slice(1);
1820
+ }
1095
1821
  }
1096
- await fsExtra.writeFile(`${stagingDir}/source/bslib.brs`, source);
1822
+ this.standardizePathCache.set(originalPath, thePath);
1823
+ return thePath;
1097
1824
  }
1098
1825
  /**
1099
- * Given a Diagnostic or BsDiagnostic, return a copy of the diagnostic
1826
+ * Given a Diagnostic or BsDiagnostic, return a deep clone of the diagnostic.
1827
+ * @param diagnostic the diagnostic to clone
1828
+ * @param relatedInformationFallbackLocation a default location to use for all `relatedInformation` entries that are missing a location
1100
1829
  */
1101
- toDiagnostic(diagnostic) {
1102
- var _a;
1103
- return {
1830
+ toDiagnostic(diagnostic, relatedInformationFallbackLocation) {
1831
+ var _a, _b, _c, _d, _e;
1832
+ let relatedInformation = (_a = diagnostic.relatedInformation) !== null && _a !== void 0 ? _a : [];
1833
+ if (relatedInformation.length > diagnosticUtils_1.MAX_RELATED_INFOS_COUNT) {
1834
+ const relatedInfoLength = relatedInformation.length;
1835
+ relatedInformation = relatedInformation.slice(0, diagnosticUtils_1.MAX_RELATED_INFOS_COUNT);
1836
+ relatedInformation.push({
1837
+ message: `...and ${relatedInfoLength - diagnosticUtils_1.MAX_RELATED_INFOS_COUNT} more`,
1838
+ location: exports.util.createLocationFromRange(' ', exports.util.createRange(0, 0, 0, 0))
1839
+ });
1840
+ }
1841
+ const range = (_c = (_b = diagnostic.location) === null || _b === void 0 ? void 0 : _b.range) !== null && _c !== void 0 ? _c : diagnostic.range;
1842
+ let result = {
1104
1843
  severity: diagnostic.severity,
1105
- range: diagnostic.range,
1844
+ range: range,
1106
1845
  message: diagnostic.message,
1107
- relatedInformation: (_a = diagnostic.relatedInformation) === null || _a === void 0 ? void 0 : _a.map(x => {
1846
+ relatedInformation: relatedInformation.map(x => {
1108
1847
  //clone related information just in case a plugin added circular ref info here
1109
- return Object.assign({}, x);
1110
- }),
1111
- code: diagnostic.code,
1112
- source: 'brs'
1848
+ const clone = Object.assign({}, x);
1849
+ if (!clone.location) {
1850
+ // use the fallback location if available
1851
+ if (relatedInformationFallbackLocation) {
1852
+ clone.location = exports.util.createLocationFromRange(relatedInformationFallbackLocation, range);
1853
+ }
1854
+ else {
1855
+ //remove this related information so it doesn't bring crash the language server
1856
+ return undefined;
1857
+ }
1858
+ }
1859
+ return clone;
1860
+ //filter out null relatedInformation items
1861
+ }).filter((x) => Boolean(x)),
1862
+ code: diagnostic.code ? diagnostic.code : diagnostic.legacyCode,
1863
+ source: (_d = diagnostic.source) !== null && _d !== void 0 ? _d : 'brs'
1113
1864
  };
1114
- }
1115
- /**
1116
- * Gets the minimum and maximum number of allowed params
1117
- * @param params The list of callable parameters to check
1118
- * @returns the minimum and maximum number of allowed params
1119
- */
1120
- getMinMaxParamCount(params) {
1121
- //get min/max parameter count for callable
1122
- let minParams = 0;
1123
- let maxParams = 0;
1124
- let continueCheckingForRequired = true;
1125
- for (let param of params) {
1126
- maxParams++;
1127
- //optional parameters must come last, so we can assume that minParams won't increase once we hit
1128
- //the first isOptional
1129
- if (continueCheckingForRequired && !param.isOptional) {
1130
- minParams++;
1131
- }
1132
- else {
1133
- continueCheckingForRequired = false;
1134
- }
1135
- }
1136
- return { min: minParams, max: maxParams };
1137
- }
1138
- /**
1139
- * Finds the array of callables from a container map, taking into account the function from which it was called
1140
- * If the callable was called in a function in a namespace, functions in that namespace are preferred
1141
- * @return an array with callable containers - could be empty if nothing was found
1142
- */
1143
- getCallableContainersFromContainerMapByFunctionCall(callablesByLowerName, expCall) {
1144
- let callablesWithThisName = [];
1145
- const lowerName = expCall.name.toLowerCase();
1146
- if (expCall.functionExpression.namespaceName) {
1147
- // prefer namespaced function
1148
- const potentialNamespacedCallable = expCall.functionExpression.namespaceName.getName(Parser_1.ParseMode.BrightScript).toLowerCase() + '_' + lowerName;
1149
- callablesWithThisName = callablesByLowerName.get(potentialNamespacedCallable.toLowerCase());
1150
- }
1151
- if (!callablesWithThisName || callablesWithThisName.length === 0) {
1152
- // just try it as is
1153
- callablesWithThisName = callablesByLowerName.get(lowerName);
1865
+ if (((_e = diagnostic === null || diagnostic === void 0 ? void 0 : diagnostic.tags) === null || _e === void 0 ? void 0 : _e.length) > 0) {
1866
+ result.tags = diagnostic.tags;
1154
1867
  }
1155
- return callablesWithThisName;
1868
+ return result;
1156
1869
  }
1157
1870
  /**
1158
1871
  * Sort an array of objects that have a Range
1159
1872
  */
1160
1873
  sortByRange(locatables) {
1161
1874
  //sort the tokens by range
1162
- return locatables.sort((a, b) => {
1875
+ return locatables === null || locatables === void 0 ? void 0 : locatables.sort((a, b) => {
1876
+ //handle undefined tokens to prevent crashes
1877
+ if (!(a === null || a === void 0 ? void 0 : a.range)) {
1878
+ return 1;
1879
+ }
1880
+ if (!(b === null || b === void 0 ? void 0 : b.range)) {
1881
+ return -1;
1882
+ }
1163
1883
  //start line
1164
1884
  if (a.range.start.line < b.range.start.line) {
1165
1885
  return -1;
@@ -1192,26 +1912,873 @@ class Util {
1192
1912
  });
1193
1913
  }
1194
1914
  /**
1195
- * Split the given text and return ranges for each chunk.
1196
- * Only works for single-line strings
1197
- */
1198
- splitGetRange(separator, text, range) {
1199
- const chunks = text.split(separator);
1200
- const result = [];
1201
- let offset = 0;
1202
- for (let i = 0; i < chunks.length; i++) {
1203
- const chunk = chunks[i];
1204
- //only keep nonzero chunks
1205
- if (chunk.length > 0) {
1206
- result.push({
1207
- text: chunk,
1208
- range: this.createRange(range.start.line, range.start.character + offset, range.end.line, range.start.character + offset + chunk.length)
1915
+ * Wrap the given code in a markdown code fence (with the language)
1916
+ */
1917
+ mdFence(code, language = '') {
1918
+ return '```' + language + '\n' + code + '\n```';
1919
+ }
1920
+ /**
1921
+ * Gets each part of the dotted get.
1922
+ * @param node any ast expression
1923
+ * @returns an array of the parts of the dotted get. If not fully a dotted get, then returns undefined
1924
+ */
1925
+ getAllDottedGetParts(node) {
1926
+ //this is a hot function and has been optimized. Don't rewrite unless necessary
1927
+ const parts = [];
1928
+ let nextPart = node;
1929
+ loop: while (nextPart) {
1930
+ switch (nextPart === null || nextPart === void 0 ? void 0 : nextPart.kind) {
1931
+ case AstNode_1.AstNodeKind.AssignmentStatement:
1932
+ return [node.tokens.name];
1933
+ case AstNode_1.AstNodeKind.DottedGetExpression:
1934
+ parts.push(nextPart === null || nextPart === void 0 ? void 0 : nextPart.tokens.name);
1935
+ nextPart = nextPart.obj;
1936
+ continue;
1937
+ case AstNode_1.AstNodeKind.CallExpression:
1938
+ nextPart = nextPart.callee;
1939
+ continue;
1940
+ case AstNode_1.AstNodeKind.CallfuncExpression:
1941
+ parts.push(nextPart === null || nextPart === void 0 ? void 0 : nextPart.tokens.methodName);
1942
+ nextPart = nextPart.callee;
1943
+ continue;
1944
+ case AstNode_1.AstNodeKind.TypeExpression:
1945
+ nextPart = nextPart.expression;
1946
+ continue;
1947
+ case AstNode_1.AstNodeKind.VariableExpression:
1948
+ parts.push(nextPart === null || nextPart === void 0 ? void 0 : nextPart.tokens.name);
1949
+ break loop;
1950
+ case AstNode_1.AstNodeKind.LiteralExpression:
1951
+ parts.push(nextPart === null || nextPart === void 0 ? void 0 : nextPart.tokens.value);
1952
+ break loop;
1953
+ case AstNode_1.AstNodeKind.IndexedGetExpression:
1954
+ nextPart = nextPart.obj;
1955
+ continue;
1956
+ case AstNode_1.AstNodeKind.FunctionParameterExpression:
1957
+ return [nextPart.tokens.name];
1958
+ case AstNode_1.AstNodeKind.GroupingExpression:
1959
+ parts.push((0, creators_1.createIdentifier)('()', nextPart.location));
1960
+ break loop;
1961
+ default:
1962
+ //we found a non-DottedGet expression, so return because this whole operation is invalid.
1963
+ return undefined;
1964
+ }
1965
+ }
1966
+ return parts.reverse();
1967
+ }
1968
+ /**
1969
+ * Given an expression, return all the DottedGet name parts as a string.
1970
+ * Mostly used to convert namespaced item full names to a strings
1971
+ */
1972
+ getAllDottedGetPartsAsString(node, parseMode = Parser_1.ParseMode.BrighterScript, lastSep = '.') {
1973
+ var _a, _b;
1974
+ //this is a hot function and has been optimized. Don't rewrite unless necessary
1975
+ /* eslint-disable no-var */
1976
+ var sep = parseMode === Parser_1.ParseMode.BrighterScript ? '.' : '_';
1977
+ const parts = (_a = this.getAllDottedGetParts(node)) !== null && _a !== void 0 ? _a : [];
1978
+ var result = (_b = parts[0]) === null || _b === void 0 ? void 0 : _b.text;
1979
+ for (var i = 1; i < parts.length; i++) {
1980
+ //some parts can be undefined (e.g. an unfinished `widget@.` callfunc with no method name)
1981
+ const part = parts[i];
1982
+ if (!part) {
1983
+ continue;
1984
+ }
1985
+ result += (i === parts.length - 1 && parseMode === Parser_1.ParseMode.BrighterScript ? lastSep : sep) + part.text;
1986
+ }
1987
+ return result;
1988
+ /* eslint-enable no-var */
1989
+ }
1990
+ /**
1991
+ * Break an expression into each part.
1992
+ */
1993
+ splitExpression(expression) {
1994
+ const parts = [expression];
1995
+ let nextPart = expression;
1996
+ while (nextPart) {
1997
+ if ((0, reflection_1.isDottedGetExpression)(nextPart) || (0, reflection_1.isIndexedGetExpression)(nextPart) || (0, reflection_1.isXmlAttributeGetExpression)(nextPart)) {
1998
+ nextPart = nextPart.obj;
1999
+ }
2000
+ else if ((0, reflection_1.isCallExpression)(nextPart) || (0, reflection_1.isCallfuncExpression)(nextPart)) {
2001
+ nextPart = nextPart.callee;
2002
+ }
2003
+ else if ((0, reflection_1.isTypeExpression)(nextPart)) {
2004
+ nextPart = nextPart.expression;
2005
+ }
2006
+ else {
2007
+ break;
2008
+ }
2009
+ parts.unshift(nextPart);
2010
+ }
2011
+ return parts;
2012
+ }
2013
+ /**
2014
+ * Returns an integer if valid, or undefined. Eliminates checking for NaN
2015
+ */
2016
+ parseInt(value) {
2017
+ const result = parseInt(value);
2018
+ if (!isNaN(result)) {
2019
+ return result;
2020
+ }
2021
+ else {
2022
+ return undefined;
2023
+ }
2024
+ }
2025
+ /**
2026
+ * Converts a range to a string in the format 1:2-3:4
2027
+ */
2028
+ rangeToString(range) {
2029
+ var _a, _b, _c, _d;
2030
+ return `${(_a = range === null || range === void 0 ? void 0 : range.start) === null || _a === void 0 ? void 0 : _a.line}:${(_b = range === null || range === void 0 ? void 0 : range.start) === null || _b === void 0 ? void 0 : _b.character}-${(_c = range === null || range === void 0 ? void 0 : range.end) === null || _c === void 0 ? void 0 : _c.line}:${(_d = range === null || range === void 0 ? void 0 : range.end) === null || _d === void 0 ? void 0 : _d.character}`;
2031
+ }
2032
+ validateTooDeepFile(file) {
2033
+ var _a, _b;
2034
+ //find any files nested too deep
2035
+ let destPath = (_a = file === null || file === void 0 ? void 0 : file.destPath) === null || _a === void 0 ? void 0 : _a.toString();
2036
+ let rootFolder = destPath === null || destPath === void 0 ? void 0 : destPath.replace(/^pkg:/, '').split(/[\\\/]/)[0].toLowerCase();
2037
+ if ((0, reflection_1.isBrsFile)(file) && rootFolder !== 'source') {
2038
+ return;
2039
+ }
2040
+ if ((0, reflection_1.isXmlFile)(file) && rootFolder !== 'components') {
2041
+ return;
2042
+ }
2043
+ let fileDepth = this.getParentDirectoryCount(destPath);
2044
+ if (fileDepth >= 8) {
2045
+ (_b = file.program) === null || _b === void 0 ? void 0 : _b.diagnostics.register(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.detectedTooDeepFileSource(fileDepth)), { location: exports.util.createLocationFromFileRange(file, this.createRange(0, 0, 0, Number.MAX_VALUE)) }));
2046
+ }
2047
+ }
2048
+ /**
2049
+ * Execute dispose for a series of disposable items
2050
+ * @param disposables a list of functions or disposables
2051
+ */
2052
+ applyDispose(disposables) {
2053
+ var _a;
2054
+ for (const disposable of disposables !== null && disposables !== void 0 ? disposables : []) {
2055
+ if (typeof disposable === 'function') {
2056
+ disposable();
2057
+ }
2058
+ else {
2059
+ (_a = disposable === null || disposable === void 0 ? void 0 : disposable.dispose) === null || _a === void 0 ? void 0 : _a.call(disposable);
2060
+ }
2061
+ }
2062
+ }
2063
+ /**
2064
+ * Race a series of promises, and return the first one that resolves AND matches the matcher function.
2065
+ * If all of the promises reject, then this will emit an AggregatreError with all of the errors.
2066
+ * If at least one promise resolves, then this will log all of the errors to the console
2067
+ * If at least one promise resolves but none of them match the matcher, then this will return undefined.
2068
+ * @param promises all of the promises to race
2069
+ * @param matcher a function that should return true if this value should be kept. Returning any value other than true means `false`
2070
+ * @returns the first resolved value that matches the matcher, or undefined if none of them match
2071
+ */
2072
+ async promiseRaceMatch(promises, matcher) {
2073
+ const workingPromises = [
2074
+ ...promises
2075
+ ];
2076
+ const results = [];
2077
+ let returnValue;
2078
+ while (workingPromises.length > 0) {
2079
+ //race the promises. If any of them resolve, evaluate it against the matcher. If that passes, return the value. otherwise, eliminate this promise and try again
2080
+ const result = await Promise.race(workingPromises.map((promise, i) => {
2081
+ return Promise.resolve(promise)
2082
+ .then(value => ({ value: value, index: i }))
2083
+ .catch(error => ({ error: error, index: i }));
2084
+ }));
2085
+ results.push(result);
2086
+ //if we got a value and it matches the matcher, return it
2087
+ if ('value' in result && (matcher === null || matcher === void 0 ? void 0 : matcher(result.value)) === true) {
2088
+ returnValue = result.value;
2089
+ break;
2090
+ }
2091
+ //remove this non-matched (or errored) promise from the list and try again
2092
+ workingPromises.splice(result.index, 1);
2093
+ }
2094
+ const errors = results
2095
+ .filter(x => 'error' in x)
2096
+ .map(x => x.error);
2097
+ //if all of them crashed, then reject
2098
+ if (promises.length > 0 && errors.length === promises.length) {
2099
+ throw new AggregateError(errors, 'All requests failed. First error message: ' + errors[0].message);
2100
+ }
2101
+ else {
2102
+ //log all of the errors
2103
+ for (const error of errors) {
2104
+ console.error(error);
2105
+ }
2106
+ }
2107
+ //return the matched value, or undefined if there wasn't one
2108
+ return returnValue;
2109
+ }
2110
+ /**
2111
+ * Wraps SourceNode's constructor to be compatible with the TranspileResult type
2112
+ */
2113
+ sourceNodeFromTranspileResult(line, column, source, chunks, name) {
2114
+ // we can use a typecast rather than actually transforming the data because SourceNode
2115
+ // accepts a more permissive type than its typedef states
2116
+ return new source_map_1.SourceNode(line, column, source, chunks, name);
2117
+ }
2118
+ /**
2119
+ * Find the index of the last item in the array that matches.
2120
+ */
2121
+ findLastIndex(array, matcher) {
2122
+ for (let i = array.length - 1; i >= 0; i--) {
2123
+ if (matcher(array[i])) {
2124
+ return i;
2125
+ }
2126
+ }
2127
+ }
2128
+ processTypeChain(typeChain) {
2129
+ var _a, _b, _c, _d, _e;
2130
+ let fullChainName = '';
2131
+ let fullErrorName = '';
2132
+ let itemName = '';
2133
+ let previousTypeName = '';
2134
+ let parentTypeName = '';
2135
+ let itemTypeKind = '';
2136
+ let parentTypeKind = '';
2137
+ let astNode;
2138
+ let errorLocation;
2139
+ let containsDynamic = false;
2140
+ let continueResolvingAllItems = true;
2141
+ let crossedCallFunc = false;
2142
+ for (let i = 0; i < typeChain.length; i++) {
2143
+ const chainItem = typeChain[i];
2144
+ const dotSep = (_b = (_a = chainItem.separatorToken) === null || _a === void 0 ? void 0 : _a.text) !== null && _b !== void 0 ? _b : '.';
2145
+ if (i > 0) {
2146
+ fullChainName += dotSep;
2147
+ }
2148
+ fullChainName += chainItem.name;
2149
+ if (continueResolvingAllItems) {
2150
+ parentTypeName = previousTypeName;
2151
+ parentTypeKind = itemTypeKind;
2152
+ fullErrorName = previousTypeName ? `${previousTypeName}${dotSep}${chainItem.name}` : chainItem.name;
2153
+ itemTypeKind = (_c = chainItem.type) === null || _c === void 0 ? void 0 : _c.kind;
2154
+ let typeString = (_d = chainItem.type) === null || _d === void 0 ? void 0 : _d.toString();
2155
+ let typeToFindStringFor = chainItem.type;
2156
+ while (typeToFindStringFor) {
2157
+ if ((0, reflection_1.isCompoundType)(chainItem.type)) {
2158
+ typeString = `(${typeToFindStringFor.toString()})`;
2159
+ break;
2160
+ }
2161
+ else if ((0, reflection_1.isCallableType)(typeToFindStringFor)) {
2162
+ if ((0, reflection_1.isTypedFunctionType)(typeToFindStringFor) && i < typeChain.length - 1) {
2163
+ typeToFindStringFor = typeToFindStringFor.returnType;
2164
+ }
2165
+ else {
2166
+ typeString = 'function';
2167
+ break;
2168
+ }
2169
+ parentTypeName = previousTypeName;
2170
+ }
2171
+ else if ((0, reflection_1.isNamespaceType)(typeToFindStringFor) && parentTypeName) {
2172
+ const chainItemTypeName = typeToFindStringFor.toString();
2173
+ typeString = parentTypeName + '.' + chainItemTypeName;
2174
+ if (chainItemTypeName.toLowerCase().startsWith(parentTypeName.toLowerCase())) {
2175
+ // the following namespace already knows...
2176
+ typeString = chainItemTypeName;
2177
+ }
2178
+ break;
2179
+ }
2180
+ else {
2181
+ typeString = typeToFindStringFor === null || typeToFindStringFor === void 0 ? void 0 : typeToFindStringFor.toString();
2182
+ break;
2183
+ }
2184
+ }
2185
+ previousTypeName = typeString !== null && typeString !== void 0 ? typeString : '';
2186
+ itemName = chainItem.name;
2187
+ astNode = chainItem.astNode;
2188
+ containsDynamic = containsDynamic || ((0, reflection_1.isDynamicType)(chainItem.type) && !(0, reflection_1.isAnyReferenceType)(chainItem.type));
2189
+ crossedCallFunc = crossedCallFunc || ((_e = chainItem.data) === null || _e === void 0 ? void 0 : _e.isFromCallFunc);
2190
+ if (!chainItem.isResolved) {
2191
+ errorLocation = chainItem.location;
2192
+ continueResolvingAllItems = false;
2193
+ }
2194
+ }
2195
+ }
2196
+ return {
2197
+ itemName: itemName,
2198
+ itemTypeKind: itemTypeKind,
2199
+ itemParentTypeName: parentTypeName,
2200
+ itemParentTypeKind: parentTypeKind,
2201
+ fullNameOfItem: fullErrorName,
2202
+ fullChainName: fullChainName,
2203
+ location: errorLocation,
2204
+ containsDynamic: containsDynamic,
2205
+ astNode: astNode,
2206
+ crossedCallFunc: crossedCallFunc
2207
+ };
2208
+ }
2209
+ getCircularReferenceDiagnosticDetail(circularReferenceInfo, defaultName = '') {
2210
+ if (!circularReferenceInfo || !circularReferenceInfo.referenceChainNames) {
2211
+ if (defaultName) {
2212
+ return [defaultName];
2213
+ }
2214
+ return [];
2215
+ }
2216
+ if (circularReferenceInfo.referenceChainNames[0] === circularReferenceInfo.referenceChainNames[circularReferenceInfo.referenceChainNames.length - 1]) {
2217
+ // last element is same as first it will read okay
2218
+ return circularReferenceInfo.referenceChainNames;
2219
+ }
2220
+ return [...circularReferenceInfo.referenceChainNames, circularReferenceInfo.referenceChainNames[0]];
2221
+ }
2222
+ isInTypeExpression(expression) {
2223
+ //TODO: this is much faster than node.findAncestor(), but may need to be updated for "complicated" type expressions
2224
+ if ((0, reflection_1.isTypeExpression)(expression) ||
2225
+ (0, reflection_1.isTypeExpression)(expression === null || expression === void 0 ? void 0 : expression.parent) ||
2226
+ (0, reflection_1.isTypedArrayExpression)(expression) ||
2227
+ (0, reflection_1.isTypedArrayExpression)(expression === null || expression === void 0 ? void 0 : expression.parent)) {
2228
+ return true;
2229
+ }
2230
+ if ((0, reflection_1.isBinaryExpression)(expression === null || expression === void 0 ? void 0 : expression.parent)) {
2231
+ let currentExpr = expression.parent;
2232
+ while ((0, reflection_1.isBinaryExpression)(currentExpr) && (currentExpr.tokens.operator.kind === TokenKind_1.TokenKind.Or || currentExpr.tokens.operator.kind === TokenKind_1.TokenKind.And)) {
2233
+ currentExpr = currentExpr.parent;
2234
+ }
2235
+ return (0, reflection_1.isTypeExpression)(currentExpr) || (0, reflection_1.isTypedArrayExpression)(currentExpr);
2236
+ }
2237
+ return false;
2238
+ }
2239
+ /**
2240
+ * Parse the `sourceMappingURL` comment from file contents and resolve it to a RawSourceMap.
2241
+ * Handles inline base64 data URIs, absolute paths, relative paths (resolved against srcPath's
2242
+ * directory), and falls back to a co-located `<srcPath>.map` file.
2243
+ * Supports both BrightScript-style comments (`'//# sourceMappingURL=...`) and XML-style
2244
+ * comments (`<!--//# sourceMappingURL=... -->`).
2245
+ * Returns undefined if no map can be found.
2246
+ */
2247
+ async resolveInputSourceMap(fileContents, srcPath) {
2248
+ // Match sourceMappingURL - [^\s]+ stops at whitespace (safe, no backtracking risk).
2249
+ // Strip any trailing XML comment close (either --> or --!>) that may have been captured
2250
+ // when the URL is not followed by a space in an XML comment like <!--//# ...=url-->.
2251
+ const match = /['"]?\/\/# sourceMappingURL=([^\s]+)/m.exec(fileContents);
2252
+ if (match) {
2253
+ const url = match[1].replace(/--!?>$/, '').trim();
2254
+ if (url.startsWith('data:')) {
2255
+ // inline base64: data:application/json;base64,<b64>
2256
+ const b64Match = /base64,([A-Za-z0-9+/=]+)$/.exec(url);
2257
+ if (b64Match) {
2258
+ return JSON.parse(Buffer.from(b64Match[1], 'base64').toString('utf8'));
2259
+ }
2260
+ }
2261
+ else {
2262
+ const mapPath = path.isAbsolute(url) ? url : path.resolve(path.dirname(srcPath), url);
2263
+ if (await fsExtra.pathExists(mapPath)) {
2264
+ return JSON.parse(await fsExtra.readFile(mapPath, 'utf8'));
2265
+ }
2266
+ }
2267
+ }
2268
+ // no usable sourceMappingURL; try co-located <srcPath>.map
2269
+ const colocated = `${srcPath}.map`;
2270
+ if (await fsExtra.pathExists(colocated)) {
2271
+ return JSON.parse(await fsExtra.readFile(colocated, 'utf8'));
2272
+ }
2273
+ return undefined;
2274
+ }
2275
+ /**
2276
+ * Apply an input sourcemap to a generated SourceMapGenerator, chaining mappings so the
2277
+ * output traces back through the input map to the original source.
2278
+ */
2279
+ async applySourceMap(generator, inputMap, sourceFile) {
2280
+ await source_map_1.SourceMapConsumer.with(inputMap, null, (consumer) => {
2281
+ generator.applySourceMap(consumer, sourceFile);
2282
+ });
2283
+ }
2284
+ /**
2285
+ * Chain a prebuild input sourcemap (loaded from a co-located `.map` file or a
2286
+ * `sourceMappingURL` comment in the file contents) onto an existing serialized output
2287
+ * sourcemap. Returns the chained sourcemap as a JSON string. If no input map is found,
2288
+ * the original output map JSON is returned unchanged.
2289
+ */
2290
+ async chainInputSourceMap(outputMapJson, file) {
2291
+ var _a;
2292
+ const inputMap = await this.resolveInputSourceMap((_a = file.fileContents) !== null && _a !== void 0 ? _a : '', file.srcPath);
2293
+ if (!inputMap) {
2294
+ return outputMapJson;
2295
+ }
2296
+ const { SourceMapConsumer: Consumer, SourceMapGenerator: Generator } = await Promise.resolve().then(() => require('source-map'));
2297
+ const outputMap = JSON.parse(outputMapJson);
2298
+ return Consumer.with(outputMap, null, async (outputConsumer) => {
2299
+ const generator = Generator.fromSourceMap(outputConsumer);
2300
+ await Consumer.with(inputMap, null, (inputConsumer) => {
2301
+ generator.applySourceMap(inputConsumer, file.srcPath);
2302
+ });
2303
+ return generator.toString();
2304
+ });
2305
+ }
2306
+ isBuiltInType(typeName) {
2307
+ const typeNameLower = typeName.toLowerCase();
2308
+ if (typeNameLower.startsWith('rosgnode')) {
2309
+ // NOTE: this is unsafe and only used to avoid validation errors in backported v1 type syntax
2310
+ return true;
2311
+ }
2312
+ return false;
2313
+ }
2314
+ isGenericNodeType(type) {
2315
+ if ((0, reflection_1.isComponentType)(type)) {
2316
+ const lowerName = type.toString().toLowerCase();
2317
+ if (lowerName === 'rosgnode' || lowerName === 'rosgnodenode') {
2318
+ return true;
2319
+ }
2320
+ }
2321
+ return false;
2322
+ }
2323
+ hasAnyRequiredSymbolChanged(requiredSymbols, changedSymbols) {
2324
+ if (!requiredSymbols || !changedSymbols) {
2325
+ return false;
2326
+ }
2327
+ const runTimeChanges = changedSymbols.get(1 /* SymbolTypeFlag.runtime */);
2328
+ const typeTimeChanges = changedSymbols.get(2 /* SymbolTypeFlag.typetime */);
2329
+ for (const symbol of requiredSymbols) {
2330
+ if (this.setContainsUnresolvedSymbol(runTimeChanges, symbol) || this.setContainsUnresolvedSymbol(typeTimeChanges, symbol)) {
2331
+ return true;
2332
+ }
2333
+ }
2334
+ return false;
2335
+ }
2336
+ setContainsUnresolvedSymbol(symbolLowerNameSet, symbol) {
2337
+ if (!symbolLowerNameSet || symbolLowerNameSet.size === 0) {
2338
+ return false;
2339
+ }
2340
+ for (const possibleNameLower of symbol.lookups) {
2341
+ if (symbolLowerNameSet.has(possibleNameLower)) {
2342
+ return true;
2343
+ }
2344
+ }
2345
+ return false;
2346
+ }
2347
+ getCustomTypesInSymbolTree(setToFill, type, filter) {
2348
+ var _a, _b;
2349
+ const subSymbolTypes = (0, reflection_1.isCompoundType)(type)
2350
+ ? type.types
2351
+ : (_b = (_a = type.getMemberTable()) === null || _a === void 0 ? void 0 : _a.getAllSymbols(1 /* SymbolTypeFlag.runtime */).map(sym => sym.type)) !== null && _b !== void 0 ? _b : [];
2352
+ for (const subSymbolType of subSymbolTypes) {
2353
+ if (!(subSymbolType === null || subSymbolType === void 0 ? void 0 : subSymbolType.isBuiltIn) && !setToFill.has(subSymbolType)) {
2354
+ if (filter && !filter(subSymbolType)) {
2355
+ continue;
2356
+ }
2357
+ // if this is a custom type, and we haven't added it to the types to check to see if can add it to the additional types
2358
+ // add the type, and investigate any members
2359
+ setToFill.add(subSymbolType);
2360
+ this.getCustomTypesInSymbolTree(setToFill, subSymbolType, filter);
2361
+ }
2362
+ }
2363
+ }
2364
+ truncate(options) {
2365
+ var _a, _b, _c, _d, _e, _f, _g;
2366
+ let leadingText = options.leadingText;
2367
+ let items = (_a = options === null || options === void 0 ? void 0 : options.items) !== null && _a !== void 0 ? _a : [];
2368
+ let trailingText = (_b = options === null || options === void 0 ? void 0 : options.trailingText) !== null && _b !== void 0 ? _b : '';
2369
+ let maxLength = (_c = options === null || options === void 0 ? void 0 : options.maxLength) !== null && _c !== void 0 ? _c : 160;
2370
+ let itemSeparator = (_d = options === null || options === void 0 ? void 0 : options.itemSeparator) !== null && _d !== void 0 ? _d : ', ';
2371
+ let partBuilder = (_e = options === null || options === void 0 ? void 0 : options.partBuilder) !== null && _e !== void 0 ? _e : ((x) => x.toString());
2372
+ let parts = [];
2373
+ let length = leadingText.length + ((_f = trailingText === null || trailingText === void 0 ? void 0 : trailingText.length) !== null && _f !== void 0 ? _f : 0);
2374
+ //calculate the max number of items we could fit in the given space
2375
+ for (let i = 0; i < items.length; i++) {
2376
+ let part = partBuilder(items[i]);
2377
+ if (i > 0) {
2378
+ part = itemSeparator + part;
2379
+ }
2380
+ parts.push(part);
2381
+ length += part.length;
2382
+ //exit the loop if we've maxed out our length
2383
+ if (length >= maxLength) {
2384
+ break;
2385
+ }
2386
+ }
2387
+ let message;
2388
+ //we have enough space to include all the parts
2389
+ if (parts.length >= items.length) {
2390
+ message = leadingText + parts.join('') + trailingText;
2391
+ //we require truncation
2392
+ }
2393
+ else {
2394
+ //account for truncation message length including max possible "more" items digits, trailing text length, and the separator between last item and trailing text
2395
+ length = leadingText.length + `...and ${items.length} more`.length + itemSeparator.length + ((_g = trailingText === null || trailingText === void 0 ? void 0 : trailingText.length) !== null && _g !== void 0 ? _g : 0);
2396
+ message = leadingText;
2397
+ for (let i = 0; i < parts.length; i++) {
2398
+ //always include at least 2 items. if this part would overflow the max, then skip it and finalize the message
2399
+ if (i > 1 && length + parts[i].length > maxLength) {
2400
+ message += itemSeparator + `...and ${items.length - i} more` + trailingText;
2401
+ return message;
2402
+ }
2403
+ else {
2404
+ message += parts[i];
2405
+ length += parts[i].length;
2406
+ }
2407
+ }
2408
+ }
2409
+ return message;
2410
+ }
2411
+ getAstNodeFriendlyName(node) {
2412
+ return node === null || node === void 0 ? void 0 : node.kind.replace(/Statement|Expression/g, '');
2413
+ }
2414
+ hasLeadingComments(input) {
2415
+ var _a;
2416
+ const leadingTrivia = (0, Token_1.isToken)(input) ? input === null || input === void 0 ? void 0 : input.leadingTrivia : (_a = input === null || input === void 0 ? void 0 : input.leadingTrivia) !== null && _a !== void 0 ? _a : [];
2417
+ return !!(leadingTrivia === null || leadingTrivia === void 0 ? void 0 : leadingTrivia.find(t => (t === null || t === void 0 ? void 0 : t.kind) === TokenKind_1.TokenKind.Comment));
2418
+ }
2419
+ getLeadingComments(input) {
2420
+ var _a;
2421
+ const leadingTrivia = (0, Token_1.isToken)(input) ? input === null || input === void 0 ? void 0 : input.leadingTrivia : (_a = input === null || input === void 0 ? void 0 : input.leadingTrivia) !== null && _a !== void 0 ? _a : [];
2422
+ return leadingTrivia.filter(t => (t === null || t === void 0 ? void 0 : t.kind) === TokenKind_1.TokenKind.Comment);
2423
+ }
2424
+ isLeadingCommentOnSameLine(line, input) {
2425
+ var _a;
2426
+ const leadingCommentRange = (_a = this.getLeadingComments(input)) === null || _a === void 0 ? void 0 : _a[0];
2427
+ if (leadingCommentRange) {
2428
+ return this.linesTouch(line, leadingCommentRange === null || leadingCommentRange === void 0 ? void 0 : leadingCommentRange.location);
2429
+ }
2430
+ return false;
2431
+ }
2432
+ isClassUsedAsFunction(potentialClassType, expression, options) {
2433
+ var _a, _b, _c;
2434
+ // eslint-disable-next-line no-bitwise
2435
+ if (((_a = options === null || options === void 0 ? void 0 : options.flags) !== null && _a !== void 0 ? _a : 0) & 1 /* SymbolTypeFlag.runtime */ &&
2436
+ (0, reflection_1.isClassType)(potentialClassType) &&
2437
+ !options.isExistenceTest &&
2438
+ ((_b = potentialClassType.name) === null || _b === void 0 ? void 0 : _b.toLowerCase()) === ((_c = this.getAllDottedGetPartsAsString(expression)) === null || _c === void 0 ? void 0 : _c.toLowerCase()) &&
2439
+ !(expression === null || expression === void 0 ? void 0 : expression.findAncestor(reflection_1.isNewExpression))) {
2440
+ return true;
2441
+ }
2442
+ return false;
2443
+ }
2444
+ getSpecialCaseCallExpressionReturnType(callExpr, options) {
2445
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
2446
+ if ((0, reflection_1.isVariableExpression)(callExpr.callee) && callExpr.callee.tokens.name.text.toLowerCase() === 'createobject') {
2447
+ const componentName = (0, reflection_1.isLiteralString)(callExpr.args[0]) ? (_b = (_a = callExpr.args[0].tokens.value) === null || _a === void 0 ? void 0 : _a.text) === null || _b === void 0 ? void 0 : _b.replace(/"/g, '') : '';
2448
+ const nodeType = componentName.toLowerCase() === 'rosgnode' && (0, reflection_1.isLiteralString)(callExpr.args[1]) ? (_d = (_c = callExpr.args[1].tokens.value) === null || _c === void 0 ? void 0 : _c.text) === null || _d === void 0 ? void 0 : _d.replace(/"/g, '') : '';
2449
+ if (componentName === null || componentName === void 0 ? void 0 : componentName.toLowerCase().startsWith('ro')) {
2450
+ let fullName = componentName + nodeType;
2451
+ if (nodeType.includes(':')) {
2452
+ // This node has a colon in its name, most likely from a component Library
2453
+ // This componentType is most likely unknown, so return `roSGNode`
2454
+ fullName = 'roSGNode';
2455
+ }
2456
+ const data = {};
2457
+ const symbolTable = callExpr.getSymbolTable();
2458
+ const foundType = symbolTable.getSymbolType(fullName, {
2459
+ flags: 2 /* SymbolTypeFlag.typetime */,
2460
+ data: data,
2461
+ tableProvider: () => callExpr === null || callExpr === void 0 ? void 0 : callExpr.getSymbolTable(),
2462
+ fullName: fullName
1209
2463
  });
2464
+ if (foundType) {
2465
+ return foundType;
2466
+ }
1210
2467
  }
1211
- offset += chunk.length + separator.length;
2468
+ }
2469
+ else if ((0, reflection_1.isDottedGetExpression)(callExpr.callee) &&
2470
+ ((_g = (_f = (_e = callExpr.callee.tokens) === null || _e === void 0 ? void 0 : _e.name) === null || _f === void 0 ? void 0 : _f.text) === null || _g === void 0 ? void 0 : _g.toLowerCase()) === 'callfunc' &&
2471
+ (0, reflection_1.isLiteralString)((_h = callExpr.args) === null || _h === void 0 ? void 0 : _h[0])) {
2472
+ return this.getCallFuncType(callExpr, (_k = (_j = callExpr.args) === null || _j === void 0 ? void 0 : _j[0]) === null || _k === void 0 ? void 0 : _k.tokens.value, options);
2473
+ }
2474
+ else if ((0, reflection_1.isDottedGetExpression)(callExpr.callee) &&
2475
+ ((_o = (_m = (_l = callExpr.callee.tokens) === null || _l === void 0 ? void 0 : _l.name) === null || _m === void 0 ? void 0 : _m.text) === null || _o === void 0 ? void 0 : _o.toLowerCase()) === 'createchild' &&
2476
+ (0, reflection_1.isComponentType)((_p = callExpr.callee.obj) === null || _p === void 0 ? void 0 : _p.getType({ flags: 1 /* SymbolTypeFlag.runtime */ })) &&
2477
+ (0, reflection_1.isLiteralString)((_q = callExpr.args) === null || _q === void 0 ? void 0 : _q[0])) {
2478
+ const fullName = `roSGNode${(_u = (_t = (_s = (_r = callExpr.args) === null || _r === void 0 ? void 0 : _r[0].tokens) === null || _s === void 0 ? void 0 : _s.value) === null || _t === void 0 ? void 0 : _t.text) === null || _u === void 0 ? void 0 : _u.replace(/"/g, '')}`;
2479
+ const data = {};
2480
+ const symbolTable = callExpr.getSymbolTable();
2481
+ return symbolTable.getSymbolType(fullName, {
2482
+ flags: 2 /* SymbolTypeFlag.typetime */,
2483
+ data: data,
2484
+ tableProvider: () => callExpr === null || callExpr === void 0 ? void 0 : callExpr.getSymbolTable(),
2485
+ fullName: fullName
2486
+ });
2487
+ }
2488
+ }
2489
+ getCallFuncType(callExpr, methodNameToken, options) {
2490
+ var _a, _b, _c, _d;
2491
+ let result;
2492
+ let methodName = (_a = methodNameToken === null || methodNameToken === void 0 ? void 0 : methodNameToken.text) === null || _a === void 0 ? void 0 : _a.replace(/"/g, ''); // remove quotes if it was the first arg of .callFunc()
2493
+ //bail early when there's no method name (e.g. an unfinished `widget@.` callfunc).
2494
+ //downstream getCallFuncType / ReferenceType paths assume a non-empty member name and
2495
+ //will eventually try `name.toLowerCase()` on undefined and crash.
2496
+ if (!methodName) {
2497
+ return undefined;
2498
+ }
2499
+ // a little hacky here with checking options.ignoreCall because callFuncExpression has the method name
2500
+ // It's nicer for CallExpression, because it's a call on any expression.
2501
+ let calleeType;
2502
+ if ((0, reflection_1.isCallfuncExpression)(callExpr)) {
2503
+ calleeType = callExpr.callee.getType(Object.assign(Object.assign({}, options), { flags: 1 /* SymbolTypeFlag.runtime */, ignoreCall: false }));
2504
+ }
2505
+ else if ((0, reflection_1.isCallExpression)(callExpr) && (0, reflection_1.isDottedGetExpression)(callExpr.callee)) {
2506
+ calleeType = callExpr.callee.obj.getType(Object.assign(Object.assign({}, options), { flags: 1 /* SymbolTypeFlag.runtime */, ignoreCall: false }));
2507
+ }
2508
+ const funcType = (_b = calleeType === null || calleeType === void 0 ? void 0 : calleeType.getCallFuncType) === null || _b === void 0 ? void 0 : _b.call(calleeType, methodName, options);
2509
+ if (funcType) {
2510
+ (_c = options.typeChain) === null || _c === void 0 ? void 0 : _c.push(new interfaces_1.TypeChainEntry({
2511
+ name: methodName,
2512
+ type: funcType,
2513
+ data: options.data,
2514
+ location: methodNameToken.location,
2515
+ separatorToken: (0, creators_1.createToken)(TokenKind_1.TokenKind.Callfunc),
2516
+ astNode: callExpr
2517
+ }));
2518
+ if (options.ignoreCall) {
2519
+ result = funcType;
2520
+ }
2521
+ else if ((0, reflection_1.isCallableType)(funcType) && (!(0, reflection_1.isReferenceType)(funcType.returnType) || funcType.returnType.isResolvable())) {
2522
+ result = funcType.returnType;
2523
+ }
2524
+ else if (!(0, reflection_1.isReferenceType)(funcType) && ((_d = funcType === null || funcType === void 0 ? void 0 : funcType.returnType) === null || _d === void 0 ? void 0 : _d.isResolvable())) {
2525
+ result = funcType.returnType;
2526
+ }
2527
+ else if (this.isUnionOfFunctions(funcType)) {
2528
+ result = this.getReturnTypeOfUnionOfFunctions(funcType);
2529
+ }
2530
+ else {
2531
+ result = new ReferenceType_1.TypePropertyReferenceType(funcType, 'returnType');
2532
+ }
2533
+ }
2534
+ if ((0, reflection_1.isVoidType)(result)) {
2535
+ // CallFunc will always return invalid, even if function called is `as void`
2536
+ result = DynamicType_1.DynamicType.instance;
2537
+ }
2538
+ if (options.data && !options.ignoreCall) {
2539
+ options.data.isFromCallFunc = true;
1212
2540
  }
1213
2541
  return result;
1214
2542
  }
2543
+ isUnionOfFunctions(type, allowReferenceTypes = false) {
2544
+ if ((0, reflection_1.isUnionType)(type)) {
2545
+ const callablesInUnion = type.types.filter(t => (0, reflection_1.isCallableType)(t) || (allowReferenceTypes && (0, reflection_1.isReferenceType)(t)));
2546
+ return callablesInUnion.length === type.types.length && callablesInUnion.length > 0;
2547
+ }
2548
+ return false;
2549
+ }
2550
+ isIntersectionOfFunctions(type, allowReferenceTypes = false) {
2551
+ if ((0, reflection_1.isIntersectionType)(type)) {
2552
+ const callablesInUnion = type.types.filter(t => (0, reflection_1.isCallableType)(t) || (allowReferenceTypes && (0, reflection_1.isReferenceType)(t)));
2553
+ return callablesInUnion.length === type.types.length && callablesInUnion.length > 0;
2554
+ }
2555
+ return false;
2556
+ }
2557
+ getFunctionTypeFromUnion(type) {
2558
+ if (this.isUnionOfFunctions(type)) {
2559
+ const typedFuncsInUnion = type.types.filter(reflection_1.isTypedFunctionType);
2560
+ if (typedFuncsInUnion.length < type.types.length) {
2561
+ // has non-typedFuncs in union
2562
+ return FunctionType_1.FunctionType.instance;
2563
+ }
2564
+ const exampleFunc = typedFuncsInUnion[0];
2565
+ const cumulativeFunction = new types_1.TypedFunctionType((0, helpers_1.getUniqueType)(typedFuncsInUnion.map(f => f.returnType), (types) => new UnionType_1.UnionType(types)))
2566
+ .setName(exampleFunc.name)
2567
+ .setSub(exampleFunc.isSub);
2568
+ for (const param of exampleFunc.params) {
2569
+ cumulativeFunction.addParameter(param.name, param.type, param.isOptional);
2570
+ }
2571
+ return cumulativeFunction;
2572
+ }
2573
+ return undefined;
2574
+ }
2575
+ getFunctionTypeFromIntersection(type) {
2576
+ if (this.isIntersectionOfFunctions(type)) {
2577
+ const typedFuncsInUnion = type.types.filter(reflection_1.isTypedFunctionType);
2578
+ if (typedFuncsInUnion.length < type.types.length) {
2579
+ // has non-typedFuncs in union
2580
+ return FunctionType_1.FunctionType.instance;
2581
+ }
2582
+ const exampleFunc = typedFuncsInUnion[0];
2583
+ const cumulativeFunction = new types_1.TypedFunctionType((0, helpers_1.getUniqueType)(typedFuncsInUnion.map(f => f.returnType), (types) => new IntersectionType_1.IntersectionType(types)))
2584
+ .setName(exampleFunc.name)
2585
+ .setSub(exampleFunc.isSub);
2586
+ for (const param of exampleFunc.params) {
2587
+ cumulativeFunction.addParameter(param.name, param.type, param.isOptional);
2588
+ }
2589
+ return cumulativeFunction;
2590
+ }
2591
+ return undefined;
2592
+ }
2593
+ getReturnTypeOfUnionOfFunctions(type) {
2594
+ if (this.isUnionOfFunctions(type, true)) {
2595
+ const typedFuncsInUnion = type.types.filter(t => (0, reflection_1.isTypedFunctionTypeLike)(t) || (0, reflection_1.isReferenceType)(t));
2596
+ if (typedFuncsInUnion.length < type.types.length) {
2597
+ // is non-typedFuncs in union
2598
+ return DynamicType_1.DynamicType.instance;
2599
+ }
2600
+ const funcReturns = typedFuncsInUnion.map(f => f.returnType);
2601
+ return (0, helpers_1.getUniqueType)(funcReturns, (types) => new UnionType_1.UnionType(types));
2602
+ }
2603
+ return InvalidType_1.InvalidType.instance;
2604
+ }
2605
+ getReturnTypeOfIntersectionOfFunctions(type) {
2606
+ if (this.isIntersectionOfFunctions(type, true)) {
2607
+ const typedFuncsInUnion = type.types.filter(t => (0, reflection_1.isTypedFunctionType)(t) || (0, reflection_1.isReferenceType)(t));
2608
+ if (typedFuncsInUnion.length < type.types.length) {
2609
+ // is non-typedFuncs in union
2610
+ return DynamicType_1.DynamicType.instance;
2611
+ }
2612
+ const funcReturns = typedFuncsInUnion.map(f => f.returnType);
2613
+ return new IntersectionType_1.IntersectionType(funcReturns); //getUniqueType(funcReturns, (types) => new UnionType(types));
2614
+ }
2615
+ return InvalidType_1.InvalidType.instance;
2616
+ }
2617
+ symbolComesFromSameNode(symbolName, definingNode, symbolTable) {
2618
+ let nsData = {};
2619
+ let foundType = symbolTable === null || symbolTable === void 0 ? void 0 : symbolTable.getSymbolType(symbolName, { flags: 1 /* SymbolTypeFlag.runtime */, data: nsData });
2620
+ if (foundType && definingNode === (nsData === null || nsData === void 0 ? void 0 : nsData.definingNode)) {
2621
+ return true;
2622
+ }
2623
+ return false;
2624
+ }
2625
+ isCalleeMemberOfNamespace(symbolName, nodeWhereUsed, namespace) {
2626
+ namespace = namespace !== null && namespace !== void 0 ? namespace : nodeWhereUsed.findAncestor(reflection_1.isNamespaceStatement);
2627
+ if (!this.isVariableMemberOfNamespace(symbolName, nodeWhereUsed, namespace)) {
2628
+ return false;
2629
+ }
2630
+ const exprType = nodeWhereUsed.getType({ flags: 1 /* SymbolTypeFlag.runtime */ });
2631
+ if ((0, reflection_1.isCallableType)(exprType) || (0, reflection_1.isClassType)(exprType)) {
2632
+ return true;
2633
+ }
2634
+ return false;
2635
+ }
2636
+ isVariableMemberOfNamespace(symbolName, nodeWhereUsed, namespace) {
2637
+ namespace = namespace !== null && namespace !== void 0 ? namespace : nodeWhereUsed.findAncestor(reflection_1.isNamespaceStatement);
2638
+ if (!(0, reflection_1.isNamespaceStatement)(namespace)) {
2639
+ return false;
2640
+ }
2641
+ const namespaceParts = namespace.getNameParts();
2642
+ let namespaceType;
2643
+ let symbolTable = namespace.getSymbolTable();
2644
+ for (const part of namespaceParts) {
2645
+ namespaceType = symbolTable.getSymbolType(part.text, { flags: 1 /* SymbolTypeFlag.runtime */ });
2646
+ if (namespaceType) {
2647
+ symbolTable = namespaceType.getMemberTable();
2648
+ }
2649
+ else {
2650
+ return false;
2651
+ }
2652
+ }
2653
+ let varData = {};
2654
+ nodeWhereUsed.getType({ flags: 1 /* SymbolTypeFlag.runtime */, data: varData });
2655
+ const isFromSameNodeInMemberTable = this.symbolComesFromSameNode(symbolName, varData === null || varData === void 0 ? void 0 : varData.definingNode, namespaceType === null || namespaceType === void 0 ? void 0 : namespaceType.getMemberTable());
2656
+ return isFromSameNodeInMemberTable;
2657
+ }
2658
+ isVariableShadowingSomething(symbolName, nodeWhereUsed) {
2659
+ let varData = {};
2660
+ let exprType = nodeWhereUsed.getType({ flags: 1 /* SymbolTypeFlag.runtime */, data: varData });
2661
+ if ((0, reflection_1.isReferenceType)(exprType)) {
2662
+ exprType = exprType.getTarget();
2663
+ }
2664
+ const namespace = nodeWhereUsed === null || nodeWhereUsed === void 0 ? void 0 : nodeWhereUsed.findAncestor(reflection_1.isNamespaceStatement);
2665
+ if ((0, reflection_1.isNamespaceStatement)(namespace)) {
2666
+ let namespaceHasSymbol = namespace.getSymbolTable().hasSymbol(symbolName, 1 /* SymbolTypeFlag.runtime */);
2667
+ // check if the namespace has a symbol with the same name, but different definiton
2668
+ if (namespaceHasSymbol && !this.symbolComesFromSameNode(symbolName, varData.definingNode, namespace.getSymbolTable())) {
2669
+ return true;
2670
+ }
2671
+ }
2672
+ const bodyTable = nodeWhereUsed.getRoot().getSymbolTable();
2673
+ const hasSymbolAtFileLevel = bodyTable.hasSymbol(symbolName, 1 /* SymbolTypeFlag.runtime */);
2674
+ if (hasSymbolAtFileLevel && !this.symbolComesFromSameNode(symbolName, varData.definingNode, bodyTable)) {
2675
+ return true;
2676
+ }
2677
+ return false;
2678
+ }
2679
+ chooseTypeFromCodeOrDocComment(codeType, docType, options) {
2680
+ let returnType;
2681
+ if (options.preferDocType && docType) {
2682
+ returnType = docType;
2683
+ if (options.data) {
2684
+ options.data.isFromDocComment = true;
2685
+ }
2686
+ }
2687
+ else {
2688
+ returnType = codeType;
2689
+ if (!returnType && docType) {
2690
+ returnType = docType;
2691
+ if (options.data) {
2692
+ options.data.isFromDocComment = true;
2693
+ }
2694
+ }
2695
+ }
2696
+ return returnType;
2697
+ }
2698
+ /**
2699
+ * Gets the type for a default value (eg. as a function param, class member or typed array)
2700
+ */
2701
+ getDefaultTypeFromValueType(valueType) {
2702
+ var _a;
2703
+ if (!valueType) {
2704
+ return undefined;
2705
+ }
2706
+ let resultType = DynamicType_1.DynamicType.instance;
2707
+ if (Array.isArray(valueType)) {
2708
+ // passed an array opf types, potential from ArrayType.innerTypes
2709
+ if (valueType.length > 0) {
2710
+ //at least one, use it
2711
+ resultType = valueType[0];
2712
+ if ((valueType === null || valueType === void 0 ? void 0 : valueType.length) > 1) {
2713
+ // more than 1, find union
2714
+ resultType = (0, helpers_1.getUniqueType)(valueType, UnionType_1.unionTypeFactory);
2715
+ }
2716
+ }
2717
+ }
2718
+ else {
2719
+ resultType = valueType;
2720
+ }
2721
+ if (!resultType.isResolvable()) {
2722
+ if ((0, reflection_1.isUnionType)(resultType)) {
2723
+ resultType = DynamicType_1.DynamicType.instance;
2724
+ }
2725
+ else if ((0, reflection_1.isParamTypeFromValueReferenceType)(resultType)) {
2726
+ //already wrapped — wrapping again would build a recursive proxy chain whose
2727
+ //get handlers loop forever via Reflect.get
2728
+ }
2729
+ else {
2730
+ resultType = new ReferenceType_1.ParamTypeFromValueReferenceType(resultType);
2731
+ }
2732
+ }
2733
+ else if ((0, reflection_1.isEnumMemberType)(resultType)) {
2734
+ // the type was an enum member... Try to get the parent enum type
2735
+ resultType = (_a = resultType.parentEnumType) !== null && _a !== void 0 ? _a : resultType;
2736
+ }
2737
+ else if ((0, reflection_1.isUnionType)(resultType)) {
2738
+ // it was a union -- I wonder if they're resolvable now?
2739
+ const moddedTypes = resultType.types.map(t => {
2740
+ var _a;
2741
+ if ((0, reflection_1.isEnumMemberType)(t)) {
2742
+ // the type was an enum member... Try to get the parent enum type
2743
+ return (_a = t.parentEnumType) !== null && _a !== void 0 ? _a : resultType;
2744
+ }
2745
+ return t;
2746
+ });
2747
+ resultType = (0, helpers_1.getUniqueType)(moddedTypes, UnionType_1.unionTypeFactory);
2748
+ }
2749
+ return resultType;
2750
+ }
2751
+ /**
2752
+ * Get the default type for an iterator of the given type
2753
+ * Used for `for each` loops
2754
+ */
2755
+ getIteratorDefaultType(iteratorType) {
2756
+ if ((0, reflection_1.isArrayType)(iteratorType)) {
2757
+ return iteratorType.defaultType;
2758
+ }
2759
+ else if ((0, reflection_1.isAssociativeArrayTypeLike)(iteratorType)) {
2760
+ return StringType_1.StringType.instance;
2761
+ }
2762
+ else if ((0, reflection_1.isBuiltInType)(iteratorType, 'roByteArray')) {
2763
+ return IntegerType_1.IntegerType.instance;
2764
+ }
2765
+ else if ((0, reflection_1.isUnionType)(iteratorType)) {
2766
+ const iteratorDefaultTypes = iteratorType.types.map(t => this.getIteratorDefaultType(t));
2767
+ return (0, helpers_1.getUniqueType)(iteratorDefaultTypes, UnionType_1.unionTypeFactory);
2768
+ }
2769
+ return DynamicType_1.DynamicType.instance;
2770
+ }
2771
+ /**
2772
+ * Get a short name that can be used to reference the project in logs. (typically something like `prj1`, `prj8`, etc...)
2773
+ */
2774
+ getProjectLogName(config) {
2775
+ //if we have a project number, use it
2776
+ if ((config === null || config === void 0 ? void 0 : config.projectNumber) !== undefined) {
2777
+ return `prj${config.projectNumber}`;
2778
+ }
2779
+ //just return empty string so log functions don't crash with undefined project numbers
2780
+ return '';
2781
+ }
1215
2782
  }
1216
2783
  exports.Util = Util;
1217
2784
  /**
@@ -1220,7 +2787,7 @@ exports.Util = Util;
1220
2787
  */
1221
2788
  function standardizePath(stringParts, ...expressions) {
1222
2789
  let result = [];
1223
- for (let i = 0; i < stringParts.length; i++) {
2790
+ for (let i = 0; i < (stringParts === null || stringParts === void 0 ? void 0 : stringParts.length); i++) {
1224
2791
  result.push(stringParts[i], expressions[i]);
1225
2792
  }
1226
2793
  return exports.util.standardizePath(result.join(''));