brighterscript 1.0.0-alpha.24 → 1.0.0-alpha.25

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