brighterscript 1.0.0-alpha.23 → 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 (536) hide show
  1. package/CHANGELOG.md +585 -218
  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 +79 -15
  33. package/dist/DiagnosticMessages.js +134 -21
  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 +222 -87
  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 +162 -81
  54. package/dist/Program.js +903 -732
  55. package/dist/Program.js.map +1 -1
  56. package/dist/ProgramBuilder.d.ts +22 -12
  57. package/dist/ProgramBuilder.js +132 -104
  58. package/dist/ProgramBuilder.js.map +1 -1
  59. package/dist/Scope.d.ts +95 -134
  60. package/dist/Scope.js +477 -551
  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 +95 -29
  65. package/dist/SymbolTable.js +256 -102
  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 -68
  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 -100
  90. package/dist/astUtils/reflection.js +225 -166
  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 +54 -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 +12 -2
  105. package/dist/bscPlugin/BscPlugin.js +41 -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.d.ts +1 -1
  117. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +21 -12
  118. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  119. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +86 -12
  120. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
  121. package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +57 -0
  122. package/dist/bscPlugin/completions/CompletionsProcessor.js +544 -0
  123. package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -0
  124. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +1909 -0
  125. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -0
  126. package/dist/bscPlugin/fileProviders/FileProvider.d.ts +9 -0
  127. package/dist/bscPlugin/fileProviders/FileProvider.js +51 -0
  128. package/dist/bscPlugin/fileProviders/FileProvider.js.map +1 -0
  129. package/dist/bscPlugin/hover/HoverProcessor.d.ts +17 -0
  130. package/dist/bscPlugin/hover/HoverProcessor.js +188 -0
  131. package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -0
  132. package/dist/bscPlugin/hover/HoverProcessor.spec.js +513 -0
  133. package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -0
  134. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +3 -1
  135. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +102 -29
  136. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
  137. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +167 -6
  138. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -1
  139. package/dist/bscPlugin/serialize/BslibInjector.spec.d.ts +1 -0
  140. package/dist/bscPlugin/serialize/BslibInjector.spec.js +19 -0
  141. package/dist/bscPlugin/serialize/BslibInjector.spec.js.map +1 -0
  142. package/dist/bscPlugin/serialize/BslibManager.d.ts +9 -0
  143. package/dist/bscPlugin/serialize/BslibManager.js +40 -0
  144. package/dist/bscPlugin/serialize/BslibManager.js.map +1 -0
  145. package/dist/bscPlugin/serialize/FileSerializer.d.ts +9 -0
  146. package/dist/bscPlugin/serialize/FileSerializer.js +72 -0
  147. package/dist/bscPlugin/serialize/FileSerializer.js.map +1 -0
  148. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.d.ts +16 -0
  149. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js +123 -0
  150. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js.map +1 -0
  151. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.d.ts +1 -0
  152. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js +41 -0
  153. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js.map +1 -0
  154. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.d.ts +12 -0
  155. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js +99 -0
  156. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js.map +1 -0
  157. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +22 -1
  158. package/dist/bscPlugin/validation/BrsFileValidator.js +316 -29
  159. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
  160. package/dist/bscPlugin/validation/BrsFileValidator.spec.d.ts +1 -0
  161. package/dist/bscPlugin/validation/BrsFileValidator.spec.js +264 -0
  162. package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +1 -0
  163. package/dist/bscPlugin/validation/ProgramValidator.d.ts +10 -0
  164. package/dist/bscPlugin/validation/ProgramValidator.js +32 -0
  165. package/dist/bscPlugin/validation/ProgramValidator.js.map +1 -0
  166. package/dist/bscPlugin/validation/ScopeValidator.d.ts +56 -8
  167. package/dist/bscPlugin/validation/ScopeValidator.js +514 -116
  168. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  169. package/dist/bscPlugin/validation/ScopeValidator.spec.d.ts +1 -0
  170. package/dist/bscPlugin/validation/ScopeValidator.spec.js +2454 -0
  171. package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -0
  172. package/dist/bscPlugin/validation/XmlFileValidator.d.ts +8 -0
  173. package/dist/bscPlugin/validation/XmlFileValidator.js +44 -0
  174. package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -0
  175. package/dist/cli.js +107 -8
  176. package/dist/cli.js.map +1 -1
  177. package/dist/deferred.d.ts +3 -3
  178. package/dist/deferred.js.map +1 -1
  179. package/dist/diagnosticUtils.d.ts +8 -2
  180. package/dist/diagnosticUtils.js +47 -17
  181. package/dist/diagnosticUtils.js.map +1 -1
  182. package/dist/examples/plugins/removePrint.js +8 -10
  183. package/dist/examples/plugins/removePrint.js.map +1 -1
  184. package/dist/files/AssetFile.d.ts +26 -0
  185. package/dist/files/AssetFile.js +26 -0
  186. package/dist/files/AssetFile.js.map +1 -0
  187. package/dist/files/BrsFile.Class.spec.js +529 -486
  188. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  189. package/dist/files/BrsFile.d.ts +124 -112
  190. package/dist/files/BrsFile.js +819 -1131
  191. package/dist/files/BrsFile.js.map +1 -1
  192. package/dist/files/BrsFile.spec.js +1869 -1277
  193. package/dist/files/BrsFile.spec.js.map +1 -1
  194. package/dist/files/BscFile.d.ts +104 -0
  195. package/dist/files/BscFile.js +16 -0
  196. package/dist/files/BscFile.js.map +1 -0
  197. package/dist/files/Factory.d.ts +25 -0
  198. package/dist/files/Factory.js +22 -0
  199. package/dist/files/Factory.js.map +1 -0
  200. package/dist/files/LazyFileData.d.ts +20 -0
  201. package/dist/files/LazyFileData.js +54 -0
  202. package/dist/files/LazyFileData.js.map +1 -0
  203. package/dist/files/LazyFileData.spec.d.ts +1 -0
  204. package/dist/files/LazyFileData.spec.js +27 -0
  205. package/dist/files/LazyFileData.spec.js.map +1 -0
  206. package/dist/files/XmlFile.d.ts +70 -32
  207. package/dist/files/XmlFile.js +106 -117
  208. package/dist/files/XmlFile.js.map +1 -1
  209. package/dist/files/XmlFile.spec.js +325 -262
  210. package/dist/files/XmlFile.spec.js.map +1 -1
  211. package/dist/files/tests/imports.spec.js +49 -41
  212. package/dist/files/tests/imports.spec.js.map +1 -1
  213. package/dist/files/tests/optionalChaning.spec.js +104 -40
  214. package/dist/files/tests/optionalChaning.spec.js.map +1 -1
  215. package/dist/globalCallables.js +16 -18
  216. package/dist/globalCallables.js.map +1 -1
  217. package/dist/index.d.ts +13 -2
  218. package/dist/index.js +15 -2
  219. package/dist/index.js.map +1 -1
  220. package/dist/interfaces.d.ts +440 -150
  221. package/dist/interfaces.js +27 -0
  222. package/dist/interfaces.js.map +1 -1
  223. package/dist/lexer/Character.spec.js +5 -5
  224. package/dist/lexer/Character.spec.js.map +1 -1
  225. package/dist/lexer/Lexer.d.ts +12 -5
  226. package/dist/lexer/Lexer.js +28 -13
  227. package/dist/lexer/Lexer.js.map +1 -1
  228. package/dist/lexer/Lexer.spec.js +187 -134
  229. package/dist/lexer/Lexer.spec.js.map +1 -1
  230. package/dist/lexer/Token.d.ts +9 -1
  231. package/dist/lexer/Token.js +9 -1
  232. package/dist/lexer/Token.js.map +1 -1
  233. package/dist/lexer/TokenKind.d.ts +9 -0
  234. package/dist/lexer/TokenKind.js +30 -5
  235. package/dist/lexer/TokenKind.js.map +1 -1
  236. package/dist/parser/AstNode.d.ts +162 -0
  237. package/dist/parser/AstNode.js +225 -0
  238. package/dist/parser/AstNode.js.map +1 -0
  239. package/dist/parser/AstNode.spec.d.ts +1 -0
  240. package/dist/parser/AstNode.spec.js +165 -0
  241. package/dist/parser/AstNode.spec.js.map +1 -0
  242. package/dist/parser/BrsTranspileState.d.ts +4 -7
  243. package/dist/parser/BrsTranspileState.js +4 -12
  244. package/dist/parser/BrsTranspileState.js.map +1 -1
  245. package/dist/parser/Expression.d.ts +126 -167
  246. package/dist/parser/Expression.js +524 -394
  247. package/dist/parser/Expression.js.map +1 -1
  248. package/dist/parser/Parser.Class.spec.js +152 -146
  249. package/dist/parser/Parser.Class.spec.js.map +1 -1
  250. package/dist/parser/Parser.d.ts +45 -196
  251. package/dist/parser/Parser.js +470 -926
  252. package/dist/parser/Parser.js.map +1 -1
  253. package/dist/parser/Parser.spec.d.ts +3 -1
  254. package/dist/parser/Parser.spec.js +1034 -805
  255. package/dist/parser/Parser.spec.js.map +1 -1
  256. package/dist/parser/SGParser.d.ts +9 -8
  257. package/dist/parser/SGParser.js +10 -8
  258. package/dist/parser/SGParser.js.map +1 -1
  259. package/dist/parser/SGParser.spec.js +27 -38
  260. package/dist/parser/SGParser.spec.js.map +1 -1
  261. package/dist/parser/SGTypes.d.ts +98 -35
  262. package/dist/parser/SGTypes.js +169 -99
  263. package/dist/parser/SGTypes.js.map +1 -1
  264. package/dist/parser/Statement.d.ts +208 -122
  265. package/dist/parser/Statement.js +599 -364
  266. package/dist/parser/Statement.js.map +1 -1
  267. package/dist/parser/Statement.spec.js +45 -21
  268. package/dist/parser/Statement.spec.js.map +1 -1
  269. package/dist/parser/TranspileState.d.ts +1 -1
  270. package/dist/parser/TranspileState.js +7 -12
  271. package/dist/parser/TranspileState.js.map +1 -1
  272. package/dist/parser/tests/Parser.spec.js +3 -2
  273. package/dist/parser/tests/Parser.spec.js.map +1 -1
  274. package/dist/parser/tests/controlFlow/For.spec.js +33 -23
  275. package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
  276. package/dist/parser/tests/controlFlow/ForEach.spec.js +25 -20
  277. package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
  278. package/dist/parser/tests/controlFlow/If.spec.js +96 -94
  279. package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
  280. package/dist/parser/tests/controlFlow/While.spec.js +22 -16
  281. package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
  282. package/dist/parser/tests/expression/Additive.spec.js +8 -8
  283. package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
  284. package/dist/parser/tests/expression/ArrayLiterals.spec.js +58 -21
  285. package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
  286. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +61 -20
  287. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
  288. package/dist/parser/tests/expression/Boolean.spec.js +8 -8
  289. package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
  290. package/dist/parser/tests/expression/Call.spec.js +129 -21
  291. package/dist/parser/tests/expression/Call.spec.js.map +1 -1
  292. package/dist/parser/tests/expression/Exponential.spec.js +5 -5
  293. package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
  294. package/dist/parser/tests/expression/Function.spec.js +36 -36
  295. package/dist/parser/tests/expression/Function.spec.js.map +1 -1
  296. package/dist/parser/tests/expression/Indexing.spec.js +67 -22
  297. package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
  298. package/dist/parser/tests/expression/Multiplicative.spec.js +9 -9
  299. package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
  300. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +123 -81
  301. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  302. package/dist/parser/tests/expression/PrefixUnary.spec.js +12 -12
  303. package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
  304. package/dist/parser/tests/expression/Primary.spec.js +12 -12
  305. package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
  306. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +10 -10
  307. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -1
  308. package/dist/parser/tests/expression/Relational.spec.js +13 -13
  309. package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
  310. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +24 -24
  311. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
  312. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +221 -81
  313. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  314. package/dist/parser/tests/expression/TernaryExpression.spec.js +287 -105
  315. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  316. package/dist/parser/tests/expression/TypeExpression.spec.d.ts +1 -0
  317. package/dist/parser/tests/expression/TypeExpression.spec.js +127 -0
  318. package/dist/parser/tests/expression/TypeExpression.spec.js.map +1 -0
  319. package/dist/parser/tests/expression/UnaryExpression.spec.d.ts +1 -0
  320. package/dist/parser/tests/expression/UnaryExpression.spec.js +52 -0
  321. package/dist/parser/tests/expression/UnaryExpression.spec.js.map +1 -0
  322. package/dist/parser/tests/statement/AssignmentOperators.spec.js +15 -15
  323. package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
  324. package/dist/parser/tests/statement/ConstStatement.spec.d.ts +1 -0
  325. package/dist/parser/tests/statement/ConstStatement.spec.js +262 -0
  326. package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -0
  327. package/dist/parser/tests/statement/Continue.spec.d.ts +1 -0
  328. package/dist/parser/tests/statement/Continue.spec.js +119 -0
  329. package/dist/parser/tests/statement/Continue.spec.js.map +1 -0
  330. package/dist/parser/tests/statement/Declaration.spec.js +19 -19
  331. package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
  332. package/dist/parser/tests/statement/Dim.spec.js +22 -22
  333. package/dist/parser/tests/statement/Dim.spec.js.map +1 -1
  334. package/dist/parser/tests/statement/Enum.spec.js +111 -300
  335. package/dist/parser/tests/statement/Enum.spec.js.map +1 -1
  336. package/dist/parser/tests/statement/For.spec.js +9 -10
  337. package/dist/parser/tests/statement/For.spec.js.map +1 -1
  338. package/dist/parser/tests/statement/ForEach.spec.js +8 -9
  339. package/dist/parser/tests/statement/ForEach.spec.js.map +1 -1
  340. package/dist/parser/tests/statement/Function.spec.js +44 -35
  341. package/dist/parser/tests/statement/Function.spec.js.map +1 -1
  342. package/dist/parser/tests/statement/Goto.spec.js +5 -5
  343. package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
  344. package/dist/parser/tests/statement/Increment.spec.js +20 -20
  345. package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
  346. package/dist/parser/tests/statement/InterfaceStatement.spec.js +30 -196
  347. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
  348. package/dist/parser/tests/statement/LibraryStatement.spec.js +11 -11
  349. package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
  350. package/dist/parser/tests/statement/Misc.spec.js +16 -78
  351. package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
  352. package/dist/parser/tests/statement/PrintStatement.spec.js +107 -90
  353. package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
  354. package/dist/parser/tests/statement/ReturnStatement.spec.js +14 -12
  355. package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
  356. package/dist/parser/tests/statement/Set.spec.js +48 -35
  357. package/dist/parser/tests/statement/Set.spec.js.map +1 -1
  358. package/dist/parser/tests/statement/Stop.spec.js +6 -6
  359. package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
  360. package/dist/parser/tests/statement/Throw.spec.js +6 -6
  361. package/dist/parser/tests/statement/Throw.spec.js.map +1 -1
  362. package/dist/parser/tests/statement/TryCatch.spec.js +18 -16
  363. package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
  364. package/dist/preprocessor/Manifest.d.ts +1 -1
  365. package/dist/preprocessor/Manifest.js +3 -3
  366. package/dist/preprocessor/Manifest.js.map +1 -1
  367. package/dist/preprocessor/Manifest.spec.js +8 -8
  368. package/dist/preprocessor/Manifest.spec.js.map +1 -1
  369. package/dist/preprocessor/Preprocessor.d.ts +5 -6
  370. package/dist/preprocessor/Preprocessor.js +15 -11
  371. package/dist/preprocessor/Preprocessor.js.map +1 -1
  372. package/dist/preprocessor/Preprocessor.spec.js +25 -25
  373. package/dist/preprocessor/Preprocessor.spec.js.map +1 -1
  374. package/dist/preprocessor/PreprocessorParser.d.ts +1 -1
  375. package/dist/preprocessor/PreprocessorParser.js +7 -1
  376. package/dist/preprocessor/PreprocessorParser.js.map +1 -1
  377. package/dist/preprocessor/PreprocessorParser.spec.js +13 -13
  378. package/dist/preprocessor/PreprocessorParser.spec.js.map +1 -1
  379. package/dist/roku-types/data.json +6544 -10519
  380. package/dist/roku-types/index.d.ts +662 -1934
  381. package/dist/types/ArrayType.d.ts +10 -9
  382. package/dist/types/ArrayType.js +65 -60
  383. package/dist/types/ArrayType.js.map +1 -1
  384. package/dist/types/ArrayType.spec.js +36 -68
  385. package/dist/types/ArrayType.spec.js.map +1 -1
  386. package/dist/types/AssociativeArrayType.d.ts +11 -0
  387. package/dist/types/AssociativeArrayType.js +52 -0
  388. package/dist/types/AssociativeArrayType.js.map +1 -0
  389. package/dist/types/BaseFunctionType.d.ts +9 -0
  390. package/dist/types/BaseFunctionType.js +25 -0
  391. package/dist/types/BaseFunctionType.js.map +1 -0
  392. package/dist/types/BooleanType.d.ts +8 -5
  393. package/dist/types/BooleanType.js +14 -7
  394. package/dist/types/BooleanType.js.map +1 -1
  395. package/dist/types/BooleanType.spec.js +10 -6
  396. package/dist/types/BooleanType.spec.js.map +1 -1
  397. package/dist/types/BscType.d.ts +32 -21
  398. package/dist/types/BscType.js +118 -21
  399. package/dist/types/BscType.js.map +1 -1
  400. package/dist/types/BscTypeKind.d.ts +25 -0
  401. package/dist/types/BscTypeKind.js +30 -0
  402. package/dist/types/BscTypeKind.js.map +1 -0
  403. package/dist/types/BuiltInInterfaceAdder.d.ts +23 -0
  404. package/dist/types/BuiltInInterfaceAdder.js +164 -0
  405. package/dist/types/BuiltInInterfaceAdder.js.map +1 -0
  406. package/dist/types/BuiltInInterfaceAdder.spec.d.ts +1 -0
  407. package/dist/types/BuiltInInterfaceAdder.spec.js +116 -0
  408. package/dist/types/BuiltInInterfaceAdder.spec.js.map +1 -0
  409. package/dist/types/ClassType.d.ts +17 -0
  410. package/dist/types/ClassType.js +58 -0
  411. package/dist/types/ClassType.js.map +1 -0
  412. package/dist/types/ClassType.spec.d.ts +1 -0
  413. package/dist/types/ClassType.spec.js +77 -0
  414. package/dist/types/ClassType.spec.js.map +1 -0
  415. package/dist/types/ComponentType.d.ts +26 -0
  416. package/dist/types/ComponentType.js +83 -0
  417. package/dist/types/ComponentType.js.map +1 -0
  418. package/dist/types/DoubleType.d.ts +8 -5
  419. package/dist/types/DoubleType.js +18 -16
  420. package/dist/types/DoubleType.js.map +1 -1
  421. package/dist/types/DoubleType.spec.js +12 -6
  422. package/dist/types/DoubleType.spec.js.map +1 -1
  423. package/dist/types/DynamicType.d.ts +10 -5
  424. package/dist/types/DynamicType.js +16 -4
  425. package/dist/types/DynamicType.js.map +1 -1
  426. package/dist/types/DynamicType.spec.js +16 -5
  427. package/dist/types/DynamicType.spec.js.map +1 -1
  428. package/dist/types/EnumType.d.ts +30 -12
  429. package/dist/types/EnumType.js +43 -17
  430. package/dist/types/EnumType.js.map +1 -1
  431. package/dist/types/EnumType.spec.d.ts +1 -0
  432. package/dist/types/EnumType.spec.js +33 -0
  433. package/dist/types/EnumType.spec.js.map +1 -0
  434. package/dist/types/FloatType.d.ts +8 -5
  435. package/dist/types/FloatType.js +18 -16
  436. package/dist/types/FloatType.js.map +1 -1
  437. package/dist/types/FloatType.spec.js +4 -6
  438. package/dist/types/FloatType.spec.js.map +1 -1
  439. package/dist/types/FunctionType.d.ts +13 -8
  440. package/dist/types/FunctionType.js +30 -14
  441. package/dist/types/FunctionType.js.map +1 -1
  442. package/dist/types/InheritableType.d.ts +28 -0
  443. package/dist/types/InheritableType.js +152 -0
  444. package/dist/types/InheritableType.js.map +1 -0
  445. package/dist/types/IntegerType.d.ts +8 -5
  446. package/dist/types/IntegerType.js +18 -16
  447. package/dist/types/IntegerType.js.map +1 -1
  448. package/dist/types/IntegerType.spec.js +8 -6
  449. package/dist/types/IntegerType.spec.js.map +1 -1
  450. package/dist/types/InterfaceType.d.ts +12 -13
  451. package/dist/types/InterfaceType.js +20 -48
  452. package/dist/types/InterfaceType.js.map +1 -1
  453. package/dist/types/InterfaceType.spec.js +90 -56
  454. package/dist/types/InterfaceType.spec.js.map +1 -1
  455. package/dist/types/InvalidType.d.ts +7 -5
  456. package/dist/types/InvalidType.js +13 -7
  457. package/dist/types/InvalidType.js.map +1 -1
  458. package/dist/types/InvalidType.spec.js +8 -6
  459. package/dist/types/InvalidType.spec.js.map +1 -1
  460. package/dist/types/LongIntegerType.d.ts +8 -5
  461. package/dist/types/LongIntegerType.js +17 -15
  462. package/dist/types/LongIntegerType.js.map +1 -1
  463. package/dist/types/LongIntegerType.spec.js +10 -6
  464. package/dist/types/LongIntegerType.spec.js.map +1 -1
  465. package/dist/types/NamespaceType.d.ts +12 -0
  466. package/dist/types/NamespaceType.js +28 -0
  467. package/dist/types/NamespaceType.js.map +1 -0
  468. package/dist/types/ObjectType.d.ts +9 -8
  469. package/dist/types/ObjectType.js +21 -11
  470. package/dist/types/ObjectType.js.map +1 -1
  471. package/dist/types/ObjectType.spec.js +3 -3
  472. package/dist/types/ObjectType.spec.js.map +1 -1
  473. package/dist/types/ReferenceType.d.ts +63 -0
  474. package/dist/types/ReferenceType.js +423 -0
  475. package/dist/types/ReferenceType.js.map +1 -0
  476. package/dist/types/ReferenceType.spec.d.ts +1 -0
  477. package/dist/types/ReferenceType.spec.js +137 -0
  478. package/dist/types/ReferenceType.spec.js.map +1 -0
  479. package/dist/types/StringType.d.ts +11 -5
  480. package/dist/types/StringType.js +18 -7
  481. package/dist/types/StringType.js.map +1 -1
  482. package/dist/types/StringType.spec.js +3 -5
  483. package/dist/types/StringType.spec.js.map +1 -1
  484. package/dist/types/TypedFunctionType.d.ts +22 -17
  485. package/dist/types/TypedFunctionType.js +78 -60
  486. package/dist/types/TypedFunctionType.js.map +1 -1
  487. package/dist/types/TypedFunctionType.spec.js +105 -20
  488. package/dist/types/TypedFunctionType.spec.js.map +1 -1
  489. package/dist/types/UninitializedType.d.ts +8 -6
  490. package/dist/types/UninitializedType.js +13 -7
  491. package/dist/types/UninitializedType.js.map +1 -1
  492. package/dist/types/UnionType.d.ts +20 -0
  493. package/dist/types/UnionType.js +123 -0
  494. package/dist/types/UnionType.js.map +1 -0
  495. package/dist/types/UnionType.spec.d.ts +1 -0
  496. package/dist/types/UnionType.spec.js +130 -0
  497. package/dist/types/UnionType.spec.js.map +1 -0
  498. package/dist/types/VoidType.d.ts +8 -5
  499. package/dist/types/VoidType.js +14 -7
  500. package/dist/types/VoidType.js.map +1 -1
  501. package/dist/types/VoidType.spec.js +3 -3
  502. package/dist/types/VoidType.spec.js.map +1 -1
  503. package/dist/types/helper.spec.d.ts +1 -0
  504. package/dist/types/helper.spec.js +145 -0
  505. package/dist/types/helper.spec.js.map +1 -0
  506. package/dist/types/helpers.d.ts +19 -37
  507. package/dist/types/helpers.js +159 -99
  508. package/dist/types/helpers.js.map +1 -1
  509. package/dist/types/index.d.ts +22 -0
  510. package/dist/types/index.js +39 -0
  511. package/dist/types/index.js.map +1 -0
  512. package/dist/util.d.ts +167 -131
  513. package/dist/util.js +890 -350
  514. package/dist/util.js.map +1 -1
  515. package/dist/validators/ClassValidator.d.ts +7 -25
  516. package/dist/validators/ClassValidator.js +103 -194
  517. package/dist/validators/ClassValidator.js.map +1 -1
  518. package/package.json +165 -149
  519. package/dist/astUtils/AstEditor.js.map +0 -1
  520. package/dist/astUtils/AstEditor.spec.js.map +0 -1
  521. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.d.ts +0 -8
  522. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js +0 -40
  523. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +0 -1
  524. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js +0 -32
  525. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js.map +0 -1
  526. package/dist/parser/SGTypes.spec.js +0 -351
  527. package/dist/parser/SGTypes.spec.js.map +0 -1
  528. package/dist/types/CustomType.d.ts +0 -12
  529. package/dist/types/CustomType.js +0 -44
  530. package/dist/types/CustomType.js.map +0 -1
  531. package/dist/types/LazyType.d.ts +0 -16
  532. package/dist/types/LazyType.js +0 -44
  533. package/dist/types/LazyType.js.map +0 -1
  534. /package/dist/astUtils/{AstEditor.spec.d.ts → Editor.spec.d.ts} +0 -0
  535. /package/dist/bscPlugin/{transpile/BrsFilePreTranspileProcessor.spec.d.ts → completions/CompletionsProcessor.spec.d.ts} +0 -0
  536. /package/dist/{parser/SGTypes.spec.d.ts → bscPlugin/hover/HoverProcessor.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,35 +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 ArrayType_1 = require("../types/ArrayType");
26
- const FloatType_1 = require("../types/FloatType");
27
- const ObjectType_1 = require("../types/ObjectType");
28
- const VoidType_1 = require("../types/VoidType");
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");
29
28
  let sinon = sinonImport.createSandbox();
30
29
  describe('BrsFile', () => {
31
- let tempDir = (0, util_1.standardizePath) `${process.cwd()}/.tmp`;
32
- let rootDir = (0, util_1.standardizePath) `${tempDir}/rootDir`;
33
30
  let program;
34
- let srcPath = (0, util_1.standardizePath) `${rootDir}/source/main.brs`;
31
+ let srcPath = (0, util_1.standardizePath) `${testHelpers_spec_2.rootDir}/source/main.brs`;
35
32
  let destPath = 'source/main.brs';
36
33
  let file;
37
- 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]);
38
36
  beforeEach(() => {
39
- fsExtra.emptyDirSync(tempDir);
40
- program = new Program_1.Program({ rootDir: rootDir, sourceMap: true });
41
- 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
+ });
42
44
  });
