brighterscript 1.0.0-alpha.24 → 1.0.0-alpha.26

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 (536) hide show
  1. package/CHANGELOG.md +521 -233
  2. package/README.md +45 -139
  3. package/bsconfig.schema.json +46 -0
  4. package/dist/ActionPipeline.d.ts +10 -0
  5. package/dist/ActionPipeline.js +40 -0
  6. package/dist/ActionPipeline.js.map +1 -0
  7. package/dist/AstValidationSegmenter.d.ts +25 -0
  8. package/dist/AstValidationSegmenter.js +152 -0
  9. package/dist/AstValidationSegmenter.js.map +1 -0
  10. package/dist/BsConfig.d.ts +40 -4
  11. package/dist/BusyStatusTracker.d.ts +31 -0
  12. package/dist/BusyStatusTracker.js +83 -0
  13. package/dist/BusyStatusTracker.js.map +1 -0
  14. package/dist/Cache.js +3 -3
  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 +3 -3
  20. package/dist/CodeActionUtil.js.map +1 -1
  21. package/dist/CommentFlagProcessor.d.ts +3 -2
  22. package/dist/CommentFlagProcessor.js +5 -4
  23. package/dist/CommentFlagProcessor.js.map +1 -1
  24. package/dist/DependencyGraph.d.ts +3 -2
  25. package/dist/DependencyGraph.js +11 -10
  26. package/dist/DependencyGraph.js.map +1 -1
  27. package/dist/DiagnosticCollection.js +9 -5
  28. package/dist/DiagnosticCollection.js.map +1 -1
  29. package/dist/DiagnosticFilterer.d.ts +1 -0
  30. package/dist/DiagnosticFilterer.js +5 -3
  31. package/dist/DiagnosticFilterer.js.map +1 -1
  32. package/dist/DiagnosticMessages.d.ts +61 -13
  33. package/dist/DiagnosticMessages.js +116 -19
  34. package/dist/DiagnosticMessages.js.map +1 -1
  35. package/dist/DiagnosticSeverityAdjuster.d.ts +7 -0
  36. package/dist/DiagnosticSeverityAdjuster.js +41 -0
  37. package/dist/DiagnosticSeverityAdjuster.js.map +1 -0
  38. package/dist/FunctionScope.d.ts +28 -0
  39. package/dist/FunctionScope.js +52 -0
  40. package/dist/FunctionScope.js.map +1 -0
  41. package/dist/KeyedThrottler.d.ts +3 -3
  42. package/dist/KeyedThrottler.js +3 -3
  43. package/dist/KeyedThrottler.js.map +1 -1
  44. package/dist/LanguageServer.d.ts +23 -11
  45. package/dist/LanguageServer.js +150 -69
  46. package/dist/LanguageServer.js.map +1 -1
  47. package/dist/Logger.d.ts +3 -2
  48. package/dist/Logger.js +11 -3
  49. package/dist/Logger.js.map +1 -1
  50. package/dist/PluginInterface.d.ts +21 -3
  51. package/dist/PluginInterface.js +74 -6
  52. package/dist/PluginInterface.js.map +1 -1
  53. package/dist/Program.d.ts +158 -79
  54. package/dist/Program.js +841 -706
  55. package/dist/Program.js.map +1 -1
  56. package/dist/ProgramBuilder.d.ts +22 -12
  57. package/dist/ProgramBuilder.js +130 -103
  58. package/dist/ProgramBuilder.js.map +1 -1
  59. package/dist/Scope.d.ts +86 -137
  60. package/dist/Scope.js +453 -519
  61. package/dist/Scope.js.map +1 -1
  62. package/dist/Stopwatch.js +1 -1
  63. package/dist/Stopwatch.js.map +1 -1
  64. package/dist/SymbolTable.d.ts +89 -34
  65. package/dist/SymbolTable.js +239 -114
  66. package/dist/SymbolTable.js.map +1 -1
  67. package/dist/Throttler.d.ts +12 -0
  68. package/dist/Throttler.js +39 -0
  69. package/dist/Throttler.js.map +1 -1
  70. package/dist/Watcher.d.ts +0 -3
  71. package/dist/Watcher.js +0 -3
  72. package/dist/Watcher.js.map +1 -1
  73. package/dist/XmlScope.d.ts +4 -11
  74. package/dist/XmlScope.js +75 -88
  75. package/dist/XmlScope.js.map +1 -1
  76. package/dist/astUtils/CachedLookups.d.ts +48 -0
  77. package/dist/astUtils/CachedLookups.js +323 -0
  78. package/dist/astUtils/CachedLookups.js.map +1 -0
  79. package/dist/astUtils/{AstEditor.d.ts → Editor.d.ts} +9 -5
  80. package/dist/astUtils/{AstEditor.js → Editor.js} +10 -4
  81. package/dist/astUtils/Editor.js.map +1 -0
  82. package/dist/astUtils/{AstEditor.spec.js → Editor.spec.js} +69 -65
  83. package/dist/astUtils/Editor.spec.js.map +1 -0
  84. package/dist/astUtils/creators.d.ts +10 -10
  85. package/dist/astUtils/creators.js +54 -24
  86. package/dist/astUtils/creators.js.map +1 -1
  87. package/dist/astUtils/creators.spec.js +5 -5
  88. package/dist/astUtils/creators.spec.js.map +1 -1
  89. package/dist/astUtils/reflection.d.ts +132 -104
  90. package/dist/astUtils/reflection.js +220 -174
  91. package/dist/astUtils/reflection.js.map +1 -1
  92. package/dist/astUtils/reflection.spec.js +256 -157
  93. package/dist/astUtils/reflection.spec.js.map +1 -1
  94. package/dist/astUtils/stackedVisitor.spec.js +12 -12
  95. package/dist/astUtils/stackedVisitor.spec.js.map +1 -1
  96. package/dist/astUtils/visitors.d.ts +53 -35
  97. package/dist/astUtils/visitors.js +29 -3
  98. package/dist/astUtils/visitors.js.map +1 -1
  99. package/dist/astUtils/visitors.spec.js +208 -52
  100. package/dist/astUtils/visitors.spec.js.map +1 -1
  101. package/dist/astUtils/xml.d.ts +9 -9
  102. package/dist/astUtils/xml.js +9 -9
  103. package/dist/astUtils/xml.js.map +1 -1
  104. package/dist/bscPlugin/BscPlugin.d.ts +11 -2
  105. package/dist/bscPlugin/BscPlugin.js +37 -3
  106. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  107. package/dist/bscPlugin/CallExpressionInfo.d.ts +36 -0
  108. package/dist/bscPlugin/CallExpressionInfo.js +131 -0
  109. package/dist/bscPlugin/CallExpressionInfo.js.map +1 -0
  110. package/dist/bscPlugin/FileWriter.d.ts +6 -0
  111. package/dist/bscPlugin/FileWriter.js +24 -0
  112. package/dist/bscPlugin/FileWriter.js.map +1 -0
  113. package/dist/bscPlugin/SignatureHelpUtil.d.ts +10 -0
  114. package/dist/bscPlugin/SignatureHelpUtil.js +136 -0
  115. package/dist/bscPlugin/SignatureHelpUtil.js.map +1 -0
  116. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +16 -13
  117. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  118. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +16 -16
  119. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
  120. package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +52 -1
  121. package/dist/bscPlugin/completions/CompletionsProcessor.js +517 -26
  122. package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -1
  123. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +1909 -0
  124. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -0
  125. package/dist/bscPlugin/definition/DefinitionProvider.d.ts +13 -0
  126. package/dist/bscPlugin/definition/DefinitionProvider.js +210 -0
  127. package/dist/bscPlugin/definition/DefinitionProvider.js.map +1 -0
  128. package/dist/bscPlugin/definition/DefinitionProvider.spec.js +88 -0
  129. package/dist/bscPlugin/definition/DefinitionProvider.spec.js.map +1 -0
  130. package/dist/bscPlugin/fileProviders/FileProvider.d.ts +9 -0
  131. package/dist/bscPlugin/fileProviders/FileProvider.js +51 -0
  132. package/dist/bscPlugin/fileProviders/FileProvider.js.map +1 -0
  133. package/dist/bscPlugin/hover/HoverProcessor.d.ts +7 -7
  134. package/dist/bscPlugin/hover/HoverProcessor.js +123 -125
  135. package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -1
  136. package/dist/bscPlugin/hover/HoverProcessor.spec.js +371 -53
  137. package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -1
  138. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +2 -1
  139. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +83 -23
  140. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
  141. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +83 -6
  142. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -1
  143. package/dist/bscPlugin/serialize/BslibInjector.spec.d.ts +1 -0
  144. package/dist/bscPlugin/serialize/BslibInjector.spec.js +19 -0
  145. package/dist/bscPlugin/serialize/BslibInjector.spec.js.map +1 -0
  146. package/dist/bscPlugin/serialize/BslibManager.d.ts +9 -0
  147. package/dist/bscPlugin/serialize/BslibManager.js +40 -0
  148. package/dist/bscPlugin/serialize/BslibManager.js.map +1 -0
  149. package/dist/bscPlugin/serialize/FileSerializer.d.ts +9 -0
  150. package/dist/bscPlugin/serialize/FileSerializer.js +72 -0
  151. package/dist/bscPlugin/serialize/FileSerializer.js.map +1 -0
  152. package/dist/bscPlugin/transpile/{BrsFilePreTranspileProcessor.d.ts → BrsFileTranspileProcessor.d.ts} +4 -2
  153. package/dist/bscPlugin/transpile/{BrsFilePreTranspileProcessor.js → BrsFileTranspileProcessor.js} +38 -12
  154. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js.map +1 -0
  155. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.d.ts +1 -0
  156. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js +41 -0
  157. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js.map +1 -0
  158. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.d.ts +12 -0
  159. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js +99 -0
  160. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js.map +1 -0
  161. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +13 -5
  162. package/dist/bscPlugin/validation/BrsFileValidator.js +262 -52
  163. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
  164. package/dist/bscPlugin/validation/BrsFileValidator.spec.js +230 -14
  165. package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +1 -1
  166. package/dist/bscPlugin/validation/ProgramValidator.d.ts +10 -0
  167. package/dist/bscPlugin/validation/ProgramValidator.js +32 -0
  168. package/dist/bscPlugin/validation/ProgramValidator.js.map +1 -0
  169. package/dist/bscPlugin/validation/ScopeValidator.d.ts +58 -27
  170. package/dist/bscPlugin/validation/ScopeValidator.js +514 -286
  171. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  172. package/dist/bscPlugin/validation/ScopeValidator.spec.d.ts +1 -0
  173. package/dist/bscPlugin/validation/ScopeValidator.spec.js +2527 -0
  174. package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -0
  175. package/dist/bscPlugin/validation/XmlFileValidator.d.ts +8 -0
  176. package/dist/bscPlugin/validation/XmlFileValidator.js +44 -0
  177. package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -0
  178. package/dist/cli.js +104 -13
  179. package/dist/cli.js.map +1 -1
  180. package/dist/deferred.d.ts +3 -3
  181. package/dist/deferred.js.map +1 -1
  182. package/dist/diagnosticUtils.d.ts +8 -2
  183. package/dist/diagnosticUtils.js +47 -17
  184. package/dist/diagnosticUtils.js.map +1 -1
  185. package/dist/examples/plugins/removePrint.js +8 -10
  186. package/dist/examples/plugins/removePrint.js.map +1 -1
  187. package/dist/files/AssetFile.d.ts +26 -0
  188. package/dist/files/AssetFile.js +26 -0
  189. package/dist/files/AssetFile.js.map +1 -0
  190. package/dist/files/BrsFile.Class.spec.js +523 -493
  191. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  192. package/dist/files/BrsFile.d.ts +111 -117
  193. package/dist/files/BrsFile.js +684 -1142
  194. package/dist/files/BrsFile.js.map +1 -1
  195. package/dist/files/BrsFile.spec.js +1783 -1233
  196. package/dist/files/BrsFile.spec.js.map +1 -1
  197. package/dist/files/BscFile.d.ts +104 -0
  198. package/dist/files/BscFile.js +16 -0
  199. package/dist/files/BscFile.js.map +1 -0
  200. package/dist/files/Factory.d.ts +25 -0
  201. package/dist/files/Factory.js +22 -0
  202. package/dist/files/Factory.js.map +1 -0
  203. package/dist/files/LazyFileData.d.ts +20 -0
  204. package/dist/files/LazyFileData.js +54 -0
  205. package/dist/files/LazyFileData.js.map +1 -0
  206. package/dist/files/LazyFileData.spec.d.ts +1 -0
  207. package/dist/files/LazyFileData.spec.js +27 -0
  208. package/dist/files/LazyFileData.spec.js.map +1 -0
  209. package/dist/files/XmlFile.d.ts +70 -32
  210. package/dist/files/XmlFile.js +106 -118
  211. package/dist/files/XmlFile.js.map +1 -1
  212. package/dist/files/XmlFile.spec.js +325 -262
  213. package/dist/files/XmlFile.spec.js.map +1 -1
  214. package/dist/files/tests/imports.spec.js +48 -40
  215. package/dist/files/tests/imports.spec.js.map +1 -1
  216. package/dist/files/tests/optionalChaning.spec.js +84 -24
  217. package/dist/files/tests/optionalChaning.spec.js.map +1 -1
  218. package/dist/globalCallables.js +16 -21
  219. package/dist/globalCallables.js.map +1 -1
  220. package/dist/index.d.ts +12 -1
  221. package/dist/index.js +12 -1
  222. package/dist/index.js.map +1 -1
  223. package/dist/interfaces.d.ts +421 -162
  224. package/dist/interfaces.js +27 -0
  225. package/dist/interfaces.js.map +1 -1
  226. package/dist/lexer/Character.spec.js +5 -5
  227. package/dist/lexer/Character.spec.js.map +1 -1
  228. package/dist/lexer/Lexer.d.ts +12 -5
  229. package/dist/lexer/Lexer.js +28 -13
  230. package/dist/lexer/Lexer.js.map +1 -1
  231. package/dist/lexer/Lexer.spec.js +181 -135
  232. package/dist/lexer/Lexer.spec.js.map +1 -1
  233. package/dist/lexer/Token.d.ts +9 -1
  234. package/dist/lexer/Token.js +9 -1
  235. package/dist/lexer/Token.js.map +1 -1
  236. package/dist/lexer/TokenKind.d.ts +8 -0
  237. package/dist/lexer/TokenKind.js +24 -4
  238. package/dist/lexer/TokenKind.js.map +1 -1
  239. package/dist/parser/AstNode.d.ts +162 -0
  240. package/dist/parser/AstNode.js +225 -0
  241. package/dist/parser/AstNode.js.map +1 -0
  242. package/dist/parser/AstNode.spec.d.ts +1 -0
  243. package/dist/parser/AstNode.spec.js +165 -0
  244. package/dist/parser/AstNode.spec.js.map +1 -0
  245. package/dist/parser/BrsTranspileState.d.ts +4 -7
  246. package/dist/parser/BrsTranspileState.js +4 -12
  247. package/dist/parser/BrsTranspileState.js.map +1 -1
  248. package/dist/parser/Expression.d.ts +376 -283
  249. package/dist/parser/Expression.js +742 -585
  250. package/dist/parser/Expression.js.map +1 -1
  251. package/dist/parser/Parser.Class.spec.js +151 -145
  252. package/dist/parser/Parser.Class.spec.js.map +1 -1
  253. package/dist/parser/Parser.d.ts +48 -201
  254. package/dist/parser/Parser.js +705 -1026
  255. package/dist/parser/Parser.js.map +1 -1
  256. package/dist/parser/Parser.spec.d.ts +3 -1
  257. package/dist/parser/Parser.spec.js +861 -848
  258. package/dist/parser/Parser.spec.js.map +1 -1
  259. package/dist/parser/SGParser.d.ts +9 -8
  260. package/dist/parser/SGParser.js +10 -8
  261. package/dist/parser/SGParser.js.map +1 -1
  262. package/dist/parser/SGParser.spec.js +27 -38
  263. package/dist/parser/SGParser.spec.js.map +1 -1
  264. package/dist/parser/SGTypes.d.ts +98 -35
  265. package/dist/parser/SGTypes.js +169 -99
  266. package/dist/parser/SGTypes.js.map +1 -1
  267. package/dist/parser/Statement.d.ts +468 -272
  268. package/dist/parser/Statement.js +904 -631
  269. package/dist/parser/Statement.js.map +1 -1
  270. package/dist/parser/Statement.spec.js +47 -23
  271. package/dist/parser/Statement.spec.js.map +1 -1
  272. package/dist/parser/TranspileState.d.ts +1 -1
  273. package/dist/parser/TranspileState.js +7 -12
  274. package/dist/parser/TranspileState.js.map +1 -1
  275. package/dist/parser/tests/Parser.spec.js +3 -2
  276. package/dist/parser/tests/Parser.spec.js.map +1 -1
  277. package/dist/parser/tests/controlFlow/For.spec.js +33 -23
  278. package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
  279. package/dist/parser/tests/controlFlow/ForEach.spec.js +25 -20
  280. package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
  281. package/dist/parser/tests/controlFlow/If.spec.js +96 -94
  282. package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
  283. package/dist/parser/tests/controlFlow/While.spec.js +22 -16
  284. package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
  285. package/dist/parser/tests/expression/Additive.spec.js +8 -8
  286. package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
  287. package/dist/parser/tests/expression/ArrayLiterals.spec.js +58 -21
  288. package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
  289. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +62 -21
  290. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
  291. package/dist/parser/tests/expression/Boolean.spec.js +8 -8
  292. package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
  293. package/dist/parser/tests/expression/Call.spec.js +129 -21
  294. package/dist/parser/tests/expression/Call.spec.js.map +1 -1
  295. package/dist/parser/tests/expression/Exponential.spec.js +5 -5
  296. package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
  297. package/dist/parser/tests/expression/Function.spec.js +36 -36
  298. package/dist/parser/tests/expression/Function.spec.js.map +1 -1
  299. package/dist/parser/tests/expression/Indexing.spec.js +92 -22
  300. package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
  301. package/dist/parser/tests/expression/Multiplicative.spec.js +9 -9
  302. package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
  303. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +59 -59
  304. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  305. package/dist/parser/tests/expression/PrefixUnary.spec.js +12 -12
  306. package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
  307. package/dist/parser/tests/expression/Primary.spec.js +12 -12
  308. package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
  309. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +10 -10
  310. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -1
  311. package/dist/parser/tests/expression/Relational.spec.js +13 -13
  312. package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
  313. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +24 -24
  314. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
  315. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +96 -57
  316. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  317. package/dist/parser/tests/expression/TernaryExpression.spec.js +89 -89
  318. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  319. package/dist/parser/tests/expression/TypeExpression.spec.d.ts +1 -0
  320. package/dist/parser/tests/expression/TypeExpression.spec.js +127 -0
  321. package/dist/parser/tests/expression/TypeExpression.spec.js.map +1 -0
  322. package/dist/parser/tests/expression/UnaryExpression.spec.d.ts +1 -0
  323. package/dist/parser/tests/expression/UnaryExpression.spec.js +52 -0
  324. package/dist/parser/tests/expression/UnaryExpression.spec.js.map +1 -0
  325. package/dist/parser/tests/statement/AssignmentOperators.spec.js +15 -15
  326. package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
  327. package/dist/parser/tests/statement/ConstStatement.spec.js +82 -33
  328. package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -1
  329. package/dist/parser/tests/statement/Continue.spec.d.ts +1 -0
  330. package/dist/parser/tests/statement/Continue.spec.js +119 -0
  331. package/dist/parser/tests/statement/Continue.spec.js.map +1 -0
  332. package/dist/parser/tests/statement/Declaration.spec.js +19 -19
  333. package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
  334. package/dist/parser/tests/statement/Dim.spec.js +22 -22
  335. package/dist/parser/tests/statement/Dim.spec.js.map +1 -1
  336. package/dist/parser/tests/statement/Enum.spec.js +98 -302
  337. package/dist/parser/tests/statement/Enum.spec.js.map +1 -1
  338. package/dist/parser/tests/statement/For.spec.js +9 -10
  339. package/dist/parser/tests/statement/For.spec.js.map +1 -1
  340. package/dist/parser/tests/statement/ForEach.spec.js +8 -9
  341. package/dist/parser/tests/statement/ForEach.spec.js.map +1 -1
  342. package/dist/parser/tests/statement/Function.spec.js +44 -35
  343. package/dist/parser/tests/statement/Function.spec.js.map +1 -1
  344. package/dist/parser/tests/statement/Goto.spec.js +5 -5
  345. package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
  346. package/dist/parser/tests/statement/Increment.spec.js +20 -20
  347. package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
  348. package/dist/parser/tests/statement/InterfaceStatement.spec.js +30 -196
  349. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
  350. package/dist/parser/tests/statement/LibraryStatement.spec.js +11 -11
  351. package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
  352. package/dist/parser/tests/statement/Misc.spec.js +16 -78
  353. package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
  354. package/dist/parser/tests/statement/PrintStatement.spec.js +36 -34
  355. package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
  356. package/dist/parser/tests/statement/ReturnStatement.spec.js +14 -12
  357. package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
  358. package/dist/parser/tests/statement/Set.spec.js +48 -35
  359. package/dist/parser/tests/statement/Set.spec.js.map +1 -1
  360. package/dist/parser/tests/statement/Stop.spec.js +6 -6
  361. package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
  362. package/dist/parser/tests/statement/Throw.spec.js +6 -6
  363. package/dist/parser/tests/statement/Throw.spec.js.map +1 -1
  364. package/dist/parser/tests/statement/TryCatch.spec.js +18 -16
  365. package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
  366. package/dist/preprocessor/Manifest.d.ts +1 -1
  367. package/dist/preprocessor/Manifest.js +2 -2
  368. package/dist/preprocessor/Manifest.js.map +1 -1
  369. package/dist/preprocessor/Manifest.spec.js +8 -8
  370. package/dist/preprocessor/Manifest.spec.js.map +1 -1
  371. package/dist/preprocessor/Preprocessor.d.ts +5 -6
  372. package/dist/preprocessor/Preprocessor.js +5 -5
  373. package/dist/preprocessor/Preprocessor.js.map +1 -1
  374. package/dist/preprocessor/Preprocessor.spec.js +25 -25
  375. package/dist/preprocessor/Preprocessor.spec.js.map +1 -1
  376. package/dist/preprocessor/PreprocessorParser.d.ts +1 -1
  377. package/dist/preprocessor/PreprocessorParser.js +7 -1
  378. package/dist/preprocessor/PreprocessorParser.js.map +1 -1
  379. package/dist/preprocessor/PreprocessorParser.spec.js +13 -13
  380. package/dist/preprocessor/PreprocessorParser.spec.js.map +1 -1
  381. package/dist/roku-types/data.json +5892 -10081
  382. package/dist/roku-types/index.d.ts +622 -1719
  383. package/dist/types/ArrayType.d.ts +10 -9
  384. package/dist/types/ArrayType.js +65 -60
  385. package/dist/types/ArrayType.js.map +1 -1
  386. package/dist/types/ArrayType.spec.js +36 -68
  387. package/dist/types/ArrayType.spec.js.map +1 -1
  388. package/dist/types/AssociativeArrayType.d.ts +11 -0
  389. package/dist/types/AssociativeArrayType.js +52 -0
  390. package/dist/types/AssociativeArrayType.js.map +1 -0
  391. package/dist/types/BaseFunctionType.d.ts +9 -0
  392. package/dist/types/BaseFunctionType.js +25 -0
  393. package/dist/types/BaseFunctionType.js.map +1 -0
  394. package/dist/types/BooleanType.d.ts +8 -5
  395. package/dist/types/BooleanType.js +14 -7
  396. package/dist/types/BooleanType.js.map +1 -1
  397. package/dist/types/BooleanType.spec.js +10 -6
  398. package/dist/types/BooleanType.spec.js.map +1 -1
  399. package/dist/types/BscType.d.ts +32 -21
  400. package/dist/types/BscType.js +118 -21
  401. package/dist/types/BscType.js.map +1 -1
  402. package/dist/types/BscTypeKind.d.ts +25 -0
  403. package/dist/types/BscTypeKind.js +30 -0
  404. package/dist/types/BscTypeKind.js.map +1 -0
  405. package/dist/types/BuiltInInterfaceAdder.d.ts +23 -0
  406. package/dist/types/BuiltInInterfaceAdder.js +171 -0
  407. package/dist/types/BuiltInInterfaceAdder.js.map +1 -0
  408. package/dist/types/BuiltInInterfaceAdder.spec.d.ts +1 -0
  409. package/dist/types/BuiltInInterfaceAdder.spec.js +116 -0
  410. package/dist/types/BuiltInInterfaceAdder.spec.js.map +1 -0
  411. package/dist/types/ClassType.d.ts +17 -0
  412. package/dist/types/ClassType.js +58 -0
  413. package/dist/types/ClassType.js.map +1 -0
  414. package/dist/types/ClassType.spec.d.ts +1 -0
  415. package/dist/types/ClassType.spec.js +77 -0
  416. package/dist/types/ClassType.spec.js.map +1 -0
  417. package/dist/types/ComponentType.d.ts +26 -0
  418. package/dist/types/ComponentType.js +83 -0
  419. package/dist/types/ComponentType.js.map +1 -0
  420. package/dist/types/DoubleType.d.ts +8 -5
  421. package/dist/types/DoubleType.js +18 -16
  422. package/dist/types/DoubleType.js.map +1 -1
  423. package/dist/types/DoubleType.spec.js +12 -6
  424. package/dist/types/DoubleType.spec.js.map +1 -1
  425. package/dist/types/DynamicType.d.ts +9 -5
  426. package/dist/types/DynamicType.js +15 -4
  427. package/dist/types/DynamicType.js.map +1 -1
  428. package/dist/types/DynamicType.spec.js +16 -5
  429. package/dist/types/DynamicType.spec.js.map +1 -1
  430. package/dist/types/EnumType.d.ts +30 -12
  431. package/dist/types/EnumType.js +43 -17
  432. package/dist/types/EnumType.js.map +1 -1
  433. package/dist/types/EnumType.spec.d.ts +1 -0
  434. package/dist/types/EnumType.spec.js +33 -0
  435. package/dist/types/EnumType.spec.js.map +1 -0
  436. package/dist/types/FloatType.d.ts +8 -5
  437. package/dist/types/FloatType.js +18 -16
  438. package/dist/types/FloatType.js.map +1 -1
  439. package/dist/types/FloatType.spec.js +4 -6
  440. package/dist/types/FloatType.spec.js.map +1 -1
  441. package/dist/types/FunctionType.d.ts +13 -8
  442. package/dist/types/FunctionType.js +30 -14
  443. package/dist/types/FunctionType.js.map +1 -1
  444. package/dist/types/InheritableType.d.ts +28 -0
  445. package/dist/types/InheritableType.js +152 -0
  446. package/dist/types/InheritableType.js.map +1 -0
  447. package/dist/types/IntegerType.d.ts +8 -5
  448. package/dist/types/IntegerType.js +18 -16
  449. package/dist/types/IntegerType.js.map +1 -1
  450. package/dist/types/IntegerType.spec.js +8 -6
  451. package/dist/types/IntegerType.spec.js.map +1 -1
  452. package/dist/types/InterfaceType.d.ts +12 -13
  453. package/dist/types/InterfaceType.js +20 -48
  454. package/dist/types/InterfaceType.js.map +1 -1
  455. package/dist/types/InterfaceType.spec.js +90 -56
  456. package/dist/types/InterfaceType.spec.js.map +1 -1
  457. package/dist/types/InvalidType.d.ts +7 -5
  458. package/dist/types/InvalidType.js +13 -7
  459. package/dist/types/InvalidType.js.map +1 -1
  460. package/dist/types/InvalidType.spec.js +8 -6
  461. package/dist/types/InvalidType.spec.js.map +1 -1
  462. package/dist/types/LongIntegerType.d.ts +8 -5
  463. package/dist/types/LongIntegerType.js +17 -15
  464. package/dist/types/LongIntegerType.js.map +1 -1
  465. package/dist/types/LongIntegerType.spec.js +10 -6
  466. package/dist/types/LongIntegerType.spec.js.map +1 -1
  467. package/dist/types/NamespaceType.d.ts +12 -0
  468. package/dist/types/NamespaceType.js +28 -0
  469. package/dist/types/NamespaceType.js.map +1 -0
  470. package/dist/types/ObjectType.d.ts +9 -8
  471. package/dist/types/ObjectType.js +21 -11
  472. package/dist/types/ObjectType.js.map +1 -1
  473. package/dist/types/ObjectType.spec.js +3 -3
  474. package/dist/types/ObjectType.spec.js.map +1 -1
  475. package/dist/types/ReferenceType.d.ts +63 -0
  476. package/dist/types/ReferenceType.js +423 -0
  477. package/dist/types/ReferenceType.js.map +1 -0
  478. package/dist/types/ReferenceType.spec.d.ts +1 -0
  479. package/dist/types/ReferenceType.spec.js +137 -0
  480. package/dist/types/ReferenceType.spec.js.map +1 -0
  481. package/dist/types/StringType.d.ts +11 -5
  482. package/dist/types/StringType.js +18 -7
  483. package/dist/types/StringType.js.map +1 -1
  484. package/dist/types/StringType.spec.js +3 -5
  485. package/dist/types/StringType.spec.js.map +1 -1
  486. package/dist/types/TypedFunctionType.d.ts +22 -17
  487. package/dist/types/TypedFunctionType.js +78 -60
  488. package/dist/types/TypedFunctionType.js.map +1 -1
  489. package/dist/types/TypedFunctionType.spec.js +105 -20
  490. package/dist/types/TypedFunctionType.spec.js.map +1 -1
  491. package/dist/types/UninitializedType.d.ts +8 -6
  492. package/dist/types/UninitializedType.js +13 -7
  493. package/dist/types/UninitializedType.js.map +1 -1
  494. package/dist/types/UnionType.d.ts +20 -0
  495. package/dist/types/UnionType.js +123 -0
  496. package/dist/types/UnionType.js.map +1 -0
  497. package/dist/types/UnionType.spec.d.ts +1 -0
  498. package/dist/types/UnionType.spec.js +130 -0
  499. package/dist/types/UnionType.spec.js.map +1 -0
  500. package/dist/types/VoidType.d.ts +8 -5
  501. package/dist/types/VoidType.js +14 -7
  502. package/dist/types/VoidType.js.map +1 -1
  503. package/dist/types/VoidType.spec.js +3 -3
  504. package/dist/types/VoidType.spec.js.map +1 -1
  505. package/dist/types/helper.spec.d.ts +1 -0
  506. package/dist/types/helper.spec.js +145 -0
  507. package/dist/types/helper.spec.js.map +1 -0
  508. package/dist/types/helpers.d.ts +19 -37
  509. package/dist/types/helpers.js +159 -99
  510. package/dist/types/helpers.js.map +1 -1
  511. package/dist/types/index.d.ts +22 -0
  512. package/dist/types/index.js +39 -0
  513. package/dist/types/index.js.map +1 -0
  514. package/dist/util.d.ts +143 -139
  515. package/dist/util.js +864 -385
  516. package/dist/util.js.map +1 -1
  517. package/dist/validators/ClassValidator.d.ts +8 -25
  518. package/dist/validators/ClassValidator.js +99 -179
  519. package/dist/validators/ClassValidator.js.map +1 -1
  520. package/package.json +165 -152
  521. package/dist/astUtils/AstEditor.js.map +0 -1
  522. package/dist/astUtils/AstEditor.spec.js.map +0 -1
  523. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +0 -1
  524. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js +0 -32
  525. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js.map +0 -1
  526. package/dist/parser/SGTypes.spec.js +0 -351
  527. package/dist/parser/SGTypes.spec.js.map +0 -1
  528. package/dist/types/CustomType.d.ts +0 -12
  529. package/dist/types/CustomType.js +0 -44
  530. package/dist/types/CustomType.js.map +0 -1
  531. package/dist/types/LazyType.d.ts +0 -16
  532. package/dist/types/LazyType.js +0 -44
  533. package/dist/types/LazyType.js.map +0 -1
  534. /package/dist/astUtils/{AstEditor.spec.d.ts → Editor.spec.d.ts} +0 -0
  535. /package/dist/bscPlugin/{transpile/BrsFilePreTranspileProcessor.spec.d.ts → completions/CompletionsProcessor.spec.d.ts} +0 -0
  536. /package/dist/{parser/SGTypes.spec.d.ts → bscPlugin/definition/DefinitionProvider.spec.d.ts} +0 -0
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const chai_1 = require("chai");
3
+ const chai_config_spec_1 = require("../chai-config.spec");
4
4
  const sinonImport = require("sinon");