43
45
  afterEach(() => {
44
46
  sinon.restore();
45
47
  program.dispose();
46
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
+ });
47
74
  describe('allowBrighterScriptInBrightScript', () => {
48
75
  it('is false by default', () => {
49
76
  program.setFile('source/main.brs', `
@@ -63,6 +90,66 @@ describe('BrsFile', () => {
63
90
  (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
64
91
  });
65
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
+ });
66
153
  it('supports the third parameter in CreateObject', () => {
67
154
  program.setFile('source/main.brs', `
68
155
  sub main()
@@ -83,17 +170,25 @@ describe('BrsFile', () => {
83
170
  });
84
171
  it('sets needsTranspiled to true for .bs files', () => {
85
172
  //BrightScript
86
- (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;
87
178
  //BrighterScript
88
- (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;
89
184
  });
90
185
  it('computes new import statements after clearing parser references', () => {
91
186
  const file = program.setFile('source/main.bs', ``);
92
- (0, chai_1.expect)(file.ownScriptImports).to.be.empty;
187
+ (0, chai_config_spec_1.expect)(file.ownScriptImports).to.be.empty;
93
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')));
94
- (0, chai_1.expect)(file.ownScriptImports).to.be.empty;
95
- file.parser.invalidateReferences();
96
- (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']);
97
192
  });
98
193
  it('allows adding diagnostics', () => {
99
194
  const expected = [{
@@ -106,282 +201,78 @@ describe('BrsFile', () => {
106
201
  });
107
202
  describe('getPartialVariableName', () => {
108
203
  let entry = {
109
- src: `${rootDir}/source/lib.brs`,
204
+ src: `${testHelpers_spec_2.rootDir}/source/lib.brs`,
110
205
  dest: `source/lib.brs`
111
206
  };
112
207
  it('creates proper tokens', () => {
113
208
  file = program.setFile(entry, `call(ModuleA.ModuleB.ModuleC.`);
114
- (0, chai_1.expect)(file['getPartialVariableName'](file.parser.tokens[7])).to.equal('ModuleA.ModuleB.ModuleC.');
115
- (0, chai_1.expect)(file['getPartialVariableName'](file.parser.tokens[6])).to.equal('ModuleA.ModuleB.ModuleC');
116
- (0, chai_1.expect)(file['getPartialVariableName'](file.parser.tokens[5])).to.equal('ModuleA.ModuleB.');
117
- (0, chai_1.expect)(file['getPartialVariableName'](file.parser.tokens[4])).to.equal('ModuleA.ModuleB');
118
- (0, chai_1.expect)(file['getPartialVariableName'](file.parser.tokens[3])).to.equal('ModuleA.');
119
- (0, chai_1.expect)(file['getPartialVariableName'](file.parser.tokens[2])).to.equal('ModuleA');
120
- });
121
- });
122
- describe('getScopesForFile', () => {
123
- it('finds the scope for the file', () => {
124
- var _a;
125
- let file = program.setFile('source/main.brs', ``);
126
- (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');
127
215
  });
128
216
  });
129
- describe('getCompletions', () => {
130
- it('does not crash for callfunc on a function call', () => {
131
- const file = program.setFile('source/main.brs', `
132
- sub main()
133
- getManager()@.
134
- end sub
135
- `);
136
- (0, chai_1.expect)(() => {
137
- program.getCompletions(file.srcPath, util_1.default.createPosition(2, 34));
138
- }).not.to.throw;
139
- });
140
- 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', () => {
141
219
  program.setFile('source/main.brs', `
142
220
  sub main()
143
- print "pkg:"
221
+ print \`pkg:\`
144
222
  end sub
145
223
  `);
146
- const result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(2, 31));
147
- const names = result.map(x => x.label);
148
- (0, chai_1.expect)(names.sort()).to.eql([
149
- 'pkg:/source/main.brs'
150
- ]);
224
+ const file = program.getFile('source/main.brs');
225
+ (0, chai_config_spec_1.expect)(file.canBePruned).to.be.false;
151
226
  });
152
- it('suggests libpkg paths in strings that match that criteria', () => {
227
+ it('returns false if target file contains a class statement', () => {
153
228
  program.setFile('source/main.brs', `
154
- sub main()
155
- print "libpkg:"
156
- end sub
229
+ class Animal
230
+ public name as string
231
+ end class
157
232
  `);
158
- const result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(2, 31));
159
- const names = result.map(x => x.label);
160
- (0, chai_1.expect)(names.sort()).to.eql([
161
- 'libpkg:/source/main.brs'
162
- ]);
233
+ const file = program.getFile('source/main.brs');
234
+ (0, chai_config_spec_1.expect)(file.canBePruned).to.be.false;
163
235
  });
164
- it('suggests pkg paths in template strings', () => {
236
+ it('returns false if target file contains a class statement', () => {
165
237
  program.setFile('source/main.brs', `
166
- sub main()
167
- print \`pkg:\`
168
- end sub
238
+ namespace Vertibrates.Birds
239
+ function GetDucks()
240
+ end function
241
+ end namespace
169
242
  `);
170
- const result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(2, 31));
171
- const names = result.map(x => x.label);
172
- (0, chai_1.expect)(names.sort()).to.eql([
173
- 'pkg:/source/main.brs'
174
- ]);
243
+ const file = program.getFile('source/main.brs');
244
+ (0, chai_config_spec_1.expect)(file.canBePruned).to.be.false;
175
245
  });
176
- it('waits for the file to be processed before collecting completions', () => {
177
- //eslint-disable-next-line @typescript-eslint/no-floating-promises
246
+ it('returns true if target file contains only enum', () => {
178
247
  program.setFile('source/main.brs', `
179
- sub Main()
180
- print "hello"
181
- Say
182
- end sub
183
-
184
- sub SayHello()
185
- end sub
186
- `);
187
- let result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(3, 23));
188
- let names = result.map(x => x.label);
189
- (0, chai_1.expect)(names).to.includes('Main');
190
- (0, chai_1.expect)(names).to.includes('SayHello');
191
- });
192
- it('includes every type of item at base level', () => {
193
- program.setFile('source/main.bs', `
194
- sub main()
195
- print
196
- end sub
197
- sub speak()
198
- end sub
199
- namespace stuff
200
- end namespace
201
- class Person
202
- end class
203
248
  enum Direction
249
+ up
250
+ down
251
+ left
252
+ right
204
253
  end enum
205
254
  `);
206
- (0, testHelpers_spec_1.expectCompletionsIncludes)(program.getCompletions('source/main.bs', util_1.default.createPosition(2, 26)), [{
207
- label: 'main',
208
- kind: vscode_languageserver_1.CompletionItemKind.Function
209
- }, {
210
- label: 'speak',
211
- kind: vscode_languageserver_1.CompletionItemKind.Function
212
- }, {
213
- label: 'stuff',
214
- kind: vscode_languageserver_1.CompletionItemKind.Module
215
- }, {
216
- label: 'Person',
217
- kind: vscode_languageserver_1.CompletionItemKind.Class
218
- }, {
219
- label: 'Direction',
220
- kind: vscode_languageserver_1.CompletionItemKind.Enum
221
- }]);
222
- });
223
- describe('namespaces', () => {
224
- it('gets full namespace completions at any point through the leading identifier', () => {
225
- program.setFile('source/main.bs', `
226
- sub main()
227
- foo.bar
228
- end sub
229
-
230
- namespace foo.bar
231
- end namespace
232
-
233
- class Person
234
- end class
235
- `);
236
- const result = program.getCompletions(`${rootDir}/source/main.bs`, vscode_languageserver_1.Position.create(2, 24)).map(x => x.label);
237
- (0, chai_1.expect)(result).includes('main');
238
- (0, chai_1.expect)(result).includes('foo');
239
- (0, chai_1.expect)(result).includes('Person');
240
- });
241
- it('gets namespace completions', () => {
242
- program.setFile('source/main.bs', `
243
- namespace foo.bar
244
- function sayHello()
245
- end function
246
- end namespace
247
-
248
- sub Main()
249
- print "hello"
250
- foo.ba
251
- foo.bar.
252
- end sub
253
- `);
254
- let result = program.getCompletions(`${rootDir}/source/main.bs`, vscode_languageserver_1.Position.create(8, 30));
255
- let names = result.map(x => x.label);
256
- (0, chai_1.expect)(names).to.includes('bar');
257
- result = program.getCompletions(`${rootDir}/source/main.bs`, vscode_languageserver_1.Position.create(9, 32));
258
- names = result.map(x => x.label);
259
- (0, chai_1.expect)(names).to.includes('sayHello');
260
- });
261
- });
262
- it('always includes `m`', () => {
263
- //eslint-disable-next-line @typescript-eslint/no-floating-promises
264
- program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
265
- sub Main()
266
-
267
- end sub
268
- `);
269
- let result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(2, 23));
270
- let names = result.map(x => x.label);
271
- (0, chai_1.expect)(names).to.contain('m');
272
- });
273
- it('does not fail for missing previousToken', () => {
274
- //add a single character to the file, and get completions after it
275
- program.setFile('source/main.brs', `i`);
276
- (0, chai_1.expect)(() => {
277
- program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(0, 1)).map(x => x.label);
278
- }).not.to.throw;
279
- });
280
- it('includes all keywords`', () => {
281
- //eslint-disable-next-line @typescript-eslint/no-floating-promises
282
- program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
283
- sub Main()
284
-
285
- end sub
286
- `);
287
- let keywords = Object.keys(TokenKind_1.Keywords).filter(x => !x.includes(' '));
288
- //inside the function
289
- let result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(2, 23));
290
- let names = result.map(x => x.label);
291
- for (let keyword of keywords) {
292
- (0, chai_1.expect)(names).to.include(keyword);
293
- }
294
- //outside the function
295
- result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(4, 8));
296
- names = result.map(x => x.label);
297
- for (let keyword of keywords) {
298
- (0, chai_1.expect)(names).to.include(keyword);
299
- }
300
- });
301
- it('does not provide completions within a comment', () => {
302
- //eslint-disable-next-line @typescript-eslint/no-floating-promises
303
- program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
304
- sub Main()
305
- 'some comment
306
- end sub
307
- `);
308
- //inside the function
309
- let result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(2, 33));
310
- (0, chai_1.expect)(result).to.be.lengthOf(0);
311
- });
312
- it('does not provide duplicate entries for variables', () => {
313
- //eslint-disable-next-line @typescript-eslint/no-floating-promises
314
- program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
315
- sub Main()
316
- name = "bob"
317
- age = 12
318
- name = "john"
319
- end sub
320
- `);
321
- let result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(3, 23));
322
- let count = result.reduce((total, x) => {
323
- return x.label === 'name' ? total + 1 : total;
324
- }, 0);
325
- (0, chai_1.expect)(count).to.equal(1);
326
- });
327
- it('does not include `as` and `string` text options when used in function params', () => {
328
- //eslint-disable-next-line @typescript-eslint/no-floating-promises
329
- program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
330
- sub Main(name as string)
331
-
332
- end sub
333
- `);
334
- let result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(2, 23));
335
- (0, chai_1.expect)(result.filter(x => x.kind === vscode_languageserver_1.CompletionItemKind.Text)).not.to.contain('as');
336
- (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;
337
257
  });
338
- it('does not provide intellisense results when inside a comment', () => {
339
- //eslint-disable-next-line @typescript-eslint/no-floating-promises
340
- program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
341
- sub Main(name as string)
342
- 'this is a comment
343
- end sub
344
- `);
345
- let results = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(2, 30));
346
- (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;
347
262
  });
348
- it('does provide intellisence for labels only after a goto keyword', () => {
349
- var _a;
350
- //eslint-disable-next-line @typescript-eslint/no-floating-promises
351
- program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
352
- sub Main(name as string)
353
- something:
354
- goto \nend sub
355
- `);
356
- let results = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(3, 25));
357
- (0, chai_1.expect)(results.length).to.equal(1);
358
- (0, chai_1.expect)((_a = results[0]) === null || _a === void 0 ? void 0 : _a.label).to.equal('something');
359
- });
360
- it('includes properties of objects', () => {
361
- //eslint-disable-next-line @typescript-eslint/no-floating-promises
263
+ it('returns true if target file only has comments', () => {
362
264
  program.setFile('source/main.brs', `
363
- sub Main()
364
- myObj = {name:"Bob", age: 34, height:6.0}
365
- myObj.
366
- end sub
265
+ ' this is an interesting comment
367
266
  `);
368
- let result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(3, 26));
369
- let names = result.map(x => x.label);
370
- (0, chai_1.expect)(names).to.contain('name');
371
- (0, chai_1.expect)(names).to.contain('age');
372
- (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;
373
269
  });
374
- it('includes properties of m', () => {
375
- //eslint-disable-next-line @typescript-eslint/no-floating-promises
376
- program.setFile('source/main.brs', `
377
- sub Main()
378
- m.someField= "hello"
379
- m.
380
- end sub
381
- `);
382
- let result = program.getCompletions(`${rootDir}/source/main.brs`, vscode_languageserver_1.Position.create(3, 22));
383
- let names = result.map(x => x.label);
384
- (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');
385
276
  });
386
277
  });
387
278
  describe('comment flags', () => {
@@ -417,14 +308,14 @@ describe('BrsFile', () => {
417
308
  (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
418
309
  });
419
310
  it('works for all', () => {
420
- 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' }, `
421
312
  sub Main()
422
313
  'bs:disable-next-line
423
314
  name = "bob
424
315
  end sub
425
316
  `);
426
- (0, chai_1.expect)(file.commentFlags[0]).to.exist;
427
- (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({
428
319
  codes: null,
429
320
  range: vscode_languageserver_1.Range.create(2, 24, 2, 45),
430
321
  affectedRange: util_1.default.createRange(3, 0, 3, Number.MAX_SAFE_INTEGER)
@@ -434,14 +325,14 @@ describe('BrsFile', () => {
434
325
  (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
435
326
  });
436
327
  it('works for specific codes', () => {
437
- 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' }, `
438
329
  sub Main()
439
330
  'bs:disable-next-line: 1083, 1001
440
331
  name = "bob
441
332
  end sub
442
333
  `);
443
- (0, chai_1.expect)(file.commentFlags[0]).to.exist;
444
- (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({
445
336
  codes: [1083, 1001],
446
337
  range: vscode_languageserver_1.Range.create(2, 24, 2, 57),
447
338
  affectedRange: util_1.default.createRange(3, 0, 3, Number.MAX_SAFE_INTEGER)
@@ -450,13 +341,13 @@ describe('BrsFile', () => {
450
341
  (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
451
342
  });
452
343
  it('recognizes non-numeric codes', () => {
453
- let file = program.setFile('source/main.brs', `
344
+ let file = program.setFile({ src: `${testHelpers_spec_2.rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
454
345
  sub Main()
455
346
  'bs:disable-next-line: LINT9999
456
347
  name = "bob
457
348
  end sub
458
- `);
459
- (0, chai_1.expect)(file.commentFlags[0]).to.exist;
349
+ `);
350
+ (0, chai_config_spec_1.expect)(file.commentFlags[0]).to.exist;
460
351
  (0, testHelpers_spec_1.expectHasDiagnostics)(program);
461
352
  });
462
353
  it('supports disabling non-numeric error codes', () => {
@@ -465,35 +356,35 @@ describe('BrsFile', () => {
465
356
  sub main()
466
357
  something = true 'bs:disable-line: LINT1005
467
358
  end sub
468
- `);
469
- file.addDiagnostics([{
470
- code: 'LINT1005',
471
- file: file,
472
- message: 'Something is not right',
473
- range: util_1.default.createRange(2, 16, 2, 26)
474
- }]);
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
+ });
475
366
  const scope = program.getScopesForFile(file)[0];
476
367
  (0, testHelpers_spec_1.expectZeroDiagnostics)(scope);
477
368
  });
478
369
  it('adds diagnostics for unknown numeric diagnostic codes', () => {
479
- program.setFile({ src: `${rootDir} / source / main.brs`, dest: 'source/main.brs' }, `
370
+ program.setFile('source/main.brs', `
480
371
  sub main()
481
372
  print "hi" 'bs:disable-line: 123456 999999 aaaab
482
373
  end sub
483
- `);
374
+ `);
484
375
  program.validate();
485
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) })]);
486
377
  });
487
378
  });
488
379
  describe('bs:disable-line', () => {
489
380
  it('works for all', () => {
490
- 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' }, `
491
382
  sub Main()
492
383
  z::;;%%%%%% 'bs:disable-line
493
384
  end sub
494
385
  `);
495
- (0, chai_1.expect)(file.commentFlags[0]).to.exist;
496
- (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({
497
388
  codes: null,
498
389
  range: vscode_languageserver_1.Range.create(2, 36, 2, 52),
499
390
  affectedRange: vscode_languageserver_1.Range.create(2, 0, 2, 36)
@@ -503,7 +394,7 @@ describe('BrsFile', () => {
503
394
  (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
504
395
  });
505
396
  it('works for specific codes', () => {
506
- program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
397
+ program.setFile('source/main.brs', `
507
398
  sub main()
508
399
  'should not have any errors
509
400
  DoSomething(1) 'bs:disable-line:1002
@@ -522,12 +413,12 @@ describe('BrsFile', () => {
522
413
  //the current version of BRS causes parse errors after the `parse` keyword, showing error in comments
523
414
  //the program should ignore all diagnostics found in brs:* comment lines EXCEPT
524
415
  //for the diagnostics about using unknown error codes
525
- program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
416
+ program.setFile('source/main.brs', `
526
417
  sub main()
527
418
  stop 'bs:disable-line
528
419
  print "need a valid line to fix stop error"
529
420
  end sub
530
- `);
421
+ `);
531
422
  program.validate();
532
423
  (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
533
424
  });
@@ -574,9 +465,9 @@ describe('BrsFile', () => {
574
465
  it('supports iife in assignment', () => {
575
466
  program.setFile('source/main.brs', `
576
467
  sub main()
577
- result = sub()
468
+ result = sub()
578
469
  end sub()
579
- result = (sub()
470
+ result = (sub()
580
471
  end sub)()
581
472
  end sub
582
473
  `);
@@ -585,7 +476,7 @@ describe('BrsFile', () => {
585
476
  it('uses the proper parse mode based on file extension', () => {
586
477
  function testParseMode(destPath, expectedParseMode) {
587
478
  const file = program.setFile(destPath, '');
588
- (0, chai_1.expect)(file.parseMode).to.equal(expectedParseMode);
479
+ (0, chai_config_spec_1.expect)(file.parseMode).to.equal(expectedParseMode);
589
480
  }
590
481
  testParseMode('source/main.brs', Parser_1.ParseMode.BrightScript);
591
482
  testParseMode('source/main.spec.brs', Parser_1.ParseMode.BrightScript);
@@ -595,26 +486,46 @@ describe('BrsFile', () => {
595
486
  testParseMode('source/main.spec.bs', Parser_1.ParseMode.BrighterScript);
596
487
  });
597
488
  it('supports labels and goto statements', () => {
598
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
489
+ let file = program.setFile('source/main.brs', `
599
490
  sub Main()
600
491
  'multiple goto statements on one line
601
- goto myLabel: goto myLabel
492
+ goto myLabel : goto myLabel
602
493
  myLabel:
603
494
  end sub
604
495
  `);
605
496
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
606
497
  });
607
498
  it('supports empty print statements', () => {
608
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
499
+ let file = program.setFile('source/main.brs', `
609
500
  sub main()
610
- print
501
+ print
611
502
  end sub
612
503
  `);
613
504
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
614
505
  });
615
506
  describe('conditional compile', () => {
507
+ it('supports case-insensitive bs_const variables', () => {
508
+ fsExtra.outputFileSync(`${testHelpers_spec_2.rootDir}/manifest`, (0, undent_1.default) `
509
+ bs_const=SomeKey=true
510
+ `);
511
+ program.setFile('source/main.brs', `
512
+ sub something()
513
+ #if somekey
514
+ print "lower"
515
+ #end if
516
+ #if SOMEKEY
517
+ print "UPPER"
518
+ #end if
519
+ #if SomeKey
520
+ print "MiXeD"
521
+ #end if
522
+ end sub
523
+ `);
524
+ program.validate();
525
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
526
+ });
616
527
  it('works for upper case keywords', () => {
617
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
528
+ let file = program.setFile('source/main.brs', `
618
529
  sub main()
619
530
  #CONST someFlag = true
620
531
  #IF someFlag
@@ -629,7 +540,7 @@ describe('BrsFile', () => {
629
540
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
630
541
  });
631
542
  it('supports single-word #elseif and #endif', () => {
632
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
543
+ let file = program.setFile('source/main.brs', `
633
544
  sub main()
634
545
  #const someFlag = true
635
546
  #if someFlag
@@ -642,7 +553,7 @@ describe('BrsFile', () => {
642
553
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
643
554
  });
644
555
  it('supports multi-word #else if and #end if', () => {
645
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
556
+ let file = program.setFile('source/main.brs', `
646
557
  sub main()
647
558
  #const someFlag = true
648
559
  #if someFlag
@@ -655,17 +566,17 @@ describe('BrsFile', () => {
655
566
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
656
567
  });
657
568
  it('does not choke on invalid code inside a false conditional compile', () => {
658
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
569
+ let file = program.setFile('source/main.brs', `
659
570
  sub main()
660
571
  #if false
661
- non - commented code here should not cause parse errors
572
+ non-commented code here should not cause parse errors
662
573
  #end if
663
574
  end sub
664
575
  `);
665
576
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
666
577
  });
667
578
  it('detects syntax error in #if', () => {
668
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
579
+ let file = program.setFile('source/main.brs', `
669
580
  sub main()
670
581
  #if true1
671
582
  print "true"
@@ -677,7 +588,7 @@ describe('BrsFile', () => {
677
588
  ]);
678
589
  });
679
590
  it('detects syntax error in #const', () => {
680
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
591
+ let file = program.setFile('source/main.brs', `
681
592
  sub main()
682
593
  #if %
683
594
  print "true"
@@ -690,7 +601,7 @@ describe('BrsFile', () => {
690
601
  ]);
691
602
  });
692
603
  it('detects #const name using reserved word', () => {
693
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
604
+ let file = program.setFile('source/main.brs', `
694
605
  sub main()
695
606
  #const function = true
696
607
  end sub
@@ -701,7 +612,7 @@ describe('BrsFile', () => {
701
612
  ]);
702
613
  });
703
614
  it('detects syntax error in #const', () => {
704
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
615
+ let file = program.setFile('source/main.brs', `
705
616
  sub main()
706
617
  #const someConst = 123
707
618
  end sub
@@ -712,22 +623,22 @@ describe('BrsFile', () => {
712
623
  });
713
624
  });
714
625
  it('supports stop statement', () => {
715
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
626
+ let file = program.setFile('source/main.brs', `
716
627
  sub main()
717
- stop
628
+ stop
718
629
  end sub
719
630
  `);
720
631
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
721
632
  });
722
633
  it('supports single-line if statements', () => {
723
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
634
+ let file = program.setFile('source/main.brs', `
724
635
  sub main()
725
636
  if 1 < 2: return true: end if
726
637
  if 1 < 2: return true
727
638
  end if
728
639
  if false : print "true" : end if
729
640
  if true: print "8 worked": else if true: print "not run": else: print "not run": end if
730
- if true then: test = sub() : print "yes" : end sub: end if
641
+ if true then : test = sub() : print "yes" : end sub : end if
731
642
  end sub
732
643
  `);
733
644
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
@@ -812,7 +723,7 @@ describe('BrsFile', () => {
812
723
  print &he2
813
724
  print 1.2E+2
814
725
  print 2!
815
- print 12D - 12
726
+ print 12D-12
816
727
  print 2.3#
817
728
  print &hFEDCBA9876543210&
818
729
  print 9876543210&
@@ -828,7 +739,7 @@ describe('BrsFile', () => {
828
739
  `);
829
740
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
830
741
  });
831
- it('does not lose function statements when mismatched end sub', () => {
742
+ it('does not lose function scopes when mismatched end sub', () => {
832
743
  file.parse(`
833
744
  sub main()
834
745
  sayHi()
@@ -838,7 +749,7 @@ describe('BrsFile', () => {
838
749
  print "hello world"
839
750
  end sub
840
751
  `);
841
- (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);
842
753
  });
843
754
  it('does not lose sub scope when mismatched end function', () => {
844
755
  file.parse(`
@@ -850,7 +761,7 @@ describe('BrsFile', () => {
850
761
  print "hello world"
851
762
  end sub
852
763
  `);
853
- (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);
854
765
  });
855
766
  it('does not error with boolean in RHS of set statement', () => {
856
767
  file.parse(`
@@ -879,11 +790,11 @@ describe('BrsFile', () => {
879
790
  it('supports variable names ending with type designators', () => {
880
791
  file.parse(`
881
792
  sub main()
882
- name$ = "bob"
883
- age% = 1
884
- height! = 5.5
885
- salary# = 9.87654321
886
- someHex& = 13
793
+ name$ = "bob"
794
+ age% = 1
795
+ height! = 5.5
796
+ salary# = 9.87654321
797
+ someHex& = 13
887
798
  end sub
888
799
  `);
889
800
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
@@ -893,7 +804,7 @@ describe('BrsFile', () => {
893
804
  sub main()
894
805
  if true then
895
806
  print "true"
896
- else if true then
807
+ else if true then
897
808
  print "also true"
898
809
  end if
899
810
  end sub
@@ -904,9 +815,9 @@ describe('BrsFile', () => {
904
815
  file.parse(`
905
816
  function GetObject()
906
817
  obj = {
907
- stop: function () as void
818
+ stop: function() as void
908
819
 
909
- end function
820
+ end function
910
821
  }
911
822
  return obj
912
823
  end function
@@ -917,10 +828,10 @@ describe('BrsFile', () => {
917
828
  file.parse(`
918
829
  function GetObject()
919
830
  obj = {
920
- run: function () as void
831
+ run: function() as void
921
832
 
922
833
  end function
923
- }
834
+ }
924
835
  return obj
925
836
  end function
926
837
  `);
@@ -948,7 +859,7 @@ describe('BrsFile', () => {
948
859
  function Main()
949
860
  promise = {
950
861
  then: sub()
951
- end sub
862
+ end sub
952
863
  }
953
864
  promise.then()
954
865
  end function
@@ -958,7 +869,8 @@ describe('BrsFile', () => {
958
869
  it('supports function as parameter type', () => {
959
870
  file.parse(`
960
871
  sub Main()
961
- doWork = function (callback as function)
872
+ doWork = function(callback as function)
873
+ callback()
962
874
  end function
963
875
  end sub
964
876
  `);
@@ -1074,7 +986,7 @@ describe('BrsFile', () => {
1074
986
  sub main()
1075
987
  end sub
1076
988
  import "file.brs"
1077
- `);
989
+ `);
1078
990
  program.validate();
1079
991
  (0, testHelpers_spec_1.expectDiagnostics)(program, [
1080
992
  DiagnosticMessages_1.DiagnosticMessages.importStatementMustBeDeclaredAtTopOfFile()
@@ -1111,7 +1023,7 @@ describe('BrsFile', () => {
1111
1023
  it('supports colons as separators in associative array properties', () => {
1112
1024
  file.parse(`
1113
1025
  sub Main()
1114
- obj = { x: 0 : y: 1 }
1026
+ obj = {x:0 : y: 1}
1115
1027
  end sub
1116
1028
  `);
1117
1029
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
@@ -1122,47 +1034,59 @@ describe('BrsFile', () => {
1122
1034
  return value.subType()
1123
1035
  end function
1124
1036
  `);
1125
- (0, chai_1.expect)(file.callables[0]).to.deep.include({
1037
+ (0, chai_config_spec_1.expect)(file.callables[0]).to.deep.include({
1126
1038
  file: file,
1127
1039
  nameRange: vscode_languageserver_1.Range.create(1, 25, 1, 36)
1128
1040
  });
1129
1041
  });
1130
1042
  it('succeeds when finding variables with the word "function" in them', () => {
1131
1043
  file.parse(`
1132
- function Test()
1133
- typeCheckFunction = RBS_CMN_GetFunction(invalid, methodName)
1044
+ function Test()
1045
+ typeCheckFunction = RBS_CMN_GetFunction(invalid, methodName)
1134
1046
  end function
1135
1047
  `);
1136
1048
  });
1137
1049
  it('finds line and column numbers for functions', () => {
1138
- 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
+ });
1139
1055
  file.parse(`
1140
1056
  function DoA()
1141
1057
  print "A"
1142
1058
  end function
1143
1059
 
1144
- function DoB()
1145
- print "B"
1146
- end function
1060
+ function DoB()
1061
+ print "B"
1062
+ end function
1147
1063
  `);
1148
- (0, chai_1.expect)(file.callables[0].name).to.equal('DoA');
1149
- (0, chai_1.expect)(file.callables[0].nameRange).to.eql(vscode_languageserver_1.Range.create(1, 25, 1, 28));
1150
- (0, chai_1.expect)(file.callables[1].name).to.equal('DoB');
1151
- (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));
1152
1068
  });
1153
1069
  it('throws an error if the file has already been parsed', () => {
1154
- 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
+ });
1155
1075
  file.parse(`'a comment`);
1156
1076
  try {
1157
1077
  file.parse(`'a new comment`);
1158
- 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');
1159
1079
  }
1160
1080
  catch (e) {
1161
1081
  //test passes
1162
1082
  }
1163
1083
  });
1164
1084
  it('finds and registers duplicate callables', () => {
1165
- 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
+ });
1166
1090
  file.parse(`
1167
1091
  function DoA()
1168
1092
  print "A"
@@ -1172,14 +1096,18 @@ describe('BrsFile', () => {
1172
1096
  print "A"
1173
1097
  end function
1174
1098
  `);
1175
- (0, chai_1.expect)(file.callables.length).to.equal(2);
1176
- (0, chai_1.expect)(file.callables[0].name).to.equal('DoA');
1177
- (0, chai_1.expect)(file.callables[0].nameRange.start.line).to.equal(1);
1178
- (0, chai_1.expect)(file.callables[1].name).to.equal('DoA');
1179
- (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);
1180
1104
  });
1181
1105
  it('finds function call line and column numbers', () => {
1182
- 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
+ });
1183
1111
  file.parse(`
1184
1112
  function DoA()
1185
1113
  DoB("a")
@@ -1188,24 +1116,59 @@ describe('BrsFile', () => {
1188
1116
  DoC()
1189
1117
  end function
1190
1118
  `);
1191
- (0, chai_1.expect)(file.functionCalls.length).to.equal(2);
1192
- (0, chai_1.expect)(file.functionCalls[0].range).to.eql(vscode_languageserver_1.Range.create(2, 20, 2, 28));
1193
- (0, chai_1.expect)(file.functionCalls[0].nameRange).to.eql(vscode_languageserver_1.Range.create(2, 20, 2, 23));
1194
- (0, chai_1.expect)(file.functionCalls[1].range).to.eql(vscode_languageserver_1.Range.create(5, 20, 5, 25));
1195
- (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));
1196
1151
  });
1197
1152
  it('sanitizes brs errors', () => {
1198
- 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
+ });
1199
1158
  file.parse(`
1200
1159
  function DoSomething
1201
1160
  end function
1202
1161
  `);
1203
1162
  (0, testHelpers_spec_1.expectHasDiagnostics)(file);
1204
- (0, chai_1.expect)(file.getDiagnostics()[0].file).to.equal(file);
1205
- (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);
1206
1165
  });
1207
1166
  it('supports using the `next` keyword in a for loop', () => {
1208
- 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
+ });
1209
1172
  file.parse(`
1210
1173
  sub countit()
1211
1174
  for each num in [1,2,3]
@@ -1217,7 +1180,11 @@ describe('BrsFile', () => {
1217
1180
  });
1218
1181
  //test is not working yet, but will be enabled when brs supports this syntax
1219
1182
  it('supports assigning functions to objects', () => {
1220
- 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
+ });
1221
1188
  file.parse(`
1222
1189
  function main()
1223
1190
  o = CreateObject("roAssociativeArray")
@@ -1228,20 +1195,42 @@ describe('BrsFile', () => {
1228
1195
  `);
1229
1196
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
1230
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
+ });
1231
1212
  });
1232
1213
  describe('findCallables', () => {
1233
1214
  it('finds range', () => {
1234
- 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
+ });
1235
1220
  file.parse(`
1236
1221
  sub Sum()
1237
1222
  print "hello world"
1238
1223
  end sub
1239
1224
  `);
1240
1225
  let callable = file.callables[0];
1241
- (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));
1242
1227
  });
1243
1228
  it('finds correct body range even with inner function', () => {
1244
- 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
+ });
1245
1234
  file.parse(`
1246
1235
  sub Sum()
1247
1236
  sayHi = sub()
@@ -1251,101 +1240,117 @@ describe('BrsFile', () => {
1251
1240
  end sub
1252
1241
  `);
1253
1242
  let callable = file.callables[0];
1254
- (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));
1255
1244
  });
1256
1245
  it('finds callable parameters', () => {
1257
- 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
+ });
1258
1251
  file.parse(`
1259
1252
  function Sum(a, b, c)
1260
1253
 
1261
1254
  end function
1262
1255
  `);
1263
1256
  let callable = file.callables[0];
1264
- (0, chai_1.expect)(callable.params[0]).to.deep.include({
1257
+ (0, chai_config_spec_1.expect)(callable.params[0]).to.deep.include({
1265
1258
  name: 'a',
1266
1259
  isOptional: false,
1267
1260
  isRestArgument: false
1268
1261
  });
1269
- (0, chai_1.expect)(callable.params[0].type).instanceof(DynamicType_1.DynamicType);
1270
- (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({
1271
1264
  name: 'b',
1272
1265
  isOptional: false,
1273
1266
  isRestArgument: false
1274
1267
  });
1275
- (0, chai_1.expect)(callable.params[1].type).instanceof(DynamicType_1.DynamicType);
1276
- (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({
1277
1270
  name: 'c',
1278
1271
  isOptional: false,
1279
1272
  isRestArgument: false
1280
1273
  });
1281
- (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);
1282
1275
  });
1283
1276
  it('finds optional parameters', () => {
1284
- 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
+ });
1285
1282
  file.parse(`
1286
1283
  function Sum(a=2)
1287
1284
 
1288
1285
  end function
1289
1286
  `);
1290
1287
  let callable = file.callables[0];
1291
- (0, chai_1.expect)(callable.params[0]).to.deep.include({
1288
+ (0, chai_config_spec_1.expect)(callable.params[0]).to.deep.include({
1292
1289
  name: 'a',
1293
1290
  isOptional: true,
1294
1291
  isRestArgument: false
1295
1292
  });
1296
- (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);
1297
1294
  });
1298
1295
  it('finds parameter types', () => {
1299
- 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
+ });
1300
1301
  file.parse(`
1301
1302
  function Sum(a, b as integer, c as string)
1302
1303
 
1303
1304
  end function
1304
1305
  `);
1305
1306
  let callable = file.callables[0];
1306
- (0, chai_1.expect)(callable.params[0]).to.deep.include({
1307
+ (0, chai_config_spec_1.expect)(callable.params[0]).to.deep.include({
1307
1308
  name: 'a',
1308
1309
  isOptional: false,
1309
1310
  isRestArgument: false
1310
1311
  });
1311
- (0, chai_1.expect)(callable.params[0].type).instanceof(DynamicType_1.DynamicType);
1312
- (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({
1313
1314
  name: 'b',
1314
1315
  isOptional: false,
1315
1316
  isRestArgument: false
1316
1317
  });
1317
- (0, chai_1.expect)(callable.params[1].type).instanceof(IntegerType_1.IntegerType);
1318
- (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({
1319
1320
  name: 'c',
1320
1321
  isOptional: false,
1321
1322
  isRestArgument: false
1322
1323
  });
1323
- (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);
1324
1325
  });
1325
1326
  });
1326
1327
  describe('findCallableInvocations', () => {
1327
1328
  it('finds arguments with literal values', () => {
1328
- 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
+ });
1329
1334
  file.parse(`
1330
1335
  function Sum()
1331
1336
  DoSomething("name", 12, true)
1332
1337
  end function
1333
1338
  `);
1334
- (0, chai_1.expect)(file.functionCalls.length).to.equal(1);
1339
+ (0, chai_config_spec_1.expect)(file.functionCalls.length).to.equal(1);
1335
1340
  const argsMap = file.functionCalls[0].args.map(arg => {
1336
1341
  // disregard arg.expression, etc.
1337
1342
  return { type: arg.type, range: arg.range, text: arg.text };
1338
1343
  });
1339
- (0, chai_1.expect)(argsMap).to.eql([{
1340
- type: new StringType_1.StringType(),
1344
+ (0, chai_config_spec_1.expect)(argsMap).to.eql([{
1345
+ type: StringType_1.StringType.instance,
1341
1346
  range: util_1.default.createRange(2, 32, 2, 38),
1342
1347
  text: '"name"'
1343
1348
  }, {
1344
- type: new IntegerType_1.IntegerType(),
1349
+ type: IntegerType_1.IntegerType.instance,
1345
1350
  range: util_1.default.createRange(2, 40, 2, 42),
1346
1351
  text: '12'
1347
1352
  }, {
1348
- type: new BooleanType_1.BooleanType(),
1353
+ type: BooleanType_1.BooleanType.instance,
1349
1354
  range: util_1.default.createRange(2, 44, 2, 48),
1350
1355
  text: 'true'
1351
1356
  }]);
@@ -1360,11 +1365,15 @@ describe('BrsFile', () => {
1360
1365
  `);
1361
1366
  program.validate();
1362
1367
  (0, testHelpers_spec_1.expectDiagnostics)(program, [
1363
- DiagnosticMessages_1.DiagnosticMessages.callToUnknownFunction('DoesNotExist', 'source')
1368
+ DiagnosticMessages_1.DiagnosticMessages.cannotFindName('DoesNotExist')
1364
1369
  ]);
1365
1370
  });
1366
1371
  it('finds arguments with variable values', () => {
1367
- 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
+ });
1368
1377
  file.parse(`
1369
1378
  function Sum()
1370
1379
  count = 1
@@ -1373,17 +1382,17 @@ describe('BrsFile', () => {
1373
1382
  DoSomething(count, name, isAlive)
1374
1383
  end function
1375
1384
  `);
1376
- (0, chai_1.expect)(file.functionCalls.length).to.equal(1);
1377
- (0, chai_1.expect)(file.functionCalls[0].args[0]).deep.include({
1378
- 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(),
1379
1388
  text: 'count'
1380
1389
  });
1381
- (0, chai_1.expect)(file.functionCalls[0].args[1]).deep.include({
1382
- 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(),
1383
1392
  text: 'name'
1384
1393
  });
1385
- (0, chai_1.expect)(file.functionCalls[0].args[2]).deep.include({
1386
- 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(),
1387
1396
  text: 'isAlive'
1388
1397
  });
1389
1398
  });
@@ -1391,32 +1400,36 @@ describe('BrsFile', () => {
1391
1400
  describe('findCallables', () => {
1392
1401
  //this test is to help with code coverage
1393
1402
  it('skips top-level statements', () => {
1394
- 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
+ });
1395
1408
  file.parse('name = "Bob"');
1396
- (0, chai_1.expect)(file.callables.length).to.equal(0);
1409
+ (0, chai_config_spec_1.expect)(file.callables.length).to.equal(0);
1397
1410
  });
1398
1411
  it('finds return type', () => {
1399
1412
  let file = program.setFile('source/main.brs', `
1400
1413
  function DoSomething() as string
1401
1414
  end function
1402
1415
  `);
1403
- (0, chai_1.expect)(file.callables[0]).to.deep.include({
1416
+ (0, chai_config_spec_1.expect)(file.callables[0]).to.deep.include({
1404
1417
  file: file,
1405
1418
  nameRange: vscode_languageserver_1.Range.create(1, 25, 1, 36),
1406
1419
  name: 'DoSomething',
1407
1420
  params: []
1408
1421
  });
1409
- (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);
1410
1423
  });
1411
1424
  });
1412
- describe('function local variable handling', () => {
1425
+ describe('createFunctionScopes', () => {
1413
1426
  it('creates range properly', () => {
1414
1427
  file.parse(`
1415
1428
  sub Main()
1416
1429
  name = 'bob"
1417
1430
  end sub
1418
1431
  `);
1419
- (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));
1420
1433
  });
1421
1434
  it('creates scopes for parent and child functions', () => {
1422
1435
  file.parse(`
@@ -1430,9 +1443,23 @@ describe('BrsFile', () => {
1430
1443
  end sub)
1431
1444
  end sub
1432
1445
  `);
1433
- (0, chai_1.expect)(file.parser.references.functionExpressions).to.be.length(3);
1446
+ (0, chai_config_spec_1.expect)(file.functionScopes).to.length(3);
1447
+ });
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);
1434
1461
  });
1435
- it('finds variables declared in function expressions', () => {
1462
+ it('finds variables declared in function scopes', () => {
1436
1463
  file.parse(`
1437
1464
  sub Main()
1438
1465
  sayHi = sub()
@@ -1444,15 +1471,24 @@ describe('BrsFile', () => {
1444
1471
  end sub)
1445
1472
  end sub
1446
1473
  `);
1447
- (0, testHelpers_spec_1.expectSymbolTableEquals)(file.parser.references.functionExpressions[0].symbolTable, [
1448
- ['sayHi', new TypedFunctionType_1.TypedFunctionType(new VoidType_1.VoidType(), true), util_1.default.createRange(2, 20, 2, 25)]
1449
- ]);
1450
- (0, testHelpers_spec_1.expectSymbolTableEquals)(file.parser.references.functionExpressions[1].symbolTable, [
1451
- ['age', new IntegerType_1.IntegerType(), util_1.default.createRange(3, 24, 3, 27)]
1452
- ]);
1453
- (0, testHelpers_spec_1.expectSymbolTableEquals)(file.parser.references.functionExpressions[2].symbolTable, [
1454
- ['name', new StringType_1.StringType(), util_1.default.createRange(7, 24, 7, 28)]
1455
- ]);
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);
1456
1492
  });
1457
1493
  it('finds variable declarations inside of if statements', () => {
1458
1494
  file.parse(`
@@ -1462,9 +1498,9 @@ describe('BrsFile', () => {
1462
1498
  end if
1463
1499
  end sub
1464
1500
  `);
1465
- (0, testHelpers_spec_1.expectSymbolTableEquals)(file.parser.references.functionExpressions[0].symbolTable, [
1466
- ['theLength', new IntegerType_1.IntegerType(), util_1.default.createRange(3, 24, 3, 33)]
1467
- ]);
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');
1468
1504
  });
1469
1505
  it('finds value from global return', () => {
1470
1506
  let file = program.setFile('source/main.brs', `
@@ -1476,21 +1512,31 @@ describe('BrsFile', () => {
1476
1512
  return "bob"
1477
1513
  end function
1478
1514
  `);
1479
- (0, testHelpers_spec_1.expectSymbolTableEquals)(file.parser.references.functionExpressions[0].symbolTable, [
1480
- ['myName', new StringType_1.StringType(), util_1.default.createRange(2, 19, 2, 25)]
1481
- ]);
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);
1482
1524
  });
1483
1525
  it('finds variable type from other variable', () => {
1484
- file.parse(`
1526
+ let file = program.setFile('source/main.brs', `
1485
1527
  sub Main()
1486
- name = "bob"
1487
- nameCopy = name
1528
+ name = "bob"
1529
+ nameCopy = name
1488
1530
  end sub
1489
1531
  `);
1490
- (0, testHelpers_spec_1.expectSymbolTableEquals)(file.parser.references.functionExpressions[0].symbolTable, [
1491
- ['name', new StringType_1.StringType(), util_1.default.createRange(2, 20, 2, 24)],
1492
- ['nameCopy', new StringType_1.StringType(), util_1.default.createRange(3, 20, 3, 28)]
1493
- ]);
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);
1494
1540
  });
1495
1541
  it('sets proper range for functions', () => {
1496
1542
  file.parse(`
@@ -1500,432 +1546,39 @@ describe('BrsFile', () => {
1500
1546
  end function
1501
1547
  end sub
1502
1548
  `);
1503
- (0, chai_1.expect)(file.parser.references.functionExpressions.map(x => x.range)).to.eql([
1504
- util_1.default.createRange(1, 16, 5, 23),
1505
- util_1.default.createRange(2, 30, 4, 32)
1506
- ]);
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));
1507
1552
  });
1508
1553
  });
1509
- describe('getHover', () => {
1510
- it('works for param types', () => {
1511
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
1512
- sub DoSomething(name as string)
1513
- name = 1
1514
- sayMyName = function (name as string)
1515
- end function
1516
- end sub
1517
- `);
1518
- //hover over the `name = 1` line
1519
- let hover = file.getHover(vscode_languageserver_1.Position.create(2, 24));
1520
- (0, chai_1.expect)(hover).to.exist;
1521
- (0, chai_1.expect)(hover.range).to.eql(vscode_languageserver_1.Range.create(2, 20, 2, 24));
1522
- //hover over the `name` parameter declaration
1523
- hover = file.getHover(vscode_languageserver_1.Position.create(1, 34));
1524
- (0, chai_1.expect)(hover).to.exist;
1525
- (0, chai_1.expect)(hover.range).to.eql(vscode_languageserver_1.Range.create(1, 32, 1, 36));
1526
- });
1527
- //ignore this for now...it's not a huge deal
1528
- it('does not match on keywords or data types', () => {
1529
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
1530
- sub Main(name as string)
1531
- end sub
1532
- sub as ()
1533
- end sub
1534
- `);
1535
- //hover over the `as `
1536
- (0, chai_1.expect)(file.getHover(vscode_languageserver_1.Position.create(1, 31))).not.to.exist;
1537
- //hover over the `string`
1538
- (0, chai_1.expect)(file.getHover(vscode_languageserver_1.Position.create(1, 36))).not.to.exist;
1539
- });
1540
- it('finds declared function', () => {
1541
- let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
1542
- function Main(count = 1)
1543
- firstName = "bob"
1544
- age = 21
1545
- shoeSize = 10
1546
- end function
1547
- `);
1548
- let hover = file.getHover(vscode_languageserver_1.Position.create(1, 28));
1549
- (0, chai_1.expect)(hover).to.exist;
1550
- (0, chai_1.expect)(hover.range).to.eql(vscode_languageserver_1.Range.create(1, 25, 1, 29));
1551
- (0, chai_1.expect)(hover.contents).to.equal([
1552
- '```brightscript',
1553
- 'function Main(count? as integer) as dynamic',
1554
- '```'
1555
- ].join('\n'));
1556
- });
1557
- it('finds declared namespace function', () => {
1558
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1559
- namespace mySpace
1560
- function Main(count = 1)
1561
- firstName = "bob"
1562
- age = 21
1563
- shoeSize = 10
1564
- end function
1565
- end namespace
1566
- `);
1567
- let hover = file.getHover(vscode_languageserver_1.Position.create(2, 28));
1568
- (0, chai_1.expect)(hover).to.exist;
1569
- (0, chai_1.expect)(hover.range).to.eql(vscode_languageserver_1.Range.create(2, 25, 2, 29));
1570
- (0, chai_1.expect)(hover.contents).to.equal([
1571
- '```brightscript',
1572
- 'function Main(count? as integer) as dynamic',
1573
- '```'
1574
- ].join('\n'));
1575
- });
1576
- it('finds variable function hover in same scope', () => {
1577
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1578
- sub Main()
1579
- sayMyName = sub(name as string)
1580
- end sub
1581
-
1582
- sayMyName()
1583
- end sub
1584
- `);
1585
- let hover = file.getHover(vscode_languageserver_1.Position.create(5, 24));
1586
- (0, chai_1.expect)(hover.range).to.eql(vscode_languageserver_1.Range.create(5, 20, 5, 29));
1587
- (0, chai_1.expect)(hover.contents).to.equal([
1588
- '```brightscript',
1589
- 'sub (name as string) as void',
1590
- '```'
1591
- ].join('\n'));
1592
- });
1593
- it('does not crash when hovering on built-in functions', async () => {
1594
- let file = program.setFile('source/main.brs', `
1595
- function doUcase(text)
1596
- return ucase(text)
1597
- end function
1598
- `);
1599
- (0, chai_1.expect)((await program.getHover(file.srcPath, vscode_languageserver_1.Position.create(2, 30))).contents).to.equal([
1600
- '```brightscript',
1601
- 'function UCase(s as string) as string',
1602
- '```'
1603
- ].join('\n'));
1604
- });
1605
- it('does not crash when hovering on object method call', async () => {
1606
- let file = program.setFile('source/main.brs', `
1607
- function getInstr(url, text)
1608
- return url.instr(text)
1609
- end function
1610
- `);
1611
- (0, chai_1.expect)((await program.getHover(file.srcPath, vscode_languageserver_1.Position.create(2, 35))).contents).to.equal([
1612
- '```brightscript',
1613
- 'instr as dynamic',
1614
- '```'
1615
- ].join('\n'));
1616
- });
1617
- it('finds function hover in file scope', () => {
1618
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1619
- sub Main()
1620
- sayMyName()
1621
- end sub
1622
-
1623
- sub sayMyName()
1624
-
1625
- end sub
1626
- `);
1627
- let hover = file.getHover(vscode_languageserver_1.Position.create(2, 25));
1628
- (0, chai_1.expect)(hover.range).to.eql(vscode_languageserver_1.Range.create(2, 20, 2, 29));
1629
- (0, chai_1.expect)(hover.contents).to.equal([
1630
- '```brightscript',
1631
- 'sub sayMyName() as void',
1632
- '```'
1633
- ].join('\n'));
1634
- });
1635
- it('finds namespace function hover in file scope', () => {
1636
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1637
- namespace mySpace
1638
- sub Main()
1639
- sayMyName()
1640
- end sub
1641
-
1642
- sub sayMyName()
1643
-
1644
- end sub
1645
- end namespace
1646
- `);
1647
- let hover = file.getHover(vscode_languageserver_1.Position.create(3, 25));
1648
- (0, chai_1.expect)(hover.range).to.eql(vscode_languageserver_1.Range.create(3, 20, 3, 29));
1649
- (0, chai_1.expect)(hover.contents).to.equal([
1650
- '```brightscript',
1651
- 'sub sayMyName() as void',
1652
- '```'
1653
- ].join('\n'));
1654
- });
1655
- it('finds function hover in scope', () => {
1656
- let rootDir = process.cwd();
1657
- program = new Program_1.Program({
1658
- rootDir: rootDir
1659
- });
1660
- let mainFile = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1661
- sub Main()
1662
- sayMyName()
1663
- end sub
1664
- `);
1665
- program.setFile({ src: `${rootDir}/source/lib.brs`, dest: 'source/lib.brs' }, `
1666
- sub sayMyName(name as string)
1667
-
1668
- end sub
1669
- `);
1670
- let hover = mainFile.getHover(vscode_languageserver_1.Position.create(2, 25));
1671
- (0, chai_1.expect)(hover).to.exist;
1672
- (0, chai_1.expect)(hover.range).to.eql(vscode_languageserver_1.Range.create(2, 20, 2, 29));
1673
- (0, chai_1.expect)(hover.contents).to.equal([
1674
- '```brightscript',
1675
- 'sub sayMyName(name as string) as void',
1676
- '```'
1677
- ].join('\n'));
1678
- });
1679
- it('finds namespace function hover in scope', () => {
1680
- let rootDir = process.cwd();
1681
- program = new Program_1.Program({
1682
- rootDir: rootDir
1683
- });
1684
- let mainFile = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1685
- sub Main()
1686
- mySpace.sayMyName()
1687
- end sub
1688
- `);
1689
- program.setFile({ src: `${rootDir}/source/lib.brs`, dest: 'source/lib.brs' }, `
1690
- namespace mySpace
1691
- sub sayMyName(name as string)
1692
- end sub
1693
- end namespace
1694
- `);
1695
- let hover = mainFile.getHover(vscode_languageserver_1.Position.create(2, 34));
1696
- (0, chai_1.expect)(hover).to.exist;
1697
- (0, chai_1.expect)(hover.range).to.eql(vscode_languageserver_1.Range.create(2, 28, 2, 37));
1698
- (0, chai_1.expect)(hover.contents).to.equal([
1699
- '```brightscript',
1700
- 'sub sayMyName(name as string) as void',
1701
- '```'
1702
- ].join('\n'));
1703
- });
1704
- it('includes markdown comments in hover.', async () => {
1705
- let rootDir = process.cwd();
1706
- program = new Program_1.Program({
1707
- rootDir: rootDir
1708
- });
1709
- const file = program.setFile('source/lib.brs', `
1710
- '
1711
- ' The main function
1712
- '
1713
- sub main()
1714
- log("hello")
1715
- end sub
1716
-
1717
- '
1718
- ' Prints a message to the log.
1719
- ' Works with *markdown* **content**
1720
- '
1721
- sub log(message as string)
1722
- print message
1723
- end sub
1724
- `);
1725
- //hover over log("hello")
1726
- (0, chai_1.expect)((await program.getHover(file.srcPath, vscode_languageserver_1.Position.create(5, 22))).contents).to.equal([
1727
- '```brightscript',
1728
- 'sub log(message as string) as void',
1729
- '```',
1730
- '***',
1731
- '',
1732
- ' Prints a message to the log.',
1733
- ' Works with *markdown* **content**',
1734
- ''
1735
- ].join('\n'));
1736
- //hover over sub ma|in()
1737
- (0, chai_1.expect)((0, testHelpers_spec_1.trim)((await program.getHover(file.srcPath, vscode_languageserver_1.Position.create(4, 22))).contents.toString())).to.equal((0, testHelpers_spec_1.trim) `
1738
- \`\`\`brightscript
1739
- sub main() as void
1740
- \`\`\`
1741
- ***
1742
-
1743
- The main function
1744
- `);
1745
- });
1746
- it('handles mixed case `then` partions of conditionals', () => {
1747
- let mainFile = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1748
- sub Main()
1749
- if true then
1750
- print "works"
1751
- end if
1752
- end sub
1753
- `);
1754
- (0, testHelpers_spec_1.expectZeroDiagnostics)(mainFile);
1755
- mainFile = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1756
- sub Main()
1757
- if true Then
1758
- print "works"
1759
- end if
1760
- end sub
1761
- `);
1762
- (0, testHelpers_spec_1.expectZeroDiagnostics)(mainFile);
1763
- mainFile = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1764
- sub Main()
1765
- if true THEN
1766
- print "works"
1767
- end if
1768
- end sub
1769
- `);
1770
- (0, testHelpers_spec_1.expectZeroDiagnostics)(mainFile);
1771
- });
1772
- it('displays the context from multiple scopes', () => {
1773
- let commonFile = program.setFile('source/common.brs', `
1774
- sub displayPi()
1775
- pi = getPi()
1776
- print pi
1777
- end sub
1778
- `);
1779
- let scope1File = program.setFile('components/comp1/scope1.brs', `
1780
- function getPi() as string
1781
- return "apple"
1782
- end function
1783
- `);
1784
- (0, chai_1.expect)(scope1File.getDiagnostics()).to.be.lengthOf(0);
1785
- program.setFile('components/comp1/comp1.xml', (0, testHelpers_spec_1.trim) `
1786
- <?xml version="1.0" encoding="utf-8" ?>
1787
- <component name="Component1" extends="Group">
1788
- <script type="text/brightscript" uri="scope1.brs" />
1789
- <script type="text/brightscript" uri="pkg:/source/common.brs" />
1790
- </component>
1791
- `);
1792
- let scope2File = program.setFile('components/comp2/scope2.brs', `
1793
- function getPi() as float
1794
- return 3.14
1795
- end function
1796
- `);
1797
- (0, chai_1.expect)(scope2File.getDiagnostics()).to.be.lengthOf(0);
1798
- program.setFile('components/comp2/comp2.xml', (0, testHelpers_spec_1.trim) `
1799
- <?xml version="1.0" encoding="utf-8" ?>
1800
- <component name="Component2" extends="Group">
1801
- <script type="text/brightscript" uri="scope2.brs" />
1802
- <script type="text/brightscript" uri="pkg:/source/common.brs" />
1803
- </component>
1804
- `);
1805
- program.validate();
1806
- let funcCallHover = commonFile.getHover(vscode_languageserver_1.Position.create(2, 27));
1807
- (0, chai_1.expect)(funcCallHover === null || funcCallHover === void 0 ? void 0 : funcCallHover.contents).to.equal([
1808
- '```brightscript',
1809
- 'function getPi() as string | function getPi() as float | getPi as uninitialized',
1810
- '```'
1811
- ].join('\n'));
1812
- let variableHover = commonFile.getHover(vscode_languageserver_1.Position.create(3, 27));
1813
- (0, chai_1.expect)(variableHover === null || variableHover === void 0 ? void 0 : variableHover.contents).to.equal([
1814
- '```brightscript',
1815
- 'pi as string | pi as float | pi as uninitialized',
1816
- '```'
1817
- ].join('\n'));
1818
- });
1819
- it('finds function with custom types as parameters and return types', () => {
1820
- let file = program.setFile('source/main.bs', `
1821
- sub main()
1822
- k = new MyKlass()
1823
- processMyKlass(k)
1824
- end sub
1825
-
1826
- function processMyKlass(data as MyKlass) as MyKlass
1827
- return data
1828
- end function
1829
-
1830
- class MyKlass
1831
- end class
1832
- `);
1833
- let hover = file.getHover(vscode_languageserver_1.Position.create(3, 29));
1834
- (0, chai_1.expect)(hover).to.exist;
1835
- (0, chai_1.expect)(hover.contents).to.equal([
1836
- '```brightscript',
1837
- 'function processMyKlass(data as MyKlass) as MyKlass',
1838
- '```'
1839
- ].join('\n'));
1840
- });
1841
- it('finds function with arrays as parameters and return types', () => {
1842
- let file = program.setFile('source/main.bs', `
1843
- sub main()
1844
- k = new MyKlass()
1845
- processData([k])
1846
- end sub
1847
-
1848
- function processData(data as MyKlass[]) as MyKlass[]
1849
- return data
1850
- end function
1851
-
1852
- class MyKlass
1853
- end class
1854
- `);
1855
- let hover = file.getHover(vscode_languageserver_1.Position.create(3, 29));
1856
- (0, chai_1.expect)(hover).to.exist;
1857
- (0, chai_1.expect)(hover.contents).to.equal([
1858
- '```brightscript',
1859
- 'function processData(data as MyKlass[]) as MyKlass[]',
1860
- '```'
1861
- ].join('\n'));
1862
- });
1863
- it('display literal enum members', () => {
1864
- let file = program.setFile('source/main.bs', `
1865
- enum MyEnum
1866
- foo
1867
- bar
1868
- end enum
1869
-
1870
- sub main()
1871
- value = MyEnum.foo
1872
- print value
1873
- end sub
1874
- `);
1875
- let hover = file.getHover(vscode_languageserver_1.Position.create(7, 38)); // 'myEnum.foo' in value assignnmnt
1876
- (0, chai_1.expect)(hover).to.exist;
1877
- (0, chai_1.expect)(hover.contents).to.equal([
1878
- '```brightscript',
1879
- 'MyEnum.foo as MyEnum',
1880
- '```'
1881
- ].join('\n'));
1882
- });
1883
- it('finds enum values from assignments', () => {
1884
- let file = program.setFile('source/main.bs', `
1885
- enum MyEnum
1886
- foo
1887
- bar
1888
- end enum
1889
-
1890
- sub main()
1891
- value = MyEnum.foo
1892
- print value
1893
- end sub
1894
- `);
1895
- let hover = file.getHover(vscode_languageserver_1.Position.create(8, 30)); // 'value' in print statement
1896
- (0, chai_1.expect)(hover).to.exist;
1897
- (0, chai_1.expect)(hover.contents).to.equal([
1898
- '```brightscript',
1899
- 'value as MyEnum',
1900
- '```'
1901
- ].join('\n'));
1902
- });
1903
- it('finds enum values as parameters', () => {
1904
- let file = program.setFile('source/main.bs', `
1905
- enum MyEnum
1906
- foo
1907
- bar
1908
- end enum
1909
-
1910
- sub printEnum(enumParamVal as MyEnum)
1911
- print enumParamVal
1912
- end sub
1913
-
1914
- sub main()
1915
- printEnum(MyEnum.foo)
1916
- end sub
1917
- `);
1918
- let hover = file.getHover(vscode_languageserver_1.Position.create(7, 30)); // 'enumParamVal' in print statement
1919
- (0, chai_1.expect)(hover).to.exist;
1920
- (0, chai_1.expect)(hover.contents).to.equal([
1921
- '```brightscript',
1922
- 'enumParamVal as MyEnum',
1923
- '```'
1924
- ].join('\n'));
1925
- });
1554
+ it('handles mixed case `then` partions of conditionals', () => {
1555
+ let mainFile = program.setFile('source/main.brs', `
1556
+ sub Main()
1557
+ if true then
1558
+ print "works"
1559
+ end if
1560
+ end sub
1561
+ `);
1562
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(mainFile);
1563
+ mainFile = program.setFile('source/main.brs', `
1564
+ sub Main()
1565
+ if true Then
1566
+ print "works"
1567
+ end if
1568
+ end sub
1569
+ `);
1570
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(mainFile);
1571
+ mainFile = program.setFile('source/main.brs', `
1572
+ sub Main()
1573
+ if true THEN
1574
+ print "works"
1575
+ end if
1576
+ end sub
1577
+ `);
1578
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(mainFile);
1926
1579
  });
1927
1580
  it('does not throw when encountering incomplete import statement', () => {
1928
- program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1581
+ program.setFile('source/main.brs', `
1929
1582
  import
1930
1583
  sub main()
1931
1584
  end sub
@@ -1934,8 +1587,28 @@ describe('BrsFile', () => {
1934
1587
  //this test will throw an exception if something went wrong
1935
1588
  });
1936
1589
  describe('transpile', () => {
1937
- it('excludes trailing commas in array literals', () => {
1938
- testTranspile(`
1590
+ it('transpilies libpkg:/ paths when encountered', async () => {
1591
+ program.setFile('source/lib.bs', `
1592
+ import "libpkg:/source/numbers.bs"
1593
+ `);
1594
+ program.setFile('source/numbers.bs', `
1595
+ sub test()
1596
+ end sub
1597
+ `);
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');
1609
+ });
1610
+ it('excludes trailing commas in array literals', async () => {
1611
+ await testTranspile(`
1939
1612
  sub main()
1940
1613
  arr = [
1941
1614
  1,
@@ -1963,72 +1636,79 @@ describe('BrsFile', () => {
1963
1636
  end sub
1964
1637
  `);
1965
1638
  });
1966
- it('transpiles if statement keywords as provided', () => {
1639
+ it('transpiles if statement keywords as provided', async () => {
1967
1640
  const code = `
1968
- If True Then
1969
- Print True
1970
- Else If True Then
1971
- print True
1972
- Else If False Then
1973
- Print False
1974
- Else
1975
- Print False
1976
- End If
1641
+ sub main()
1642
+ If True Then
1643
+ Print True
1644
+ Else If True Then
1645
+ print True
1646
+ Else If False Then
1647
+ Print False
1648
+ Else
1649
+ Print False
1650
+ End If
1651
+ end sub
1977
1652
  `;
1978
- testTranspile(code);
1979
- testTranspile(code.toLowerCase());
1980
- testTranspile(code.toUpperCase());
1653
+ await testTranspile(code);
1654
+ await testTranspile(code.toLowerCase());
1655
+ await testTranspile(code.toUpperCase());
1981
1656
  });
1982
- it('does not transpile `then` tokens', () => {
1983
- const code = `
1984
- if true
1985
- print true
1986
- else if true
1987
- print false
1988
- end if
1989
- `;
1990
- testTranspile(code);
1991
- });
1992
- it('honors spacing between multi-word tokens', () => {
1993
- testTranspile(`
1994
- if true
1995
- print true
1996
- elseif true
1997
- print false
1998
- endif
1999
- `);
2000
- });
2001
- it('handles when only some of the statements have `then`', () => {
2002
- testTranspile(`
2003
- if true
2004
- else if true then
2005
- else if true
2006
- else if true then
2007
- if true then
2008
- return true
1657
+ it('does not transpile `then` tokens', async () => {
1658
+ await testTranspile(`
1659
+ sub main()
1660
+ if true
1661
+ print true
1662
+ else if true
1663
+ print false
2009
1664
  end if
2010
- end if
1665
+ end sub
1666
+ `);
1667
+ });
1668
+ it('honors spacing between multi-word tokens', async () => {
1669
+ await testTranspile(`
1670
+ sub main()
1671
+ if true
1672
+ print true
1673
+ elseif true
1674
+ print false
1675
+ endif
1676
+ end sub
2011
1677
  `);
2012
1678
  });
2013
- it('retains casing of parameter types', () => {
2014
- function test(type) {
2015
- testTranspile(`
1679
+ it('handles when only some of the statements have `then`', async () => {
1680
+ await testTranspile(`
1681
+ sub main()
1682
+ if true
1683
+ else if true then
1684
+ else if true
1685
+ else if true then
1686
+ if true then
1687
+ return
1688
+ end if
1689
+ end if
1690
+ end sub
1691
+ `);
1692
+ });
1693
+ it('retains casing of parameter types', async () => {
1694
+ async function test(type) {
1695
+ await testTranspile(`
2016
1696
  sub one(a as ${type}, b as ${type.toUpperCase()}, c as ${type.toLowerCase()})
2017
1697
  end sub
2018
1698
  `);
2019
1699
  }
2020
- test('Boolean');
2021
- test('Double');
2022
- test('Dynamic');
2023
- test('Float');
2024
- test('Integer');
2025
- test('LongInteger');
2026
- test('Object');
2027
- test('String');
2028
- });
2029
- it('retains casing of return types', () => {
2030
- function test(type) {
2031
- 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(`
2032
1712
  sub one() as ${type}
2033
1713
  end sub
2034
1714
 
@@ -2039,19 +1719,19 @@ describe('BrsFile', () => {
2039
1719
  end sub
2040
1720
  `);
2041
1721
  }
2042
- test('Boolean');
2043
- test('Double');
2044
- test('Dynamic');
2045
- test('Float');
2046
- test('Integer');
2047
- test('LongInteger');
2048
- test('Object');
2049
- test('String');
2050
- test('Void');
2051
- });
2052
- it('retains casing of literal types', () => {
2053
- function test(type) {
2054
- 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(`
2055
1735
  sub main()
2056
1736
  thing = ${type}
2057
1737
  thing = ${type.toLowerCase()}
@@ -2059,13 +1739,13 @@ describe('BrsFile', () => {
2059
1739
  end sub
2060
1740
  `);
2061
1741
  }
2062
- test('Invalid');
2063
- test('True');
2064
- test('False');
1742
+ await test('Invalid');
1743
+ await test('True');
1744
+ await test('False');
2065
1745
  });
2066
1746
  describe('throwStatement', () => {
2067
- it('transpiles properly', () => {
2068
- testTranspile(`
1747
+ it('transpiles properly', async () => {
1748
+ await testTranspile(`
2069
1749
  sub main()
2070
1750
  try
2071
1751
  throw "some message"
@@ -2076,11 +1756,11 @@ describe('BrsFile', () => {
2076
1756
  });
2077
1757
  });
2078
1758
  describe('try/catch', () => {
2079
- it('transpiles properly', () => {
2080
- testTranspile(`
1759
+ it('transpiles properly', async () => {
1760
+ await testTranspile(`
2081
1761
  sub main()
2082
1762
  try
2083
- print a.b.c
1763
+ print m.b.c
2084
1764
  catch e
2085
1765
  print e
2086
1766
  end try
@@ -2089,8 +1769,8 @@ describe('BrsFile', () => {
2089
1769
  });
2090
1770
  });
2091
1771
  describe('namespaces', () => {
2092
- it('properly transpiles namespace functions for assignments', () => {
2093
- testTranspile(`
1772
+ it('properly transpiles namespace functions for assignments', async () => {
1773
+ await testTranspile(`
2094
1774
  namespace NameA.NameB
2095
1775
  sub Speak()
2096
1776
  end sub
@@ -2098,7 +1778,7 @@ describe('BrsFile', () => {
2098
1778
  sub main()
2099
1779
  sayHello = NameA.NameB.Speak
2100
1780
  sayHello()
2101
- someOtherObject = some.other.object
1781
+ someOtherObject = m.other.object
2102
1782
  end sub
2103
1783
  `, `
2104
1784
  sub NameA_NameB_Speak()
@@ -2107,12 +1787,12 @@ describe('BrsFile', () => {
2107
1787
  sub main()
2108
1788
  sayHello = NameA_NameB_Speak
2109
1789
  sayHello()
2110
- someOtherObject = some.other.object
1790
+ someOtherObject = m.other.object
2111
1791
  end sub
2112
1792
  `);
2113
1793
  });
2114
- it('properly transpiles inferred namespace function for assignment', () => {
2115
- testTranspile(`
1794
+ it('properly transpiles inferred namespace function for assignment', async () => {
1795
+ await testTranspile(`
2116
1796
  namespace NameA.NameB
2117
1797
  sub Speak()
2118
1798
  end sub
@@ -2132,24 +1812,47 @@ describe('BrsFile', () => {
2132
1812
  `);
2133
1813
  });
2134
1814
  });
2135
- it('includes all text to end of line for a non-terminated string', () => {
2136
- 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);
2137
1817
  });
2138
- it('escapes quotes in string literals', () => {
2139
- testTranspile(`
1818
+ it('escapes quotes in string literals', async () => {
1819
+ await testTranspile(`
2140
1820
  sub main()
1821
+ expected = "Hello"
2141
1822
  expected += chr(10) + " version=""2.0"""
2142
1823
  end sub
2143
1824
  `);
2144
1825
  });
2145
- it('keeps function parameter types in proper order', () => {
2146
- testTranspile(`
1826
+ it('keeps function parameter types in proper order', async () => {
1827
+ await testTranspile(`
2147
1828
  function CreateTestStatistic(name as string, result = "Success" as string, time = 0 as integer, errorCode = 0 as integer, errorMessage = "" as string) as object
2148
1829
  end function
2149
1830
  `);
2150
1831
  });
2151
- it('transpiles local var assignment operators', () => {
2152
- 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(`
2153
1856
  sub main()
2154
1857
  count = 0
2155
1858
  count += 1
@@ -2162,8 +1865,8 @@ describe('BrsFile', () => {
2162
1865
  end sub
2163
1866
  `);
2164
1867
  });
2165
- it('transpiles AA property assignment operators', () => {
2166
- testTranspile(`
1868
+ it('transpiles AA property assignment operators', async () => {
1869
+ await testTranspile(`
2167
1870
  sub main()
2168
1871
  person = {
2169
1872
  count: 0
@@ -2172,8 +1875,8 @@ describe('BrsFile', () => {
2172
1875
  end sub
2173
1876
  `);
2174
1877
  });
2175
- it('transpiles AA indexed assignment operators', () => {
2176
- testTranspile(`
1878
+ it('transpiles AA indexed assignment operators', async () => {
1879
+ await testTranspile(`
2177
1880
  sub main()
2178
1881
  person = {
2179
1882
  count: 0
@@ -2182,8 +1885,8 @@ describe('BrsFile', () => {
2182
1885
  end sub
2183
1886
  `);
2184
1887
  });
2185
- it('relative-referenced namespaced functions get prefixed', () => {
2186
- testTranspile(`
1888
+ it('relative-referenced namespaced functions get prefixed', async () => {
1889
+ await testTranspile(`
2187
1890
  namespace Vertibrates.Birds
2188
1891
  function GetAllBirds()
2189
1892
  return [
@@ -2213,8 +1916,8 @@ describe('BrsFile', () => {
2213
1916
  end function
2214
1917
  `, 'trim', 'source/main.bs');
2215
1918
  });
2216
- it('transpiles namespaced functions', () => {
2217
- testTranspile(`
1919
+ it('transpiles namespaced functions', async () => {
1920
+ await testTranspile(`
2218
1921
  namespace NameA
2219
1922
  sub alert()
2220
1923
  end sub
@@ -2230,32 +1933,47 @@ describe('BrsFile', () => {
2230
1933
  end sub
2231
1934
  `, 'trim', 'source/main.bs');
2232
1935
  });
2233
- it('transpiles dim', () => {
2234
- testTranspile(`Dim c[5]`, `Dim c[5]`);
2235
- testTranspile(`Dim c[5, 4]`, `Dim c[5, 4]`);
2236
- testTranspile(`Dim c[5, 4, 6]`, `Dim c[5, 4, 6]`);
2237
- testTranspile(`Dim requestData[requestList.count()]`, `Dim requestData[requestList.count()]`);
2238
- testTranspile(`Dim requestData[1, requestList.count()]`, `Dim requestData[1, requestList.count()]`);
2239
- testTranspile(`Dim requestData[1, requestList.count(), 2]`, `Dim requestData[1, requestList.count(), 2]`);
2240
- testTranspile(`Dim requestData[requestList[2]]`, `Dim requestData[requestList[2]]`);
2241
- testTranspile(`Dim requestData[1, requestList[2]]`, `Dim requestData[1, requestList[2]]`);
2242
- testTranspile(`Dim requestData[1, requestList[2], 2]`, `Dim requestData[1, requestList[2], 2]`);
2243
- testTranspile(`Dim requestData[requestList["2"]]`, `Dim requestData[requestList["2"]]`);
2244
- testTranspile(`Dim requestData[1, requestList["2"]]`, `Dim requestData[1, requestList["2"]]`);
2245
- testTranspile(`Dim requestData[1, requestList["2"], 2]`, `Dim requestData[1, requestList["2"], 2]`);
2246
- testTranspile(`Dim requestData[1, getValue(), 2]`, `Dim requestData[1, getValue(), 2]`);
2247
- testTranspile(`
2248
- Dim requestData[1, getValue({
2249
- key: "value"
2250
- }), 2]
2251
- `, `
2252
- Dim requestData[1, getValue({
2253
- key: "value"
2254
- }), 2]
1936
+ it('transpiles dim', async () => {
1937
+ async function doTest(code) {
1938
+ await testTranspile(`
1939
+ sub main()
1940
+ requestList = []
1941
+ ${code}
1942
+ end sub
1943
+ `, `
1944
+ sub main()
1945
+ requestList = []
1946
+ ${code}
1947
+ end sub
1948
+ `);
1949
+ }
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(`
1964
+ function getValue(param1)
1965
+ end function
1966
+
1967
+ sub main()
1968
+ requestList = []
1969
+ Dim requestData[1, getValue({
1970
+ key: "value"
1971
+ }), 2]
1972
+ end sub
2255
1973
  `);
2256
1974
  });
2257
- it('transpiles calls to fully-qualified namespaced functions', () => {
2258
- testTranspile(`
1975
+ it('transpiles calls to fully-qualified namespaced functions', async () => {
1976
+ await testTranspile(`
2259
1977
  namespace NameA
2260
1978
  sub alert()
2261
1979
  end sub
@@ -2280,15 +1998,15 @@ describe('BrsFile', () => {
2280
1998
  end sub
2281
1999
  `, 'trim', 'source/main.bs');
2282
2000
  });
2283
- it('keeps end-of-line comments with their line', () => {
2284
- testTranspile(`
2001
+ it('keeps end-of-line comments with their line', async () => {
2002
+ await testTranspile(`
2285
2003
  function DoSomething() 'comment 1
2286
2004
  name = "bob" 'comment 2
2287
2005
  end function 'comment 3
2288
2006
  `);
2289
2007
  });
2290
- it('works for functions', () => {
2291
- testTranspile(`
2008
+ it('works for functions', async () => {
2009
+ await testTranspile(`
2292
2010
  function DoSomething()
2293
2011
  'lots of empty white space
2294
2012
  'that will be removed during transpile
@@ -2303,16 +2021,16 @@ describe('BrsFile', () => {
2303
2021
  end function
2304
2022
  `);
2305
2023
  });
2306
- it('keeps empty AAs and arrays on same line', () => {
2307
- testTranspile(`
2024
+ it('keeps empty AAs and arrays on same line', async () => {
2025
+ await testTranspile(`
2308
2026
  sub a()
2309
2027
  person = {}
2310
2028
  stuff = []
2311
2029
  end sub
2312
2030
  `, null, 'trim');
2313
2031
  });
2314
- it('does not add leading or trailing newlines', () => {
2315
- 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');
2316
2034
  });
2317
2035
  it('handles sourcemap edge case', async () => {
2318
2036
  let source = 'sub main()\n' +
@@ -2321,18 +2039,18 @@ describe('BrsFile', () => {
2321
2039
  '\n' +
2322
2040
  'end sub';
2323
2041
  program.options.sourceMap = true;
2324
- 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');
2325
2043
  //load the source map
2326
- 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) => {
2327
2045
  return consumer.generatedPositionFor({
2328
2046
  line: 3,
2329
2047
  column: 0,
2330
- source: (0, util_1.standardizePath) `${rootDir}/source/main.bs`,
2048
+ source: (0, util_1.standardizePath) `${testHelpers_spec_2.rootDir}/source/main.bs`,
2331
2049
  bias: source_map_1.SourceMapConsumer.LEAST_UPPER_BOUND
2332
2050
  });
2333
2051
  });
2334
- (0, chai_1.expect)(location.line).to.eql(2);
2335
- (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);
2336
2054
  });
2337
2055
  it('computes correct locations for sourcemap', async () => {
2338
2056
  let source = `function abc(name)\n firstName = name\nend function`;
@@ -2340,7 +2058,7 @@ describe('BrsFile', () => {
2340
2058
  //remove newlines and EOF
2341
2059
  .filter(x => x.kind !== TokenKind_1.TokenKind.Eof && x.kind !== TokenKind_1.TokenKind.Newline);
2342
2060
  program.options.sourceMap = true;
2343
- let result = testTranspile(source, source, 'none');
2061
+ let result = await testTranspile(source, source, 'none');
2344
2062
  //load the source map
2345
2063
  await source_map_1.SourceMapConsumer.with(result.map.toString(), null, (consumer) => {
2346
2064
  let tokenResult = tokens.map(token => ({
@@ -2360,58 +2078,76 @@ describe('BrsFile', () => {
2360
2078
  originalPosition.line - 1, originalPosition.column)
2361
2079
  };
2362
2080
  });
2363
- (0, chai_1.expect)(sourcemapResult).to.eql(tokenResult);
2081
+ (0, chai_config_spec_1.expect)(sourcemapResult).to.eql(tokenResult);
2364
2082
  });
2365
2083
  });
2366
- it('handles empty if block', () => {
2367
- testTranspile(`
2368
- if true then
2369
- end if
2370
- if true then
2371
- else
2372
- print "else"
2373
- end if
2374
- if true then
2375
- else if true then
2376
- print "else"
2377
- end if
2378
- if true then
2379
- else if true then
2380
- print "elseif"
2381
- else
2382
- print "else"
2383
- end if
2084
+ it('handles empty if block', async () => {
2085
+ await testTranspile(`
2086
+ sub main()
2087
+ if true then
2088
+ end if
2089
+ if true then
2090
+ else
2091
+ print "else"
2092
+ end if
2093
+ if true then
2094
+ else if true then
2095
+ print "else"
2096
+ end if
2097
+ if true then
2098
+ else if true then
2099
+ print "elseif"
2100
+ else
2101
+ print "else"
2102
+ end if
2103
+ end sub
2384
2104
  `);
2385
2105
  });
2386
- it('handles empty elseif block', () => {
2387
- testTranspile(`
2388
- if true then
2389
- print "if"
2390
- else if true then
2391
- end if
2392
- if true then
2393
- print "if"
2394
- else if true then
2395
- else if true then
2396
- end if
2106
+ it('handles empty elseif block', async () => {
2107
+ await testTranspile(`
2108
+ sub main()
2109
+ if true then
2110
+ print "if"
2111
+ else if true then
2112
+ end if
2113
+ if true then
2114
+ print "if"
2115
+ else if true then
2116
+ else if true then
2117
+ end if
2118
+ end sub
2397
2119
  `);
2398
2120
  });
2399
- it('handles empty else block', () => {
2400
- testTranspile(`
2401
- if true then
2402
- print "if"
2403
- else
2404
- end if
2405
- if true then
2406
- print "if"
2407
- else if true then
2408
- print "elseif"
2409
- else
2410
- end if
2121
+ it('handles empty else block', async () => {
2122
+ await testTranspile(`
2123
+ sub main()
2124
+ if true then
2125
+ print "if"
2126
+ else
2127
+ end if
2128
+ if true then
2129
+ print "if"
2130
+ else if true then
2131
+ print "elseif"
2132
+ else
2133
+ end if
2134
+ end sub
2135
+ `);
2136
+ });
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
2411
2147
  `);
2412
2148
  });
2413
- it('works for function parameters', () => {
2414
- testTranspile(`
2149
+ it('works for function parameters', async () => {
2150
+ await testTranspile(`
2415
2151
  function DoSomething(name, age as integer, text as string)
2416
2152
  end function
2417
2153
  `, `
@@ -2419,8 +2155,8 @@ describe('BrsFile', () => {
2419
2155
  end function
2420
2156
  `);
2421
2157
  });
2422
- it('adds newlines between top-level statements', () => {
2423
- testTranspile(`
2158
+ it('adds newlines between top-level statements', async () => {
2159
+ await testTranspile(`
2424
2160
  function a()
2425
2161
  end function
2426
2162
 
@@ -2428,8 +2164,8 @@ describe('BrsFile', () => {
2428
2164
  end function
2429
2165
  `);
2430
2166
  });
2431
- it('properly indents nested AA literals', () => {
2432
- testTranspile(`
2167
+ it('properly indents nested AA literals', async () => {
2168
+ await testTranspile(`
2433
2169
  sub doSomething()
2434
2170
  grandparent = {
2435
2171
  parent: {
@@ -2443,8 +2179,8 @@ describe('BrsFile', () => {
2443
2179
  end sub
2444
2180
  `);
2445
2181
  });
2446
- it('does not add comma after final object property even when comments are present', () => {
2447
- testTranspile(`
2182
+ it('does not add comma after final object property even when comments are present', async () => {
2183
+ await testTranspile(`
2448
2184
  sub doSomething()
2449
2185
  person = {
2450
2186
  age: 12 'comment
@@ -2467,8 +2203,8 @@ describe('BrsFile', () => {
2467
2203
  end sub
2468
2204
  `);
2469
2205
  });
2470
- it('works for a complex function with comments all over the place', () => {
2471
- testTranspile(`
2206
+ it('works for a complex function with comments all over the place', async () => {
2207
+ await testTranspile(`
2472
2208
  'import some library
2473
2209
  library "v30/bslCore.brs" 'comment
2474
2210
 
@@ -2517,7 +2253,7 @@ describe('BrsFile', () => {
2517
2253
  3 'comment
2518
2254
  ] 'comment
2519
2255
  firstIndex = indexes[0] 'comment
2520
- for each idx in indxes 'comment
2256
+ for each idx in indexes 'comment
2521
2257
  indexes[idx] = idx + 1 'comment
2522
2258
  end for 'comment
2523
2259
  if not true then 'comment
@@ -2558,25 +2294,25 @@ describe('BrsFile', () => {
2558
2294
  sub logInfo()
2559
2295
  end sub
2560
2296
  `);
2561
- file.needsTranspiled = false;
2297
+ file['needsTranspiled'] = false;
2562
2298
  const { code } = file.transpile();
2563
- (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;
2564
2300
  });
2565
2301
  it('AST generated files include a reference to the source map', () => {
2566
2302
  let file = program.setFile('source/logger.brs', (0, testHelpers_spec_1.trim) `
2567
2303
  sub logInfo()
2568
2304
  end sub
2569
2305
  `);
2570
- file.needsTranspiled = true;
2306
+ file['needsTranspiled'] = true;
2571
2307
  const { code } = file.transpile();
2572
- (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;
2573
2309
  });
2574
- it('replaces custom types in parameter types and return types', () => {
2310
+ it('replaces custom types in parameter types and return types', async () => {
2575
2311
  program.setFile('source/SomeKlass.bs', `
2576
2312
  class SomeKlass
2577
2313
  end class
2578
2314
  `);
2579
- testTranspile(`
2315
+ await testTranspile(`
2580
2316
  function foo() as SomeKlass
2581
2317
  return new SomeKlass()
2582
2318
  end function
@@ -2584,11 +2320,70 @@ describe('BrsFile', () => {
2584
2320
  sub bar(obj as SomeKlass)
2585
2321
  end sub
2586
2322
  `, `
2587
- function foo() as object
2323
+ function foo() as dynamic
2588
2324
  return SomeKlass()
2589
2325
  end function
2590
2326
 
2591
- 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()
2592
2387
  end sub
2593
2388
  `);
2594
2389
  });
@@ -2597,35 +2392,40 @@ describe('BrsFile', () => {
2597
2392
  describe('transpile', () => {
2598
2393
  it('does not produce diagnostics', () => {
2599
2394
  program.setFile('source/main.bs', `
2600
- sub main()
2601
- someObject@.someFunction(paramObject.value)
2395
+ sub test()
2396
+ someNode = createObject("roSGNode", "Rectangle")
2397
+ someNode@.someFunction(test.value)
2602
2398
  end sub
2603
2399
  `);
2604
2400
  program.validate();
2605
2401
  (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2606
2402
  });
2607
- it('sets invalid on empty callfunc', () => {
2608
- testTranspile(`
2403
+ it('sets invalid on empty callfunc', async () => {
2404
+ await testTranspile(`
2609
2405
  sub main()
2406
+ node = invalid
2610
2407
  node@.doSomething()
2611
2408
  m.top.node@.doSomething()
2612
2409
  m.top.node@.doSomething(1)
2613
2410
  end sub
2614
2411
  `, `
2615
2412
  sub main()
2413
+ node = invalid
2616
2414
  node.callfunc("doSomething", invalid)
2617
2415
  m.top.node.callfunc("doSomething", invalid)
2618
2416
  m.top.node.callfunc("doSomething", 1)
2619
2417
  end sub
2620
2418
  `);
2621
2419
  });
2622
- it('includes original arguments', () => {
2623
- testTranspile(`
2420
+ it('includes original arguments', async () => {
2421
+ await testTranspile(`
2624
2422
  sub main()
2423
+ node = invalid
2625
2424
  node@.doSomething(1, true, m.top.someVal)
2626
2425
  end sub
2627
2426
  `, `
2628
2427
  sub main()
2428
+ node = invalid
2629
2429
  node.callfunc("doSomething", 1, true, m.top.someVal)
2630
2430
  end sub
2631
2431
  `);
@@ -2642,34 +2442,34 @@ describe('BrsFile', () => {
2642
2442
  name: 'transform callback',
2643
2443
  afterFileParse: onParsed
2644
2444
  });
2645
- file = program.setFile({ src: `absolute_path/file${ext}`, dest: `relative_path/file${ext}` }, `
2445
+ file = program.setFile(`source/file${ext}`, `
2646
2446
  sub Sum()
2647
- print "hello world"
2447
+ print "hello world"
2648
2448
  end sub
2649
2449
  `);
2650
- (0, chai_1.expect)(file.extension).to.equal(ext);
2450
+ (0, chai_config_spec_1.expect)(file.extension).to.equal(ext);
2651
2451
  return file;
2652
2452
  }
2653
2453
  it('called for BRS file', () => {
2654
2454
  const onParsed = sinon.spy();
2655
2455
  parseFileWithCallback('.brs', onParsed);
2656
- (0, chai_1.expect)(onParsed.callCount).to.equal(1);
2456
+ (0, chai_config_spec_1.expect)(onParsed.callCount).to.equal(1);
2657
2457
  });
2658
- it('called for BS file', () => {
2458
+ it('called for BR file', () => {
2659
2459
  const onParsed = sinon.spy();
2660
2460
  parseFileWithCallback('.bs', onParsed);
2661
- (0, chai_1.expect)(onParsed.callCount).to.equal(1);
2461
+ (0, chai_config_spec_1.expect)(onParsed.callCount).to.equal(1);
2662
2462
  });
2663
2463
  });
2664
2464
  describe('typedefKey', () => {
2665
2465
  it('works for .brs files', () => {
2666
- (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`);
2667
2467
  });
2668
2468
  it('returns undefined for files that should not have a typedef', () => {
2669
- (0, chai_1.expect)((program.setFile('source/main.bs', '')).typedefSrcPath).to.be.undefined;
2670
- (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;
2671
2471
  const xmlFile = program.setFile('components/comp.xml', '');
2672
- (0, chai_1.expect)(xmlFile.typedefSrcPath).to.be.undefined;
2472
+ (0, chai_config_spec_1.expect)(xmlFile.typedefKey).to.be.undefined;
2673
2473
  });
2674
2474
  });
2675
2475
  describe('type definitions', () => {
@@ -2687,8 +2487,8 @@ describe('BrsFile', () => {
2687
2487
  `);
2688
2488
  const sourceScope = program.getScopeByName('source');
2689
2489
  const functionNames = sourceScope.getAllCallables().map(x => x.callable.name);
2690
- (0, chai_1.expect)(functionNames).to.include('main');
2691
- (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');
2692
2492
  });
2693
2493
  it('reacts to typedef file changes', () => {
2694
2494
  let file = program.setFile('source/main.brs', `
@@ -2697,14 +2497,14 @@ describe('BrsFile', () => {
2697
2497
  sub speak()
2698
2498
  end sub
2699
2499
  `);
2700
- (0, chai_1.expect)(file.hasTypedef).to.be.false;
2701
- (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;
2702
2502
  program.setFile('source/main.d.bs', `
2703
2503
  sub main()
2704
2504
  end sub
2705
2505
  `);
2706
- (0, chai_1.expect)(file.hasTypedef).to.be.true;
2707
- (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;
2708
2508
  //add replace file, does it still find the typedef
2709
2509
  file = program.setFile('source/main.brs', `
2710
2510
  sub main()
@@ -2712,46 +2512,72 @@ describe('BrsFile', () => {
2712
2512
  sub speak()
2713
2513
  end sub
2714
2514
  `);
2715
- (0, chai_1.expect)(file.hasTypedef).to.be.true;
2716
- (0, chai_1.expect)(file.typedefFile).to.exist;
2717
- program.removeFile((0, util_1.standardizePath) `${rootDir}/source/main.d.bs`);
2718
- (0, chai_1.expect)(file.hasTypedef).to.be.false;
2719
- (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;
2720
2520
  });
2721
2521
  });
2722
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
+ });
2723
2548
  it('sets typedef path properly', () => {
2724
- (0, chai_1.expect)((program.setFile('source/main1.brs', '')).typedefSrcPath).to.equal((0, util_1.standardizePath) `${rootDir}/source/main1.d.bs`.toLowerCase());
2725
- (0, chai_1.expect)((program.setFile('source/main2.d.bs', '')).typedefSrcPath).to.equal(undefined);
2726
- (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);
2727
2552
  //works for dest with `.brs` extension
2728
- (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);
2729
2554
  });
2730
2555
  it('does not link when missing from program', () => {
2731
2556
  const file = program.setFile('source/main.brs', ``);
2732
- (0, chai_1.expect)(file.typedefFile).not.to.exist;
2557
+ (0, chai_config_spec_1.expect)(file.typedefFile).not.to.exist;
2733
2558
  });
2734
2559
  it('links typedef when added BEFORE .brs file', () => {
2735
2560
  const typedef = program.setFile('source/main.d.bs', ``);
2736
2561
  const file = program.setFile('source/main.brs', ``);
2737
- (0, chai_1.expect)(file.typedefFile).to.equal(typedef);
2562
+ (0, chai_config_spec_1.expect)(file.typedefFile).to.equal(typedef);
2738
2563
  });
2739
2564
  it('links typedef when added AFTER .brs file', () => {
2740
2565
  const file = program.setFile('source/main.brs', ``);
2741
2566
  const typedef = program.setFile('source/main.d.bs', ``);
2742
- (0, chai_1.expect)(file.typedefFile).to.eql(typedef);
2567
+ (0, chai_config_spec_1.expect)(file.typedefFile).to.eql(typedef);
2743
2568
  });
2744
2569
  it('removes typedef link when typedef is removed', () => {
2745
2570
  const typedef = program.setFile('source/main.d.bs', ``);
2746
2571
  const file = program.setFile('source/main.brs', ``);
2747
2572
  program.removeFile(typedef.srcPath);
2748
- (0, chai_1.expect)(file.typedefFile).to.be.undefined;
2573
+ (0, chai_config_spec_1.expect)(file.typedefFile).to.be.undefined;
2749
2574
  });
2750
2575
  });
2751
2576
  describe('getTypedef', () => {
2752
2577
  function testTypedef(original, expected) {
2753
2578
  let file = program.setFile('source/main.brs', original);
2754
- (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);
2755
2581
  }
2756
2582
  it('includes namespace on extend class names', () => {
2757
2583
  testTypedef(`
@@ -3040,9 +2866,9 @@ describe('BrsFile', () => {
3040
2866
  file['_parser'] = undefined;
3041
2867
  //force the file to get a new instance of parser
3042
2868
  const newParser = file.parser;
3043
- (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);
3044
2870
  //reference shouldn't change in subsequent accesses
3045
- (0, chai_1.expect)(file.parser).to.equal(newParser);
2871
+ (0, chai_config_spec_1.expect)(file.parser).to.equal(newParser);
3046
2872
  });
3047
2873
  it('call parse when previously skipped', () => {
3048
2874
  program.setFile('source/main.d.bs', `'typedef
@@ -3054,11 +2880,11 @@ describe('BrsFile', () => {
3054
2880
  end sub
3055
2881
  `);
3056
2882
  //no functions should be found since the parser was skipped
3057
- (0, chai_1.expect)(file['_parser']).to.not.exist;
2883
+ (0, chai_config_spec_1.expect)(file['_parser']).to.not.exist;
3058
2884
  const stub = sinon.stub(file, 'parse').callThrough();
3059
2885
  //`file.parser` is a getter, so that should force the parse to occur
3060
- (0, chai_1.expect)(file.parser.references.functionStatements).to.be.lengthOf(1);
3061
- (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;
3062
2888
  //parse should have been called
3063
2889
  });
3064
2890
  });
@@ -3067,12 +2893,12 @@ describe('BrsFile', () => {
3067
2893
  let idx = 1;
3068
2894
  beforeEach(() => {
3069
2895
  pluginFileName = `plugin-${idx++}.js`;
3070
- fsExtra.outputFileSync((0, util_1.standardizePath) `${tempDir}/plugins/${pluginFileName}`, `
2896
+ fsExtra.outputFileSync((0, util_1.standardizePath) `${testHelpers_spec_2.tempDir}/plugins/${pluginFileName}`, `
3071
2897
  function plugin() {
3072
2898
  return {
3073
2899
  name: 'lower-file-name',
3074
- afterFileParse: (evt) => {
3075
- evt.file._customProp = true;
2900
+ afterProvideFile: (evt) => {
2901
+ evt.files[0]._customProp = true;
3076
2902
  }
3077
2903
  };
3078
2904
  }
@@ -3080,234 +2906,1000 @@ describe('BrsFile', () => {
3080
2906
  `);
3081
2907
  });
3082
2908
  it('can load an absolute plugin which receives callbacks', () => {
3083
- program.plugins = new PluginInterface_1.default(util_1.default.loadPlugins(tempDir, [
3084
- (0, util_1.standardizePath) `${tempDir}/plugins/${pluginFileName}`
3085
- ]), 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
+ }
3086
2912
  const file = program.setFile('source/MAIN.brs', '');
3087
- (0, chai_1.expect)(file._customProp).to.exist;
2913
+ (0, chai_config_spec_1.expect)(file._customProp).to.exist;
3088
2914
  });
3089
2915
  it('can load a relative plugin which receives callbacks', () => {
3090
- program.plugins = new PluginInterface_1.default(util_1.default.loadPlugins(tempDir, [
3091
- `./plugins/${pluginFileName}`
3092
- ]), 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
+ }
3093
2919
  const file = program.setFile('source/MAIN.brs', '');
3094
- (0, chai_1.expect)(file._customProp).to.exist;
2920
+ (0, chai_config_spec_1.expect)(file._customProp).to.exist;
3095
2921
  });
3096
2922
  });
3097
- describe('getSymbolTypeFromToken', () => {
3098
- function checkSymbolLookups(file, funcExpr, lookups) {
3099
- const mainScope = program.getScopesForFile(file)[0];
3100
- mainScope.linkSymbolTable();
3101
- for (const lookup of lookups) {
3102
- const position = vscode_languageserver_1.Position.create(lookup.line, lookup.col);
3103
- const token = file.parser.getTokenAt(position);
3104
- const symbol = file.getSymbolTypeFromToken(token, funcExpr, mainScope);
3105
- const context = {
3106
- file: file,
3107
- scope: mainScope,
3108
- position: position
3109
- };
3110
- (0, chai_1.expect)(symbol.expandedTokenText).to.equal(lookup.name);
3111
- (0, chai_1.expect)(symbol.type.equals(lookup.type, context)).be.true;
3112
- }
3113
- }
3114
- it('gets simple types based on the containing function expression', () => {
2923
+ describe('getDefinition', () => {
2924
+ it('returns const locations', () => {
3115
2925
  const file = program.setFile('source/main.bs', `
3116
- sub doSomething(aInt as integer, aFloat as float, aStr as string, aBool as boolean, aObj as object)
3117
- print aInt
3118
- print aFloat
3119
- print aStr
3120
- print aBool
3121
- print aObj
3122
- end sub
3123
- `);
3124
- const funcExpr = file.parser.references.functionExpressions[0];
3125
- const lookups = [
3126
- { line: 2, col: 28, name: 'aInt', type: new IntegerType_1.IntegerType() },
3127
- { line: 3, col: 28, name: 'aFloat', type: new FloatType_1.FloatType() },
3128
- { line: 4, col: 28, name: 'aStr', type: new StringType_1.StringType() },
3129
- { line: 5, col: 28, name: 'aBool', type: new BooleanType_1.BooleanType() },
3130
- { line: 6, col: 28, name: 'aObj', type: new ObjectType_1.ObjectType() }
3131
- ];
3132
- checkSymbolLookups(file, funcExpr, lookups);
3133
- (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
+ }]);
3134
2939
  });
3135
- it('gets custom types based on the containing function expression', () => {
2940
+ it('returns enum locations', () => {
3136
2941
  const file = program.setFile('source/main.bs', `
3137
- sub doSomething(klass as MyKlass)
3138
- print klass
2942
+ sub main()
2943
+ print alpha.beta.people.charlie
3139
2944
  end sub
3140
-
3141
- class MyKlass
3142
- end class
2945
+ namespace alpha.beta
2946
+ enum people
2947
+ charlie = "charles"
2948
+ end enum
2949
+ end namespace
3143
2950
  `);
3144
- const mainScope = program.getScopesForFile(file)[0];
3145
- mainScope.linkSymbolTable();
3146
- const funcExpr = file.parser.references.functionExpressions[0];
3147
- const token = file.parser.getTokenAt(vscode_languageserver_1.Position.create(2, 28));
3148
- const symbol = file.getSymbolTypeFromToken(token, funcExpr, mainScope);
3149
- (0, chai_1.expect)(symbol.expandedTokenText).to.equal('klass');
3150
- const classStmt = file.parser.references.classStatements[0];
3151
- (0, chai_1.expect)(classStmt.name.text).to.equal('MyKlass');
3152
- (0, chai_1.expect)(symbol.type.isAssignableTo(classStmt.getThisBscType())).be.true;
3153
- (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
+ }]);
3154
2957
  });
3155
- it('gets types of properties of a klass', () => {
2958
+ it('returns interface location', () => {
3156
2959
  const file = program.setFile('source/main.bs', `
3157
- sub doSomething()
3158
- klass = new MyKlass()
3159
- print klass.name
3160
- print klass.age
3161
- ' verify case insensitivity
3162
- print KLASS.NAME
3163
- print klass.AGE
2960
+ sub test(selectedMovie as Movie)
2961
+ print selectedMovie
3164
2962
  end sub
3165
-
3166
- class MyKlass
3167
- name as string
3168
- 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
3169
2999
  end class
3170
3000
  `);
3171
- const funcExpr = file.parser.references.functionExpressions[0];
3172
- const lookups = [
3173
- { line: 3, col: 35, name: 'MyKlass.name', type: new StringType_1.StringType() },
3174
- { line: 4, col: 35, name: 'MyKlass.age', type: new IntegerType_1.IntegerType() }
3175
- ];
3176
- checkSymbolLookups(file, funcExpr, lookups);
3177
- (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
+ }]);
3178
3007
  });
3179
- it('gets types of properties of an object', () => {
3008
+ it('returns namespaced class location', () => {
3180
3009
  const file = program.setFile('source/main.bs', `
3181
- sub doSomething()
3182
- obj = { name: "Joe", age: 37}
3183
- print obj.name
3184
- print obj.age
3010
+ sub test(selectedMovie as classes.Movie)
3011
+ print selectedMovie
3185
3012
  end sub
3013
+ namespace classes
3014
+ class Movie
3015
+ url as string
3016
+ end class
3017
+ end namespace
3186
3018
  `);
3187
- const funcExpr = file.parser.references.functionExpressions[0];
3188
- const lookups = [
3189
- { line: 3, col: 32, name: 'obj.name', type: new StringType_1.StringType() },
3190
- { line: 4, col: 32, name: 'obj.age', type: new IntegerType_1.IntegerType() }
3191
- ];
3192
- checkSymbolLookups(file, funcExpr, lookups);
3193
- (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
+ }]);
3194
3025
  });
3195
- it('gets return types of functions', () => {
3026
+ it('does not crash on nulls', () => {
3196
3027
  const file = program.setFile('source/main.bs', `
3197
- sub doSomething()
3198
- pi = makeKlass().getSelf().getPi()
3199
- print pi
3028
+ sub main()
3029
+ print alpha.beta
3030
+ end sub
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
3084
+ end function
3085
+
3086
+ sub useKlass()
3087
+ k = new Klass()
3088
+ k.addTwo()
3200
3089
  end sub
3201
3090
 
3202
- function makeKlass() as MyKlass
3203
- return new MyKlass()
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())
3204
3108
  end function
3205
3109
 
3206
- class MyKlass
3207
- function getPi() as float
3208
- return 3.14
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()
3209
3142
  end function
3143
+ end class
3144
+ `);
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
+ ]);
3154
+ });
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
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
3210
3251
 
3211
- function getSelf() as MyKlass
3212
- return m
3252
+ class DataObject extends BaseData
3253
+ kind as DataKind
3254
+ function process(dataProcess as DataProcessor) as ProcessedData
3255
+ return dataProcess.work(m)
3213
3256
  end function
3214
3257
  end class
3215
3258
  `);
3216
- const mainScope = program.getScopesForFile(file)[0];
3217
- mainScope.linkSymbolTable();
3218
- const funcExpr = file.parser.references.functionExpressions[0];
3219
- const klassMemberTable = file.parser.references.classStatements[0].memberTable;
3220
- const lookups = [
3221
- { line: 2, col: 31, name: 'makeKlass', type: file.parser.references.functionExpressions[1].getFunctionType() },
3222
- // The expanded text for this should probably be MyKlass.getSelf()
3223
- { line: 2, col: 41, name: 'MyKlass.MyKlass', type: klassMemberTable.getSymbol('getSelf')[0].type },
3224
- { line: 2, col: 51, name: 'MyKlass.getPi', type: klassMemberTable.getSymbol('getPi')[0].type },
3225
- { line: 3, col: 28, name: 'pi', type: new FloatType_1.FloatType() }
3226
- ];
3227
- checkSymbolLookups(file, funcExpr, lookups);
3228
- (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
+ ]);
3229
3273
  });
3230
- it('gets types of elements of arrays', () => {
3231
- const file = program.setFile('source/main.bs', `
3232
- sub doSomething(words as string[], klasses as MyKlass[])
3233
- myWord = words[0]
3234
- pi = klasses[0].getPi()
3235
- print myWord
3236
- print pi
3237
- end sub
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
3291
+ `);
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']);
3304
+ });
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
3238
3309
 
3239
- class MyKlass
3240
- function getPi() as float
3241
- return 3.14
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
3324
+ end function
3325
+ `);
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);
3329
+ });
3330
+ });
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()
3242
3385
  end function
3243
3386
  end class
3387
+
3388
+ class Klass3
3389
+ propClass = new Klass2()
3390
+ end class
3244
3391
  `);
3245
- const mainScope = program.getScopesForFile(file)[0];
3246
- mainScope.linkSymbolTable();
3247
- const funcExpr = file.parser.references.functionExpressions[0];
3248
- const klassMemberTable = file.parser.references.classStatements[0].memberTable;
3249
- const lookups = [
3250
- { line: 2, col: 34, name: 'words', type: new ArrayType_1.ArrayType(new StringType_1.StringType()) },
3251
- { line: 3, col: 41, name: 'MyKlass.getPi', type: klassMemberTable.getSymbol('getPi')[0].type },
3252
- { line: 4, col: 28, name: 'myWord', type: new StringType_1.StringType() },
3253
- { line: 5, col: 28, name: 'pi', type: new FloatType_1.FloatType() }
3254
- ];
3255
- checkSymbolLookups(file, funcExpr, lookups);
3256
- (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
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
3421
+ end namespace
3422
+ `);
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
+ });
3257
3846
  });
3258
- it('gets types of elements of arrays via square bracket reference', () => {
3259
- const file = program.setFile('source/main.bs', `
3260
- function printFirst(numbers as float[]) as float
3261
- firstFloat = numbers[0]
3262
- print firstFloat
3263
- return firstFloat
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)
3264
3874
  end function
3265
3875
  `);
3266
- const mainScope = program.getScopesForFile(file)[0];
3267
- mainScope.linkSymbolTable();
3268
- const funcExpr = file.parser.references.functionExpressions[0];
3269
- const lookups = [
3270
- { line: 2, col: 26, name: 'firstFloat', type: new FloatType_1.FloatType() },
3271
- { line: 3, col: 32, name: 'firstFloat', type: new FloatType_1.FloatType() }
3876
+ const expected = [
3877
+ 'field1', 'field2', 'field3', 'field4', 'field5', 'field6',
3878
+ 'prop1', 'prop2', 'prop3', 'prop4', 'prop5', 'prop6', 'prop7', 'prop8', 'prop9'
3272
3879
  ];
3273
- checkSymbolLookups(file, funcExpr, lookups);
3274
- (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
3880
+ const { propertyHints } = file['_cachedLookups'];
3881
+ (0, chai_config_spec_1.expect)(Object.keys(propertyHints).sort()).to.deep.equal(expected, 'Initial hints');
3275
3882
  });
3276
- it('gets types of elements of arrays after for each', () => {
3277
- const file = program.setFile('source/main.bs', `
3278
- function printAllReturnFirst(numbers as float[]) as float
3279
- for each num in numbers
3280
- print num
3281
- end for
3282
-
3283
- firstFloat = numbers[0]
3284
- print firstFloat
3285
- return firstFloat
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
3286
3895
  end function
3287
3896
  `);
3288
- const mainScope = program.getScopesForFile(file)[0];
3289
- mainScope.linkSymbolTable();
3290
- const funcExpr = file.parser.references.functionExpressions[0];
3291
- const lookups = [
3292
- { line: 6, col: 26, name: 'firstFloat', type: new FloatType_1.FloatType() },
3293
- { line: 7, col: 32, name: 'firstFloat', type: new FloatType_1.FloatType() }
3897
+ const expected = [
3898
+ 'constructor', 'tostring', 'valueof'
3294
3899
  ];
3295
- checkSymbolLookups(file, funcExpr, lookups);
3296
- (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
3900
+ const { propertyHints } = file['_cachedLookups'];
3901
+ (0, chai_config_spec_1.expect)(Object.keys(propertyHints).sort()).to.deep.equal(expected, 'Initial hints');
3297
3902
  });
3298
3903
  });
3299
- it('defaults to `dynamic` type for a complex expression', () => {
3300
- const file = program.setFile('source/main.brs', `
3301
- sub main()
3302
- name = "cat"
3303
- thing = m["key"](true)
3304
- end sub
3305
- `);
3306
- program.validate();
3307
- //sanity check
3308
- (0, chai_1.expect)(file.parser.references.assignmentStatements[0].containingFunction.symbolTable.getSymbolType('name')).be.instanceof(StringType_1.StringType);
3309
- //this complex expression should resolve to dynamic type when not known
3310
- (0, chai_1.expect)(file.parser.references.assignmentStatements[0].containingFunction.symbolTable.getSymbolType('thing')).be.instanceof(DynamicType_1.DynamicType);
3311
- });
3312
3904
  });
3313
3905
  //# sourceMappingURL=BrsFile.spec.js.map