5
5
  const vscode_languageserver_1 = require("vscode-languageserver");
6
6
  const Program_1 = require("../Program");
@@ -15,37 +15,62 @@ const Lexer_1 = require("../lexer/Lexer");
15
15
  const TokenKind_1 = require("../lexer/TokenKind");
16
16
  const DiagnosticMessages_1 = require("../DiagnosticMessages");
17
17
  const util_1 = require("../util");
18
- const PluginInterface_1 = require("../PluginInterface");
19
18
  const testHelpers_spec_1 = require("../testHelpers.spec");
20
19
  const Parser_1 = require("../parser/Parser");
21
- const Logger_1 = require("../Logger");
22
20
  const Statement_1 = require("../parser/Statement");
23
21
  const creators_1 = require("../astUtils/creators");
24
22
  const fsExtra = require("fs-extra");
25
- const undent_1 = require("undent");
26
- const ArrayType_1 = require("../types/ArrayType");
27
- const FloatType_1 = require("../types/FloatType");
28
- const ObjectType_1 = require("../types/ObjectType");
29
- const VoidType_1 = require("../types/VoidType");
30
23
  const vscode_uri_1 = require("vscode-uri");
24
+ const undent_1 = require("undent");
25
+ const testHelpers_spec_2 = require("../testHelpers.spec");
26
+ const SymbolTable_1 = require("../SymbolTable");
27
+ const types_1 = require("../types");
31
28
  let sinon = sinonImport.createSandbox();
32
29
  describe('BrsFile', () => {
33
- let tempDir = (0, util_1.standardizePath) `${process.cwd()}/.tmp`;
34
- let rootDir = (0, util_1.standardizePath) `${tempDir}/rootDir`;
35
30
  let program;
36
- let srcPath = (0, util_1.standardizePath) `${rootDir}/source/main.brs`;
31
+ let srcPath = (0, util_1.standardizePath) `${testHelpers_spec_2.rootDir}/source/main.brs`;
37
32
  let destPath = 'source/main.brs';
38
33
  let file;
39
- let testTranspile = (0, testHelpers_spec_1.getTestTranspile)(() => [program, rootDir]);
34
+ let testTranspile = (0, testHelpers_spec_1.getTestTranspile)(() => [program, testHelpers_spec_2.rootDir]);
35
+ let testGetTypedef = (0, testHelpers_spec_1.getTestGetTypedef)(() => [program, testHelpers_spec_2.rootDir]);
40
36
  beforeEach(() => {
41
- fsExtra.emptyDirSync(tempDir);
42
- program = new Program_1.Program({ rootDir: rootDir, sourceMap: true });
43
- file = new BrsFile_1.BrsFile(srcPath, destPath, program);
37
+ fsExtra.emptyDirSync(testHelpers_spec_2.tempDir);
38
+ program = new Program_1.Program({ rootDir: testHelpers_spec_2.rootDir, sourceMap: true });
39
+ file = new BrsFile_1.BrsFile({
40
+ srcPath: srcPath,
41
+ destPath: destPath,
42
+ program: program
43
+ });
44
44
  });
45
45
  afterEach(() => {
46
46
  sinon.restore();
47
47
  program.dispose();
48
48
  });
49
+ describe('constructor', () => {
50
+ it('calculates correct paths when no pkgPath specified', () => {
51
+ (0, chai_config_spec_1.expect)(new BrsFile_1.BrsFile({
52
+ srcPath: (0, util_1.standardizePath) `${testHelpers_spec_2.rootDir}/source/main.bs`,
53
+ destPath: (0, util_1.standardizePath) `source/main.bs`,
54
+ program: program
55
+ })).to.include({
56
+ srcPath: (0, util_1.standardizePath) `${testHelpers_spec_2.rootDir}/source/main.bs`,
57
+ destPath: (0, util_1.standardizePath) `source/main.bs`,
58
+ pkgPath: (0, util_1.standardizePath) `source/main.brs`
59
+ });
60
+ });
61
+ it('uses supplied pkgPath', () => {
62
+ (0, chai_config_spec_1.expect)(new BrsFile_1.BrsFile({
63
+ srcPath: (0, util_1.standardizePath) `${testHelpers_spec_2.rootDir}/source/main.bs`,
64
+ destPath: (0, util_1.standardizePath) `source/main.bs`,
65
+ pkgPath: (0, util_1.standardizePath) `source/main.transpiled.brs`,
66
+ program: program
67
+ })).to.include({
68
+ srcPath: (0, util_1.standardizePath) `${testHelpers_spec_2.rootDir}/source/main.bs`,
69
+ destPath: (0, util_1.standardizePath) `source/main.bs`,
70
+ pkgPath: (0, util_1.standardizePath) `source/main.transpiled.brs`
71
+ });
72
+ });
73
+ });
49
74
  describe('allowBrighterScriptInBrightScript', () => {
50
75
  it('is false by default', () => {
51
76
  program.setFile('source/main.brs', `
@@ -65,6 +90,66 @@ describe('BrsFile', () => {
65
90
  (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
66
91
  });
67
92
  });
93
+ it('flags namespaces used as variables', () => {
94
+ program.setFile('source/main.bs', `
95
+ sub main()
96
+ alpha.beta.charlie.test()
97
+ print alpha
98
+ print alpha.beta
99
+ print alpha.beta.charlie
100
+ end sub
101
+
102
+ namespace alpha
103
+ namespace beta
104
+ namespace charlie
105
+ sub test()
106
+ end sub
107
+ end namespace
108
+ end namespace
109
+ end namespace
110
+ `);
111
+ program.validate();
112
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('namespace')), { range: util_1.default.createRange(3, 22, 3, 27) }), Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('namespace')), { range: util_1.default.createRange(4, 22, 4, 32) }), Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('namespace')), { range: util_1.default.createRange(5, 22, 5, 40) })]);
113
+ });
114
+ it('allows namespaces with the name `optional`', () => {
115
+ program.setFile('source/main.bs', `
116
+ namespace optional
117
+ namespace optional
118
+ end namespace
119
+ end namespace
120
+ namespace alpha
121
+ namespace optional
122
+ end namespace
123
+ end namespace
124
+ namespace alpha.beta.optional
125
+ end namespace
126
+ `);
127
+ program.validate();
128
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
129
+ });
130
+ it('flags enums used as variables', () => {
131
+ program.setFile('source/main.bs', `
132
+ enum Foo
133
+ bar
134
+ baz
135
+ end enum
136
+
137
+ sub main()
138
+ print getFooValue()
139
+ print getFoo()
140
+ end sub
141
+
142
+ function getFoo() as Foo
143
+ return Foo ' Error - cannot return an enum, just an enum value
144
+ end function
145
+
146
+ function getFooValue() as Foo
147
+ return Foo.bar
148
+ end function
149
+ `);
150
+ program.validate();
151
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('enum').message]);
152
+ });
68
153
  it('supports the third parameter in CreateObject', () => {
69
154
  program.setFile('source/main.brs', `
70
155
  sub main()
@@ -85,17 +170,28 @@ describe('BrsFile', () => {
85
170
  });
86
171
  it('sets needsTranspiled to true for .bs files', () => {
87
172
  //BrightScript
88
- (0, chai_1.expect)(new BrsFile_1.BrsFile(`${rootDir}/source/main.brs`, 'source/main.brs', program).needsTranspiled).to.be.false;
173
+ (0, chai_config_spec_1.expect)(new BrsFile_1.BrsFile({
174
+ srcPath: `${testHelpers_spec_2.rootDir}/source/main.brs`,
175
+ destPath: 'source/main.brs',
176
+ program: program
177
+ })['needsTranspiled']).to.be.false;
89
178
  //BrighterScript
90
- (0, chai_1.expect)(new BrsFile_1.BrsFile(`${rootDir}/source/main.bs`, 'source/main.bs', program).needsTranspiled).to.be.true;
179
+ (0, chai_config_spec_1.expect)(new BrsFile_1.BrsFile({
180
+ srcPath: `${testHelpers_spec_2.rootDir}/source/main.bs`,
181
+ destPath: 'source/main.bs',
182
+ program: program
183
+ })['needsTranspiled']).to.be.true;
91
184
  });
92
185
  it('computes new import statements after clearing parser references', () => {
93
186
  const file = program.setFile('source/main.bs', ``);
94
- (0, chai_1.expect)(file.ownScriptImports).to.be.empty;
95
- file.parser.ast.statements.push(new Statement_1.ImportStatement((0, creators_1.createToken)(TokenKind_1.TokenKind.Import), (0, creators_1.createToken)(TokenKind_1.TokenKind.StringLiteral, 'pkg:/source/lib.brs')));
96
- (0, chai_1.expect)(file.ownScriptImports).to.be.empty;
97
- file.parser.invalidateReferences();
98
- (0, chai_1.expect)(file.ownScriptImports.map(x => x.text)).to.eql(['pkg:/source/lib.brs']);
187
+ (0, chai_config_spec_1.expect)(file.ownScriptImports).to.be.empty;
188
+ file.parser.ast.statements.push(new Statement_1.ImportStatement({
189
+ import: (0, creators_1.createToken)(TokenKind_1.TokenKind.Import),
190
+ filePath: (0, creators_1.createToken)(TokenKind_1.TokenKind.StringLiteral, 'pkg:/source/lib.brs')
191
+ }));
192
+ (0, chai_config_spec_1.expect)(file.ownScriptImports).to.be.empty;
193
+ file['_cachedLookups'].invalidate();
194
+ (0, chai_config_spec_1.expect)(file.ownScriptImports.map(x => x.text)).to.eql(['pkg:/source/lib.brs']);
99
195
  });
100
196
  it('allows adding diagnostics', () => {
101
197
  const expected = [{
@@ -108,282 +204,78 @@ describe('BrsFile', () => {
108
204
  });
109
205
  describe('getPartialVariableName', () => {
110
206
  let entry = {
111
- src: `${rootDir}/source/lib.brs`,
207
+ src: `${testHelpers_spec_2.rootDir}/source/lib.brs`,
112
208
  dest: `source/lib.brs`
113
209
  };
114
210
  it('creates proper tokens', () => {
115
211
  file = program.setFile(entry, `call(ModuleA.ModuleB.ModuleC.`);
116
- (0, chai_1.expect)(file['getPartialVariableName'](file.parser.tokens[7])).to.equal('ModuleA.ModuleB.ModuleC.');
117
- (0, chai_1.expect)(file['getPartialVariableName'](file.parser.tokens[6])).to.equal('ModuleA.ModuleB.ModuleC');
118
- (0, chai_1.expect)(file['getPartialVariableName'](file.parser.tokens[5])).to.equal('ModuleA.ModuleB.');
119
- (0, chai_1.expect)(file['getPartialVariableName'](file.parser.tokens[4])).to.equal('ModuleA.ModuleB');
120
- (0, chai_1.expect)(file['getPartialVariableName'](file.parser.tokens[3])).to.equal('ModuleA.');
121
- (0, chai_1.expect)(file['getPartialVariableName'](file.parser.tokens[2])).to.equal('ModuleA');
122
- });
123
- });
124
- describe('getScopesForFile', () => {
125
- it('finds the scope for the file', () => {
126
- var _a;
127
- let file = program.setFile('source/main.brs', ``);
128
- (0, chai_1.expect)((_a = program.getScopesForFile(file)[0]) === null || _a === void 0 ? void 0 : _a.name).to.equal('source');
212
+ (0, chai_config_spec_1.expect)(file['getPartialVariableName'](file.parser.tokens[7])).to.equal('ModuleA.ModuleB.ModuleC.');
213
+ (0, chai_config_spec_1.expect)(file['getPartialVariableName'](file.parser.tokens[6])).to.equal('ModuleA.ModuleB.ModuleC');
214
+ (0, chai_config_spec_1.expect)(file['getPartialVariableName'](file.parser.tokens[5])).to.equal('ModuleA.ModuleB.');
215
+ (0, chai_config_spec_1.expect)(file['getPartialVariableName'](file.parser.tokens[4])).to.equal('ModuleA.ModuleB');
216
+ (0, chai_config_spec_1.expect)(file['getPartialVariableName'](file.parser.tokens[3])).to.equal('ModuleA.');
217
+ (0, chai_config_spec_1.expect)(file['getPartialVariableName'](file.parser.tokens[2])).to.equal('ModuleA');
129
218
  });
130
219
  });
131
- describe('getCompletions', () => {
132
- it('does not crash for callfunc on a function call', () => {
133
- const file = program.setFile('source/main.brs', `
134
- sub main()
135
- getManager()@.
136
- end sub
137
- `);
138
- (0, chai_1.expect)(() => {
139
- program.getCompletions(file.srcPath, util_1.default.createPosition(2, 34));
140
- }).not.to.throw;
141
- });
142
- it('suggests pkg paths in strings that match that criteria', () => {
220
+ describe('canBePruned', () => {
221
+ it('returns false is target file has contains a function statement', () => {
143
222
  program.setFile('source/main.brs', `
144
223
  sub main()
145
- print "pkg:"
224
+ print \`pkg:\`
146
225
  end sub
147
226
  `);
148
- const result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(2, 31));
149
- const names = result.map(x => x.label);
150
- (0, chai_1.expect)(names.sort()).to.eql([
151
- 'pkg:/source/main.brs'
152
- ]);
227
+ const file = program.getFile('source/main.brs');
228
+ (0, chai_config_spec_1.expect)(file.canBePruned).to.be.false;
153
229
  });
154
- it('suggests libpkg paths in strings that match that criteria', () => {
230
+ it('returns false if target file contains a class statement', () => {
155
231
  program.setFile('source/main.brs', `
156
- sub main()
157
- print "libpkg:"
158
- end sub
232
+ class Animal
233
+ public name as string
234
+ end class
159
235
  `);
160
- const result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(2, 31));
161
- const names = result.map(x => x.label);
162
- (0, chai_1.expect)(names.sort()).to.eql([
163
- 'libpkg:/source/main.brs'
164
- ]);
236
+ const file = program.getFile('source/main.brs');
237
+ (0, chai_config_spec_1.expect)(file.canBePruned).to.be.false;
165
238
  });
166
- it('suggests pkg paths in template strings', () => {
239
+ it('returns false if target file contains a class statement', () => {
167
240
  program.setFile('source/main.brs', `
168
- sub main()
169
- print \`pkg:\`
170
- end sub
241
+ namespace Vertibrates.Birds
242
+ function GetDucks()
243
+ end function
244
+ end namespace
171
245
  `);
172
- const result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(2, 31));
173
- const names = result.map(x => x.label);
174
- (0, chai_1.expect)(names.sort()).to.eql([
175
- 'pkg:/source/main.brs'
176
- ]);
246
+ const file = program.getFile('source/main.brs');
247
+ (0, chai_config_spec_1.expect)(file.canBePruned).to.be.false;
177
248
  });
178
- it('waits for the file to be processed before collecting completions', () => {
179
- //eslint-disable-next-line @typescript-eslint/no-floating-promises
249
+ it('returns true if target file contains only enum', () => {
180
250
  program.setFile('source/main.brs', `
181
- sub Main()
182
- print "hello"
183
- Say
184
- end sub
185
-
186
- sub SayHello()
187
- end sub
188
- `);
189
- let result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(3, 23));
190
- let names = result.map(x => x.label);
191
- (0, chai_1.expect)(names).to.includes('Main');
192
- (0, chai_1.expect)(names).to.includes('SayHello');
193
- });
194
- it('includes every type of item at base level', () => {
195
- program.setFile('source/main.bs', `
196
- sub main()
197
- print
198
- end sub
199
- sub speak()
200
- end sub
201
- namespace stuff
202
- end namespace
203
- class Person
204
- end class
205
251
  enum Direction
252
+ up
253
+ down
254
+ left
255
+ right
206
256
  end enum
207
257
  `);
208
- (0, testHelpers_spec_1.expectCompletionsIncludes)(program.getCompletions('source/main.bs', util_1.default.createPosition(2, 26)), [{
209
- label: 'main',
210
- kind: vscode_languageserver_1.CompletionItemKind.Function
211
- }, {
212
- label: 'speak',
213
- kind: vscode_languageserver_1.CompletionItemKind.Function
214
- }, {
215
- label: 'stuff',
216
- kind: vscode_languageserver_1.CompletionItemKind.Module
217
- }, {
218
- label: 'Person',
219
- kind: vscode_languageserver_1.CompletionItemKind.Class
220
- }, {
221
- label: 'Direction',
222
- kind: vscode_languageserver_1.CompletionItemKind.Enum
223
- }]);
224
- });
225
- describe('namespaces', () => {
226
- it('gets full namespace completions at any point through the leading identifier', () => {
227
- program.setFile('source/main.bs', `
228
- sub main()
229
- foo.bar
230
- end sub
231
-
232
- namespace foo.bar
233
- end namespace
234
-
235
- class Person
236
- end class
237
- `);
238
- const result = program.getCompletions(`${rootDir}/source/main.bs`, vscode_languageserver_1.Position.create(2, 24)).map(x => x.label);
239
- (0, chai_1.expect)(result).includes('main');
240
- (0, chai_1.expect)(result).includes('foo');
241
- (0, chai_1.expect)(result).includes('Person');
242
- });
243
- it('gets namespace completions', () => {
244
- program.setFile('source/main.bs', `
245
- namespace foo.bar
246
- function sayHello()
247
- end function
248
- end namespace
249
-
250
- sub Main()
251
- print "hello"
252
- foo.ba
253
- foo.bar.
254
- end sub
255
- `);
256
- let result = program.getCompletions(`${rootDir}/source/main.bs`, vscode_languageserver_1.Position.create(8, 30));
257
- let names = result.map(x => x.label);
258
- (0, chai_1.expect)(names).to.includes('bar');
259
- result = program.getCompletions(`${rootDir}/source/main.bs`, vscode_languageserver_1.Position.create(9, 32));
260
- names = result.map(x => x.label);
261
- (0, chai_1.expect)(names).to.includes('sayHello');
262
- });
263
- });
264
- it('always includes `m`', () => {
265
- //eslint-disable-next-line @typescript-eslint/no-floating-promises
266
- program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
267
- sub Main()
268
-
269
- end sub
270
- `);
271
- let result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(2, 23));
272
- let names = result.map(x => x.label);
273
- (0, chai_1.expect)(names).to.contain('m');
274
- });
275
- it('does not fail for missing previousToken', () => {
276
- //add a single character to the file, and get completions after it
277
- program.setFile('source/main.brs', `i`);
278
- (0, chai_1.expect)(() => {
279
- program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(0, 1)).map(x => x.label);
280
- }).not.to.throw;
281
- });
282
- it('includes all keywords`', () => {
283
- //eslint-disable-next-line @typescript-eslint/no-floating-promises
284
- program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
285
- sub Main()
286
-
287
- end sub
288
- `);
289
- let keywords = Object.keys(TokenKind_1.Keywords).filter(x => !x.includes(' '));
290
- //inside the function
291
- let result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(2, 23));
292
- let names = result.map(x => x.label);
293
- for (let keyword of keywords) {
294
- (0, chai_1.expect)(names).to.include(keyword);
295
- }
296
- //outside the function
297
- result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(4, 8));
298
- names = result.map(x => x.label);
299
- for (let keyword of keywords) {
300
- (0, chai_1.expect)(names).to.include(keyword);
301
- }
302
- });
303
- it('does not provide completions within a comment', () => {
304
- //eslint-disable-next-line @typescript-eslint/no-floating-promises
305
- program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
306
- sub Main()
307
- 'some comment
308
- end sub
309
- `);
310
- //inside the function
311
- let result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(2, 33));
312
- (0, chai_1.expect)(result).to.be.lengthOf(0);
313
- });
314
- it('does not provide duplicate entries for variables', () => {
315
- //eslint-disable-next-line @typescript-eslint/no-floating-promises
316
- program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
317
- sub Main()
318
- name = "bob"
319
- age = 12
320
- name = "john"
321
- end sub
322
- `);
323
- let result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(3, 23));
324
- let count = result.reduce((total, x) => {
325
- return x.label === 'name' ? total + 1 : total;
326
- }, 0);
327
- (0, chai_1.expect)(count).to.equal(1);
328
- });
329
- it('does not include `as` and `string` text options when used in function params', () => {
330
- //eslint-disable-next-line @typescript-eslint/no-floating-promises
331
- program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
332
- sub Main(name as string)
333
-
334
- end sub
335
- `);
336
- let result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(2, 23));
337
- (0, chai_1.expect)(result.filter(x => x.kind === vscode_languageserver_1.CompletionItemKind.Text)).not.to.contain('as');
338
- (0, chai_1.expect)(result.filter(x => x.kind === vscode_languageserver_1.CompletionItemKind.Text)).not.to.contain('string');
258
+ const file = program.getFile('source/main.brs');
259
+ (0, chai_config_spec_1.expect)(file.canBePruned).to.be.true;
339
260
  });
340
- it('does not provide intellisense results when inside a comment', () => {
341
- //eslint-disable-next-line @typescript-eslint/no-floating-promises
342
- program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
343
- sub Main(name as string)
344
- 'this is a comment
345
- end sub
346
- `);
347
- let results = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(2, 30));
348
- (0, chai_1.expect)(results).to.be.empty;
261
+ it('returns true if target file is empty', () => {
262
+ program.setFile('source/main.brs', '');
263
+ const file = program.getFile('source/main.brs');
264
+ (0, chai_config_spec_1.expect)(file.canBePruned).to.be.true;
349
265
  });
350
- it('does provide intellisence for labels only after a goto keyword', () => {
351
- var _a;
352
- //eslint-disable-next-line @typescript-eslint/no-floating-promises
353
- program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
354
- sub Main(name as string)
355
- something:
356
- goto \nend sub
357
- `);
358
- let results = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(3, 25));
359
- (0, chai_1.expect)(results.length).to.equal(1);
360
- (0, chai_1.expect)((_a = results[0]) === null || _a === void 0 ? void 0 : _a.label).to.equal('something');
361
- });
362
- it('includes properties of objects', () => {
363
- //eslint-disable-next-line @typescript-eslint/no-floating-promises
266
+ it('returns true if target file only has comments', () => {
364
267
  program.setFile('source/main.brs', `
365
- sub Main()
366
- myObj = {name:"Bob", age: 34, height:6.0}
367
- myObj.
368
- end sub
268
+ ' this is an interesting comment
369
269
  `);
370
- let result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(3, 26));
371
- let names = result.map(x => x.label);
372
- (0, chai_1.expect)(names).to.contain('name');
373
- (0, chai_1.expect)(names).to.contain('age');
374
- (0, chai_1.expect)(names).to.contain('height');
270
+ const file = program.getFile('source/main.brs');
271
+ (0, chai_config_spec_1.expect)(file.canBePruned).to.be.true;
375
272
  });
376
- it('includes properties of m', () => {
377
- //eslint-disable-next-line @typescript-eslint/no-floating-promises
378
- program.setFile('source/main.brs', `
379
- sub Main()
380
- m.someField= "hello"
381
- m.
382
- end sub
383
- `);
384
- let result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(3, 22));
385
- let names = result.map(x => x.label);
386
- (0, chai_1.expect)(names).to.contain('someField');
273
+ });
274
+ describe('getScopesForFile', () => {
275
+ it('finds the scope for the file', () => {
276
+ var _a;
277
+ let file = program.setFile('source/main.brs', ``);
278
+ (0, chai_config_spec_1.expect)((_a = program.getScopesForFile(file)[0]) === null || _a === void 0 ? void 0 : _a.name).to.equal('source');
387
279
  });
388
280
  });
389
281
  describe('comment flags', () => {
@@ -419,14 +311,14 @@ describe('BrsFile', () => {
419
311
  (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
420
312
  });
421
313
  it('works for all', () => {
422
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
314
+ let file = program.setFile({ src: `${testHelpers_spec_2.rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
423
315
  sub Main()
424
316
  'bs:disable-next-line
425
317
  name = "bob
426
318
  end sub
427
319
  `);
428
- (0, chai_1.expect)(file.commentFlags[0]).to.exist;
429
- (0, chai_1.expect)(file.commentFlags[0]).to.deep.include({
320
+ (0, chai_config_spec_1.expect)(file.commentFlags[0]).to.exist;
321
+ (0, chai_config_spec_1.expect)(file.commentFlags[0]).to.deep.include({
430
322
  codes: null,
431
323
  range: vscode_languageserver_1.Range.create(2, 24, 2, 45),
432
324
  affectedRange: util_1.default.createRange(3, 0, 3, Number.MAX_SAFE_INTEGER)
@@ -436,14 +328,14 @@ describe('BrsFile', () => {
436
328
  (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
437
329
  });
438
330
  it('works for specific codes', () => {
439
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
331
+ let file = program.setFile({ src: `${testHelpers_spec_2.rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
440
332
  sub Main()
441
333
  'bs:disable-next-line: 1083, 1001
442
334
  name = "bob
443
335
  end sub
444
336
  `);
445
- (0, chai_1.expect)(file.commentFlags[0]).to.exist;
446
- (0, chai_1.expect)(file.commentFlags[0]).to.deep.include({
337
+ (0, chai_config_spec_1.expect)(file.commentFlags[0]).to.exist;
338
+ (0, chai_config_spec_1.expect)(file.commentFlags[0]).to.deep.include({
447
339
  codes: [1083, 1001],
448
340
  range: vscode_languageserver_1.Range.create(2, 24, 2, 57),
449
341
  affectedRange: util_1.default.createRange(3, 0, 3, Number.MAX_SAFE_INTEGER)
@@ -452,13 +344,13 @@ describe('BrsFile', () => {
452
344
  (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
453
345
  });
454
346
  it('recognizes non-numeric codes', () => {
455
- let file = program.setFile('source/main.brs', `
347
+ let file = program.setFile({ src: `${testHelpers_spec_2.rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
456
348
  sub Main()
457
349
  'bs:disable-next-line: LINT9999
458
350
  name = "bob
459
351
  end sub
460
- `);
461
- (0, chai_1.expect)(file.commentFlags[0]).to.exist;
352
+ `);
353
+ (0, chai_config_spec_1.expect)(file.commentFlags[0]).to.exist;
462
354
  (0, testHelpers_spec_1.expectHasDiagnostics)(program);
463
355
  });
464
356
  it('supports disabling non-numeric error codes', () => {
@@ -467,35 +359,35 @@ describe('BrsFile', () => {
467
359
  sub main()
468
360
  something = true 'bs:disable-line: LINT1005
469
361
  end sub
470
- `);
471
- file.addDiagnostics([{
472
- code: 'LINT1005',
473
- file: file,
474
- message: 'Something is not right',
475
- range: util_1.default.createRange(2, 16, 2, 26)
476
- }]);
362
+ `);
363
+ file.diagnostics.push({
364
+ code: 'LINT1005',
365
+ file: file,
366
+ message: 'Something is not right',
367
+ range: util_1.default.createRange(2, 16, 2, 26)
368
+ });
477
369
  const scope = program.getScopesForFile(file)[0];
478
370
  (0, testHelpers_spec_1.expectZeroDiagnostics)(scope);
479
371
  });
480
372
  it('adds diagnostics for unknown numeric diagnostic codes', () => {
481
- program.setFile({ src: `${rootDir} / source / main.brs`, dest: 'source/main.brs' }, `
373
+ program.setFile('source/main.brs', `
482
374
  sub main()
483
375
  print "hi" 'bs:disable-line: 123456 999999 aaaab
484
376
  end sub
485
- `);
377
+ `);
486
378
  program.validate();
487
379
  (0, testHelpers_spec_1.expectDiagnostics)(program, [Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unknownDiagnosticCode(123456)), { range: vscode_languageserver_1.Range.create(2, 53, 2, 59) }), Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unknownDiagnosticCode(999999)), { range: vscode_languageserver_1.Range.create(2, 60, 2, 66) })]);
488
380
  });
489
381
  });
490
382
  describe('bs:disable-line', () => {
491
383
  it('works for all', () => {
492
- let file = program.setFile({ src: `${rootDir} / source / main.brs`, dest: 'source/main.brs' }, `
384
+ let file = program.setFile({ src: `${testHelpers_spec_2.rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
493
385
  sub Main()
494
386
  z::;;%%%%%% 'bs:disable-line
495
387
  end sub
496
388
  `);
497
- (0, chai_1.expect)(file.commentFlags[0]).to.exist;
498
- (0, chai_1.expect)(file.commentFlags[0]).to.deep.include({
389
+ (0, chai_config_spec_1.expect)(file.commentFlags[0]).to.exist;
390
+ (0, chai_config_spec_1.expect)(file.commentFlags[0]).to.deep.include({
499
391
  codes: null,
500
392
  range: vscode_languageserver_1.Range.create(2, 36, 2, 52),
501
393
  affectedRange: vscode_languageserver_1.Range.create(2, 0, 2, 36)
@@ -505,7 +397,7 @@ describe('BrsFile', () => {
505
397
  (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
506
398
  });
507
399
  it('works for specific codes', () => {
508
- program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
400
+ program.setFile('source/main.brs', `
509
401
  sub main()
510
402
  'should not have any errors
511
403
  DoSomething(1) 'bs:disable-line:1002
@@ -524,12 +416,12 @@ describe('BrsFile', () => {
524
416
  //the current version of BRS causes parse errors after the `parse` keyword, showing error in comments
525
417
  //the program should ignore all diagnostics found in brs:* comment lines EXCEPT
526
418
  //for the diagnostics about using unknown error codes
527
- program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
419
+ program.setFile('source/main.brs', `
528
420
  sub main()
529
421
  stop 'bs:disable-line
530
422
  print "need a valid line to fix stop error"
531
423
  end sub
532
- `);
424
+ `);
533
425
  program.validate();
534
426
  (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
535
427
  });
@@ -576,9 +468,9 @@ describe('BrsFile', () => {
576
468
  it('supports iife in assignment', () => {
577
469
  program.setFile('source/main.brs', `
578
470
  sub main()
579
- result = sub()
471
+ result = sub()
580
472
  end sub()
581
- result = (sub()
473
+ result = (sub()
582
474
  end sub)()
583
475
  end sub
584
476
  `);
@@ -587,7 +479,7 @@ describe('BrsFile', () => {
587
479
  it('uses the proper parse mode based on file extension', () => {
588
480
  function testParseMode(destPath, expectedParseMode) {
589
481
  const file = program.setFile(destPath, '');
590
- (0, chai_1.expect)(file.parseMode).to.equal(expectedParseMode);
482
+ (0, chai_config_spec_1.expect)(file.parseMode).to.equal(expectedParseMode);
591
483
  }
592
484
  testParseMode('source/main.brs', Parser_1.ParseMode.BrightScript);
593
485
  testParseMode('source/main.spec.brs', Parser_1.ParseMode.BrightScript);
@@ -597,26 +489,26 @@ describe('BrsFile', () => {
597
489
  testParseMode('source/main.spec.bs', Parser_1.ParseMode.BrighterScript);
598
490
  });
599
491
  it('supports labels and goto statements', () => {
600
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
492
+ let file = program.setFile('source/main.brs', `
601
493
  sub Main()
602
494
  'multiple goto statements on one line
603
- goto myLabel: goto myLabel
495
+ goto myLabel : goto myLabel
604
496
  myLabel:
605
497
  end sub
606
498
  `);
607
499
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
608
500
  });
609
501
  it('supports empty print statements', () => {
610
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
502
+ let file = program.setFile('source/main.brs', `
611
503
  sub main()
612
- print
504
+ print
613
505
  end sub
614
506
  `);
615
507
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
616
508
  });
617
509
  describe('conditional compile', () => {
618
510
  it('supports case-insensitive bs_const variables', () => {
619
- fsExtra.outputFileSync(`${rootDir}/manifest`, (0, undent_1.default) `
511
+ fsExtra.outputFileSync(`${testHelpers_spec_2.rootDir}/manifest`, (0, undent_1.default) `
620
512
  bs_const=SomeKey=true
621
513
  `);
622
514
  program.setFile('source/main.brs', `
@@ -636,7 +528,7 @@ describe('BrsFile', () => {
636
528
  (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
637
529
  });
638
530
  it('works for upper case keywords', () => {
639
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
531
+ let file = program.setFile('source/main.brs', `
640
532
  sub main()
641
533
  #CONST someFlag = true
642
534
  #IF someFlag
@@ -651,7 +543,7 @@ describe('BrsFile', () => {
651
543
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
652
544
  });
653
545
  it('supports single-word #elseif and #endif', () => {
654
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
546
+ let file = program.setFile('source/main.brs', `
655
547
  sub main()
656
548
  #const someFlag = true
657
549
  #if someFlag
@@ -664,7 +556,7 @@ describe('BrsFile', () => {
664
556
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
665
557
  });
666
558
  it('supports multi-word #else if and #end if', () => {
667
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
559
+ let file = program.setFile('source/main.brs', `
668
560
  sub main()
669
561
  #const someFlag = true
670
562
  #if someFlag
@@ -677,17 +569,17 @@ describe('BrsFile', () => {
677
569
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
678
570
  });
679
571
  it('does not choke on invalid code inside a false conditional compile', () => {
680
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
572
+ let file = program.setFile('source/main.brs', `
681
573
  sub main()
682
574
  #if false
683
- non - commented code here should not cause parse errors
575
+ non-commented code here should not cause parse errors
684
576
  #end if
685
577
  end sub
686
578
  `);
687
579
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
688
580
  });
689
581
  it('detects syntax error in #if', () => {
690
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
582
+ let file = program.setFile('source/main.brs', `
691
583
  sub main()
692
584
  #if true1
693
585
  print "true"
@@ -699,7 +591,7 @@ describe('BrsFile', () => {
699
591
  ]);
700
592
  });
701
593
  it('detects syntax error in #const', () => {
702
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
594
+ let file = program.setFile('source/main.brs', `
703
595
  sub main()
704
596
  #if %
705
597
  print "true"
@@ -712,7 +604,7 @@ describe('BrsFile', () => {
712
604
  ]);
713
605
  });
714
606
  it('detects #const name using reserved word', () => {
715
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
607
+ let file = program.setFile('source/main.brs', `
716
608
  sub main()
717
609
  #const function = true
718
610
  end sub
@@ -723,7 +615,7 @@ describe('BrsFile', () => {
723
615
  ]);
724
616
  });
725
617
  it('detects syntax error in #const', () => {
726
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
618
+ let file = program.setFile('source/main.brs', `
727
619
  sub main()
728
620
  #const someConst = 123
729
621
  end sub
@@ -734,22 +626,22 @@ describe('BrsFile', () => {
734
626
  });
735
627
  });
736
628
  it('supports stop statement', () => {
737
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
629
+ let file = program.setFile('source/main.brs', `
738
630
  sub main()
739
- stop
631
+ stop
740
632
  end sub
741
633
  `);
742
634
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
743
635
  });
744
636
  it('supports single-line if statements', () => {
745
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
637
+ let file = program.setFile('source/main.brs', `
746
638
  sub main()
747
639
  if 1 < 2: return true: end if
748
640
  if 1 < 2: return true
749
641
  end if
750
642
  if false : print "true" : end if
751
643
  if true: print "8 worked": else if true: print "not run": else: print "not run": end if
752
- if true then: test = sub() : print "yes" : end sub: end if
644
+ if true then : test = sub() : print "yes" : end sub : end if
753
645
  end sub
754
646
  `);
755
647
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
@@ -834,7 +726,7 @@ describe('BrsFile', () => {
834
726
  print &he2
835
727
  print 1.2E+2
836
728
  print 2!
837
- print 12D - 12
729
+ print 12D-12
838
730
  print 2.3#
839
731
  print &hFEDCBA9876543210&
840
732
  print 9876543210&
@@ -850,7 +742,7 @@ describe('BrsFile', () => {
850
742
  `);
851
743
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
852
744
  });
853
- it('does not lose function statements when mismatched end sub', () => {
745
+ it('does not lose function scopes when mismatched end sub', () => {
854
746
  file.parse(`
855
747
  sub main()
856
748
  sayHi()
@@ -860,7 +752,7 @@ describe('BrsFile', () => {
860
752
  print "hello world"
861
753
  end sub
862
754
  `);
863
- (0, chai_1.expect)(file.parser.references.functionStatements).to.be.lengthOf(2);
755
+ (0, chai_config_spec_1.expect)(file.functionScopes).to.be.lengthOf(2);
864
756
  });
865
757
  it('does not lose sub scope when mismatched end function', () => {
866
758
  file.parse(`
@@ -872,7 +764,7 @@ describe('BrsFile', () => {
872
764
  print "hello world"
873
765
  end sub
874
766
  `);
875
- (0, chai_1.expect)(file.parser.references.functionStatements).to.be.lengthOf(2);
767
+ (0, chai_config_spec_1.expect)(file.functionScopes).to.be.lengthOf(2);
876
768
  });
877
769
  it('does not error with boolean in RHS of set statement', () => {
878
770
  file.parse(`
@@ -901,11 +793,11 @@ describe('BrsFile', () => {
901
793
  it('supports variable names ending with type designators', () => {
902
794
  file.parse(`
903
795
  sub main()
904
- name$ = "bob"
905
- age% = 1
906
- height! = 5.5
907
- salary# = 9.87654321
908
- someHex& = 13
796
+ name$ = "bob"
797
+ age% = 1
798
+ height! = 5.5
799
+ salary# = 9.87654321
800
+ someHex& = 13
909
801
  end sub
910
802
  `);
911
803
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
@@ -915,7 +807,7 @@ describe('BrsFile', () => {
915
807
  sub main()
916
808
  if true then
917
809
  print "true"
918
- else if true then
810
+ else if true then
919
811
  print "also true"
920
812
  end if
921
813
  end sub
@@ -926,9 +818,9 @@ describe('BrsFile', () => {
926
818
  file.parse(`
927
819
  function GetObject()
928
820
  obj = {
929
- stop: function () as void
821
+ stop: function() as void
930
822
 
931
- end function
823
+ end function
932
824
  }
933
825
  return obj
934
826
  end function
@@ -939,10 +831,10 @@ describe('BrsFile', () => {
939
831
  file.parse(`
940
832
  function GetObject()
941
833
  obj = {
942
- run: function () as void
834
+ run: function() as void
943
835
 
944
836
  end function
945
- }
837
+ }
946
838
  return obj
947
839
  end function
948
840
  `);
@@ -970,7 +862,7 @@ describe('BrsFile', () => {
970
862
  function Main()
971
863
  promise = {
972
864
  then: sub()
973
- end sub
865
+ end sub
974
866
  }
975
867
  promise.then()
976
868
  end function
@@ -980,7 +872,8 @@ describe('BrsFile', () => {
980
872
  it('supports function as parameter type', () => {
981
873
  file.parse(`
982
874
  sub Main()
983
- doWork = function (callback as function)
875
+ doWork = function(callback as function)
876
+ callback()
984
877
  end function
985
878
  end sub
986
879
  `);
@@ -1096,7 +989,7 @@ describe('BrsFile', () => {
1096
989
  sub main()
1097
990
  end sub
1098
991
  import "file.brs"
1099
- `);
992
+ `);
1100
993
  program.validate();
1101
994
  (0, testHelpers_spec_1.expectDiagnostics)(program, [
1102
995
  DiagnosticMessages_1.DiagnosticMessages.importStatementMustBeDeclaredAtTopOfFile()
@@ -1133,7 +1026,7 @@ describe('BrsFile', () => {
1133
1026
  it('supports colons as separators in associative array properties', () => {
1134
1027
  file.parse(`
1135
1028
  sub Main()
1136
- obj = { x: 0 : y: 1 }
1029
+ obj = {x:0 : y: 1}
1137
1030
  end sub
1138
1031
  `);
1139
1032
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
@@ -1144,47 +1037,59 @@ describe('BrsFile', () => {
1144
1037
  return value.subType()
1145
1038
  end function
1146
1039
  `);
1147
- (0, chai_1.expect)(file.callables[0]).to.deep.include({
1040
+ (0, chai_config_spec_1.expect)(file.callables[0]).to.deep.include({
1148
1041
  file: file,
1149
1042
  nameRange: vscode_languageserver_1.Range.create(1, 25, 1, 36)
1150
1043
  });
1151
1044
  });
1152
1045
  it('succeeds when finding variables with the word "function" in them', () => {
1153
1046
  file.parse(`
1154
- function Test()
1155
- typeCheckFunction = RBS_CMN_GetFunction(invalid, methodName)
1047
+ function Test()
1048
+ typeCheckFunction = RBS_CMN_GetFunction(invalid, methodName)
1156
1049
  end function
1157
1050
  `);
1158
1051
  });
1159
1052
  it('finds line and column numbers for functions', () => {
1160
- let file = new BrsFile_1.BrsFile('absolute_path/file.brs', 'relative_path/file.brs', program);
1053
+ let file = new BrsFile_1.BrsFile({
1054
+ srcPath: 'absolute_path/file.brs',
1055
+ destPath: 'relative_path/file.brs',
1056
+ program: program
1057
+ });
1161
1058
  file.parse(`
1162
1059
  function DoA()
1163
1060
  print "A"
1164
1061
  end function
1165
1062
 
1166
- function DoB()
1167
- print "B"
1168
- end function
1063
+ function DoB()
1064
+ print "B"
1065
+ end function
1169
1066
  `);
1170
- (0, chai_1.expect)(file.callables[0].name).to.equal('DoA');
1171
- (0, chai_1.expect)(file.callables[0].nameRange).to.eql(vscode_languageserver_1.Range.create(1, 25, 1, 28));
1172
- (0, chai_1.expect)(file.callables[1].name).to.equal('DoB');
1173
- (0, chai_1.expect)(file.callables[1].nameRange).to.eql(vscode_languageserver_1.Range.create(5, 25, 5, 28));
1067
+ (0, chai_config_spec_1.expect)(file.callables[0].name).to.equal('DoA');
1068
+ (0, chai_config_spec_1.expect)(file.callables[0].nameRange).to.eql(vscode_languageserver_1.Range.create(1, 25, 1, 28));
1069
+ (0, chai_config_spec_1.expect)(file.callables[1].name).to.equal('DoB');
1070
+ (0, chai_config_spec_1.expect)(file.callables[1].nameRange).to.eql(vscode_languageserver_1.Range.create(5, 26, 5, 29));
1174
1071
  });
1175
1072
  it('throws an error if the file has already been parsed', () => {
1176
- let file = new BrsFile_1.BrsFile('abspath', 'relpath', program);
1073
+ let file = new BrsFile_1.BrsFile({
1074
+ srcPath: 'abspath',
1075
+ destPath: 'relpath',
1076
+ program: program
1077
+ });
1177
1078
  file.parse(`'a comment`);
1178
1079
  try {
1179
1080
  file.parse(`'a new comment`);
1180
- chai_1.assert.fail(null, null, 'Should have thrown an exception, but did not');
1081
+ chai_config_spec_1.assert.fail(null, null, 'Should have thrown an exception, but did not');
1181
1082
  }
1182
1083
  catch (e) {
1183
1084
  //test passes
1184
1085
  }
1185
1086
  });
1186
1087
  it('finds and registers duplicate callables', () => {
1187
- let file = new BrsFile_1.BrsFile('absolute_path/file.brs', 'relative_path/file.brs', program);
1088
+ let file = new BrsFile_1.BrsFile({
1089
+ srcPath: 'absolute_path/file.brs',
1090
+ destPath: 'relative_path/file.brs',
1091
+ program: program
1092
+ });
1188
1093
  file.parse(`
1189
1094
  function DoA()
1190
1095
  print "A"
@@ -1194,14 +1099,18 @@ describe('BrsFile', () => {
1194
1099
  print "A"
1195
1100
  end function
1196
1101
  `);
1197
- (0, chai_1.expect)(file.callables.length).to.equal(2);
1198
- (0, chai_1.expect)(file.callables[0].name).to.equal('DoA');
1199
- (0, chai_1.expect)(file.callables[0].nameRange.start.line).to.equal(1);
1200
- (0, chai_1.expect)(file.callables[1].name).to.equal('DoA');
1201
- (0, chai_1.expect)(file.callables[1].nameRange.start.line).to.equal(5);
1102
+ (0, chai_config_spec_1.expect)(file.callables.length).to.equal(2);
1103
+ (0, chai_config_spec_1.expect)(file.callables[0].name).to.equal('DoA');
1104
+ (0, chai_config_spec_1.expect)(file.callables[0].nameRange.start.line).to.equal(1);
1105
+ (0, chai_config_spec_1.expect)(file.callables[1].name).to.equal('DoA');
1106
+ (0, chai_config_spec_1.expect)(file.callables[1].nameRange.start.line).to.equal(5);
1202
1107
  });
1203
1108
  it('finds function call line and column numbers', () => {
1204
- let file = new BrsFile_1.BrsFile('absolute_path/file.brs', 'relative_path/file.brs', program);
1109
+ let file = new BrsFile_1.BrsFile({
1110
+ srcPath: 'absolute_path/file.brs',
1111
+ destPath: 'relative_path/file.brs',
1112
+ program: program
1113
+ });
1205
1114
  file.parse(`
1206
1115
  function DoA()
1207
1116
  DoB("a")
@@ -1210,24 +1119,59 @@ describe('BrsFile', () => {
1210
1119
  DoC()
1211
1120
  end function
1212
1121
  `);
1213
- (0, chai_1.expect)(file.functionCalls.length).to.equal(2);
1214
- (0, chai_1.expect)(file.functionCalls[0].range).to.eql(vscode_languageserver_1.Range.create(2, 20, 2, 28));
1215
- (0, chai_1.expect)(file.functionCalls[0].nameRange).to.eql(vscode_languageserver_1.Range.create(2, 20, 2, 23));
1216
- (0, chai_1.expect)(file.functionCalls[1].range).to.eql(vscode_languageserver_1.Range.create(5, 20, 5, 25));
1217
- (0, chai_1.expect)(file.functionCalls[1].nameRange).to.eql(vscode_languageserver_1.Range.create(5, 20, 5, 23));
1122
+ (0, chai_config_spec_1.expect)(file.functionCalls.length).to.equal(2);
1123
+ (0, chai_config_spec_1.expect)(file.functionCalls[0].range).to.eql(vscode_languageserver_1.Range.create(2, 20, 2, 28));
1124
+ (0, chai_config_spec_1.expect)(file.functionCalls[0].nameRange).to.eql(vscode_languageserver_1.Range.create(2, 20, 2, 23));
1125
+ (0, chai_config_spec_1.expect)(file.functionCalls[1].range).to.eql(vscode_languageserver_1.Range.create(5, 20, 5, 25));
1126
+ (0, chai_config_spec_1.expect)(file.functionCalls[1].nameRange).to.eql(vscode_languageserver_1.Range.create(5, 20, 5, 23));
1127
+ });
1128
+ it('finds function calls that are unfinished', () => {
1129
+ let file = new BrsFile_1.BrsFile({
1130
+ srcPath: 'absolute_path/file.brs',
1131
+ destPath: 'relative_path/file.brs',
1132
+ program: program
1133
+ });
1134
+ file.parse(`
1135
+ function DoA()
1136
+ DoB("a"
1137
+ end function
1138
+ function DoB(a as string)
1139
+ DoC(
1140
+ end function
1141
+ `);
1142
+ (0, testHelpers_spec_1.expectDiagnostics)(file.parser.diagnostics, [
1143
+ DiagnosticMessages_1.DiagnosticMessages.expectedRightParenAfterFunctionCallArguments(),
1144
+ DiagnosticMessages_1.DiagnosticMessages.expectedNewlineOrColon(),
1145
+ DiagnosticMessages_1.DiagnosticMessages.unexpectedToken('end function'),
1146
+ DiagnosticMessages_1.DiagnosticMessages.expectedRightParenAfterFunctionCallArguments(),
1147
+ DiagnosticMessages_1.DiagnosticMessages.expectedNewlineOrColon()
1148
+ ]);
1149
+ (0, chai_config_spec_1.expect)(file.functionCalls.length).to.equal(2);
1150
+ (0, chai_config_spec_1.expect)(file.functionCalls[0].range).to.eql(vscode_languageserver_1.Range.create(2, 20, 2, 27));
1151
+ (0, chai_config_spec_1.expect)(file.functionCalls[0].nameRange).to.eql(vscode_languageserver_1.Range.create(2, 20, 2, 23));
1152
+ (0, chai_config_spec_1.expect)(file.functionCalls[1].range).to.eql(vscode_languageserver_1.Range.create(5, 20, 5, 24));
1153
+ (0, chai_config_spec_1.expect)(file.functionCalls[1].nameRange).to.eql(vscode_languageserver_1.Range.create(5, 20, 5, 23));
1218
1154
  });
1219
1155
  it('sanitizes brs errors', () => {
1220
- let file = new BrsFile_1.BrsFile('absolute_path/file.brs', 'relative_path/file.brs', program);
1156
+ let file = new BrsFile_1.BrsFile({
1157
+ srcPath: 'absolute_path/file.brs',
1158
+ destPath: 'relative_path/file.brs',
1159
+ program: program
1160
+ });
1221
1161
  file.parse(`
1222
1162
  function DoSomething
1223
1163
  end function
1224
1164
  `);
1225
1165
  (0, testHelpers_spec_1.expectHasDiagnostics)(file);
1226
- (0, chai_1.expect)(file.getDiagnostics()[0].file).to.equal(file);
1227
- (0, chai_1.expect)(file.getDiagnostics()[0].range.start.line).to.equal(1);
1166
+ (0, chai_config_spec_1.expect)(file.getDiagnostics()[0].file).to.equal(file);
1167
+ (0, chai_config_spec_1.expect)(file.getDiagnostics()[0].range.start.line).to.equal(1);
1228
1168
  });
1229
1169
  it('supports using the `next` keyword in a for loop', () => {
1230
- let file = new BrsFile_1.BrsFile('absolute_path/file.brs', 'relative_path/file.brs', program);
1170
+ let file = new BrsFile_1.BrsFile({
1171
+ srcPath: 'absolute_path/file.brs',
1172
+ destPath: 'relative_path/file.brs',
1173
+ program: program
1174
+ });
1231
1175
  file.parse(`
1232
1176
  sub countit()
1233
1177
  for each num in [1,2,3]
@@ -1239,7 +1183,11 @@ describe('BrsFile', () => {
1239
1183
  });
1240
1184
  //test is not working yet, but will be enabled when brs supports this syntax
1241
1185
  it('supports assigning functions to objects', () => {
1242
- let file = new BrsFile_1.BrsFile('absolute_path/file.brs', 'relative_path/file.brs', program);
1186
+ let file = new BrsFile_1.BrsFile({
1187
+ srcPath: 'absolute_path/file.brs',
1188
+ destPath: 'relative_path/file.brs',
1189
+ program: program
1190
+ });
1243
1191
  file.parse(`
1244
1192
  function main()
1245
1193
  o = CreateObject("roAssociativeArray")
@@ -1250,20 +1198,42 @@ describe('BrsFile', () => {
1250
1198
  `);
1251
1199
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
1252
1200
  });
1201
+ it('supports parameter types in functions in AA literals', () => {
1202
+ program.setFile('source/main.brs', `
1203
+ sub main()
1204
+ aa = {
1205
+ name: "test"
1206
+ addInts: function(a as integer, b as integer) as integer
1207
+ return a + b
1208
+ end function
1209
+ }
1210
+ end sub
1211
+ `);
1212
+ program.validate();
1213
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1214
+ });
1253
1215
  });
1254
1216
  describe('findCallables', () => {
1255
1217
  it('finds range', () => {
1256
- let file = new BrsFile_1.BrsFile('absolute_path/file.brs', 'relative_path/file.brs', program);
1218
+ let file = new BrsFile_1.BrsFile({
1219
+ srcPath: 'absolute_path/file.brs',
1220
+ destPath: 'relative_path/file.brs',
1221
+ program: program
1222
+ });
1257
1223
  file.parse(`
1258
1224
  sub Sum()
1259
1225
  print "hello world"
1260
1226
  end sub
1261
1227
  `);
1262
1228
  let callable = file.callables[0];
1263
- (0, chai_1.expect)(callable.range).to.eql(vscode_languageserver_1.Range.create(1, 16, 3, 23));
1229
+ (0, chai_config_spec_1.expect)(callable.range).to.eql(vscode_languageserver_1.Range.create(1, 16, 3, 23));
1264
1230
  });
1265
1231
  it('finds correct body range even with inner function', () => {
1266
- let file = new BrsFile_1.BrsFile('absolute_path/file.brs', 'relative_path/file.brs', program);
1232
+ let file = new BrsFile_1.BrsFile({
1233
+ srcPath: 'absolute_path/file.brs',
1234
+ destPath: 'relative_path/file.brs',
1235
+ program: program
1236
+ });
1267
1237
  file.parse(`
1268
1238
  sub Sum()
1269
1239
  sayHi = sub()
@@ -1273,101 +1243,117 @@ describe('BrsFile', () => {
1273
1243
  end sub
1274
1244
  `);
1275
1245
  let callable = file.callables[0];
1276
- (0, chai_1.expect)(callable.range).to.eql(vscode_languageserver_1.Range.create(1, 16, 6, 23));
1246
+ (0, chai_config_spec_1.expect)(callable.range).to.eql(vscode_languageserver_1.Range.create(1, 16, 6, 23));
1277
1247
  });
1278
1248
  it('finds callable parameters', () => {
1279
- let file = new BrsFile_1.BrsFile('absolute_path/file.brs', 'relative_path/file.brs', program);
1249
+ let file = new BrsFile_1.BrsFile({
1250
+ srcPath: 'absolute_path/file.brs',
1251
+ destPath: 'relative_path/file.brs',
1252
+ program: program
1253
+ });
1280
1254
  file.parse(`
1281
1255
  function Sum(a, b, c)
1282
1256
 
1283
1257
  end function
1284
1258
  `);
1285
1259
  let callable = file.callables[0];
1286
- (0, chai_1.expect)(callable.params[0]).to.deep.include({
1260
+ (0, chai_config_spec_1.expect)(callable.params[0]).to.deep.include({
1287
1261
  name: 'a',
1288
1262
  isOptional: false,
1289
1263
  isRestArgument: false
1290
1264
  });
1291
- (0, chai_1.expect)(callable.params[0].type).instanceof(DynamicType_1.DynamicType);
1292
- (0, chai_1.expect)(callable.params[1]).to.deep.include({
1265
+ (0, chai_config_spec_1.expect)(callable.params[0].type).instanceof(DynamicType_1.DynamicType);
1266
+ (0, chai_config_spec_1.expect)(callable.params[1]).to.deep.include({
1293
1267
  name: 'b',
1294
1268
  isOptional: false,
1295
1269
  isRestArgument: false
1296
1270
  });
1297
- (0, chai_1.expect)(callable.params[1].type).instanceof(DynamicType_1.DynamicType);
1298
- (0, chai_1.expect)(callable.params[2]).to.deep.include({
1271
+ (0, chai_config_spec_1.expect)(callable.params[1].type).instanceof(DynamicType_1.DynamicType);
1272
+ (0, chai_config_spec_1.expect)(callable.params[2]).to.deep.include({
1299
1273
  name: 'c',
1300
1274
  isOptional: false,
1301
1275
  isRestArgument: false
1302
1276
  });
1303
- (0, chai_1.expect)(callable.params[2].type).instanceof(DynamicType_1.DynamicType);
1277
+ (0, chai_config_spec_1.expect)(callable.params[2].type).instanceof(DynamicType_1.DynamicType);
1304
1278
  });
1305
1279
  it('finds optional parameters', () => {
1306
- let file = new BrsFile_1.BrsFile('absolute_path/file.brs', 'relative_path/file.brs', program);
1280
+ let file = new BrsFile_1.BrsFile({
1281
+ srcPath: 'absolute_path/file.brs',
1282
+ destPath: 'relative_path/file.brs',
1283
+ program: program
1284
+ });
1307
1285
  file.parse(`
1308
1286
  function Sum(a=2)
1309
1287
 
1310
1288
  end function
1311
1289
  `);
1312
1290
  let callable = file.callables[0];
1313
- (0, chai_1.expect)(callable.params[0]).to.deep.include({
1291
+ (0, chai_config_spec_1.expect)(callable.params[0]).to.deep.include({
1314
1292
  name: 'a',
1315
1293
  isOptional: true,
1316
1294
  isRestArgument: false
1317
1295
  });
1318
- (0, chai_1.expect)(callable.params[0].type).instanceof(IntegerType_1.IntegerType);
1296
+ (0, chai_config_spec_1.expect)(callable.params[0].type).instanceof(IntegerType_1.IntegerType);
1319
1297
  });
1320
1298
  it('finds parameter types', () => {
1321
- let file = new BrsFile_1.BrsFile('absolute_path/file.brs', 'relative_path/file.brs', program);
1299
+ let file = new BrsFile_1.BrsFile({
1300
+ srcPath: 'absolute_path/file.brs',
1301
+ destPath: 'relative_path/file.brs',
1302
+ program: program
1303
+ });
1322
1304
  file.parse(`
1323
1305
  function Sum(a, b as integer, c as string)
1324
1306
 
1325
1307
  end function
1326
1308
  `);
1327
1309
  let callable = file.callables[0];
1328
- (0, chai_1.expect)(callable.params[0]).to.deep.include({
1310
+ (0, chai_config_spec_1.expect)(callable.params[0]).to.deep.include({
1329
1311
  name: 'a',
1330
1312
  isOptional: false,
1331
1313
  isRestArgument: false
1332
1314
  });
1333
- (0, chai_1.expect)(callable.params[0].type).instanceof(DynamicType_1.DynamicType);
1334
- (0, chai_1.expect)(callable.params[1]).to.deep.include({
1315
+ (0, chai_config_spec_1.expect)(callable.params[0].type).instanceof(DynamicType_1.DynamicType);
1316
+ (0, chai_config_spec_1.expect)(callable.params[1]).to.deep.include({
1335
1317
  name: 'b',
1336
1318
  isOptional: false,
1337
1319
  isRestArgument: false
1338
1320
  });
1339
- (0, chai_1.expect)(callable.params[1].type).instanceof(IntegerType_1.IntegerType);
1340
- (0, chai_1.expect)(callable.params[2]).to.deep.include({
1321
+ (0, chai_config_spec_1.expect)(callable.params[1].type).instanceof(IntegerType_1.IntegerType);
1322
+ (0, chai_config_spec_1.expect)(callable.params[2]).to.deep.include({
1341
1323
  name: 'c',
1342
1324
  isOptional: false,
1343
1325
  isRestArgument: false
1344
1326
  });
1345
- (0, chai_1.expect)(callable.params[2].type).instanceof(StringType_1.StringType);
1327
+ (0, chai_config_spec_1.expect)(callable.params[2].type).instanceof(StringType_1.StringType);
1346
1328
  });
1347
1329
  });
1348
1330
  describe('findCallableInvocations', () => {
1349
1331
  it('finds arguments with literal values', () => {
1350
- let file = new BrsFile_1.BrsFile('absolute_path/file.brs', 'relative_path/file.brs', program);
1332
+ let file = new BrsFile_1.BrsFile({
1333
+ srcPath: 'absolute_path/file.brs',
1334
+ destPath: 'relative_path/file.brs',
1335
+ program: program
1336
+ });
1351
1337
  file.parse(`
1352
1338
  function Sum()
1353
1339
  DoSomething("name", 12, true)
1354
1340
  end function
1355
1341
  `);
1356
- (0, chai_1.expect)(file.functionCalls.length).to.equal(1);
1342
+ (0, chai_config_spec_1.expect)(file.functionCalls.length).to.equal(1);
1357
1343
  const argsMap = file.functionCalls[0].args.map(arg => {
1358
1344
  // disregard arg.expression, etc.
1359
1345
  return { type: arg.type, range: arg.range, text: arg.text };
1360
1346
  });
1361
- (0, chai_1.expect)(argsMap).to.eql([{
1362
- type: new StringType_1.StringType(),
1347
+ (0, chai_config_spec_1.expect)(argsMap).to.eql([{
1348
+ type: StringType_1.StringType.instance,
1363
1349
  range: util_1.default.createRange(2, 32, 2, 38),
1364
1350
  text: '"name"'
1365
1351
  }, {
1366
- type: new IntegerType_1.IntegerType(),
1352
+ type: IntegerType_1.IntegerType.instance,
1367
1353
  range: util_1.default.createRange(2, 40, 2, 42),
1368
1354
  text: '12'
1369
1355
  }, {
1370
- type: new BooleanType_1.BooleanType(),
1356
+ type: BooleanType_1.BooleanType.instance,
1371
1357
  range: util_1.default.createRange(2, 44, 2, 48),
1372
1358
  text: 'true'
1373
1359
  }]);
@@ -1386,7 +1372,11 @@ describe('BrsFile', () => {
1386
1372
  ]);
1387
1373
  });
1388
1374
  it('finds arguments with variable values', () => {
1389
- let file = new BrsFile_1.BrsFile('absolute_path/file.brs', 'relative_path/file.brs', program);
1375
+ let file = new BrsFile_1.BrsFile({
1376
+ srcPath: 'absolute_path/file.brs',
1377
+ destPath: 'relative_path/file.brs',
1378
+ program: program
1379
+ });
1390
1380
  file.parse(`
1391
1381
  function Sum()
1392
1382
  count = 1
@@ -1395,17 +1385,17 @@ describe('BrsFile', () => {
1395
1385
  DoSomething(count, name, isAlive)
1396
1386
  end function
1397
1387
  `);
1398
- (0, chai_1.expect)(file.functionCalls.length).to.equal(1);
1399
- (0, chai_1.expect)(file.functionCalls[0].args[0]).deep.include({
1400
- type: new IntegerType_1.IntegerType(),
1388
+ (0, chai_config_spec_1.expect)(file.functionCalls.length).to.equal(1);
1389
+ (0, chai_config_spec_1.expect)(file.functionCalls[0].args[0]).deep.include({
1390
+ type: new DynamicType_1.DynamicType(),
1401
1391
  text: 'count'
1402
1392
  });
1403
- (0, chai_1.expect)(file.functionCalls[0].args[1]).deep.include({
1404
- type: new StringType_1.StringType(),
1393
+ (0, chai_config_spec_1.expect)(file.functionCalls[0].args[1]).deep.include({
1394
+ type: new DynamicType_1.DynamicType(),
1405
1395
  text: 'name'
1406
1396
  });
1407
- (0, chai_1.expect)(file.functionCalls[0].args[2]).deep.include({
1408
- type: new BooleanType_1.BooleanType(),
1397
+ (0, chai_config_spec_1.expect)(file.functionCalls[0].args[2]).deep.include({
1398
+ type: new DynamicType_1.DynamicType(),
1409
1399
  text: 'isAlive'
1410
1400
  });
1411
1401
  });
@@ -1413,32 +1403,36 @@ describe('BrsFile', () => {
1413
1403
  describe('findCallables', () => {
1414
1404
  //this test is to help with code coverage
1415
1405
  it('skips top-level statements', () => {
1416
- let file = new BrsFile_1.BrsFile('absolute', 'relative', program);
1406
+ let file = new BrsFile_1.BrsFile({
1407
+ srcPath: 'absolute',
1408
+ destPath: 'relative',
1409
+ program: program
1410
+ });
1417
1411
  file.parse('name = "Bob"');
1418
- (0, chai_1.expect)(file.callables.length).to.equal(0);
1412
+ (0, chai_config_spec_1.expect)(file.callables.length).to.equal(0);
1419
1413
  });
1420
1414
  it('finds return type', () => {
1421
1415
  let file = program.setFile('source/main.brs', `
1422
1416
  function DoSomething() as string
1423
1417
  end function
1424
1418
  `);
1425
- (0, chai_1.expect)(file.callables[0]).to.deep.include({
1419
+ (0, chai_config_spec_1.expect)(file.callables[0]).to.deep.include({
1426
1420
  file: file,
1427
1421
  nameRange: vscode_languageserver_1.Range.create(1, 25, 1, 36),
1428
1422
  name: 'DoSomething',
1429
1423
  params: []
1430
1424
  });
1431
- (0, chai_1.expect)(file.callables[0].type.returnType).instanceof(StringType_1.StringType);
1425
+ (0, chai_config_spec_1.expect)(file.callables[0].type.returnType).instanceof(StringType_1.StringType);
1432
1426
  });
1433
1427
  });
1434
- describe('function local variable handling', () => {
1428
+ describe('createFunctionScopes', () => {
1435
1429
  it('creates range properly', () => {
1436
1430
  file.parse(`
1437
1431
  sub Main()
1438
1432
  name = 'bob"
1439
1433
  end sub
1440
1434
  `);
1441
- (0, chai_1.expect)(file.parser.references.functionStatements[0].range).to.eql(vscode_languageserver_1.Range.create(1, 16, 3, 23));
1435
+ (0, chai_config_spec_1.expect)(file.functionScopes[0].range).to.eql(vscode_languageserver_1.Range.create(1, 16, 3, 23));
1442
1436
  });
1443
1437
  it('creates scopes for parent and child functions', () => {
1444
1438
  file.parse(`
@@ -1452,9 +1446,23 @@ describe('BrsFile', () => {
1452
1446
  end sub)
1453
1447
  end sub
1454
1448
  `);
1455
- (0, chai_1.expect)(file.parser.references.functionExpressions).to.be.length(3);
1449
+ (0, chai_config_spec_1.expect)(file.functionScopes).to.length(3);
1456
1450
  });
1457
- it('finds variables declared in function expressions', () => {
1451
+ it('outer function does not capture inner statements', () => {
1452
+ file.parse(`
1453
+ sub Main()
1454
+ name = "john"
1455
+ sayHi = sub()
1456
+ age = 12
1457
+ end sub
1458
+ end sub
1459
+ `);
1460
+ let outerScope = file.getFunctionScopeAtPosition(vscode_languageserver_1.Position.create(2, 25));
1461
+ (0, chai_config_spec_1.expect)(outerScope.variableDeclarations).to.be.lengthOf(2);
1462
+ let innerScope = file.getFunctionScopeAtPosition(vscode_languageserver_1.Position.create(4, 10));
1463
+ (0, chai_config_spec_1.expect)(innerScope.variableDeclarations).to.be.lengthOf(1);
1464
+ });
1465
+ it('finds variables declared in function scopes', () => {
1458
1466
  file.parse(`
1459
1467
  sub Main()
1460
1468
  sayHi = sub()
@@ -1466,15 +1474,24 @@ describe('BrsFile', () => {
1466
1474
  end sub)
1467
1475
  end sub
1468
1476
  `);
1469
- (0, testHelpers_spec_1.expectSymbolTableEquals)(file.parser.references.functionExpressions[0].symbolTable, [
1470
- ['sayHi', new TypedFunctionType_1.TypedFunctionType(new VoidType_1.VoidType(), true), util_1.default.createRange(2, 20, 2, 25)]
1471
- ]);
1472
- (0, testHelpers_spec_1.expectSymbolTableEquals)(file.parser.references.functionExpressions[1].symbolTable, [
1473
- ['age', new IntegerType_1.IntegerType(), util_1.default.createRange(3, 24, 3, 27)]
1474
- ]);
1475
- (0, testHelpers_spec_1.expectSymbolTableEquals)(file.parser.references.functionExpressions[2].symbolTable, [
1476
- ['name', new StringType_1.StringType(), util_1.default.createRange(7, 24, 7, 28)]
1477
- ]);
1477
+ (0, chai_config_spec_1.expect)(file.functionScopes[0].variableDeclarations).to.be.length(1);
1478
+ (0, chai_config_spec_1.expect)(file.functionScopes[0].variableDeclarations[0]).to.deep.include({
1479
+ lineIndex: 2,
1480
+ name: 'sayHi'
1481
+ });
1482
+ (0, chai_config_spec_1.expect)(file.functionScopes[0].variableDeclarations[0].getType()).instanceof(TypedFunctionType_1.TypedFunctionType);
1483
+ (0, chai_config_spec_1.expect)(file.functionScopes[1].variableDeclarations).to.be.length(1);
1484
+ (0, chai_config_spec_1.expect)(file.functionScopes[1].variableDeclarations[0]).to.deep.include({
1485
+ lineIndex: 3,
1486
+ name: 'age'
1487
+ });
1488
+ (0, chai_config_spec_1.expect)(file.functionScopes[1].variableDeclarations[0].getType()).instanceof(IntegerType_1.IntegerType);
1489
+ (0, chai_config_spec_1.expect)(file.functionScopes[2].variableDeclarations).to.be.length(1);
1490
+ (0, chai_config_spec_1.expect)(file.functionScopes[2].variableDeclarations[0]).to.deep.include({
1491
+ lineIndex: 7,
1492
+ name: 'name'
1493
+ });
1494
+ (0, chai_config_spec_1.expect)(file.functionScopes[2].variableDeclarations[0].getType()).instanceof(StringType_1.StringType);
1478
1495
  });
1479
1496
  it('finds variable declarations inside of if statements', () => {
1480
1497
  file.parse(`
@@ -1484,9 +1501,9 @@ describe('BrsFile', () => {
1484
1501
  end if
1485
1502
  end sub
1486
1503
  `);
1487
- (0, testHelpers_spec_1.expectSymbolTableEquals)(file.parser.references.functionExpressions[0].symbolTable, [
1488
- ['theLength', new IntegerType_1.IntegerType(), util_1.default.createRange(3, 24, 3, 33)]
1489
- ]);
1504
+ let scope = file.getFunctionScopeAtPosition(vscode_languageserver_1.Position.create(3, 0));
1505
+ (0, chai_config_spec_1.expect)(scope.variableDeclarations[0]).to.exist;
1506
+ (0, chai_config_spec_1.expect)(scope.variableDeclarations[0].name).to.equal('theLength');
1490
1507
  });
1491
1508
  it('finds value from global return', () => {
1492
1509
  let file = program.setFile('source/main.brs', `
@@ -1498,21 +1515,31 @@ describe('BrsFile', () => {
1498
1515
  return "bob"
1499
1516
  end function
1500
1517
  `);
1501
- (0, testHelpers_spec_1.expectSymbolTableEquals)(file.parser.references.functionExpressions[0].symbolTable, [
1502
- ['myName', new StringType_1.StringType(), util_1.default.createRange(2, 19, 2, 25)]
1503
- ]);
1518
+ // Types are only guaranteed after validation
1519
+ program.validate();
1520
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1521
+ (0, chai_config_spec_1.expect)(file.functionScopes[0].variableDeclarations).to.be.length(1);
1522
+ (0, chai_config_spec_1.expect)(file.functionScopes[0].variableDeclarations[0]).to.deep.include({
1523
+ lineIndex: 2,
1524
+ name: 'myName'
1525
+ });
1526
+ (0, testHelpers_spec_1.expectTypeToBe)(file.functionScopes[0].variableDeclarations[0].getType(), StringType_1.StringType);
1504
1527
  });
1505
1528
  it('finds variable type from other variable', () => {
1506
- file.parse(`
1529
+ let file = program.setFile('source/main.brs', `
1507
1530
  sub Main()
1508
- name = "bob"
1509
- nameCopy = name
1531
+ name = "bob"
1532
+ nameCopy = name
1510
1533
  end sub
1511
1534
  `);
1512
- (0, testHelpers_spec_1.expectSymbolTableEquals)(file.parser.references.functionExpressions[0].symbolTable, [
1513
- ['name', new StringType_1.StringType(), util_1.default.createRange(2, 20, 2, 24)],
1514
- ['nameCopy', new StringType_1.StringType(), util_1.default.createRange(3, 20, 3, 28)]
1515
- ]);
1535
+ // Types are only guaranteed after validation
1536
+ program.validate();
1537
+ (0, chai_config_spec_1.expect)(file.functionScopes[0].variableDeclarations).to.be.length(2);
1538
+ (0, chai_config_spec_1.expect)(file.functionScopes[0].variableDeclarations[1]).to.deep.include({
1539
+ lineIndex: 3,
1540
+ name: 'nameCopy'
1541
+ });
1542
+ (0, testHelpers_spec_1.expectTypeToBe)(file.functionScopes[0].variableDeclarations[1].getType(), StringType_1.StringType);
1516
1543
  });
1517
1544
  it('sets proper range for functions', () => {
1518
1545
  file.parse(`
@@ -1522,469 +1549,69 @@ describe('BrsFile', () => {
1522
1549
  end function
1523
1550
  end sub
1524
1551
  `);
1525
- (0, chai_1.expect)(file.parser.references.functionExpressions.map(x => x.range)).to.eql([
1526
- util_1.default.createRange(1, 16, 5, 23),
1527
- util_1.default.createRange(2, 30, 4, 32)
1528
- ]);
1552
+ (0, chai_config_spec_1.expect)(file.functionScopes).to.be.length(2);
1553
+ (0, chai_config_spec_1.expect)(file.functionScopes[0].range).to.eql(vscode_languageserver_1.Range.create(1, 16, 5, 23));
1554
+ (0, chai_config_spec_1.expect)(file.functionScopes[1].range).to.eql(vscode_languageserver_1.Range.create(2, 30, 4, 32));
1529
1555
  });
1530
1556
  });
1531
1557
  it('handles mixed case `then` partions of conditionals', () => {
1532
- let mainFile = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1558
+ let mainFile = program.setFile('source/main.brs', `
1533
1559
  sub Main()
1534
1560
  if true then
1535
1561
  print "works"
1536
1562
  end if
1537
1563
  end sub
1538
1564
  `);
1539
- (0, chai_1.expect)(mainFile.getDiagnostics()).to.be.lengthOf(0);
1540
- mainFile = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1565
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(mainFile);
1566
+ mainFile = program.setFile('source/main.brs', `
1541
1567
  sub Main()
1542
1568
  if true Then
1543
1569
  print "works"
1544
1570
  end if
1545
1571
  end sub
1546
1572
  `);
1547
- (0, chai_1.expect)(mainFile.getDiagnostics()).to.be.lengthOf(0);
1548
- mainFile = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1573
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(mainFile);
1574
+ mainFile = program.setFile('source/main.brs', `
1549
1575
  sub Main()
1550
1576
  if true THEN
1551
1577
  print "works"
1552
1578
  end if
1553
1579
  end sub
1554
1580
  `);
1555
- (0, chai_1.expect)(mainFile.getDiagnostics()).to.be.lengthOf(0);
1581
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(mainFile);
1556
1582
  });
1557
- describe('getHover', () => {
1558
- it('works for param types', () => {
1559
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
1560
- sub DoSomething(name as string)
1561
- name = 1
1562
- sayMyName = function (name as string)
1563
- end function
1564
- end sub
1583
+ it('does not throw when encountering incomplete import statement', () => {
1584
+ program.setFile('source/main.brs', `
1585
+ import
1586
+ sub main()
1587
+ end sub
1588
+ `);
1589
+ program.validate();
1590
+ //this test will throw an exception if something went wrong
1591
+ });
1592
+ describe('transpile', () => {
1593
+ it('transpilies libpkg:/ paths when encountered', async () => {
1594
+ program.setFile('source/lib.bs', `
1595
+ import "libpkg:/source/numbers.bs"
1565
1596
  `);
1566
- //hover over the `name = 1` line
1567
- let hover = program.getHover(file.srcPath, vscode_languageserver_1.Position.create(2, 24))[0];
1568
- (0, chai_1.expect)(hover).to.exist;
1569
- (0, chai_1.expect)(hover.range).to.eql(vscode_languageserver_1.Range.create(2, 20, 2, 24));
1570
- //hover over the `name` parameter declaration
1571
- hover = program.getHover(file.srcPath, vscode_languageserver_1.Position.create(1, 34))[0];
1572
- (0, chai_1.expect)(hover).to.exist;
1573
- (0, chai_1.expect)(hover.range).to.eql(vscode_languageserver_1.Range.create(1, 32, 1, 36));
1574
- });
1575
- //ignore this for now...it's not a huge deal
1576
- it('does not match on keywords or data types', () => {
1577
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
1578
- sub Main(name as string)
1579
- end sub
1580
- sub as ()
1597
+ program.setFile('source/numbers.bs', `
1598
+ sub test()
1581
1599
  end sub
1582
1600
  `);
1583
- //hover over the `as`
1584
- (0, chai_1.expect)(program.getHover(file.srcPath, vscode_languageserver_1.Position.create(1, 31))).to.be.empty;
1585
- //hover over the `string`
1586
- (0, chai_1.expect)(program.getHover(file.srcPath, vscode_languageserver_1.Position.create(1, 36))).to.be.empty;
1601
+ await testTranspile(`
1602
+ <component name="TestButton" extends="Group">
1603
+ <script type="text/brightscript" uri="libpkg:/source/lib.bs"/>
1604
+ </component>
1605
+ `, `
1606
+ <component name="TestButton" extends="Group">
1607
+ <script type="text/brightscript" uri="libpkg:/source/lib.brs" />
1608
+ <script type="text/brightscript" uri="pkg:/source/numbers.brs" />
1609
+ <script type="text/brightscript" uri="pkg:/source/bslib.brs" />
1610
+ </component>
1611
+ `, undefined, 'components/TestButton.xml');
1587
1612
  });
1588
- it('finds declared function', () => {
1589
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
1590
- function Main(count = 1)
1591
- firstName = "bob"
1592
- age = 21
1593
- shoeSize = 10
1594
- end function
1595
- `);
1596
- let hover = program.getHover(file.srcPath, vscode_languageserver_1.Position.create(1, 28))[0];
1597
- (0, chai_1.expect)(hover).to.exist;
1598
- (0, chai_1.expect)(hover.range).to.eql(vscode_languageserver_1.Range.create(1, 25, 1, 29));
1599
- (0, chai_1.expect)(hover.contents).to.equal([
1600
- '```brightscript',
1601
- 'function Main(count? as integer) as dynamic',
1602
- '```'
1603
- ].join('\n'));
1604
- });
1605
- it('finds declared namespace function', () => {
1606
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1607
- namespace mySpace
1608
- function Main(count = 1)
1609
- firstName = "bob"
1610
- age = 21
1611
- shoeSize = 10
1612
- end function
1613
- end namespace
1614
- `);
1615
- let hover = program.getHover(file.srcPath, vscode_languageserver_1.Position.create(2, 28))[0];
1616
- (0, chai_1.expect)(hover).to.exist;
1617
- (0, chai_1.expect)(hover.range).to.eql(vscode_languageserver_1.Range.create(2, 25, 2, 29));
1618
- (0, chai_1.expect)(hover.contents).to.equal([
1619
- '```brightscript',
1620
- 'function Main(count? as integer) as dynamic',
1621
- '```'
1622
- ].join('\n'));
1623
- });
1624
- it('finds variable function hover in same scope', () => {
1625
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1626
- sub Main()
1627
- sayMyName = sub(name as string)
1628
- end sub
1629
-
1630
- sayMyName()
1631
- end sub
1632
- `);
1633
- let hover = program.getHover(file.srcPath, vscode_languageserver_1.Position.create(5, 24))[0];
1634
- (0, chai_1.expect)(hover.range).to.eql(vscode_languageserver_1.Range.create(5, 20, 5, 29));
1635
- (0, chai_1.expect)(hover.contents).to.equal([
1636
- '```brightscript',
1637
- 'sub (name as string) as void',
1638
- '```'
1639
- ].join('\n'));
1640
- });
1641
- it('does not crash when hovering on built-in functions', () => {
1642
- let file = program.setFile('source/main.brs', `
1643
- function doUcase(text)
1644
- return ucase(text)
1645
- end function
1646
- `);
1647
- (0, chai_1.expect)(program.getHover(file.srcPath, vscode_languageserver_1.Position.create(2, 30))[0].contents).to.equal([
1648
- '```brightscript',
1649
- 'function UCase(s as string) as string',
1650
- '```'
1651
- ].join('\n'));
1652
- });
1653
- it('does not crash when hovering on object method call', () => {
1654
- let file = program.setFile('source/main.brs', `
1655
- function getInstr(url, text)
1656
- return url.instr(text)
1657
- end function
1658
- `);
1659
- (0, chai_1.expect)(program.getHover(file.srcPath, vscode_languageserver_1.Position.create(2, 35))[0].contents).to.equal([
1660
- '```brightscript',
1661
- 'instr as dynamic',
1662
- '```'
1663
- ].join('\n'));
1664
- });
1665
- it('finds function hover in file scope', () => {
1666
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1667
- sub Main()
1668
- sayMyName()
1669
- end sub
1670
-
1671
- sub sayMyName()
1672
-
1673
- end sub
1674
- `);
1675
- let hover = program.getHover(file.srcPath, vscode_languageserver_1.Position.create(2, 25))[0];
1676
- (0, chai_1.expect)(hover.range).to.eql(vscode_languageserver_1.Range.create(2, 20, 2, 29));
1677
- (0, chai_1.expect)(hover.contents).to.equal([
1678
- '```brightscript',
1679
- 'sub sayMyName() as void',
1680
- '```'
1681
- ].join('\n'));
1682
- });
1683
- it('finds namespace function hover in file scope', () => {
1684
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1685
- namespace mySpace
1686
- sub Main()
1687
- sayMyName()
1688
- end sub
1689
-
1690
- sub sayMyName()
1691
-
1692
- end sub
1693
- end namespace
1694
- `);
1695
- let hover = program.getHover(file.srcPath, vscode_languageserver_1.Position.create(3, 25))[0];
1696
- (0, chai_1.expect)(hover.range).to.eql(vscode_languageserver_1.Range.create(3, 20, 3, 29));
1697
- (0, chai_1.expect)(hover.contents).to.equal([
1698
- '```brightscript',
1699
- 'sub sayMyName() as void',
1700
- '```'
1701
- ].join('\n'));
1702
- });
1703
- it('finds function hover in scope', () => {
1704
- let rootDir = process.cwd();
1705
- program = new Program_1.Program({
1706
- rootDir: rootDir
1707
- });
1708
- let mainFile = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1709
- sub Main()
1710
- sayMyName()
1711
- end sub
1712
- `);
1713
- program.setFile({ src: `${rootDir}/source/lib.brs`, dest: 'source/lib.brs' }, `
1714
- sub sayMyName(name as string)
1715
-
1716
- end sub
1717
- `);
1718
- let hover = program.getHover(mainFile.srcPath, vscode_languageserver_1.Position.create(2, 25))[0];
1719
- (0, chai_1.expect)(hover).to.exist;
1720
- (0, chai_1.expect)(hover.range).to.eql(vscode_languageserver_1.Range.create(2, 20, 2, 29));
1721
- (0, chai_1.expect)(hover.contents).to.equal([
1722
- '```brightscript',
1723
- 'sub sayMyName(name as string) as void',
1724
- '```'
1725
- ].join('\n'));
1726
- });
1727
- it('finds namespace function hover in scope', () => {
1728
- let rootDir = process.cwd();
1729
- program = new Program_1.Program({
1730
- rootDir: rootDir
1731
- });
1732
- let mainFile = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1733
- sub Main()
1734
- mySpace.sayMyName()
1735
- end sub
1736
- `);
1737
- program.setFile({ src: `${rootDir}/source/lib.brs`, dest: 'source/lib.brs' }, `
1738
- namespace mySpace
1739
- sub sayMyName(name as string)
1740
- end sub
1741
- end namespace
1742
- `);
1743
- let hover = program.getHover(mainFile.srcPath, vscode_languageserver_1.Position.create(2, 34))[0];
1744
- (0, chai_1.expect)(hover).to.exist;
1745
- (0, chai_1.expect)(hover.range).to.eql(vscode_languageserver_1.Range.create(2, 28, 2, 37));
1746
- (0, chai_1.expect)(hover.contents).to.equal([
1747
- '```brightscript',
1748
- 'sub sayMyName(name as string) as void',
1749
- '```'
1750
- ].join('\n'));
1751
- });
1752
- it('includes markdown comments in hover.', () => {
1753
- let rootDir = process.cwd();
1754
- program = new Program_1.Program({
1755
- rootDir: rootDir
1756
- });
1757
- const file = program.setFile('source/lib.brs', `
1758
- '
1759
- ' The main function
1760
- '
1761
- sub main()
1762
- log("hello")
1763
- end sub
1764
-
1765
- '
1766
- ' Prints a message to the log.
1767
- ' Works with *markdown* **content**
1768
- '
1769
- sub log(message as string)
1770
- print message
1771
- end sub
1772
- `);
1773
- //hover over log("hello")
1774
- (0, chai_1.expect)(program.getHover(file.srcPath, vscode_languageserver_1.Position.create(5, 22))[0].contents).to.equal([
1775
- '```brightscript',
1776
- 'sub log(message as string) as void',
1777
- '```',
1778
- '***',
1779
- '',
1780
- ' Prints a message to the log.',
1781
- ' Works with *markdown* **content**',
1782
- ''
1783
- ].join('\n'));
1784
- //hover over sub ma|in()
1785
- (0, chai_1.expect)((0, testHelpers_spec_1.trim)(program.getHover(file.srcPath, vscode_languageserver_1.Position.create(4, 22))[0].contents.toString())).to.equal((0, testHelpers_spec_1.trim) `
1786
- \`\`\`brightscript
1787
- sub main() as void
1788
- \`\`\`
1789
- ***
1790
-
1791
- The main function
1792
- `);
1793
- });
1794
- it('handles mixed case `then` partions of conditionals', () => {
1795
- let mainFile = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1796
- sub Main()
1797
- if true then
1798
- print "works"
1799
- end if
1800
- end sub
1801
- `);
1802
- (0, testHelpers_spec_1.expectZeroDiagnostics)(mainFile);
1803
- mainFile = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1804
- sub Main()
1805
- if true Then
1806
- print "works"
1807
- end if
1808
- end sub
1809
- `);
1810
- (0, testHelpers_spec_1.expectZeroDiagnostics)(mainFile);
1811
- mainFile = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1812
- sub Main()
1813
- if true THEN
1814
- print "works"
1815
- end if
1816
- end sub
1817
- `);
1818
- (0, testHelpers_spec_1.expectZeroDiagnostics)(mainFile);
1819
- });
1820
- it('displays the context from multiple scopes', () => {
1821
- var _a, _b;
1822
- let commonFile = program.setFile('source/common.brs', `
1823
- sub displayPi()
1824
- pi = getPi()
1825
- print pi
1826
- end sub
1827
- `);
1828
- let scope1File = program.setFile('components/comp1/scope1.brs', `
1829
- function getPi() as string
1830
- return "apple"
1831
- end function
1832
- `);
1833
- (0, chai_1.expect)(scope1File.getDiagnostics()).to.be.lengthOf(0);
1834
- program.setFile('components/comp1/comp1.xml', (0, testHelpers_spec_1.trim) `
1835
- <?xml version="1.0" encoding="utf-8" ?>
1836
- <component name="Component1" extends="Group">
1837
- <script type="text/brightscript" uri="scope1.brs" />
1838
- <script type="text/brightscript" uri="pkg:/source/common.brs" />
1839
- </component>
1840
- `);
1841
- let scope2File = program.setFile('components/comp2/scope2.brs', `
1842
- function getPi() as float
1843
- return 3.14
1844
- end function
1845
- `);
1846
- (0, chai_1.expect)(scope2File.getDiagnostics()).to.be.lengthOf(0);
1847
- program.setFile('components/comp2/comp2.xml', (0, testHelpers_spec_1.trim) `
1848
- <?xml version="1.0" encoding="utf-8" ?>
1849
- <component name="Component2" extends="Group">
1850
- <script type="text/brightscript" uri="scope2.brs" />
1851
- <script type="text/brightscript" uri="pkg:/source/common.brs" />
1852
- </component>
1853
- `);
1854
- program.validate();
1855
- let funcCallHover = program.getHover(commonFile.srcPath, vscode_languageserver_1.Position.create(2, 27));
1856
- (0, chai_1.expect)((_a = funcCallHover[0]) === null || _a === void 0 ? void 0 : _a.contents).to.equal([
1857
- '```brightscript',
1858
- 'function getPi() as string | function getPi() as float | getPi as uninitialized',
1859
- '```'
1860
- ].join('\n'));
1861
- let variableHover = program.getHover(commonFile.srcPath, vscode_languageserver_1.Position.create(3, 27));
1862
- (0, chai_1.expect)((_b = variableHover[0]) === null || _b === void 0 ? void 0 : _b.contents).to.equal([
1863
- '```brightscript',
1864
- 'pi as string | pi as float | pi as uninitialized',
1865
- '```'
1866
- ].join('\n'));
1867
- });
1868
- it('finds function with custom types as parameters and return types', () => {
1869
- let file = program.setFile('source/main.bs', `
1870
- sub main()
1871
- k = new MyKlass()
1872
- processMyKlass(k)
1873
- end sub
1874
-
1875
- function processMyKlass(data as MyKlass) as MyKlass
1876
- return data
1877
- end function
1878
-
1879
- class MyKlass
1880
- end class
1881
- `);
1882
- let hover = program.getHover(file.srcPath, vscode_languageserver_1.Position.create(3, 29));
1883
- (0, chai_1.expect)(hover).to.exist;
1884
- (0, chai_1.expect)(hover[0].contents).to.equal([
1885
- '```brightscript',
1886
- 'function processMyKlass(data as MyKlass) as MyKlass',
1887
- '```'
1888
- ].join('\n'));
1889
- });
1890
- it('finds function with arrays as parameters and return types', () => {
1891
- let file = program.setFile('source/main.bs', `
1892
- sub main()
1893
- k = new MyKlass()
1894
- processData([k])
1895
- end sub
1896
-
1897
- function processData(data as MyKlass[]) as MyKlass[]
1898
- return data
1899
- end function
1900
-
1901
- class MyKlass
1902
- end class
1903
- `);
1904
- let hover = program.getHover(file.srcPath, vscode_languageserver_1.Position.create(3, 29));
1905
- (0, chai_1.expect)(hover).to.exist;
1906
- (0, chai_1.expect)(hover[0].contents).to.equal([
1907
- '```brightscript',
1908
- 'function processData(data as MyKlass[]) as MyKlass[]',
1909
- '```'
1910
- ].join('\n'));
1911
- });
1912
- it('display literal enum members', () => {
1913
- let file = program.setFile('source/main.bs', `
1914
- enum MyEnum
1915
- foo
1916
- bar
1917
- end enum
1918
-
1919
- sub main()
1920
- value = MyEnum.foo
1921
- print value
1922
- end sub
1923
- `);
1924
- let hover = program.getHover(file.srcPath, vscode_languageserver_1.Position.create(7, 38)); // 'myEnum.foo' in value assignnmnt
1925
- (0, chai_1.expect)(hover).to.exist;
1926
- (0, chai_1.expect)(hover[0].contents).to.equal([
1927
- '```brightscript',
1928
- 'MyEnum.foo as MyEnum',
1929
- '```'
1930
- ].join('\n'));
1931
- });
1932
- it('finds enum values from assignments', () => {
1933
- let file = program.setFile('source/main.bs', `
1934
- enum MyEnum
1935
- foo
1936
- bar
1937
- end enum
1938
-
1939
- sub main()
1940
- value = MyEnum.foo
1941
- print value
1942
- end sub
1943
- `);
1944
- let hover = program.getHover(file.srcPath, vscode_languageserver_1.Position.create(8, 30)); // 'value' in print statement
1945
- (0, chai_1.expect)(hover).to.exist;
1946
- (0, chai_1.expect)(hover[0].contents).to.equal([
1947
- '```brightscript',
1948
- 'value as MyEnum',
1949
- '```'
1950
- ].join('\n'));
1951
- });
1952
- it('finds enum values as parameters', () => {
1953
- let file = program.setFile('source/main.bs', `
1954
- enum MyEnum
1955
- foo
1956
- bar
1957
- end enum
1958
-
1959
- sub printEnum(enumParamVal as MyEnum)
1960
- print enumParamVal
1961
- end sub
1962
-
1963
- sub main()
1964
- printEnum(MyEnum.foo)
1965
- end sub
1966
- `);
1967
- let hover = program.getHover(file.srcPath, vscode_languageserver_1.Position.create(7, 30)); // 'enumParamVal' in print statement
1968
- (0, chai_1.expect)(hover).to.exist;
1969
- (0, chai_1.expect)(hover[0].contents).to.equal([
1970
- '```brightscript',
1971
- 'enumParamVal as MyEnum',
1972
- '```'
1973
- ].join('\n'));
1974
- });
1975
- });
1976
- it('does not throw when encountering incomplete import statement', () => {
1977
- program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1978
- import
1979
- sub main()
1980
- end sub
1981
- `);
1982
- program.validate();
1983
- //this test will throw an exception if something went wrong
1984
- });
1985
- describe('transpile', () => {
1986
- it('excludes trailing commas in array literals', () => {
1987
- testTranspile(`
1613
+ it('excludes trailing commas in array literals', async () => {
1614
+ await testTranspile(`
1988
1615
  sub main()
1989
1616
  arr = [
1990
1617
  1,
@@ -2012,7 +1639,7 @@ describe('BrsFile', () => {
2012
1639
  end sub
2013
1640
  `);
2014
1641
  });
2015
- it('transpiles if statement keywords as provided', () => {
1642
+ it('transpiles if statement keywords as provided', async () => {
2016
1643
  const code = `
2017
1644
  sub main()
2018
1645
  If True Then
@@ -2026,12 +1653,12 @@ describe('BrsFile', () => {
2026
1653
  End If
2027
1654
  end sub
2028
1655
  `;
2029
- testTranspile(code);
2030
- testTranspile(code.toLowerCase());
2031
- testTranspile(code.toUpperCase());
1656
+ await testTranspile(code);
1657
+ await testTranspile(code.toLowerCase());
1658
+ await testTranspile(code.toUpperCase());
2032
1659
  });
2033
- it('does not transpile `then` tokens', () => {
2034
- testTranspile(`
1660
+ it('does not transpile `then` tokens', async () => {
1661
+ await testTranspile(`
2035
1662
  sub main()
2036
1663
  if true
2037
1664
  print true
@@ -2041,8 +1668,8 @@ describe('BrsFile', () => {
2041
1668
  end sub
2042
1669
  `);
2043
1670
  });
2044
- it('honors spacing between multi-word tokens', () => {
2045
- testTranspile(`
1671
+ it('honors spacing between multi-word tokens', async () => {
1672
+ await testTranspile(`
2046
1673
  sub main()
2047
1674
  if true
2048
1675
  print true
@@ -2052,39 +1679,39 @@ describe('BrsFile', () => {
2052
1679
  end sub
2053
1680
  `);
2054
1681
  });
2055
- it('handles when only some of the statements have `then`', () => {
2056
- testTranspile(`
1682
+ it('handles when only some of the statements have `then`', async () => {
1683
+ await testTranspile(`
2057
1684
  sub main()
2058
1685
  if true
2059
1686
  else if true then
2060
1687
  else if true
2061
1688
  else if true then
2062
1689
  if true then
2063
- return true
1690
+ return
2064
1691
  end if
2065
1692
  end if
2066
1693
  end sub
2067
1694
  `);
2068
1695
  });
2069
- it('retains casing of parameter types', () => {
2070
- function test(type) {
2071
- testTranspile(`
1696
+ it('retains casing of parameter types', async () => {
1697
+ async function test(type) {
1698
+ await testTranspile(`
2072
1699
  sub one(a as ${type}, b as ${type.toUpperCase()}, c as ${type.toLowerCase()})
2073
1700
  end sub
2074
1701
  `);
2075
1702
  }
2076
- test('Boolean');
2077
- test('Double');
2078
- test('Dynamic');
2079
- test('Float');
2080
- test('Integer');
2081
- test('LongInteger');
2082
- test('Object');
2083
- test('String');
2084
- });
2085
- it('retains casing of return types', () => {
2086
- function test(type) {
2087
- testTranspile(`
1703
+ await test('Boolean');
1704
+ await test('Double');
1705
+ await test('Dynamic');
1706
+ await test('Float');
1707
+ await test('Integer');
1708
+ await test('LongInteger');
1709
+ await test('Object');
1710
+ await test('String');
1711
+ });
1712
+ it('retains casing of return types', async () => {
1713
+ async function test(type) {
1714
+ await testTranspile(`
2088
1715
  sub one() as ${type}
2089
1716
  end sub
2090
1717
 
@@ -2095,19 +1722,19 @@ describe('BrsFile', () => {
2095
1722
  end sub
2096
1723
  `);
2097
1724
  }
2098
- test('Boolean');
2099
- test('Double');
2100
- test('Dynamic');
2101
- test('Float');
2102
- test('Integer');
2103
- test('LongInteger');
2104
- test('Object');
2105
- test('String');
2106
- test('Void');
2107
- });
2108
- it('retains casing of literal types', () => {
2109
- function test(type) {
2110
- testTranspile(`
1725
+ await test('Boolean');
1726
+ await test('Double');
1727
+ await test('Dynamic');
1728
+ await test('Float');
1729
+ await test('Integer');
1730
+ await test('LongInteger');
1731
+ await test('Object');
1732
+ await test('String');
1733
+ await test('Void');
1734
+ });
1735
+ it('retains casing of literal types', async () => {
1736
+ async function test(type) {
1737
+ await testTranspile(`
2111
1738
  sub main()
2112
1739
  thing = ${type}
2113
1740
  thing = ${type.toLowerCase()}
@@ -2115,13 +1742,13 @@ describe('BrsFile', () => {
2115
1742
  end sub
2116
1743
  `);
2117
1744
  }
2118
- test('Invalid');
2119
- test('True');
2120
- test('False');
1745
+ await test('Invalid');
1746
+ await test('True');
1747
+ await test('False');
2121
1748
  });
2122
1749
  describe('throwStatement', () => {
2123
- it('transpiles properly', () => {
2124
- testTranspile(`
1750
+ it('transpiles properly', async () => {
1751
+ await testTranspile(`
2125
1752
  sub main()
2126
1753
  try
2127
1754
  throw "some message"
@@ -2132,8 +1759,8 @@ describe('BrsFile', () => {
2132
1759
  });
2133
1760
  });
2134
1761
  describe('try/catch', () => {
2135
- it('transpiles properly', () => {
2136
- testTranspile(`
1762
+ it('transpiles properly', async () => {
1763
+ await testTranspile(`
2137
1764
  sub main()
2138
1765
  try
2139
1766
  print m.b.c
@@ -2145,8 +1772,8 @@ describe('BrsFile', () => {
2145
1772
  });
2146
1773
  });
2147
1774
  describe('namespaces', () => {
2148
- it('properly transpiles namespace functions for assignments', () => {
2149
- testTranspile(`
1775
+ it('properly transpiles namespace functions for assignments', async () => {
1776
+ await testTranspile(`
2150
1777
  namespace NameA.NameB
2151
1778
  sub Speak()
2152
1779
  end sub
@@ -2167,8 +1794,8 @@ describe('BrsFile', () => {
2167
1794
  end sub
2168
1795
  `);
2169
1796
  });
2170
- it('properly transpiles inferred namespace function for assignment', () => {
2171
- testTranspile(`
1797
+ it('properly transpiles inferred namespace function for assignment', async () => {
1798
+ await testTranspile(`
2172
1799
  namespace NameA.NameB
2173
1800
  sub Speak()
2174
1801
  end sub
@@ -2188,24 +1815,47 @@ describe('BrsFile', () => {
2188
1815
  `);
2189
1816
  });
2190
1817
  });
2191
- it('includes all text to end of line for a non-terminated string', () => {
2192
- testTranspile('sub main()\n name = "john \nend sub', 'sub main()\n name = "john "\nend sub', null, 'source/main.bs', false);
1818
+ it('includes all text to end of line for a non-terminated string', async () => {
1819
+ await testTranspile('sub main()\n name = "john \nend sub', 'sub main()\n name = "john "\nend sub', null, 'source/main.bs', false);
2193
1820
  });
2194
- it('escapes quotes in string literals', () => {
2195
- testTranspile(`
1821
+ it('escapes quotes in string literals', async () => {
1822
+ await testTranspile(`
2196
1823
  sub main()
1824
+ expected = "Hello"
2197
1825
  expected += chr(10) + " version=""2.0"""
2198
1826
  end sub
2199
1827
  `);
2200
1828
  });
2201
- it('keeps function parameter types in proper order', () => {
2202
- testTranspile(`
1829
+ it('keeps function parameter types in proper order', async () => {
1830
+ await testTranspile(`
2203
1831
  function CreateTestStatistic(name as string, result = "Success" as string, time = 0 as integer, errorCode = 0 as integer, errorMessage = "" as string) as object
2204
1832
  end function
2205
1833
  `);
2206
1834
  });
2207
- it('transpiles local var assignment operators', () => {
2208
- testTranspile(`
1835
+ it('discard parameter types when removeParameterTypes is true', async () => {
1836
+ program.options.removeParameterTypes = true;
1837
+ await testTranspile(`
1838
+ sub one(a as integer, b = "" as string, c = invalid as dynamic)
1839
+ end sub
1840
+ `, `
1841
+ sub one(a, b = "", c = invalid)
1842
+ end sub
1843
+ `);
1844
+ });
1845
+ it('discard return type when removeParameterTypes is true', async () => {
1846
+ program.options.removeParameterTypes = true;
1847
+ await testTranspile(`
1848
+ function one() as string
1849
+ return ""
1850
+ end function
1851
+ `, `
1852
+ function one()
1853
+ return ""
1854
+ end function
1855
+ `);
1856
+ });
1857
+ it('transpiles local var assignment operators', async () => {
1858
+ await testTranspile(`
2209
1859
  sub main()
2210
1860
  count = 0
2211
1861
  count += 1
@@ -2218,8 +1868,8 @@ describe('BrsFile', () => {
2218
1868
  end sub
2219
1869
  `);
2220
1870
  });
2221
- it('transpiles AA property assignment operators', () => {
2222
- testTranspile(`
1871
+ it('transpiles AA property assignment operators', async () => {
1872
+ await testTranspile(`
2223
1873
  sub main()
2224
1874
  person = {
2225
1875
  count: 0
@@ -2228,8 +1878,8 @@ describe('BrsFile', () => {
2228
1878
  end sub
2229
1879
  `);
2230
1880
  });
2231
- it('transpiles AA indexed assignment operators', () => {
2232
- testTranspile(`
1881
+ it('transpiles AA indexed assignment operators', async () => {
1882
+ await testTranspile(`
2233
1883
  sub main()
2234
1884
  person = {
2235
1885
  count: 0
@@ -2238,8 +1888,8 @@ describe('BrsFile', () => {
2238
1888
  end sub
2239
1889
  `);
2240
1890
  });
2241
- it('relative-referenced namespaced functions get prefixed', () => {
2242
- testTranspile(`
1891
+ it('relative-referenced namespaced functions get prefixed', async () => {
1892
+ await testTranspile(`
2243
1893
  namespace Vertibrates.Birds
2244
1894
  function GetAllBirds()
2245
1895
  return [
@@ -2269,8 +1919,8 @@ describe('BrsFile', () => {
2269
1919
  end function
2270
1920
  `, 'trim', 'source/main.bs');
2271
1921
  });
2272
- it('transpiles namespaced functions', () => {
2273
- testTranspile(`
1922
+ it('transpiles namespaced functions', async () => {
1923
+ await testTranspile(`
2274
1924
  namespace NameA
2275
1925
  sub alert()
2276
1926
  end sub
@@ -2286,9 +1936,9 @@ describe('BrsFile', () => {
2286
1936
  end sub
2287
1937
  `, 'trim', 'source/main.bs');
2288
1938
  });
2289
- it('transpiles dim', () => {
2290
- function doTest(code) {
2291
- testTranspile(`
1939
+ it('transpiles dim', async () => {
1940
+ async function doTest(code) {
1941
+ await testTranspile(`
2292
1942
  sub main()
2293
1943
  requestList = []
2294
1944
  ${code}
@@ -2300,20 +1950,20 @@ describe('BrsFile', () => {
2300
1950
  end sub
2301
1951
  `);
2302
1952
  }
2303
- doTest(`Dim c[5]`);
2304
- doTest(`Dim c[5, 4]`);
2305
- doTest(`Dim c[5, 4, 6]`);
2306
- doTest(`Dim requestData[requestList.count()]`);
2307
- doTest(`Dim requestData[1, requestList.count()]`);
2308
- doTest(`Dim requestData[1, requestList.count(), 2]`);
2309
- doTest(`Dim requestData[requestList[2]]`);
2310
- doTest(`Dim requestData[1, requestList[2]]`);
2311
- doTest(`Dim requestData[1, requestList[2], 2]`);
2312
- doTest(`Dim requestData[requestList["2"]]`);
2313
- doTest(`Dim requestData[1, requestList["2"]]`);
2314
- doTest(`Dim requestData[1, requestList["2"], 2]`);
2315
- doTest(`Dim requestData[1, StrToI("1"), 2]`);
2316
- testTranspile(`
1953
+ await doTest(`Dim c[5]`);
1954
+ await doTest(`Dim c[5, 4]`);
1955
+ await doTest(`Dim c[5, 4, 6]`);
1956
+ await doTest(`Dim requestData[requestList.count()]`);
1957
+ await doTest(`Dim requestData[1, requestList.count()]`);
1958
+ await doTest(`Dim requestData[1, requestList.count(), 2]`);
1959
+ await doTest(`Dim requestData[requestList[2]]`);
1960
+ await doTest(`Dim requestData[1, requestList[2]]`);
1961
+ await doTest(`Dim requestData[1, requestList[2], 2]`);
1962
+ await doTest(`Dim requestData[requestList["2"]]`);
1963
+ await doTest(`Dim requestData[1, requestList["2"]]`);
1964
+ await doTest(`Dim requestData[1, requestList["2"], 2]`);
1965
+ await doTest(`Dim requestData[1, StrToI("1"), 2]`);
1966
+ await testTranspile(`
2317
1967
  function getValue(param1)
2318
1968
  end function
2319
1969
 
@@ -2325,8 +1975,41 @@ describe('BrsFile', () => {
2325
1975
  end sub
2326
1976
  `);
2327
1977
  });
2328
- it('transpiles calls to fully-qualified namespaced functions', () => {
2329
- testTranspile(`
1978
+ it('handles multi-index multi-dimensional arrays', async () => {
1979
+ await testTranspile(`
1980
+ sub main()
1981
+ myMultiArray = [[[[[[[[["hello"]]]]]]]]]
1982
+ myMultiArray[0][0][0][0][0][0][0][0][0] = "goodbye"
1983
+ print myMultiArray[0, 0, 0, 0, 0, 0, 0, 0, 0]
1984
+ end sub
1985
+ `, `
1986
+ sub main()
1987
+ myMultiArray = [
1988
+ [
1989
+ [
1990
+ [
1991
+ [
1992
+ [
1993
+ [
1994
+ [
1995
+ [
1996
+ "hello"
1997
+ ]
1998
+ ]
1999
+ ]
2000
+ ]
2001
+ ]
2002
+ ]
2003
+ ]
2004
+ ]
2005
+ ]
2006
+ myMultiArray[0][0][0][0][0][0][0][0][0] = "goodbye"
2007
+ print myMultiArray[0, 0, 0, 0, 0, 0, 0, 0, 0]
2008
+ end sub
2009
+ `);
2010
+ });
2011
+ it('transpiles calls to fully-qualified namespaced functions', async () => {
2012
+ await testTranspile(`
2330
2013
  namespace NameA
2331
2014
  sub alert()
2332
2015
  end sub
@@ -2351,15 +2034,15 @@ describe('BrsFile', () => {
2351
2034
  end sub
2352
2035
  `, 'trim', 'source/main.bs');
2353
2036
  });
2354
- it('keeps end-of-line comments with their line', () => {
2355
- testTranspile(`
2037
+ it('keeps end-of-line comments with their line', async () => {
2038
+ await testTranspile(`
2356
2039
  function DoSomething() 'comment 1
2357
2040
  name = "bob" 'comment 2
2358
2041
  end function 'comment 3
2359
2042
  `);
2360
2043
  });
2361
- it('works for functions', () => {
2362
- testTranspile(`
2044
+ it('works for functions', async () => {
2045
+ await testTranspile(`
2363
2046
  function DoSomething()
2364
2047
  'lots of empty white space
2365
2048
  'that will be removed during transpile
@@ -2374,16 +2057,16 @@ describe('BrsFile', () => {
2374
2057
  end function
2375
2058
  `);
2376
2059
  });
2377
- it('keeps empty AAs and arrays on same line', () => {
2378
- testTranspile(`
2060
+ it('keeps empty AAs and arrays on same line', async () => {
2061
+ await testTranspile(`
2379
2062
  sub a()
2380
2063
  person = {}
2381
2064
  stuff = []
2382
2065
  end sub
2383
2066
  `, null, 'trim');
2384
2067
  });
2385
- it('does not add leading or trailing newlines', () => {
2386
- testTranspile(`function abc()\nend function`, undefined, 'none');
2068
+ it('does not add leading or trailing newlines', async () => {
2069
+ await testTranspile(`function abc()\nend function`, undefined, 'none');
2387
2070
  });
2388
2071
  it('handles sourcemap edge case', async () => {
2389
2072
  let source = 'sub main()\n' +
@@ -2392,18 +2075,18 @@ describe('BrsFile', () => {
2392
2075
  '\n' +
2393
2076
  'end sub';
2394
2077
  program.options.sourceMap = true;
2395
- let result = testTranspile(source, `sub main()\n print 1\nend sub`, 'none', 'source/main.bs');
2078
+ let result = await testTranspile(source, `sub main()\n print 1\nend sub`, 'none', 'source/main.bs');
2396
2079
  //load the source map
2397
- let location = await source_map_1.SourceMapConsumer.with(result.map.toJSON(), null, (consumer) => {
2080
+ let location = await source_map_1.SourceMapConsumer.with(result.map, null, (consumer) => {
2398
2081
  return consumer.generatedPositionFor({
2399
2082
  line: 3,
2400
2083
  column: 0,
2401
- source: (0, util_1.standardizePath) `${rootDir}/source/main.bs`,
2084
+ source: (0, util_1.standardizePath) `${testHelpers_spec_2.rootDir}/source/main.bs`,
2402
2085
  bias: source_map_1.SourceMapConsumer.LEAST_UPPER_BOUND
2403
2086
  });
2404
2087
  });
2405
- (0, chai_1.expect)(location.line).to.eql(2);
2406
- (0, chai_1.expect)(location.column).eql(4);
2088
+ (0, chai_config_spec_1.expect)(location.line).to.eql(2);
2089
+ (0, chai_config_spec_1.expect)(location.column).eql(4);
2407
2090
  });
2408
2091
  it('computes correct locations for sourcemap', async () => {
2409
2092
  let source = `function abc(name)\n firstName = name\nend function`;
@@ -2411,7 +2094,7 @@ describe('BrsFile', () => {
2411
2094
  //remove newlines and EOF
2412
2095
  .filter(x => x.kind !== TokenKind_1.TokenKind.Eof && x.kind !== TokenKind_1.TokenKind.Newline);
2413
2096
  program.options.sourceMap = true;
2414
- let result = testTranspile(source, source, 'none');
2097
+ let result = await testTranspile(source, source, 'none');
2415
2098
  //load the source map
2416
2099
  await source_map_1.SourceMapConsumer.with(result.map.toString(), null, (consumer) => {
2417
2100
  let tokenResult = tokens.map(token => ({
@@ -2431,11 +2114,11 @@ describe('BrsFile', () => {
2431
2114
  originalPosition.line - 1, originalPosition.column)
2432
2115
  };
2433
2116
  });
2434
- (0, chai_1.expect)(sourcemapResult).to.eql(tokenResult);
2117
+ (0, chai_config_spec_1.expect)(sourcemapResult).to.eql(tokenResult);
2435
2118
  });
2436
2119
  });
2437
- it('handles empty if block', () => {
2438
- testTranspile(`
2120
+ it('handles empty if block', async () => {
2121
+ await testTranspile(`
2439
2122
  sub main()
2440
2123
  if true then
2441
2124
  end if
@@ -2456,8 +2139,8 @@ describe('BrsFile', () => {
2456
2139
  end sub
2457
2140
  `);
2458
2141
  });
2459
- it('handles empty elseif block', () => {
2460
- testTranspile(`
2142
+ it('handles empty elseif block', async () => {
2143
+ await testTranspile(`
2461
2144
  sub main()
2462
2145
  if true then
2463
2146
  print "if"
@@ -2471,8 +2154,8 @@ describe('BrsFile', () => {
2471
2154
  end sub
2472
2155
  `);
2473
2156
  });
2474
- it('handles empty else block', () => {
2475
- testTranspile(`
2157
+ it('handles empty else block', async () => {
2158
+ await testTranspile(`
2476
2159
  sub main()
2477
2160
  if true then
2478
2161
  print "if"
@@ -2487,8 +2170,20 @@ describe('BrsFile', () => {
2487
2170
  end sub
2488
2171
  `);
2489
2172
  });
2490
- it('works for function parameters', () => {
2491
- testTranspile(`
2173
+ it('handles else block with a leading comment', async () => {
2174
+ await testTranspile(`
2175
+ sub main()
2176
+ if true then
2177
+ print "if"
2178
+ else
2179
+ ' leading comment
2180
+ print "else"
2181
+ end if
2182
+ end sub
2183
+ `);
2184
+ });
2185
+ it('works for function parameters', async () => {
2186
+ await testTranspile(`
2492
2187
  function DoSomething(name, age as integer, text as string)
2493
2188
  end function
2494
2189
  `, `
@@ -2496,8 +2191,8 @@ describe('BrsFile', () => {
2496
2191
  end function
2497
2192
  `);
2498
2193
  });
2499
- it('adds newlines between top-level statements', () => {
2500
- testTranspile(`
2194
+ it('adds newlines between top-level statements', async () => {
2195
+ await testTranspile(`
2501
2196
  function a()
2502
2197
  end function
2503
2198
 
@@ -2505,8 +2200,8 @@ describe('BrsFile', () => {
2505
2200
  end function
2506
2201
  `);
2507
2202
  });
2508
- it('properly indents nested AA literals', () => {
2509
- testTranspile(`
2203
+ it('properly indents nested AA literals', async () => {
2204
+ await testTranspile(`
2510
2205
  sub doSomething()
2511
2206
  grandparent = {
2512
2207
  parent: {
@@ -2520,8 +2215,8 @@ describe('BrsFile', () => {
2520
2215
  end sub
2521
2216
  `);
2522
2217
  });
2523
- it('does not add comma after final object property even when comments are present', () => {
2524
- testTranspile(`
2218
+ it('does not add comma after final object property even when comments are present', async () => {
2219
+ await testTranspile(`
2525
2220
  sub doSomething()
2526
2221
  person = {
2527
2222
  age: 12 'comment
@@ -2544,8 +2239,8 @@ describe('BrsFile', () => {
2544
2239
  end sub
2545
2240
  `);
2546
2241
  });
2547
- it('works for a complex function with comments all over the place', () => {
2548
- testTranspile(`
2242
+ it('works for a complex function with comments all over the place', async () => {
2243
+ await testTranspile(`
2549
2244
  'import some library
2550
2245
  library "v30/bslCore.brs" 'comment
2551
2246
 
@@ -2635,25 +2330,25 @@ describe('BrsFile', () => {
2635
2330
  sub logInfo()
2636
2331
  end sub
2637
2332
  `);
2638
- file.needsTranspiled = false;
2333
+ file['needsTranspiled'] = false;
2639
2334
  const { code } = file.transpile();
2640
- (0, chai_1.expect)(code.endsWith(`'//# sourceMappingURL=./logger.brs.map`)).to.be.true;
2335
+ (0, chai_config_spec_1.expect)(code.endsWith(`'//# sourceMappingURL=./logger.brs.map`)).to.be.true;
2641
2336
  });
2642
2337
  it('AST generated files include a reference to the source map', () => {
2643
2338
  let file = program.setFile('source/logger.brs', (0, testHelpers_spec_1.trim) `
2644
2339
  sub logInfo()
2645
2340
  end sub
2646
2341
  `);
2647
- file.needsTranspiled = true;
2342
+ file['needsTranspiled'] = true;
2648
2343
  const { code } = file.transpile();
2649
- (0, chai_1.expect)(code.endsWith(`'//# sourceMappingURL=./logger.brs.map`)).to.be.true;
2344
+ (0, chai_config_spec_1.expect)(code.endsWith(`'//# sourceMappingURL=./logger.brs.map`)).to.be.true;
2650
2345
  });
2651
- it('replaces custom types in parameter types and return types', () => {
2346
+ it('replaces custom types in parameter types and return types', async () => {
2652
2347
  program.setFile('source/SomeKlass.bs', `
2653
2348
  class SomeKlass
2654
2349
  end class
2655
2350
  `);
2656
- testTranspile(`
2351
+ await testTranspile(`
2657
2352
  function foo() as SomeKlass
2658
2353
  return new SomeKlass()
2659
2354
  end function
@@ -2661,11 +2356,70 @@ describe('BrsFile', () => {
2661
2356
  sub bar(obj as SomeKlass)
2662
2357
  end sub
2663
2358
  `, `
2664
- function foo() as object
2359
+ function foo() as dynamic
2665
2360
  return SomeKlass()
2666
2361
  end function
2667
2362
 
2668
- sub bar(obj as object)
2363
+ sub bar(obj as dynamic)
2364
+ end sub
2365
+ `);
2366
+ });
2367
+ it('allows typecasts wrapped in parens', async () => {
2368
+ program.setFile('source/SomeKlass.bs', `
2369
+ class SomeKlass
2370
+ end class
2371
+ `);
2372
+ await testTranspile(`
2373
+ sub foo(obj as SomeKlass)
2374
+ (obj as roAssociativeArray).append({key:"value"})
2375
+ print 3 + (obj as roAssociativeArray).count()
2376
+ end sub
2377
+ `, `
2378
+ sub foo(obj as dynamic)
2379
+ obj.append({
2380
+ key: "value"
2381
+ })
2382
+ print 3 + obj.count()
2383
+ end sub
2384
+ `);
2385
+ });
2386
+ it('allows multiple typecasts wrapped in parens', async () => {
2387
+ program.setFile('source/SomeKlass.bs', `
2388
+ class SomeKlass
2389
+ function value()
2390
+ return 0.123
2391
+ end function
2392
+ end class
2393
+ `);
2394
+ await testTranspile(`
2395
+ sub foo(obj)
2396
+ print val( sin( (0.707 + (obj as SomeKlass).value()) as float ).toStr() as string)
2397
+ end sub
2398
+ `, `
2399
+ sub foo(obj)
2400
+ print val(sin((0.707 + obj.value())).toStr())
2401
+ end sub
2402
+ `);
2403
+ });
2404
+ it('allows a string of typecasts wrapped in parens', async () => {
2405
+ program.setFile('source/SomeKlass.bs', `
2406
+ class SomeKlass
2407
+ function data()
2408
+ return {key: "value"}
2409
+ end function
2410
+ end class
2411
+
2412
+ interface SomeIFace
2413
+ key
2414
+ end interface
2415
+ `);
2416
+ await testTranspile(`
2417
+ sub foo(obj)
2418
+ print (((obj as SomeKlass).data() as SomeIFace).key as string).len() as integer
2419
+ end sub
2420
+ `, `
2421
+ sub foo(obj)
2422
+ print obj.data().key.len()
2669
2423
  end sub
2670
2424
  `);
2671
2425
  });
@@ -2682,28 +2436,50 @@ describe('BrsFile', () => {
2682
2436
  program.validate();
2683
2437
  (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2684
2438
  });
2685
- it('sets invalid on empty callfunc', () => {
2686
- testTranspile(`
2439
+ it('sets invalid on empty callfunc with legacyCallfuncHandling=true', async () => {
2440
+ program.options.legacyCallfuncHandling = true;
2441
+ await testTranspile(`
2687
2442
  sub main()
2443
+ node = invalid
2688
2444
  node@.doSomething()
2689
2445
  m.top.node@.doSomething()
2690
2446
  m.top.node@.doSomething(1)
2691
2447
  end sub
2692
2448
  `, `
2693
2449
  sub main()
2450
+ node = invalid
2694
2451
  node.callfunc("doSomething", invalid)
2695
2452
  m.top.node.callfunc("doSomething", invalid)
2696
2453
  m.top.node.callfunc("doSomething", 1)
2697
2454
  end sub
2698
2455
  `);
2699
2456
  });
2700
- it('includes original arguments', () => {
2701
- testTranspile(`
2457
+ it('empty callfunc allowed by default', async () => {
2458
+ await testTranspile(`
2459
+ sub main()
2460
+ node = invalid
2461
+ node@.doSomething()
2462
+ m.top.node@.doSomething()
2463
+ m.top.node@.doSomething(1)
2464
+ end sub
2465
+ `, `
2466
+ sub main()
2467
+ node = invalid
2468
+ node.callfunc("doSomething")
2469
+ m.top.node.callfunc("doSomething")
2470
+ m.top.node.callfunc("doSomething", 1)
2471
+ end sub
2472
+ `);
2473
+ });
2474
+ it('includes original arguments', async () => {
2475
+ await testTranspile(`
2702
2476
  sub main()
2477
+ node = invalid
2703
2478
  node@.doSomething(1, true, m.top.someVal)
2704
2479
  end sub
2705
2480
  `, `
2706
2481
  sub main()
2482
+ node = invalid
2707
2483
  node.callfunc("doSomething", 1, true, m.top.someVal)
2708
2484
  end sub
2709
2485
  `);
@@ -2720,34 +2496,34 @@ describe('BrsFile', () => {
2720
2496
  name: 'transform callback',
2721
2497
  afterFileParse: onParsed
2722
2498
  });
2723
- file = program.setFile({ src: `absolute_path/file${ext}`, dest: `relative_path/file${ext}` }, `
2499
+ file = program.setFile(`source/file${ext}`, `
2724
2500
  sub Sum()
2725
- print "hello world"
2501
+ print "hello world"
2726
2502
  end sub
2727
2503
  `);
2728
- (0, chai_1.expect)(file.extension).to.equal(ext);
2504
+ (0, chai_config_spec_1.expect)(file.extension).to.equal(ext);
2729
2505
  return file;
2730
2506
  }
2731
2507
  it('called for BRS file', () => {
2732
2508
  const onParsed = sinon.spy();
2733
2509
  parseFileWithCallback('.brs', onParsed);
2734
- (0, chai_1.expect)(onParsed.callCount).to.equal(1);
2510
+ (0, chai_config_spec_1.expect)(onParsed.callCount).to.equal(1);
2735
2511
  });
2736
- it('called for BS file', () => {
2512
+ it('called for BR file', () => {
2737
2513
  const onParsed = sinon.spy();
2738
2514
  parseFileWithCallback('.bs', onParsed);
2739
- (0, chai_1.expect)(onParsed.callCount).to.equal(1);
2515
+ (0, chai_config_spec_1.expect)(onParsed.callCount).to.equal(1);
2740
2516
  });
2741
2517
  });
2742
2518
  describe('typedefKey', () => {
2743
2519
  it('works for .brs files', () => {
2744
- (0, chai_1.expect)((0, util_1.standardizePath)((program.setFile('source/main.brs', '')).typedefSrcPath)).to.equal((0, util_1.standardizePath) `${rootDir.toLowerCase()}/source/main.d.bs`);
2520
+ (0, chai_config_spec_1.expect)((0, util_1.standardizePath)((program.setFile('source/main.brs', '')).typedefKey)).to.equal((0, util_1.standardizePath) `${testHelpers_spec_2.rootDir.toLowerCase()}/source/main.d.bs`);
2745
2521
  });
2746
2522
  it('returns undefined for files that should not have a typedef', () => {
2747
- (0, chai_1.expect)((program.setFile('source/main.bs', '')).typedefSrcPath).to.be.undefined;
2748
- (0, chai_1.expect)((program.setFile('source/main.d.bs', '')).typedefSrcPath).to.be.undefined;
2523
+ (0, chai_config_spec_1.expect)((program.setFile('source/main.bs', '')).typedefKey).to.be.undefined;
2524
+ (0, chai_config_spec_1.expect)((program.setFile('source/main.d.bs', '')).typedefKey).to.be.undefined;
2749
2525
  const xmlFile = program.setFile('components/comp.xml', '');
2750
- (0, chai_1.expect)(xmlFile.typedefSrcPath).to.be.undefined;
2526
+ (0, chai_config_spec_1.expect)(xmlFile.typedefKey).to.be.undefined;
2751
2527
  });
2752
2528
  });
2753
2529
  describe('type definitions', () => {
@@ -2765,8 +2541,8 @@ describe('BrsFile', () => {
2765
2541
  `);
2766
2542
  const sourceScope = program.getScopeByName('source');
2767
2543
  const functionNames = sourceScope.getAllCallables().map(x => x.callable.name);
2768
- (0, chai_1.expect)(functionNames).to.include('main');
2769
- (0, chai_1.expect)(functionNames).not.to.include('speak');
2544
+ (0, chai_config_spec_1.expect)(functionNames).to.include('main');
2545
+ (0, chai_config_spec_1.expect)(functionNames).not.to.include('speak');
2770
2546
  });
2771
2547
  it('reacts to typedef file changes', () => {
2772
2548
  let file = program.setFile('source/main.brs', `
@@ -2775,14 +2551,14 @@ describe('BrsFile', () => {
2775
2551
  sub speak()
2776
2552
  end sub
2777
2553
  `);
2778
- (0, chai_1.expect)(file.hasTypedef).to.be.false;
2779
- (0, chai_1.expect)(file.typedefFile).not.to.exist;
2554
+ (0, chai_config_spec_1.expect)(file.hasTypedef).to.be.false;
2555
+ (0, chai_config_spec_1.expect)(file.typedefFile).not.to.exist;
2780
2556
  program.setFile('source/main.d.bs', `
2781
2557
  sub main()
2782
2558
  end sub
2783
2559
  `);
2784
- (0, chai_1.expect)(file.hasTypedef).to.be.true;
2785
- (0, chai_1.expect)(file.typedefFile).to.exist;
2560
+ (0, chai_config_spec_1.expect)(file.hasTypedef).to.be.true;
2561
+ (0, chai_config_spec_1.expect)(file.typedefFile).to.exist;
2786
2562
  //add replace file, does it still find the typedef
2787
2563
  file = program.setFile('source/main.brs', `
2788
2564
  sub main()
@@ -2790,46 +2566,72 @@ describe('BrsFile', () => {
2790
2566
  sub speak()
2791
2567
  end sub
2792
2568
  `);
2793
- (0, chai_1.expect)(file.hasTypedef).to.be.true;
2794
- (0, chai_1.expect)(file.typedefFile).to.exist;
2795
- program.removeFile((0, util_1.standardizePath) `${rootDir}/source/main.d.bs`);
2796
- (0, chai_1.expect)(file.hasTypedef).to.be.false;
2797
- (0, chai_1.expect)(file.typedefFile).not.to.exist;
2569
+ (0, chai_config_spec_1.expect)(file.hasTypedef).to.be.true;
2570
+ (0, chai_config_spec_1.expect)(file.typedefFile).to.exist;
2571
+ program.removeFile((0, util_1.standardizePath) `${testHelpers_spec_2.rootDir}/source/main.d.bs`);
2572
+ (0, chai_config_spec_1.expect)(file.hasTypedef).to.be.false;
2573
+ (0, chai_config_spec_1.expect)(file.typedefFile).not.to.exist;
2798
2574
  });
2799
2575
  });
2800
2576
  describe('typedef', () => {
2577
+ it('includes enum and interface types', async () => {
2578
+ await testGetTypedef(`
2579
+ interface Foo
2580
+ field as string
2581
+ end interface
2582
+
2583
+ enum Bar
2584
+ value
2585
+ end enum
2586
+
2587
+ function baz(parameter as Foo) as Bar
2588
+ return Bar.value
2589
+ end function
2590
+ `, `
2591
+ interface Foo
2592
+ field as string
2593
+ end interface
2594
+
2595
+ enum Bar
2596
+ value
2597
+ end enum
2598
+ function baz(parameter as Foo) as Bar
2599
+ end function
2600
+ `);
2601
+ });
2801
2602
  it('sets typedef path properly', () => {
2802
- (0, chai_1.expect)((program.setFile('source/main1.brs', '')).typedefSrcPath).to.equal((0, util_1.standardizePath) `${rootDir}/source/main1.d.bs`.toLowerCase());
2803
- (0, chai_1.expect)((program.setFile('source/main2.d.bs', '')).typedefSrcPath).to.equal(undefined);
2804
- (0, chai_1.expect)((program.setFile('source/main3.bs', '')).typedefSrcPath).to.equal(undefined);
2603
+ (0, chai_config_spec_1.expect)((program.setFile('source/main1.brs', '')).typedefKey).to.equal((0, util_1.standardizePath) `${testHelpers_spec_2.rootDir}/source/main1.d.bs`.toLowerCase());
2604
+ (0, chai_config_spec_1.expect)((program.setFile('source/main2.d.bs', '')).typedefKey).to.equal(undefined);
2605
+ (0, chai_config_spec_1.expect)((program.setFile('source/main3.bs', '')).typedefKey).to.equal(undefined);
2805
2606
  //works for dest with `.brs` extension
2806
- (0, chai_1.expect)((program.setFile({ src: 'source/main4.bs', dest: 'source/main4.brs' }, '')).typedefSrcPath).to.equal(undefined);
2607
+ (0, chai_config_spec_1.expect)((program.setFile({ src: 'source/main4.bs', dest: 'source/main4.brs' }, '')).typedefKey).to.equal(undefined);
2807
2608
  });
2808
2609
  it('does not link when missing from program', () => {
2809
2610
  const file = program.setFile('source/main.brs', ``);
2810
- (0, chai_1.expect)(file.typedefFile).not.to.exist;
2611
+ (0, chai_config_spec_1.expect)(file.typedefFile).not.to.exist;
2811
2612
  });
2812
2613
  it('links typedef when added BEFORE .brs file', () => {
2813
2614
  const typedef = program.setFile('source/main.d.bs', ``);
2814
2615
  const file = program.setFile('source/main.brs', ``);
2815
- (0, chai_1.expect)(file.typedefFile).to.equal(typedef);
2616
+ (0, chai_config_spec_1.expect)(file.typedefFile).to.equal(typedef);
2816
2617
  });
2817
2618
  it('links typedef when added AFTER .brs file', () => {
2818
2619
  const file = program.setFile('source/main.brs', ``);
2819
2620
  const typedef = program.setFile('source/main.d.bs', ``);
2820
- (0, chai_1.expect)(file.typedefFile).to.eql(typedef);
2621
+ (0, chai_config_spec_1.expect)(file.typedefFile).to.eql(typedef);
2821
2622
  });
2822
2623
  it('removes typedef link when typedef is removed', () => {
2823
2624
  const typedef = program.setFile('source/main.d.bs', ``);
2824
2625
  const file = program.setFile('source/main.brs', ``);
2825
2626
  program.removeFile(typedef.srcPath);
2826
- (0, chai_1.expect)(file.typedefFile).to.be.undefined;
2627
+ (0, chai_config_spec_1.expect)(file.typedefFile).to.be.undefined;
2827
2628
  });
2828
2629
  });
2829
2630
  describe('getTypedef', () => {
2830
2631
  function testTypedef(original, expected) {
2831
2632
  let file = program.setFile('source/main.brs', original);
2832
- (0, chai_1.expect)(file.getTypedef().trimEnd()).to.eql(expected);
2633
+ program.validate();
2634
+ (0, chai_config_spec_1.expect)(file.getTypedef().trimEnd()).to.eql(expected);
2833
2635
  }
2834
2636
  it('includes namespace on extend class names', () => {
2835
2637
  testTypedef(`
@@ -3118,9 +2920,9 @@ describe('BrsFile', () => {
3118
2920
  file['_parser'] = undefined;
3119
2921
  //force the file to get a new instance of parser
3120
2922
  const newParser = file.parser;
3121
- (0, chai_1.expect)(newParser).to.exist.and.to.not.equal(parser);
2923
+ (0, chai_config_spec_1.expect)(newParser).to.exist.and.to.not.equal(parser);
3122
2924
  //reference shouldn't change in subsequent accesses
3123
- (0, chai_1.expect)(file.parser).to.equal(newParser);
2925
+ (0, chai_config_spec_1.expect)(file.parser).to.equal(newParser);
3124
2926
  });
3125
2927
  it('call parse when previously skipped', () => {
3126
2928
  program.setFile('source/main.d.bs', `'typedef
@@ -3132,11 +2934,11 @@ describe('BrsFile', () => {
3132
2934
  end sub
3133
2935
  `);
3134
2936
  //no functions should be found since the parser was skipped
3135
- (0, chai_1.expect)(file['_parser']).to.not.exist;
2937
+ (0, chai_config_spec_1.expect)(file['_parser']).to.not.exist;
3136
2938
  const stub = sinon.stub(file, 'parse').callThrough();
3137
2939
  //`file.parser` is a getter, so that should force the parse to occur
3138
- (0, chai_1.expect)(file.parser.references.functionStatements).to.be.lengthOf(1);
3139
- (0, chai_1.expect)(stub.called).to.be.true;
2940
+ (0, chai_config_spec_1.expect)(file.parser.ast).to.exist;
2941
+ (0, chai_config_spec_1.expect)(stub.called).to.be.true;
3140
2942
  //parse should have been called
3141
2943
  });
3142
2944
  });
@@ -3145,12 +2947,12 @@ describe('BrsFile', () => {
3145
2947
  let idx = 1;
3146
2948
  beforeEach(() => {
3147
2949
  pluginFileName = `plugin-${idx++}.js`;
3148
- fsExtra.outputFileSync((0, util_1.standardizePath) `${tempDir}/plugins/${pluginFileName}`, `
2950
+ fsExtra.outputFileSync((0, util_1.standardizePath) `${testHelpers_spec_2.tempDir}/plugins/${pluginFileName}`, `
3149
2951
  function plugin() {
3150
2952
  return {
3151
2953
  name: 'lower-file-name',
3152
- afterFileParse: (evt) => {
3153
- evt.file._customProp = true;
2954
+ afterProvideFile: (evt) => {
2955
+ evt.files[0]._customProp = true;
3154
2956
  }
3155
2957
  };
3156
2958
  }
@@ -3158,251 +2960,999 @@ describe('BrsFile', () => {
3158
2960
  `);
3159
2961
  });
3160
2962
  it('can load an absolute plugin which receives callbacks', () => {
3161
- program.plugins = new PluginInterface_1.default(util_1.default.loadPlugins(tempDir, [
3162
- (0, util_1.standardizePath) `${tempDir}/plugins/${pluginFileName}`
3163
- ]), new Logger_1.Logger());
2963
+ for (const plugin of util_1.default.loadPlugins(testHelpers_spec_2.tempDir, [(0, util_1.standardizePath) `${testHelpers_spec_2.tempDir}/plugins/${pluginFileName}`])) {
2964
+ program.plugins.add(plugin);
2965
+ }
3164
2966
  const file = program.setFile('source/MAIN.brs', '');
3165
- (0, chai_1.expect)(file._customProp).to.exist;
2967
+ (0, chai_config_spec_1.expect)(file._customProp).to.exist;
3166
2968
  });
3167
2969
  it('can load a relative plugin which receives callbacks', () => {
3168
- program.plugins = new PluginInterface_1.default(util_1.default.loadPlugins(tempDir, [
3169
- `./plugins/${pluginFileName}`
3170
- ]), new Logger_1.Logger());
2970
+ for (const plugin of util_1.default.loadPlugins(testHelpers_spec_2.tempDir, [`./plugins/${pluginFileName}`])) {
2971
+ program.plugins.add(plugin);
2972
+ }
3171
2973
  const file = program.setFile('source/MAIN.brs', '');
3172
- (0, chai_1.expect)(file._customProp).to.exist;
2974
+ (0, chai_config_spec_1.expect)(file._customProp).to.exist;
3173
2975
  });
3174
2976
  });
3175
- describe('getSymbolTypeFromToken', () => {
3176
- function checkSymbolLookups(file, funcExpr, lookups) {
3177
- const mainScope = program.getScopesForFile(file)[0];
3178
- mainScope.linkSymbolTable();
3179
- for (const lookup of lookups) {
3180
- const position = vscode_languageserver_1.Position.create(lookup.line, lookup.col);
3181
- const token = file.parser.getTokenAt(position);
3182
- const symbol = file.getSymbolTypeFromToken(token, funcExpr, mainScope);
3183
- const context = {
3184
- file: file,
3185
- scope: mainScope,
3186
- position: position
3187
- };
3188
- (0, chai_1.expect)(symbol.expandedTokenText).to.equal(lookup.name);
3189
- (0, chai_1.expect)(symbol.type.equals(lookup.type, context)).be.true;
3190
- }
3191
- }
3192
- it('gets simple types based on the containing function expression', () => {
2977
+ describe('getDefinition', () => {
2978
+ it('returns const locations', () => {
3193
2979
  const file = program.setFile('source/main.bs', `
3194
- sub doSomething(aInt as integer, aFloat as float, aStr as string, aBool as boolean, aObj as object)
3195
- print aInt
3196
- print aFloat
3197
- print aStr
3198
- print aBool
3199
- print aObj
3200
- end sub
3201
- `);
3202
- const funcExpr = file.parser.references.functionExpressions[0];
3203
- const lookups = [
3204
- { line: 2, col: 28, name: 'aInt', type: new IntegerType_1.IntegerType() },
3205
- { line: 3, col: 28, name: 'aFloat', type: new FloatType_1.FloatType() },
3206
- { line: 4, col: 28, name: 'aStr', type: new StringType_1.StringType() },
3207
- { line: 5, col: 28, name: 'aBool', type: new BooleanType_1.BooleanType() },
3208
- { line: 6, col: 28, name: 'aObj', type: new ObjectType_1.ObjectType() }
3209
- ];
3210
- checkSymbolLookups(file, funcExpr, lookups);
3211
- (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2980
+ sub main()
2981
+ print alpha.beta.charlie
2982
+ end sub
2983
+ namespace alpha.beta
2984
+ const CHARLIE = true
2985
+ end namespace
2986
+ `);
2987
+ program.validate();
2988
+ //print alpha.beta.char|lie
2989
+ (0, chai_config_spec_1.expect)(program.getDefinition(file.srcPath, vscode_languageserver_1.Position.create(2, 41))).to.eql([{
2990
+ uri: vscode_uri_1.URI.file(file.srcPath).toString(),
2991
+ range: util_1.default.createRange(5, 26, 5, 33)
2992
+ }]);
3212
2993
  });
3213
- it('gets custom types based on the containing function expression', () => {
2994
+ it('returns enum locations', () => {
3214
2995
  const file = program.setFile('source/main.bs', `
3215
- sub doSomething(klass as MyKlass)
3216
- print klass
2996
+ sub main()
2997
+ print alpha.beta.people.charlie
3217
2998
  end sub
3218
-
3219
- class MyKlass
3220
- end class
2999
+ namespace alpha.beta
3000
+ enum people
3001
+ charlie = "charles"
3002
+ end enum
3003
+ end namespace
3221
3004
  `);
3222
- const mainScope = program.getScopesForFile(file)[0];
3223
- mainScope.linkSymbolTable();
3224
- const funcExpr = file.parser.references.functionExpressions[0];
3225
- const token = file.parser.getTokenAt(vscode_languageserver_1.Position.create(2, 28));
3226
- const symbol = file.getSymbolTypeFromToken(token, funcExpr, mainScope);
3227
- (0, chai_1.expect)(symbol.expandedTokenText).to.equal('klass');
3228
- const classStmt = file.parser.references.classStatements[0];
3229
- (0, chai_1.expect)(classStmt.name.text).to.equal('MyKlass');
3230
- (0, chai_1.expect)(symbol.type.isAssignableTo(classStmt.getThisBscType())).be.true;
3231
- (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
3005
+ program.validate();
3006
+ //print alpha.beta.char|lie
3007
+ (0, chai_config_spec_1.expect)(program.getDefinition(file.srcPath, vscode_languageserver_1.Position.create(2, 40))).to.eql([{
3008
+ uri: vscode_uri_1.URI.file(file.srcPath).toString(),
3009
+ range: util_1.default.createRange(5, 25, 5, 31)
3010
+ }]);
3232
3011
  });
3233
- it('gets types of properties of a klass', () => {
3012
+ it('returns interface location', () => {
3234
3013
  const file = program.setFile('source/main.bs', `
3235
- sub doSomething()
3236
- klass = new MyKlass()
3237
- print klass.name
3238
- print klass.age
3239
- ' verify case insensitivity
3240
- print KLASS.NAME
3241
- print klass.AGE
3014
+ sub test(selectedMovie as Movie)
3015
+ print selectedMovie
3242
3016
  end sub
3243
-
3244
- class MyKlass
3245
- name as string
3246
- age as integer
3017
+ interface Movie
3018
+ url as string
3019
+ end interface
3020
+ `);
3021
+ program.validate();
3022
+ // sub test(selectedMovie as Mo|vie)
3023
+ (0, chai_config_spec_1.expect)(program.getDefinition(file.srcPath, vscode_languageserver_1.Position.create(1, 44))).to.eql([{
3024
+ uri: vscode_uri_1.URI.file(file.srcPath).toString(),
3025
+ range: util_1.default.createRange(4, 26, 4, 31)
3026
+ }]);
3027
+ });
3028
+ it('returns namespaced interface location', () => {
3029
+ const file = program.setFile('source/main.bs', `
3030
+ sub test(selectedMovie as interfaces.Movie)
3031
+ print selectedMovie
3032
+ end sub
3033
+ namespace interfaces
3034
+ interface Movie
3035
+ url as string
3036
+ end interface
3037
+ end namespace
3038
+ `);
3039
+ program.validate();
3040
+ //sub test(selectedMovie as interfaces.Mo|vie)
3041
+ (0, chai_config_spec_1.expect)(program.getDefinition(file.srcPath, vscode_languageserver_1.Position.create(1, 55))).to.eql([{
3042
+ uri: vscode_uri_1.URI.file(file.srcPath).toString(),
3043
+ range: util_1.default.createRange(5, 30, 5, 35)
3044
+ }]);
3045
+ });
3046
+ it('returns class location', () => {
3047
+ const file = program.setFile('source/main.bs', `
3048
+ sub test(selectedMovie as Movie)
3049
+ print selectedMovie
3050
+ end sub
3051
+ class Movie
3052
+ url as string
3247
3053
  end class
3248
3054
  `);
3249
- const funcExpr = file.parser.references.functionExpressions[0];
3250
- const lookups = [
3251
- { line: 3, col: 35, name: 'MyKlass.name', type: new StringType_1.StringType() },
3252
- { line: 4, col: 35, name: 'MyKlass.age', type: new IntegerType_1.IntegerType() }
3253
- ];
3254
- checkSymbolLookups(file, funcExpr, lookups);
3255
- (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
3055
+ program.validate();
3056
+ //sub test(selectedMovie as Mo|vie)
3057
+ (0, chai_config_spec_1.expect)(program.getDefinition(file.srcPath, vscode_languageserver_1.Position.create(1, 44))).to.eql([{
3058
+ uri: vscode_uri_1.URI.file(file.srcPath).toString(),
3059
+ range: util_1.default.createRange(4, 22, 4, 27)
3060
+ }]);
3256
3061
  });
3257
- it('gets types of properties of an object', () => {
3062
+ it('returns namespaced class location', () => {
3258
3063
  const file = program.setFile('source/main.bs', `
3259
- sub doSomething()
3260
- obj = { name: "Joe", age: 37}
3261
- print obj.name
3262
- print obj.age
3064
+ sub test(selectedMovie as classes.Movie)
3065
+ print selectedMovie
3263
3066
  end sub
3067
+ namespace classes
3068
+ class Movie
3069
+ url as string
3070
+ end class
3071
+ end namespace
3264
3072
  `);
3265
- const funcExpr = file.parser.references.functionExpressions[0];
3266
- const lookups = [
3267
- { line: 3, col: 32, name: 'obj.name', type: new StringType_1.StringType() },
3268
- { line: 4, col: 32, name: 'obj.age', type: new IntegerType_1.IntegerType() }
3269
- ];
3270
- checkSymbolLookups(file, funcExpr, lookups);
3271
- (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
3073
+ program.validate();
3074
+ //sub test(selectedMovie as classes.Mo|vie)
3075
+ (0, chai_config_spec_1.expect)(program.getDefinition(file.srcPath, vscode_languageserver_1.Position.create(1, 52))).to.eql([{
3076
+ uri: vscode_uri_1.URI.file(file.srcPath).toString(),
3077
+ range: util_1.default.createRange(5, 26, 5, 31)
3078
+ }]);
3272
3079
  });
3273
- it('gets return types of functions', () => {
3080
+ it('does not crash on nulls', () => {
3274
3081
  const file = program.setFile('source/main.bs', `
3275
- sub doSomething()
3276
- pi = makeKlass().getSelf().getPi()
3277
- print pi
3082
+ sub main()
3083
+ print alpha.beta
3278
3084
  end sub
3279
-
3280
- function makeKlass() as MyKlass
3281
- return new MyKlass()
3085
+ `);
3086
+ program.validate();
3087
+ sinon.stub(util_1.default, 'getAllDottedGetParts').returns(null);
3088
+ // print alpha.be|ta
3089
+ (0, chai_config_spec_1.expect)(program.getDefinition(file.srcPath, vscode_languageserver_1.Position.create(2, 34))).to.eql([]);
3090
+ });
3091
+ it('returns enum member locations', () => {
3092
+ const file = program.setFile('source/main.bs', `
3093
+ sub main()
3094
+ print alpha.beta.people.charlie
3095
+ end sub
3096
+ namespace alpha.beta
3097
+ enum people
3098
+ charlie = "charles"
3099
+ end enum
3100
+ end namespace
3101
+ `);
3102
+ program.validate();
3103
+ //print alpha.beta.char|lie
3104
+ (0, chai_config_spec_1.expect)(program.getDefinition(file.srcPath, vscode_languageserver_1.Position.create(2, 48))).to.eql([{
3105
+ uri: vscode_uri_1.URI.file(file.srcPath).toString(),
3106
+ range: util_1.default.createRange(6, 24, 6, 31)
3107
+ }]);
3108
+ });
3109
+ });
3110
+ it('catches mismatched `end` keywords for functions', () => {
3111
+ program.setFile('source/main.brs', `
3112
+ function speak()
3113
+ end sub
3114
+ sub walk()
3115
+ end function
3116
+ `);
3117
+ program.validate();
3118
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.mismatchedEndCallableKeyword('function', 'sub')), { range: util_1.default.createRange(2, 12, 2, 19) }), Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.mismatchedEndCallableKeyword('sub', 'function')), { range: util_1.default.createRange(4, 12, 4, 24) })]);
3119
+ });
3120
+ describe('requiredSymbols', () => {
3121
+ it('should be empty for a simple file', () => {
3122
+ const mainFile = program.setFile('source/main.bs', `
3123
+ function someFunc() as integer
3124
+ return 1
3125
+ end function
3126
+ `);
3127
+ const validateFileEvent = {
3128
+ program: program,
3129
+ file: mainFile
3130
+ };
3131
+ program.plugins.emit('onFileValidate', validateFileEvent);
3132
+ (0, chai_config_spec_1.expect)(mainFile.requiredSymbols.length).to.eq(0);
3133
+ });
3134
+ it('should be empty if the file needs no external symbols', () => {
3135
+ const mainFile = program.setFile('source/main.bs', `
3136
+ function someFunc() as integer
3137
+ return 1
3282
3138
  end function
3283
3139
 
3284
- class MyKlass
3285
- function getPi() as float
3286
- return 3.14
3287
- end function
3140
+ sub useKlass()
3141
+ k = new Klass()
3142
+ k.addTwo()
3143
+ end sub
3144
+
3145
+ class Klass
3146
+ sub addTwo()
3147
+ print someFunc() + someFunc()
3148
+ end sub
3149
+ end class
3150
+ `);
3151
+ const validateFileEvent = {
3152
+ program: program,
3153
+ file: mainFile
3154
+ };
3155
+ program.plugins.emit('onFileValidate', validateFileEvent);
3156
+ (0, chai_config_spec_1.expect)(mainFile.requiredSymbols.length).to.eq(0);
3157
+ });
3158
+ it('should not include global callables or types', () => {
3159
+ const mainFile = program.setFile('source/main.bs', `
3160
+ function printLower(s as string) as integer
3161
+ print lcase(s.trim())
3162
+ end function
3288
3163
 
3289
- function getSelf() as MyKlass
3290
- return m
3164
+ sub setLabelText( label as roSGNodeLabel, text as string)
3165
+ label.text = text
3166
+ end sub
3167
+ `);
3168
+ const validateFileEvent = {
3169
+ program: program,
3170
+ file: mainFile
3171
+ };
3172
+ program.plugins.emit('onFileValidate', validateFileEvent);
3173
+ (0, chai_config_spec_1.expect)(mainFile.requiredSymbols.length).to.eq(0);
3174
+ });
3175
+ it('should include unknown param and return types', () => {
3176
+ const mainFile = program.setFile('source/main.bs', `
3177
+ function someFunc(arg as OneType) as TwoType
3178
+ return arg.getTwo()
3179
+ end function
3180
+ `);
3181
+ const validateFileEvent = {
3182
+ program: program,
3183
+ file: mainFile
3184
+ };
3185
+ program.plugins.emit('onFileValidate', validateFileEvent);
3186
+ (0, chai_config_spec_1.expect)(mainFile.requiredSymbols.length).to.eq(2);
3187
+ (0, chai_config_spec_1.expect)(mainFile.requiredSymbols.map(x => x.typeChain[0].name)).to.have.same.members([
3188
+ 'TwoType', 'OneType'
3189
+ ]);
3190
+ });
3191
+ it('should include unknown param and return types on class methods', () => {
3192
+ const mainFile = program.setFile('source/main.bs', `
3193
+ class Klass
3194
+ function someFunc(arg as OneType) as TwoType
3195
+ return arg.getTwo()
3291
3196
  end function
3292
3197
  end class
3293
3198
  `);
3294
- const mainScope = program.getScopesForFile(file)[0];
3295
- mainScope.linkSymbolTable();
3296
- const funcExpr = file.parser.references.functionExpressions[0];
3297
- const klassMemberTable = file.parser.references.classStatements[0].memberTable;
3298
- const lookups = [
3299
- { line: 2, col: 31, name: 'makeKlass', type: file.parser.references.functionExpressions[1].getFunctionType() },
3300
- // The expanded text for this should probably be MyKlass.getSelf()
3301
- { line: 2, col: 41, name: 'MyKlass.MyKlass', type: klassMemberTable.getSymbol('getSelf')[0].type },
3302
- { line: 2, col: 51, name: 'MyKlass.getPi', type: klassMemberTable.getSymbol('getPi')[0].type },
3303
- { line: 3, col: 28, name: 'pi', type: new FloatType_1.FloatType() }
3304
- ];
3305
- checkSymbolLookups(file, funcExpr, lookups);
3306
- (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
3199
+ const validateFileEvent = {
3200
+ program: program,
3201
+ file: mainFile
3202
+ };
3203
+ program.plugins.emit('onFileValidate', validateFileEvent);
3204
+ (0, chai_config_spec_1.expect)(mainFile.requiredSymbols.length).to.eq(2);
3205
+ (0, chai_config_spec_1.expect)(mainFile.requiredSymbols.map(x => x.typeChain[0].name)).to.have.same.members([
3206
+ 'TwoType', 'OneType'
3207
+ ]);
3307
3208
  });
3308
- it('gets types of elements of arrays', () => {
3309
- const file = program.setFile('source/main.bs', `
3310
- sub doSomething(words as string[], klasses as MyKlass[])
3311
- myWord = words[0]
3312
- pi = klasses[0].getPi()
3313
- print myWord
3314
- print pi
3209
+ it('should not include assigned symbols', () => {
3210
+ const mainFile = program.setFile('source/main.bs', `
3211
+ sub someFunc(arg as SomeOtherType)
3212
+ x = arg.member
3213
+ print x+1
3214
+ end sub
3215
+ `);
3216
+ const validateFileEvent = {
3217
+ program: program,
3218
+ file: mainFile
3219
+ };
3220
+ program.plugins.emit('onFileValidate', validateFileEvent);
3221
+ (0, chai_config_spec_1.expect)(mainFile.requiredSymbols.length).to.eq(1);
3222
+ // x and arg are assigned.. they are not included in the required symbols
3223
+ (0, chai_config_spec_1.expect)(mainFile.requiredSymbols[0].typeChain[0].name).to.equal('SomeOtherType');
3224
+ });
3225
+ it('should include functions called that are not in the file', () => {
3226
+ const mainFile = program.setFile('source/main.bs', `
3227
+ sub someFunc()
3228
+ x = otherFileFunc1()
3229
+ print x+1
3230
+ end sub
3231
+
3232
+ function deepFunctionCall(i as integer)
3233
+ x = 2*i and otherFileFunc2()
3234
+ y = sin(x+fix(78.2)*log(otherFileFunc3()))
3235
+ ' this is a comment otherFileFunc5()
3236
+ return y-otherFileFunc4()
3237
+ end function
3238
+ `);
3239
+ const validateFileEvent = {
3240
+ program: program,
3241
+ file: mainFile
3242
+ };
3243
+ program.plugins.emit('onFileValidate', validateFileEvent);
3244
+ (0, chai_config_spec_1.expect)(mainFile.requiredSymbols.length).to.eq(4);
3245
+ (0, chai_config_spec_1.expect)(mainFile.requiredSymbols.map(x => x.typeChain[0].name)).to.have.same.members([
3246
+ 'otherFileFunc1', 'otherFileFunc2', 'otherFileFunc3', 'otherFileFunc4'
3247
+ ]);
3248
+ });
3249
+ it('should include classes called that are not in the file', () => {
3250
+ const mainFile = program.setFile('source/main.bs', `
3251
+ function someFunc(other as OtherKlass) as NS1.Thing
3252
+ x = new AnotherClass()
3253
+ return other.getThing(x)
3254
+ end function
3255
+ `);
3256
+ const validateFileEvent = {
3257
+ program: program,
3258
+ file: mainFile
3259
+ };
3260
+ program.plugins.emit('onFileValidate', validateFileEvent);
3261
+ (0, chai_config_spec_1.expect)(mainFile.requiredSymbols.length).to.eq(3);
3262
+ const requiredTypeChains = mainFile.requiredSymbols.map(x => x.typeChain.map(tc => tc.name).join('.'));
3263
+ (0, chai_config_spec_1.expect)(requiredTypeChains).to.have.same.members([
3264
+ 'OtherKlass', 'NS1.Thing', 'AnotherClass'
3265
+ ]);
3266
+ const requiredSymbolsFlags = mainFile.requiredSymbols.map(x => x.flags);
3267
+ (0, chai_config_spec_1.expect)(requiredSymbolsFlags).to.have.same.members([
3268
+ SymbolTable_1.SymbolTypeFlag.typetime, SymbolTable_1.SymbolTypeFlag.typetime, SymbolTable_1.SymbolTypeFlag.runtime
3269
+ ]);
3270
+ });
3271
+ it('should include enums and consts that are not in the file', () => {
3272
+ const mainFile = program.setFile('source/main.bs', `
3273
+ sub someFunc(myEnum as SomeEnum)
3274
+ if myEnum = SomeEnum.value1
3275
+ print 1
3276
+ else if myEnum = SomeEnum.value2
3277
+ print 2
3278
+ else if myEnum = SomeConstValue
3279
+ print 3
3280
+ end if
3315
3281
  end sub
3282
+ `);
3283
+ const validateFileEvent = {
3284
+ program: program,
3285
+ file: mainFile
3286
+ };
3287
+ program.plugins.emit('onFileValidate', validateFileEvent);
3288
+ (0, chai_config_spec_1.expect)(mainFile.requiredSymbols.length).to.eq(4);
3289
+ const requiredTypeChains = mainFile.requiredSymbols.map(x => x.typeChain.map(tc => tc.name).join('.'));
3290
+ (0, chai_config_spec_1.expect)(requiredTypeChains).to.have.same.members([
3291
+ 'SomeEnum', 'SomeEnum.value1', 'SomeEnum.value2', 'SomeConstValue'
3292
+ ]);
3293
+ const requiredSymbolsFlags = mainFile.requiredSymbols.map(x => x.flags);
3294
+ (0, chai_config_spec_1.expect)(requiredSymbolsFlags).to.have.same.members([
3295
+ SymbolTable_1.SymbolTypeFlag.typetime, SymbolTable_1.SymbolTypeFlag.runtime, SymbolTable_1.SymbolTypeFlag.runtime, SymbolTable_1.SymbolTypeFlag.runtime
3296
+ ]);
3297
+ });
3298
+ it('should include types not defined in the file', () => {
3299
+ const mainFile = program.setFile('source/main.bs', `
3300
+ interface Data
3301
+ kind as DataKind
3302
+ getObj as DataObject
3303
+ subData as SubData
3304
+ end interface
3316
3305
 
3317
- class MyKlass
3318
- function getPi() as float
3319
- return 3.14
3306
+ class DataObject extends BaseData
3307
+ kind as DataKind
3308
+ function process(dataProcess as DataProcessor) as ProcessedData
3309
+ return dataProcess.work(m)
3320
3310
  end function
3321
3311
  end class
3322
3312
  `);
3323
- const mainScope = program.getScopesForFile(file)[0];
3324
- mainScope.linkSymbolTable();
3325
- const funcExpr = file.parser.references.functionExpressions[0];
3326
- const klassMemberTable = file.parser.references.classStatements[0].memberTable;
3327
- const lookups = [
3328
- { line: 2, col: 34, name: 'words', type: new ArrayType_1.ArrayType(new StringType_1.StringType()) },
3329
- { line: 3, col: 41, name: 'MyKlass.getPi', type: klassMemberTable.getSymbol('getPi')[0].type },
3330
- { line: 4, col: 28, name: 'myWord', type: new StringType_1.StringType() },
3331
- { line: 5, col: 28, name: 'pi', type: new FloatType_1.FloatType() }
3332
- ];
3333
- checkSymbolLookups(file, funcExpr, lookups);
3334
- (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
3313
+ const validateFileEvent = {
3314
+ program: program,
3315
+ file: mainFile
3316
+ };
3317
+ program.plugins.emit('onFileValidate', validateFileEvent);
3318
+ (0, chai_config_spec_1.expect)(mainFile.requiredSymbols.length).to.eq(5);
3319
+ const requiredTypeChains = mainFile.requiredSymbols.map(x => x.typeChain.map(tc => tc.name).join('.'));
3320
+ (0, chai_config_spec_1.expect)(requiredTypeChains).to.have.same.members([
3321
+ 'DataKind', 'SubData', 'BaseData', 'DataProcessor', 'ProcessedData'
3322
+ ]);
3323
+ const requiredSymbolsFlags = mainFile.requiredSymbols.map(x => x.flags);
3324
+ (0, chai_config_spec_1.expect)(requiredSymbolsFlags).to.have.same.members([
3325
+ SymbolTable_1.SymbolTypeFlag.typetime, SymbolTable_1.SymbolTypeFlag.typetime, SymbolTable_1.SymbolTypeFlag.typetime, SymbolTable_1.SymbolTypeFlag.typetime, SymbolTable_1.SymbolTypeFlag.typetime
3326
+ ]);
3335
3327
  });
3336
- it('gets types of elements of arrays via square bracket reference', () => {
3337
- const file = program.setFile('source/main.bs', `
3338
- function printFirst(numbers as float[]) as float
3339
- firstFloat = numbers[0]
3340
- print firstFloat
3341
- return firstFloat
3342
- end function
3328
+ it('includes namespace details', () => {
3329
+ const mainFile = program.setFile('source/main.bs', `
3330
+ namespace Alpha.Beta
3331
+ sub printConstVal()
3332
+ print CONST_VALUE
3333
+ end sub
3334
+ end namespace
3335
+
3336
+ namespace Delta
3337
+ namespace Gamma
3338
+ namespace Eta
3339
+ sub doStuff(x as OtherType)
3340
+ x.something()
3341
+ end sub
3342
+ end namespace
3343
+ end namespace
3344
+ end namespace
3343
3345
  `);
3344
- const mainScope = program.getScopesForFile(file)[0];
3345
- mainScope.linkSymbolTable();
3346
- const funcExpr = file.parser.references.functionExpressions[0];
3347
- const lookups = [
3348
- { line: 2, col: 26, name: 'firstFloat', type: new FloatType_1.FloatType() },
3349
- { line: 3, col: 32, name: 'firstFloat', type: new FloatType_1.FloatType() }
3350
- ];
3351
- checkSymbolLookups(file, funcExpr, lookups);
3352
- (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
3346
+ const validateFileEvent = {
3347
+ program: program,
3348
+ file: mainFile
3349
+ };
3350
+ program.plugins.emit('onFileValidate', validateFileEvent);
3351
+ (0, chai_config_spec_1.expect)(mainFile.requiredSymbols.length).to.eq(2);
3352
+ const requiredTypeChains = mainFile.requiredSymbols.map(x => x.typeChain.map(tc => tc.name).join('.'));
3353
+ (0, chai_config_spec_1.expect)(requiredTypeChains).to.have.same.members([
3354
+ 'CONST_VALUE', 'OtherType'
3355
+ ]);
3356
+ (0, chai_config_spec_1.expect)(mainFile.requiredSymbols[0].containingNamespaces).to.have.same.members(['Alpha', 'Beta']);
3357
+ (0, chai_config_spec_1.expect)(mainFile.requiredSymbols[1].containingNamespaces).to.have.same.members(['Delta', 'Gamma', 'Eta']);
3353
3358
  });
3354
- it('gets types of elements of arrays after for each', () => {
3355
- const file = program.setFile('source/main.bs', `
3356
- function printAllReturnFirst(numbers as float[]) as float
3357
- for each num in numbers
3358
- print num
3359
- end for
3359
+ it('does not include namespaces that are defined in the file', () => {
3360
+ const mainFile = program.setFile('source/main.bs', `
3361
+ namespace name1
3362
+ const PI = 3.14
3360
3363
 
3361
- firstFloat = numbers[0]
3362
- print firstFloat
3363
- return firstFloat
3364
+ namespace name2
3365
+ function getPi() as float
3366
+ return name1.PI
3367
+ end function
3368
+ end namespace
3369
+ end namespace
3370
+ `);
3371
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3372
+ (0, chai_config_spec_1.expect)(mainFile.requiredSymbols.length).to.eq(0);
3373
+ });
3374
+ it('should put types from typecasts as typetime required', () => {
3375
+ const mainFile = program.setFile('source/main.bs', `
3376
+ function takesIface(z) as string
3377
+ return (z as MyInterface).name
3364
3378
  end function
3365
3379
  `);
3366
- const mainScope = program.getScopesForFile(file)[0];
3367
- mainScope.linkSymbolTable();
3368
- const funcExpr = file.parser.references.functionExpressions[0];
3369
- const lookups = [
3370
- { line: 6, col: 26, name: 'firstFloat', type: new FloatType_1.FloatType() },
3371
- { line: 7, col: 32, name: 'firstFloat', type: new FloatType_1.FloatType() }
3372
- ];
3373
- checkSymbolLookups(file, funcExpr, lookups);
3374
- (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
3380
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3381
+ (0, chai_config_spec_1.expect)(mainFile.requiredSymbols.length).to.eq(1);
3382
+ (0, chai_config_spec_1.expect)(mainFile.requiredSymbols[0].flags).to.eq(SymbolTable_1.SymbolTypeFlag.typetime);
3375
3383
  });
3376
3384
  });
3377
- it('defaults to `dynamic` type for a complex expression', () => {
3378
- const file = program.setFile('source/main.brs', `
3379
- sub main()
3380
- name = "cat"
3381
- thing = m["key"](true)
3382
- end sub
3383
- `);
3384
- program.validate();
3385
- const symbolTable = file.parser.references.functionExpressions[0].symbolTable;
3386
- //sanity check
3387
- (0, chai_1.expect)(symbolTable.getSymbolType('name')).be.instanceof(StringType_1.StringType);
3388
- //this complex expression should resolve to dynamic type when not known
3389
- (0, chai_1.expect)(symbolTable.getSymbolType('thing')).be.instanceof(DynamicType_1.DynamicType);
3390
- });
3391
- describe('getDefinition', () => {
3392
- it('returns const locations', () => {
3393
- const file = program.setFile('source/main.bs', `
3394
- sub main()
3395
- print alpha.beta.charlie
3396
- end sub
3397
- namespace alpha.beta
3398
- const CHARLIE = true
3385
+ describe('providedSymbols', () => {
3386
+ it('includes functions defined in the file', () => {
3387
+ const mainFile = program.setFile('source/main.bs', `
3388
+ function someFunc() as integer
3389
+ return 1
3390
+ end function
3391
+
3392
+ function someFunc2() as float
3393
+ return 2.3
3394
+ end function
3395
+ `);
3396
+ const validateFileEvent = {
3397
+ program: program,
3398
+ file: mainFile
3399
+ };
3400
+ program.plugins.emit('onFileValidate', validateFileEvent);
3401
+ const runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3402
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(2);
3403
+ const someFuncType = runtimeSymbols.get('somefunc').type;
3404
+ (0, testHelpers_spec_1.expectTypeToBe)(someFuncType, TypedFunctionType_1.TypedFunctionType);
3405
+ const someFunc2Type = runtimeSymbols.get('somefunc2').type;
3406
+ (0, testHelpers_spec_1.expectTypeToBe)(someFunc2Type, TypedFunctionType_1.TypedFunctionType);
3407
+ });
3408
+ it('includes functions with unresolved params/return types', () => {
3409
+ const mainFile = program.setFile('source/main.bs', `
3410
+ function someFunc() as OtherFileType
3411
+ return new OtherFileType()
3412
+ end function
3413
+ `);
3414
+ const validateFileEvent = {
3415
+ program: program,
3416
+ file: mainFile
3417
+ };
3418
+ program.plugins.emit('onFileValidate', validateFileEvent);
3419
+ const runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3420
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(1);
3421
+ const someFuncType = runtimeSymbols.get('somefunc').type;
3422
+ (0, testHelpers_spec_1.expectTypeToBe)(someFuncType, TypedFunctionType_1.TypedFunctionType);
3423
+ const requiredSymbols = mainFile.requiredSymbols.map(x => x.typeChain[0].name);
3424
+ (0, chai_config_spec_1.expect)(requiredSymbols).to.have.same.members(['OtherFileType', 'OtherFileType']);
3425
+ const requiredSymbolTypes = mainFile.requiredSymbols.map(x => x.flags);
3426
+ (0, chai_config_spec_1.expect)(requiredSymbolTypes).to.have.same.members([SymbolTable_1.SymbolTypeFlag.runtime, SymbolTable_1.SymbolTypeFlag.typetime]);
3427
+ });
3428
+ it('includes classes defined in the file', () => {
3429
+ const mainFile = program.setFile('source/main.bs', `
3430
+ class Klass
3431
+ name as string
3432
+ end class
3433
+
3434
+ class Klass2 extends Klass
3435
+ age as integer
3436
+
3437
+ function getId() as string
3438
+ return m.name + " " + m.age.toStr()
3439
+ end function
3440
+ end class
3441
+
3442
+ class Klass3
3443
+ propClass = new Klass2()
3444
+ end class
3445
+ `);
3446
+ const validateFileEvent = {
3447
+ program: program,
3448
+ file: mainFile
3449
+ };
3450
+ program.plugins.emit('onFileValidate', validateFileEvent);
3451
+ const runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3452
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(3);
3453
+ (0, testHelpers_spec_1.expectTypeToBe)(runtimeSymbols.get('klass').type, types_1.ClassType);
3454
+ (0, testHelpers_spec_1.expectTypeToBe)(runtimeSymbols.get('klass2').type, types_1.ClassType);
3455
+ (0, testHelpers_spec_1.expectTypeToBe)(runtimeSymbols.get('klass3').type, types_1.ClassType);
3456
+ const typetimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.typetime);
3457
+ (0, chai_config_spec_1.expect)(typetimeSymbols.size).to.eq(3);
3458
+ (0, testHelpers_spec_1.expectTypeToBe)(runtimeSymbols.get('klass').type, types_1.ClassType);
3459
+ (0, testHelpers_spec_1.expectTypeToBe)(runtimeSymbols.get('klass2').type, types_1.ClassType);
3460
+ (0, testHelpers_spec_1.expectTypeToBe)(runtimeSymbols.get('klass3').type, types_1.ClassType);
3461
+ });
3462
+ it('includes other types defined in the file', () => {
3463
+ const mainFile = program.setFile('source/main.bs', `
3464
+ interface MyInterface
3465
+ name as string
3466
+ end interface
3467
+
3468
+ enum MyEnum
3469
+ val1
3470
+ val2
3471
+ end enum
3472
+
3473
+ namespace MyNamespace
3474
+ const MyConst = 3.14
3399
3475
  end namespace
3400
3476
  `);
3401
- //print alpha.beta.char|lie
3402
- (0, chai_1.expect)(program.getDefinition(file.srcPath, vscode_languageserver_1.Position.create(2, 41))).to.eql([{
3403
- uri: vscode_uri_1.URI.file(file.srcPath).toString(),
3404
- range: util_1.default.createRange(5, 26, 5, 33)
3405
- }]);
3477
+ const validateFileEvent = {
3478
+ program: program,
3479
+ file: mainFile
3480
+ };
3481
+ program.plugins.emit('onFileValidate', validateFileEvent);
3482
+ const runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3483
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(2);
3484
+ (0, testHelpers_spec_1.expectTypeToBe)(runtimeSymbols.get('myenum').type, types_1.EnumType);
3485
+ (0, testHelpers_spec_1.expectTypeToBe)(runtimeSymbols.get('mynamespace.myconst').type, types_1.FloatType);
3486
+ const typetimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.typetime);
3487
+ (0, chai_config_spec_1.expect)(typetimeSymbols.size).to.eq(2);
3488
+ (0, testHelpers_spec_1.expectTypeToBe)(typetimeSymbols.get('myinterface').type, types_1.InterfaceType);
3489
+ (0, testHelpers_spec_1.expectTypeToBe)(runtimeSymbols.get('myenum').type, types_1.EnumType);
3490
+ });
3491
+ describe('changes', () => {
3492
+ it('new symbols are added to the changes set', () => {
3493
+ let mainFile = program.setFile('source/main.bs', `
3494
+ sub someFunc()
3495
+ print 1
3496
+ end sub
3497
+ `);
3498
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3499
+ let runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3500
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(1);
3501
+ mainFile = program.setFile('source/main.bs', `
3502
+ sub someFunc()
3503
+ print 1
3504
+ end sub
3505
+
3506
+ sub someFunc2()
3507
+ print 2
3508
+ end sub
3509
+ `);
3510
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3511
+ runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3512
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(2);
3513
+ let runtimeChanges = mainFile.providedSymbols.changes.get(SymbolTable_1.SymbolTypeFlag.runtime);
3514
+ (0, chai_config_spec_1.expect)(runtimeChanges.size).to.eq(1);
3515
+ (0, chai_config_spec_1.expect)(runtimeChanges.has('somefunc2')).to.be.true;
3516
+ });
3517
+ it('removed symbols are added to the changes set', () => {
3518
+ let mainFile = program.setFile('source/main.bs', `
3519
+ sub someFunc()
3520
+ print 1
3521
+ end sub
3522
+
3523
+ sub someFunc2()
3524
+ print 2
3525
+ end sub
3526
+ `);
3527
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3528
+ let runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3529
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(2);
3530
+ mainFile = program.setFile('source/main.bs', `
3531
+ sub someFunc()
3532
+ print 1
3533
+ end sub
3534
+ `);
3535
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3536
+ runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3537
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(1);
3538
+ let runtimeChanges = mainFile.providedSymbols.changes.get(SymbolTable_1.SymbolTypeFlag.runtime);
3539
+ (0, chai_config_spec_1.expect)(runtimeChanges.size).to.eq(1);
3540
+ (0, chai_config_spec_1.expect)(runtimeChanges.has('somefunc2')).to.be.true;
3541
+ });
3542
+ it('new symbols in a namespace are added to the changes set', () => {
3543
+ let mainFile = program.setFile('source/main.bs', `
3544
+ namespace Alpha
3545
+ end namespace
3546
+ `);
3547
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3548
+ let runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3549
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(0);
3550
+ mainFile = program.setFile('source/main.bs', `
3551
+ namespace Alpha
3552
+ const ABC = "abc"
3553
+ end namespace
3554
+ `);
3555
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3556
+ runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3557
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(1);
3558
+ let runtimeChanges = mainFile.providedSymbols.changes.get(SymbolTable_1.SymbolTypeFlag.runtime);
3559
+ (0, chai_config_spec_1.expect)(runtimeChanges.size).to.eq(1);
3560
+ (0, chai_config_spec_1.expect)(runtimeChanges.has('alpha.abc')).to.be.true;
3561
+ });
3562
+ it('should be empty if no changes in actual provided symbols', () => {
3563
+ let mainFile = program.setFile('source/main.bs', `
3564
+ sub printSomething()
3565
+ print "Something"
3566
+ end sub
3567
+
3568
+ namespace alpha.beta
3569
+ const PI = 3.14
3570
+ end namespace
3571
+ `);
3572
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3573
+ let runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3574
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(2);
3575
+ mainFile = program.setFile('source/main.bs', `
3576
+ sub printSomething()
3577
+ print "Something Else"
3578
+ end sub
3579
+
3580
+ namespace alpha.beta
3581
+ const PI = 3.14159
3582
+ end namespace
3583
+ `);
3584
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3585
+ runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3586
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(2);
3587
+ let runtimeChanges = mainFile.providedSymbols.changes.get(SymbolTable_1.SymbolTypeFlag.runtime);
3588
+ (0, chai_config_spec_1.expect)(runtimeChanges.size).to.eq(0);
3589
+ });
3590
+ it('should include changes in function signatures', () => {
3591
+ let mainFile = program.setFile('source/main.bs', `
3592
+ function someFunc(x)
3593
+ return x
3594
+ end function
3595
+ `);
3596
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3597
+ let runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3598
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(1);
3599
+ mainFile = program.setFile('source/main.bs', `
3600
+ function someFunc(x, y)
3601
+ return x+y
3602
+ end function
3603
+ `);
3604
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3605
+ runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3606
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(1);
3607
+ let runtimeChanges = mainFile.providedSymbols.changes.get(SymbolTable_1.SymbolTypeFlag.runtime);
3608
+ (0, chai_config_spec_1.expect)(runtimeChanges.size).to.eq(1);
3609
+ (0, chai_config_spec_1.expect)(runtimeChanges.has('somefunc'));
3610
+ });
3611
+ it('should include changes in classes', () => {
3612
+ let mainFile = program.setFile('source/main.bs', `
3613
+ class MyKlass
3614
+ name as string
3615
+ function getValue() as float
3616
+ return 3.14
3617
+ end function
3618
+ end class
3619
+ `);
3620
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3621
+ let runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3622
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(1);
3623
+ mainFile = program.setFile('source/main.bs', `
3624
+ class MyKlass
3625
+ name as string
3626
+ function getValue() as string
3627
+ return "hello"
3628
+ end function
3629
+ end class
3630
+ `);
3631
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3632
+ runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3633
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(1);
3634
+ let runtimeChanges = mainFile.providedSymbols.changes.get(SymbolTable_1.SymbolTypeFlag.runtime);
3635
+ (0, chai_config_spec_1.expect)(runtimeChanges.size).to.eq(1);
3636
+ (0, chai_config_spec_1.expect)(runtimeChanges.has('myklass'));
3637
+ let typeTimeChanges = mainFile.providedSymbols.changes.get(SymbolTable_1.SymbolTypeFlag.typetime);
3638
+ (0, chai_config_spec_1.expect)(typeTimeChanges.size).to.eq(1);
3639
+ (0, chai_config_spec_1.expect)(typeTimeChanges.has('myklass'));
3640
+ });
3641
+ it('should include changes in interfaces', () => {
3642
+ let mainFile = program.setFile('source/main.bs', `
3643
+ interface Iface1
3644
+ name as string
3645
+ function doStuff() as float
3646
+ end interface
3647
+ `);
3648
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3649
+ let typetimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.typetime);
3650
+ (0, chai_config_spec_1.expect)(typetimeSymbols.size).to.eq(1);
3651
+ let runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3652
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(0);
3653
+ mainFile = program.setFile('source/main.bs', `
3654
+ interface Iface1
3655
+ name as string
3656
+ age as integer
3657
+ function doStuff() as float
3658
+ end interface
3659
+ `);
3660
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3661
+ typetimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.typetime);
3662
+ (0, chai_config_spec_1.expect)(typetimeSymbols.size).to.eq(1);
3663
+ let typeTimeChanges = mainFile.providedSymbols.changes.get(SymbolTable_1.SymbolTypeFlag.typetime);
3664
+ (0, chai_config_spec_1.expect)(typeTimeChanges.size).to.eq(1);
3665
+ (0, chai_config_spec_1.expect)(typeTimeChanges.has('iface1'));
3666
+ let runtimeChanges = mainFile.providedSymbols.changes.get(SymbolTable_1.SymbolTypeFlag.runtime);
3667
+ (0, chai_config_spec_1.expect)(runtimeChanges.size).to.eq(0);
3668
+ });
3669
+ it('should not include changes in enum values, if inner type is the same', () => {
3670
+ let mainFile = program.setFile('source/main.bs', `
3671
+ enum MyEnum
3672
+ north = 4
3673
+ east = 3
3674
+ south = 2
3675
+ west = 1
3676
+ end enum
3677
+ `);
3678
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3679
+ let runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3680
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(1);
3681
+ mainFile = program.setFile('source/main.bs', `
3682
+ enum MyEnum
3683
+ north = 1
3684
+ east = 2
3685
+ south = 3
3686
+ west = 4
3687
+ end enum
3688
+ `);
3689
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3690
+ runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3691
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(1);
3692
+ let runtimeChanges = mainFile.providedSymbols.changes.get(SymbolTable_1.SymbolTypeFlag.runtime);
3693
+ (0, chai_config_spec_1.expect)(runtimeChanges.size).to.eq(0);
3694
+ let typetimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.typetime);
3695
+ (0, chai_config_spec_1.expect)(typetimeSymbols.size).to.eq(1);
3696
+ let typetimeChanges = mainFile.providedSymbols.changes.get(SymbolTable_1.SymbolTypeFlag.typetime);
3697
+ (0, chai_config_spec_1.expect)(typetimeChanges.size).to.eq(0);
3698
+ });
3699
+ it('should include changes in enum, if different number of members', () => {
3700
+ let mainFile = program.setFile('source/main.bs', `
3701
+ enum Direction
3702
+ north = 1
3703
+ east = 2
3704
+ south = 3
3705
+ west = 4
3706
+ end enum
3707
+
3708
+ enum Weather
3709
+ rainy
3710
+ sunny
3711
+ end enum
3712
+
3713
+ enum Colors
3714
+ blue
3715
+ red
3716
+ green
3717
+ purple
3718
+ end enum
3719
+ `);
3720
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3721
+ let runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3722
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(3);
3723
+ mainFile = program.setFile('source/main.bs', `
3724
+ enum Direction ' same
3725
+ north = 1
3726
+ east = 2
3727
+ south = 3
3728
+ west = 4
3729
+ end enum
3730
+
3731
+ enum Weather 'added member
3732
+ rainy
3733
+ sunny
3734
+ snowy
3735
+ end enum
3736
+
3737
+ enum Colors 'removed member
3738
+ blue
3739
+ red
3740
+ green
3741
+ end enum
3742
+ `);
3743
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3744
+ runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3745
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(3);
3746
+ let runtimeChanges = mainFile.providedSymbols.changes.get(SymbolTable_1.SymbolTypeFlag.runtime);
3747
+ (0, chai_config_spec_1.expect)(runtimeChanges.size).to.eq(2);
3748
+ (0, chai_config_spec_1.expect)(runtimeChanges.has('weather'));
3749
+ (0, chai_config_spec_1.expect)(runtimeChanges.has('colors'));
3750
+ });
3751
+ it('should include changes in enum, if different underlying type', () => {
3752
+ let mainFile = program.setFile('source/main.bs', `
3753
+ enum Direction
3754
+ north = 1
3755
+ east = 2
3756
+ south = 3
3757
+ west = 4
3758
+ end enum
3759
+ `);
3760
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3761
+ let runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3762
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(1);
3763
+ mainFile = program.setFile('source/main.bs', `
3764
+ enum Direction ' now is a string
3765
+ north = "N"
3766
+ east = "E"
3767
+ south = "S"
3768
+ west = "W"
3769
+ end enum
3770
+ `);
3771
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3772
+ runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3773
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(1);
3774
+ let runtimeChanges = mainFile.providedSymbols.changes.get(SymbolTable_1.SymbolTypeFlag.runtime);
3775
+ (0, chai_config_spec_1.expect)(runtimeChanges.size).to.eq(1);
3776
+ (0, chai_config_spec_1.expect)(runtimeChanges.has('direction'));
3777
+ });
3778
+ it('should include changes in const, if different underlying type', () => {
3779
+ let mainFile = program.setFile('source/main.bs', `
3780
+ namespace alpha.beta
3781
+ const PI = 3.14
3782
+ end namespace
3783
+ `);
3784
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3785
+ let runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3786
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(1);
3787
+ mainFile = program.setFile('source/main.bs', `
3788
+ namespace alpha.beta
3789
+ const PI = "lemon chiffon"
3790
+ end namespace
3791
+ `);
3792
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3793
+ runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3794
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(1);
3795
+ let runtimeChanges = mainFile.providedSymbols.changes.get(SymbolTable_1.SymbolTypeFlag.runtime);
3796
+ (0, chai_config_spec_1.expect)(runtimeChanges.size).to.eq(1);
3797
+ (0, chai_config_spec_1.expect)(runtimeChanges.has('alpha.beta.pi'));
3798
+ });
3799
+ it('should not include changes inside a function if the param types are known', () => {
3800
+ let mainFile = program.setFile('source/main.bs', `
3801
+ function func1(p as string) as integer
3802
+ return len(p)
3803
+ end function
3804
+
3805
+ sub displayModelTypeInLabel(myLabel as roSgNodeLabel)
3806
+ print myLabel.text
3807
+ di = createObject("roDeviceInfo")' as roDeviceInfo
3808
+ myLabel.text = di.GetFriendlyName()
3809
+ print myLabel.getChildren(0, -1)
3810
+ end sub
3811
+ `);
3812
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3813
+ let runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3814
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(2);
3815
+ mainFile = program.setFile('source/main.bs', `
3816
+ function func1(p as string) as integer
3817
+ return len(p)+1
3818
+ end function
3819
+
3820
+ sub displayModelTypeInLabel(myLabel as roSgNodeLabel)
3821
+ print myLabel.text
3822
+ di = createObject("roDeviceInfo") as roDeviceInfo
3823
+ myLabel.text = di.GetFriendlyName()
3824
+ print myLabel.getChildren(0, -1)
3825
+ end sub
3826
+ `);
3827
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3828
+ runtimeSymbols = mainFile.providedSymbols.symbolMap.get(SymbolTable_1.SymbolTypeFlag.runtime);
3829
+ (0, chai_config_spec_1.expect)(runtimeSymbols.size).to.eq(2);
3830
+ let runtimeChanges = mainFile.providedSymbols.changes.get(SymbolTable_1.SymbolTypeFlag.runtime);
3831
+ (0, chai_config_spec_1.expect)(runtimeChanges.size).to.eq(0);
3832
+ });
3833
+ it('classes that override AA built-in methods show change properly', () => {
3834
+ const classFileContent = `
3835
+ class AAOverRide
3836
+ sub count(num as integer) as void
3837
+ print num
3838
+ end sub
3839
+ end class
3840
+ `;
3841
+ let mainFile = program.setFile('source/class.bs', classFileContent);
3842
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3843
+ // No changes!
3844
+ mainFile = program.setFile('source/class.bs', classFileContent);
3845
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3846
+ let runtimeChanges = mainFile.providedSymbols.changes.get(SymbolTable_1.SymbolTypeFlag.runtime);
3847
+ (0, chai_config_spec_1.expect)(runtimeChanges.size).to.eq(0);
3848
+ });
3849
+ it('functions in a namespace that return classes show change properly', () => {
3850
+ const fileContent = `
3851
+ namespace Alpha.Beta
3852
+
3853
+ class SomeKlass
3854
+ name as string
3855
+ function combineName(klass as SomeKlass)
3856
+ m.name = m.name+klass.name
3857
+ end function
3858
+ end class
3859
+
3860
+ function getSomeKlass(name as string) as SomeKlass
3861
+ k = new SomeKlass()
3862
+ k.name = name
3863
+ return k
3864
+ end function
3865
+ end namespace
3866
+ `;
3867
+ let mainFile = program.setFile('source/class.bs', fileContent);
3868
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3869
+ // No changes!
3870
+ mainFile = program.setFile('source/class.bs', fileContent);
3871
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3872
+ let runtimeChanges = mainFile.providedSymbols.changes.get(SymbolTable_1.SymbolTypeFlag.runtime);
3873
+ (0, chai_config_spec_1.expect)(runtimeChanges.size).to.eq(0);
3874
+ });
3875
+ it('functions in a namespace that have class params show change properly', () => {
3876
+ const fileContent = `
3877
+ namespace Alpha.Beta
3878
+
3879
+ class SomeKlass
3880
+ name as string
3881
+ function combineName(klass as SomeKlass)
3882
+ m.name = m.name+klass.name
3883
+ end function
3884
+ end class
3885
+
3886
+ function combineKlass(klass1 as SomeKlass, klass2 as SomeKlass) as SomeKlass
3887
+ klass1.combineName(klass2)
3888
+ return klass1
3889
+ end function
3890
+ end namespace
3891
+ `;
3892
+ let mainFile = program.setFile('source/class.bs', fileContent);
3893
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3894
+ // No changes!
3895
+ mainFile = program.setFile('source/class.bs', fileContent);
3896
+ program.plugins.emit('onFileValidate', { program: program, file: mainFile });
3897
+ let runtimeChanges = mainFile.providedSymbols.changes.get(SymbolTable_1.SymbolTypeFlag.runtime);
3898
+ (0, chai_config_spec_1.expect)(runtimeChanges.size).to.eq(0);
3899
+ });
3900
+ });
3901
+ });
3902
+ describe('propertyHints', () => {
3903
+ it('extracts property names for completion', () => {
3904
+ const file = program.setFile('source/main.brs', `
3905
+ function main(arg as string)
3906
+ aa1 = {
3907
+ "sprop1": 0,
3908
+ prop1: 1
3909
+ prop2: {
3910
+ prop3: 2
3911
+ }
3912
+ }
3913
+ aa2 = {
3914
+ prop4: {
3915
+ prop5: 5,
3916
+ "sprop2": 0,
3917
+ prop6: 6
3918
+ },
3919
+ prop7: 7
3920
+ }
3921
+ calling({
3922
+ prop8: 8,
3923
+ prop9: 9
3924
+ })
3925
+ aa1.field1 = 1
3926
+ aa1.field2.field3 = 2
3927
+ calling(aa2.field4, 3 + aa2.field5.field6)
3928
+ end function
3929
+ `);
3930
+ const expected = [
3931
+ 'field1', 'field2', 'field3', 'field4', 'field5', 'field6',
3932
+ 'prop1', 'prop2', 'prop3', 'prop4', 'prop5', 'prop6', 'prop7', 'prop8', 'prop9'
3933
+ ];
3934
+ const { propertyHints } = file['_cachedLookups'];
3935
+ (0, chai_config_spec_1.expect)(Object.keys(propertyHints).sort()).to.deep.equal(expected, 'Initial hints');
3936
+ });
3937
+ it('extracts property names matching JavaScript reserved names', () => {
3938
+ const file = program.setFile('source/main.brs', `
3939
+ function main(arg as string)
3940
+ aa1 = {
3941
+ "constructor": 0,
3942
+ constructor: 1
3943
+ valueOf: {
3944
+ toString: 2
3945
+ }
3946
+ }
3947
+ aa1.constructor = 1
3948
+ aa1.valueOf.toString = 2
3949
+ end function
3950
+ `);
3951
+ const expected = [
3952
+ 'constructor', 'tostring', 'valueof'
3953
+ ];
3954
+ const { propertyHints } = file['_cachedLookups'];
3955
+ (0, chai_config_spec_1.expect)(Object.keys(propertyHints).sort()).to.deep.equal(expected, 'Initial hints');
3406
3956
  });
3407
3957
  });
3408
3958
  });