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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (536) hide show
  1. package/CHANGELOG.md +521 -233
  2. package/README.md +45 -139
  3. package/bsconfig.schema.json +46 -0
  4. package/dist/ActionPipeline.d.ts +10 -0
  5. package/dist/ActionPipeline.js +40 -0
  6. package/dist/ActionPipeline.js.map +1 -0
  7. package/dist/AstValidationSegmenter.d.ts +25 -0
  8. package/dist/AstValidationSegmenter.js +152 -0
  9. package/dist/AstValidationSegmenter.js.map +1 -0
  10. package/dist/BsConfig.d.ts +40 -4
  11. package/dist/BusyStatusTracker.d.ts +31 -0
  12. package/dist/BusyStatusTracker.js +83 -0
  13. package/dist/BusyStatusTracker.js.map +1 -0
  14. package/dist/Cache.js +3 -3
  15. package/dist/Cache.js.map +1 -1
  16. package/dist/CacheVerifier.d.ts +7 -0
  17. package/dist/CacheVerifier.js +20 -0
  18. package/dist/CacheVerifier.js.map +1 -0
  19. package/dist/CodeActionUtil.d.ts +3 -3
  20. package/dist/CodeActionUtil.js.map +1 -1
  21. package/dist/CommentFlagProcessor.d.ts +3 -2
  22. package/dist/CommentFlagProcessor.js +5 -4
  23. package/dist/CommentFlagProcessor.js.map +1 -1
  24. package/dist/DependencyGraph.d.ts +3 -2
  25. package/dist/DependencyGraph.js +11 -10
  26. package/dist/DependencyGraph.js.map +1 -1
  27. package/dist/DiagnosticCollection.js +9 -5
  28. package/dist/DiagnosticCollection.js.map +1 -1
  29. package/dist/DiagnosticFilterer.d.ts +1 -0
  30. package/dist/DiagnosticFilterer.js +5 -3
  31. package/dist/DiagnosticFilterer.js.map +1 -1
  32. package/dist/DiagnosticMessages.d.ts +61 -13
  33. package/dist/DiagnosticMessages.js +116 -19
  34. package/dist/DiagnosticMessages.js.map +1 -1
  35. package/dist/DiagnosticSeverityAdjuster.d.ts +7 -0
  36. package/dist/DiagnosticSeverityAdjuster.js +41 -0
  37. package/dist/DiagnosticSeverityAdjuster.js.map +1 -0
  38. package/dist/FunctionScope.d.ts +28 -0
  39. package/dist/FunctionScope.js +52 -0
  40. package/dist/FunctionScope.js.map +1 -0
  41. package/dist/KeyedThrottler.d.ts +3 -3
  42. package/dist/KeyedThrottler.js +3 -3
  43. package/dist/KeyedThrottler.js.map +1 -1
  44. package/dist/LanguageServer.d.ts +23 -11
  45. package/dist/LanguageServer.js +150 -69
  46. package/dist/LanguageServer.js.map +1 -1
  47. package/dist/Logger.d.ts +3 -2
  48. package/dist/Logger.js +11 -3
  49. package/dist/Logger.js.map +1 -1
  50. package/dist/PluginInterface.d.ts +21 -3
  51. package/dist/PluginInterface.js +74 -6
  52. package/dist/PluginInterface.js.map +1 -1
  53. package/dist/Program.d.ts +158 -79
  54. package/dist/Program.js +841 -706
  55. package/dist/Program.js.map +1 -1
  56. package/dist/ProgramBuilder.d.ts +22 -12
  57. package/dist/ProgramBuilder.js +130 -103
  58. package/dist/ProgramBuilder.js.map +1 -1
  59. package/dist/Scope.d.ts +86 -137
  60. package/dist/Scope.js +453 -519
  61. package/dist/Scope.js.map +1 -1
  62. package/dist/Stopwatch.js +1 -1
  63. package/dist/Stopwatch.js.map +1 -1
  64. package/dist/SymbolTable.d.ts +89 -34
  65. package/dist/SymbolTable.js +239 -114
  66. package/dist/SymbolTable.js.map +1 -1
  67. package/dist/Throttler.d.ts +12 -0
  68. package/dist/Throttler.js +39 -0
  69. package/dist/Throttler.js.map +1 -1
  70. package/dist/Watcher.d.ts +0 -3
  71. package/dist/Watcher.js +0 -3
  72. package/dist/Watcher.js.map +1 -1
  73. package/dist/XmlScope.d.ts +4 -11
  74. package/dist/XmlScope.js +75 -88
  75. package/dist/XmlScope.js.map +1 -1
  76. package/dist/astUtils/CachedLookups.d.ts +48 -0
  77. package/dist/astUtils/CachedLookups.js +323 -0
  78. package/dist/astUtils/CachedLookups.js.map +1 -0
  79. package/dist/astUtils/{AstEditor.d.ts → Editor.d.ts} +9 -5
  80. package/dist/astUtils/{AstEditor.js → Editor.js} +10 -4
  81. package/dist/astUtils/Editor.js.map +1 -0
  82. package/dist/astUtils/{AstEditor.spec.js → Editor.spec.js} +69 -65
  83. package/dist/astUtils/Editor.spec.js.map +1 -0
  84. package/dist/astUtils/creators.d.ts +10 -10
  85. package/dist/astUtils/creators.js +54 -24
  86. package/dist/astUtils/creators.js.map +1 -1
  87. package/dist/astUtils/creators.spec.js +5 -5
  88. package/dist/astUtils/creators.spec.js.map +1 -1
  89. package/dist/astUtils/reflection.d.ts +132 -104
  90. package/dist/astUtils/reflection.js +220 -174
  91. package/dist/astUtils/reflection.js.map +1 -1
  92. package/dist/astUtils/reflection.spec.js +256 -157
  93. package/dist/astUtils/reflection.spec.js.map +1 -1
  94. package/dist/astUtils/stackedVisitor.spec.js +12 -12
  95. package/dist/astUtils/stackedVisitor.spec.js.map +1 -1
  96. package/dist/astUtils/visitors.d.ts +53 -35
  97. package/dist/astUtils/visitors.js +29 -3
  98. package/dist/astUtils/visitors.js.map +1 -1
  99. package/dist/astUtils/visitors.spec.js +208 -52
  100. package/dist/astUtils/visitors.spec.js.map +1 -1
  101. package/dist/astUtils/xml.d.ts +9 -9
  102. package/dist/astUtils/xml.js +9 -9
  103. package/dist/astUtils/xml.js.map +1 -1
  104. package/dist/bscPlugin/BscPlugin.d.ts +11 -2
  105. package/dist/bscPlugin/BscPlugin.js +37 -3
  106. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  107. package/dist/bscPlugin/CallExpressionInfo.d.ts +36 -0
  108. package/dist/bscPlugin/CallExpressionInfo.js +131 -0
  109. package/dist/bscPlugin/CallExpressionInfo.js.map +1 -0
  110. package/dist/bscPlugin/FileWriter.d.ts +6 -0
  111. package/dist/bscPlugin/FileWriter.js +24 -0
  112. package/dist/bscPlugin/FileWriter.js.map +1 -0
  113. package/dist/bscPlugin/SignatureHelpUtil.d.ts +10 -0
  114. package/dist/bscPlugin/SignatureHelpUtil.js +136 -0
  115. package/dist/bscPlugin/SignatureHelpUtil.js.map +1 -0
  116. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +16 -13
  117. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  118. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +16 -16
  119. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
  120. package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +52 -1
  121. package/dist/bscPlugin/completions/CompletionsProcessor.js +517 -26
  122. package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -1
  123. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +1909 -0
  124. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -0
  125. package/dist/bscPlugin/definition/DefinitionProvider.d.ts +13 -0
  126. package/dist/bscPlugin/definition/DefinitionProvider.js +210 -0
  127. package/dist/bscPlugin/definition/DefinitionProvider.js.map +1 -0
  128. package/dist/bscPlugin/definition/DefinitionProvider.spec.js +88 -0
  129. package/dist/bscPlugin/definition/DefinitionProvider.spec.js.map +1 -0
  130. package/dist/bscPlugin/fileProviders/FileProvider.d.ts +9 -0
  131. package/dist/bscPlugin/fileProviders/FileProvider.js +51 -0
  132. package/dist/bscPlugin/fileProviders/FileProvider.js.map +1 -0
  133. package/dist/bscPlugin/hover/HoverProcessor.d.ts +7 -7
  134. package/dist/bscPlugin/hover/HoverProcessor.js +123 -125
  135. package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -1
  136. package/dist/bscPlugin/hover/HoverProcessor.spec.js +371 -53
  137. package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -1
  138. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +2 -1
  139. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +83 -23
  140. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
  141. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +83 -6
  142. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -1
  143. package/dist/bscPlugin/serialize/BslibInjector.spec.d.ts +1 -0
  144. package/dist/bscPlugin/serialize/BslibInjector.spec.js +19 -0
  145. package/dist/bscPlugin/serialize/BslibInjector.spec.js.map +1 -0
  146. package/dist/bscPlugin/serialize/BslibManager.d.ts +9 -0
  147. package/dist/bscPlugin/serialize/BslibManager.js +40 -0
  148. package/dist/bscPlugin/serialize/BslibManager.js.map +1 -0
  149. package/dist/bscPlugin/serialize/FileSerializer.d.ts +9 -0
  150. package/dist/bscPlugin/serialize/FileSerializer.js +72 -0
  151. package/dist/bscPlugin/serialize/FileSerializer.js.map +1 -0
  152. package/dist/bscPlugin/transpile/{BrsFilePreTranspileProcessor.d.ts → BrsFileTranspileProcessor.d.ts} +4 -2
  153. package/dist/bscPlugin/transpile/{BrsFilePreTranspileProcessor.js → BrsFileTranspileProcessor.js} +38 -12
  154. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js.map +1 -0
  155. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.d.ts +1 -0
  156. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js +41 -0
  157. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js.map +1 -0
  158. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.d.ts +12 -0
  159. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js +99 -0
  160. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js.map +1 -0
  161. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +13 -5
  162. package/dist/bscPlugin/validation/BrsFileValidator.js +262 -52
  163. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
  164. package/dist/bscPlugin/validation/BrsFileValidator.spec.js +230 -14
  165. package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +1 -1
  166. package/dist/bscPlugin/validation/ProgramValidator.d.ts +10 -0
  167. package/dist/bscPlugin/validation/ProgramValidator.js +32 -0
  168. package/dist/bscPlugin/validation/ProgramValidator.js.map +1 -0
  169. package/dist/bscPlugin/validation/ScopeValidator.d.ts +58 -27
  170. package/dist/bscPlugin/validation/ScopeValidator.js +514 -286
  171. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  172. package/dist/bscPlugin/validation/ScopeValidator.spec.d.ts +1 -0
  173. package/dist/bscPlugin/validation/ScopeValidator.spec.js +2527 -0
  174. package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -0
  175. package/dist/bscPlugin/validation/XmlFileValidator.d.ts +8 -0
  176. package/dist/bscPlugin/validation/XmlFileValidator.js +44 -0
  177. package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -0
  178. package/dist/cli.js +104 -13
  179. package/dist/cli.js.map +1 -1
  180. package/dist/deferred.d.ts +3 -3
  181. package/dist/deferred.js.map +1 -1
  182. package/dist/diagnosticUtils.d.ts +8 -2
  183. package/dist/diagnosticUtils.js +47 -17
  184. package/dist/diagnosticUtils.js.map +1 -1
  185. package/dist/examples/plugins/removePrint.js +8 -10
  186. package/dist/examples/plugins/removePrint.js.map +1 -1
  187. package/dist/files/AssetFile.d.ts +26 -0
  188. package/dist/files/AssetFile.js +26 -0
  189. package/dist/files/AssetFile.js.map +1 -0
  190. package/dist/files/BrsFile.Class.spec.js +523 -493
  191. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  192. package/dist/files/BrsFile.d.ts +111 -117
  193. package/dist/files/BrsFile.js +684 -1142
  194. package/dist/files/BrsFile.js.map +1 -1
  195. package/dist/files/BrsFile.spec.js +1783 -1233
  196. package/dist/files/BrsFile.spec.js.map +1 -1
  197. package/dist/files/BscFile.d.ts +104 -0
  198. package/dist/files/BscFile.js +16 -0
  199. package/dist/files/BscFile.js.map +1 -0
  200. package/dist/files/Factory.d.ts +25 -0
  201. package/dist/files/Factory.js +22 -0
  202. package/dist/files/Factory.js.map +1 -0
  203. package/dist/files/LazyFileData.d.ts +20 -0
  204. package/dist/files/LazyFileData.js +54 -0
  205. package/dist/files/LazyFileData.js.map +1 -0
  206. package/dist/files/LazyFileData.spec.d.ts +1 -0
  207. package/dist/files/LazyFileData.spec.js +27 -0
  208. package/dist/files/LazyFileData.spec.js.map +1 -0
  209. package/dist/files/XmlFile.d.ts +70 -32
  210. package/dist/files/XmlFile.js +106 -118
  211. package/dist/files/XmlFile.js.map +1 -1
  212. package/dist/files/XmlFile.spec.js +325 -262
  213. package/dist/files/XmlFile.spec.js.map +1 -1
  214. package/dist/files/tests/imports.spec.js +48 -40
  215. package/dist/files/tests/imports.spec.js.map +1 -1
  216. package/dist/files/tests/optionalChaning.spec.js +84 -24
  217. package/dist/files/tests/optionalChaning.spec.js.map +1 -1
  218. package/dist/globalCallables.js +16 -21
  219. package/dist/globalCallables.js.map +1 -1
  220. package/dist/index.d.ts +12 -1
  221. package/dist/index.js +12 -1
  222. package/dist/index.js.map +1 -1
  223. package/dist/interfaces.d.ts +421 -162
  224. package/dist/interfaces.js +27 -0
  225. package/dist/interfaces.js.map +1 -1
  226. package/dist/lexer/Character.spec.js +5 -5
  227. package/dist/lexer/Character.spec.js.map +1 -1
  228. package/dist/lexer/Lexer.d.ts +12 -5
  229. package/dist/lexer/Lexer.js +28 -13
  230. package/dist/lexer/Lexer.js.map +1 -1
  231. package/dist/lexer/Lexer.spec.js +181 -135
  232. package/dist/lexer/Lexer.spec.js.map +1 -1
  233. package/dist/lexer/Token.d.ts +9 -1
  234. package/dist/lexer/Token.js +9 -1
  235. package/dist/lexer/Token.js.map +1 -1
  236. package/dist/lexer/TokenKind.d.ts +8 -0
  237. package/dist/lexer/TokenKind.js +24 -4
  238. package/dist/lexer/TokenKind.js.map +1 -1
  239. package/dist/parser/AstNode.d.ts +162 -0
  240. package/dist/parser/AstNode.js +225 -0
  241. package/dist/parser/AstNode.js.map +1 -0
  242. package/dist/parser/AstNode.spec.d.ts +1 -0
  243. package/dist/parser/AstNode.spec.js +165 -0
  244. package/dist/parser/AstNode.spec.js.map +1 -0
  245. package/dist/parser/BrsTranspileState.d.ts +4 -7
  246. package/dist/parser/BrsTranspileState.js +4 -12
  247. package/dist/parser/BrsTranspileState.js.map +1 -1
  248. package/dist/parser/Expression.d.ts +376 -283
  249. package/dist/parser/Expression.js +742 -585
  250. package/dist/parser/Expression.js.map +1 -1
  251. package/dist/parser/Parser.Class.spec.js +151 -145
  252. package/dist/parser/Parser.Class.spec.js.map +1 -1
  253. package/dist/parser/Parser.d.ts +48 -201
  254. package/dist/parser/Parser.js +705 -1026
  255. package/dist/parser/Parser.js.map +1 -1
  256. package/dist/parser/Parser.spec.d.ts +3 -1
  257. package/dist/parser/Parser.spec.js +861 -848
  258. package/dist/parser/Parser.spec.js.map +1 -1
  259. package/dist/parser/SGParser.d.ts +9 -8
  260. package/dist/parser/SGParser.js +10 -8
  261. package/dist/parser/SGParser.js.map +1 -1
  262. package/dist/parser/SGParser.spec.js +27 -38
  263. package/dist/parser/SGParser.spec.js.map +1 -1
  264. package/dist/parser/SGTypes.d.ts +98 -35
  265. package/dist/parser/SGTypes.js +169 -99
  266. package/dist/parser/SGTypes.js.map +1 -1
  267. package/dist/parser/Statement.d.ts +468 -272
  268. package/dist/parser/Statement.js +904 -631
  269. package/dist/parser/Statement.js.map +1 -1
  270. package/dist/parser/Statement.spec.js +47 -23
  271. package/dist/parser/Statement.spec.js.map +1 -1
  272. package/dist/parser/TranspileState.d.ts +1 -1
  273. package/dist/parser/TranspileState.js +7 -12
  274. package/dist/parser/TranspileState.js.map +1 -1
  275. package/dist/parser/tests/Parser.spec.js +3 -2
  276. package/dist/parser/tests/Parser.spec.js.map +1 -1
  277. package/dist/parser/tests/controlFlow/For.spec.js +33 -23
  278. package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
  279. package/dist/parser/tests/controlFlow/ForEach.spec.js +25 -20
  280. package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
  281. package/dist/parser/tests/controlFlow/If.spec.js +96 -94
  282. package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
  283. package/dist/parser/tests/controlFlow/While.spec.js +22 -16
  284. package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
  285. package/dist/parser/tests/expression/Additive.spec.js +8 -8
  286. package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
  287. package/dist/parser/tests/expression/ArrayLiterals.spec.js +58 -21
  288. package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
  289. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +62 -21
  290. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
  291. package/dist/parser/tests/expression/Boolean.spec.js +8 -8
  292. package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
  293. package/dist/parser/tests/expression/Call.spec.js +129 -21
  294. package/dist/parser/tests/expression/Call.spec.js.map +1 -1
  295. package/dist/parser/tests/expression/Exponential.spec.js +5 -5
  296. package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
  297. package/dist/parser/tests/expression/Function.spec.js +36 -36
  298. package/dist/parser/tests/expression/Function.spec.js.map +1 -1
  299. package/dist/parser/tests/expression/Indexing.spec.js +92 -22
  300. package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
  301. package/dist/parser/tests/expression/Multiplicative.spec.js +9 -9
  302. package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
  303. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +59 -59
  304. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  305. package/dist/parser/tests/expression/PrefixUnary.spec.js +12 -12
  306. package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
  307. package/dist/parser/tests/expression/Primary.spec.js +12 -12
  308. package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
  309. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +10 -10
  310. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -1
  311. package/dist/parser/tests/expression/Relational.spec.js +13 -13
  312. package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
  313. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +24 -24
  314. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
  315. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +96 -57
  316. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  317. package/dist/parser/tests/expression/TernaryExpression.spec.js +89 -89
  318. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  319. package/dist/parser/tests/expression/TypeExpression.spec.d.ts +1 -0
  320. package/dist/parser/tests/expression/TypeExpression.spec.js +127 -0
  321. package/dist/parser/tests/expression/TypeExpression.spec.js.map +1 -0
  322. package/dist/parser/tests/expression/UnaryExpression.spec.d.ts +1 -0
  323. package/dist/parser/tests/expression/UnaryExpression.spec.js +52 -0
  324. package/dist/parser/tests/expression/UnaryExpression.spec.js.map +1 -0
  325. package/dist/parser/tests/statement/AssignmentOperators.spec.js +15 -15
  326. package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
  327. package/dist/parser/tests/statement/ConstStatement.spec.js +82 -33
  328. package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -1
  329. package/dist/parser/tests/statement/Continue.spec.d.ts +1 -0
  330. package/dist/parser/tests/statement/Continue.spec.js +119 -0
  331. package/dist/parser/tests/statement/Continue.spec.js.map +1 -0
  332. package/dist/parser/tests/statement/Declaration.spec.js +19 -19
  333. package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
  334. package/dist/parser/tests/statement/Dim.spec.js +22 -22
  335. package/dist/parser/tests/statement/Dim.spec.js.map +1 -1
  336. package/dist/parser/tests/statement/Enum.spec.js +98 -302
  337. package/dist/parser/tests/statement/Enum.spec.js.map +1 -1
  338. package/dist/parser/tests/statement/For.spec.js +9 -10
  339. package/dist/parser/tests/statement/For.spec.js.map +1 -1
  340. package/dist/parser/tests/statement/ForEach.spec.js +8 -9
  341. package/dist/parser/tests/statement/ForEach.spec.js.map +1 -1
  342. package/dist/parser/tests/statement/Function.spec.js +44 -35
  343. package/dist/parser/tests/statement/Function.spec.js.map +1 -1
  344. package/dist/parser/tests/statement/Goto.spec.js +5 -5
  345. package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
  346. package/dist/parser/tests/statement/Increment.spec.js +20 -20
  347. package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
  348. package/dist/parser/tests/statement/InterfaceStatement.spec.js +30 -196
  349. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
  350. package/dist/parser/tests/statement/LibraryStatement.spec.js +11 -11
  351. package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
  352. package/dist/parser/tests/statement/Misc.spec.js +16 -78
  353. package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
  354. package/dist/parser/tests/statement/PrintStatement.spec.js +36 -34
  355. package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
  356. package/dist/parser/tests/statement/ReturnStatement.spec.js +14 -12
  357. package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
  358. package/dist/parser/tests/statement/Set.spec.js +48 -35
  359. package/dist/parser/tests/statement/Set.spec.js.map +1 -1
  360. package/dist/parser/tests/statement/Stop.spec.js +6 -6
  361. package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
  362. package/dist/parser/tests/statement/Throw.spec.js +6 -6
  363. package/dist/parser/tests/statement/Throw.spec.js.map +1 -1
  364. package/dist/parser/tests/statement/TryCatch.spec.js +18 -16
  365. package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
  366. package/dist/preprocessor/Manifest.d.ts +1 -1
  367. package/dist/preprocessor/Manifest.js +2 -2
  368. package/dist/preprocessor/Manifest.js.map +1 -1
  369. package/dist/preprocessor/Manifest.spec.js +8 -8
  370. package/dist/preprocessor/Manifest.spec.js.map +1 -1
  371. package/dist/preprocessor/Preprocessor.d.ts +5 -6
  372. package/dist/preprocessor/Preprocessor.js +5 -5
  373. package/dist/preprocessor/Preprocessor.js.map +1 -1
  374. package/dist/preprocessor/Preprocessor.spec.js +25 -25
  375. package/dist/preprocessor/Preprocessor.spec.js.map +1 -1
  376. package/dist/preprocessor/PreprocessorParser.d.ts +1 -1
  377. package/dist/preprocessor/PreprocessorParser.js +7 -1
  378. package/dist/preprocessor/PreprocessorParser.js.map +1 -1
  379. package/dist/preprocessor/PreprocessorParser.spec.js +13 -13
  380. package/dist/preprocessor/PreprocessorParser.spec.js.map +1 -1
  381. package/dist/roku-types/data.json +5892 -10081
  382. package/dist/roku-types/index.d.ts +622 -1719
  383. package/dist/types/ArrayType.d.ts +10 -9
  384. package/dist/types/ArrayType.js +65 -60
  385. package/dist/types/ArrayType.js.map +1 -1
  386. package/dist/types/ArrayType.spec.js +36 -68
  387. package/dist/types/ArrayType.spec.js.map +1 -1
  388. package/dist/types/AssociativeArrayType.d.ts +11 -0
  389. package/dist/types/AssociativeArrayType.js +52 -0
  390. package/dist/types/AssociativeArrayType.js.map +1 -0
  391. package/dist/types/BaseFunctionType.d.ts +9 -0
  392. package/dist/types/BaseFunctionType.js +25 -0
  393. package/dist/types/BaseFunctionType.js.map +1 -0
  394. package/dist/types/BooleanType.d.ts +8 -5
  395. package/dist/types/BooleanType.js +14 -7
  396. package/dist/types/BooleanType.js.map +1 -1
  397. package/dist/types/BooleanType.spec.js +10 -6
  398. package/dist/types/BooleanType.spec.js.map +1 -1
  399. package/dist/types/BscType.d.ts +32 -21
  400. package/dist/types/BscType.js +118 -21
  401. package/dist/types/BscType.js.map +1 -1
  402. package/dist/types/BscTypeKind.d.ts +25 -0
  403. package/dist/types/BscTypeKind.js +30 -0
  404. package/dist/types/BscTypeKind.js.map +1 -0
  405. package/dist/types/BuiltInInterfaceAdder.d.ts +23 -0
  406. package/dist/types/BuiltInInterfaceAdder.js +171 -0
  407. package/dist/types/BuiltInInterfaceAdder.js.map +1 -0
  408. package/dist/types/BuiltInInterfaceAdder.spec.d.ts +1 -0
  409. package/dist/types/BuiltInInterfaceAdder.spec.js +116 -0
  410. package/dist/types/BuiltInInterfaceAdder.spec.js.map +1 -0
  411. package/dist/types/ClassType.d.ts +17 -0
  412. package/dist/types/ClassType.js +58 -0
  413. package/dist/types/ClassType.js.map +1 -0
  414. package/dist/types/ClassType.spec.d.ts +1 -0
  415. package/dist/types/ClassType.spec.js +77 -0
  416. package/dist/types/ClassType.spec.js.map +1 -0
  417. package/dist/types/ComponentType.d.ts +26 -0
  418. package/dist/types/ComponentType.js +83 -0
  419. package/dist/types/ComponentType.js.map +1 -0
  420. package/dist/types/DoubleType.d.ts +8 -5
  421. package/dist/types/DoubleType.js +18 -16
  422. package/dist/types/DoubleType.js.map +1 -1
  423. package/dist/types/DoubleType.spec.js +12 -6
  424. package/dist/types/DoubleType.spec.js.map +1 -1
  425. package/dist/types/DynamicType.d.ts +9 -5
  426. package/dist/types/DynamicType.js +15 -4
  427. package/dist/types/DynamicType.js.map +1 -1
  428. package/dist/types/DynamicType.spec.js +16 -5
  429. package/dist/types/DynamicType.spec.js.map +1 -1
  430. package/dist/types/EnumType.d.ts +30 -12
  431. package/dist/types/EnumType.js +43 -17
  432. package/dist/types/EnumType.js.map +1 -1
  433. package/dist/types/EnumType.spec.d.ts +1 -0
  434. package/dist/types/EnumType.spec.js +33 -0
  435. package/dist/types/EnumType.spec.js.map +1 -0
  436. package/dist/types/FloatType.d.ts +8 -5
  437. package/dist/types/FloatType.js +18 -16
  438. package/dist/types/FloatType.js.map +1 -1
  439. package/dist/types/FloatType.spec.js +4 -6
  440. package/dist/types/FloatType.spec.js.map +1 -1
  441. package/dist/types/FunctionType.d.ts +13 -8
  442. package/dist/types/FunctionType.js +30 -14
  443. package/dist/types/FunctionType.js.map +1 -1
  444. package/dist/types/InheritableType.d.ts +28 -0
  445. package/dist/types/InheritableType.js +152 -0
  446. package/dist/types/InheritableType.js.map +1 -0
  447. package/dist/types/IntegerType.d.ts +8 -5
  448. package/dist/types/IntegerType.js +18 -16
  449. package/dist/types/IntegerType.js.map +1 -1
  450. package/dist/types/IntegerType.spec.js +8 -6
  451. package/dist/types/IntegerType.spec.js.map +1 -1
  452. package/dist/types/InterfaceType.d.ts +12 -13
  453. package/dist/types/InterfaceType.js +20 -48
  454. package/dist/types/InterfaceType.js.map +1 -1
  455. package/dist/types/InterfaceType.spec.js +90 -56
  456. package/dist/types/InterfaceType.spec.js.map +1 -1
  457. package/dist/types/InvalidType.d.ts +7 -5
  458. package/dist/types/InvalidType.js +13 -7
  459. package/dist/types/InvalidType.js.map +1 -1
  460. package/dist/types/InvalidType.spec.js +8 -6
  461. package/dist/types/InvalidType.spec.js.map +1 -1
  462. package/dist/types/LongIntegerType.d.ts +8 -5
  463. package/dist/types/LongIntegerType.js +17 -15
  464. package/dist/types/LongIntegerType.js.map +1 -1
  465. package/dist/types/LongIntegerType.spec.js +10 -6
  466. package/dist/types/LongIntegerType.spec.js.map +1 -1
  467. package/dist/types/NamespaceType.d.ts +12 -0
  468. package/dist/types/NamespaceType.js +28 -0
  469. package/dist/types/NamespaceType.js.map +1 -0
  470. package/dist/types/ObjectType.d.ts +9 -8
  471. package/dist/types/ObjectType.js +21 -11
  472. package/dist/types/ObjectType.js.map +1 -1
  473. package/dist/types/ObjectType.spec.js +3 -3
  474. package/dist/types/ObjectType.spec.js.map +1 -1
  475. package/dist/types/ReferenceType.d.ts +63 -0
  476. package/dist/types/ReferenceType.js +423 -0
  477. package/dist/types/ReferenceType.js.map +1 -0
  478. package/dist/types/ReferenceType.spec.d.ts +1 -0
  479. package/dist/types/ReferenceType.spec.js +137 -0
  480. package/dist/types/ReferenceType.spec.js.map +1 -0
  481. package/dist/types/StringType.d.ts +11 -5
  482. package/dist/types/StringType.js +18 -7
  483. package/dist/types/StringType.js.map +1 -1
  484. package/dist/types/StringType.spec.js +3 -5
  485. package/dist/types/StringType.spec.js.map +1 -1
  486. package/dist/types/TypedFunctionType.d.ts +22 -17
  487. package/dist/types/TypedFunctionType.js +78 -60
  488. package/dist/types/TypedFunctionType.js.map +1 -1
  489. package/dist/types/TypedFunctionType.spec.js +105 -20
  490. package/dist/types/TypedFunctionType.spec.js.map +1 -1
  491. package/dist/types/UninitializedType.d.ts +8 -6
  492. package/dist/types/UninitializedType.js +13 -7
  493. package/dist/types/UninitializedType.js.map +1 -1
  494. package/dist/types/UnionType.d.ts +20 -0
  495. package/dist/types/UnionType.js +123 -0
  496. package/dist/types/UnionType.js.map +1 -0
  497. package/dist/types/UnionType.spec.d.ts +1 -0
  498. package/dist/types/UnionType.spec.js +130 -0
  499. package/dist/types/UnionType.spec.js.map +1 -0
  500. package/dist/types/VoidType.d.ts +8 -5
  501. package/dist/types/VoidType.js +14 -7
  502. package/dist/types/VoidType.js.map +1 -1
  503. package/dist/types/VoidType.spec.js +3 -3
  504. package/dist/types/VoidType.spec.js.map +1 -1
  505. package/dist/types/helper.spec.d.ts +1 -0
  506. package/dist/types/helper.spec.js +145 -0
  507. package/dist/types/helper.spec.js.map +1 -0
  508. package/dist/types/helpers.d.ts +19 -37
  509. package/dist/types/helpers.js +159 -99
  510. package/dist/types/helpers.js.map +1 -1
  511. package/dist/types/index.d.ts +22 -0
  512. package/dist/types/index.js +39 -0
  513. package/dist/types/index.js.map +1 -0
  514. package/dist/util.d.ts +143 -139
  515. package/dist/util.js +864 -385
  516. package/dist/util.js.map +1 -1
  517. package/dist/validators/ClassValidator.d.ts +8 -25
  518. package/dist/validators/ClassValidator.js +99 -179
  519. package/dist/validators/ClassValidator.js.map +1 -1
  520. package/package.json +165 -152
  521. package/dist/astUtils/AstEditor.js.map +0 -1
  522. package/dist/astUtils/AstEditor.spec.js.map +0 -1
  523. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +0 -1
  524. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js +0 -32
  525. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js.map +0 -1
  526. package/dist/parser/SGTypes.spec.js +0 -351
  527. package/dist/parser/SGTypes.spec.js.map +0 -1
  528. package/dist/types/CustomType.d.ts +0 -12
  529. package/dist/types/CustomType.js +0 -44
  530. package/dist/types/CustomType.js.map +0 -1
  531. package/dist/types/LazyType.d.ts +0 -16
  532. package/dist/types/LazyType.js +0 -44
  533. package/dist/types/LazyType.js.map +0 -1
  534. /package/dist/astUtils/{AstEditor.spec.d.ts → Editor.spec.d.ts} +0 -0
  535. /package/dist/bscPlugin/{transpile/BrsFilePreTranspileProcessor.spec.d.ts → completions/CompletionsProcessor.spec.d.ts} +0 -0
  536. /package/dist/{parser/SGTypes.spec.d.ts → bscPlugin/definition/DefinitionProvider.spec.d.ts} +0 -0
@@ -0,0 +1,2527 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const sinonImport = require("sinon");
4
+ const DiagnosticMessages_1 = require("../../DiagnosticMessages");
5
+ const Program_1 = require("../../Program");
6
+ const testHelpers_spec_1 = require("../../testHelpers.spec");
7
+ const chai_1 = require("chai");
8
+ const IntegerType_1 = require("../../types/IntegerType");
9
+ const StringType_1 = require("../../types/StringType");
10
+ const types_1 = require("../../types");
11
+ const SymbolTable_1 = require("../../SymbolTable");
12
+ describe('ScopeValidator', () => {
13
+ let sinon = sinonImport.createSandbox();
14
+ let rootDir = process.cwd();
15
+ let program;
16
+ beforeEach(() => {
17
+ program = new Program_1.Program({
18
+ rootDir: rootDir
19
+ });
20
+ program.createSourceScope();
21
+ });
22
+ afterEach(() => {
23
+ sinon.restore();
24
+ program.dispose();
25
+ });
26
+ describe('mismatchArgumentCount', () => {
27
+ it('detects calling functions with too many arguments', () => {
28
+ program.setFile('source/file.brs', `
29
+ sub a()
30
+ end sub
31
+ sub b()
32
+ a(1)
33
+ end sub
34
+ `);
35
+ program.validate();
36
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
37
+ DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(0, 1).message
38
+ ]);
39
+ });
40
+ it('detects calling class constructors with too many arguments', () => {
41
+ program.setFile('source/main.bs', `
42
+ function noop0()
43
+ end function
44
+
45
+ function noop1(p1)
46
+ end function
47
+
48
+ sub main()
49
+ noop0(1)
50
+ noop1(1,2)
51
+ noop1()
52
+ end sub
53
+ `);
54
+ program.validate();
55
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
56
+ DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(0, 1),
57
+ DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(1, 2),
58
+ DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(1, 0)
59
+ ]);
60
+ });
61
+ it('detects calling functions with too few arguments', () => {
62
+ program.setFile('source/file.brs', `
63
+ sub a(name)
64
+ end sub
65
+ sub b()
66
+ a()
67
+ end sub
68
+ `);
69
+ program.validate();
70
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
71
+ DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(1, 0)
72
+ ]);
73
+ });
74
+ it('allows skipping optional parameter', () => {
75
+ program.setFile('source/file.brs', `
76
+ sub a(name="Bob")
77
+ end sub
78
+ sub b()
79
+ a()
80
+ end sub
81
+ `);
82
+ program.validate();
83
+ //should have an error
84
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
85
+ });
86
+ it('shows expected parameter range in error message', () => {
87
+ program.setFile('source/file.brs', `
88
+ sub a(age, name="Bob")
89
+ end sub
90
+ sub b()
91
+ a()
92
+ end sub
93
+ `);
94
+ program.validate();
95
+ //should have an error
96
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
97
+ DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount('1-2', 0)
98
+ ]);
99
+ });
100
+ it('handles expressions as arguments to a function', () => {
101
+ program.setFile('source/file.brs', `
102
+ sub a(age, name="Bob")
103
+ end sub
104
+ sub b()
105
+ a("cat" + "dog" + "mouse")
106
+ end sub
107
+ `);
108
+ program.validate();
109
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
110
+ });
111
+ it('Catches extra arguments for expressions as arguments to a function', () => {
112
+ program.setFile('source/file.brs', `
113
+ sub a(age)
114
+ end sub
115
+ sub b()
116
+ a(m.lib.movies[0], 1)
117
+ end sub
118
+ `);
119
+ program.validate();
120
+ //should have an error
121
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
122
+ DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(1, 2)
123
+ ]);
124
+ });
125
+ it('allows any number of parameters in a function used as an argument', () => {
126
+ program.setFile('source/file.brs', `
127
+ sub tryManyParams(someFunc as function)
128
+ someFunc(1, 2, "hello", "world")
129
+ end sub
130
+ `);
131
+ program.validate();
132
+ //should have no errors
133
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
134
+ });
135
+ it('checks for at least the number of non-optional args on variadic (callFunc) functions', () => {
136
+ program.setFile('components/Widget.xml', (0, testHelpers_spec_1.trim) `
137
+ <?xml version="1.0" encoding="utf-8" ?>
138
+ <component name="Widget" extends="Group">
139
+ <script uri="Widget.brs"/>
140
+ <interface>
141
+ <function name="someFunc" />
142
+ </interface>
143
+ </component>
144
+ `);
145
+ program.setFile('components/Widget.brs', `
146
+ sub someFunc(input as object)
147
+ print input
148
+ end sub
149
+ `);
150
+ program.setFile('source/util.brs', `
151
+ sub useCallFunc(input as roSGNodeWidget)
152
+ input.callFunc()
153
+ end sub
154
+ `);
155
+ program.validate();
156
+ //should have an error
157
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
158
+ DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount('1-32', 0)
159
+ ]);
160
+ });
161
+ it('any number number of args on variadic (callFunc) functions', () => {
162
+ program.setFile('components/Widget.xml', (0, testHelpers_spec_1.trim) `
163
+ <?xml version="1.0" encoding="utf-8" ?>
164
+ <component name="Widget" extends="Group">
165
+ <script uri="Widget.brs"/>
166
+ <interface>
167
+ <function name="someFunc" />
168
+ </interface>
169
+ </component>
170
+ `);
171
+ program.setFile('components/Widget.brs', `
172
+ sub someFunc(input as object)
173
+ print input
174
+ end sub
175
+ `);
176
+ program.setFile('source/util.brs', `
177
+ sub useCallFunc(input as roSGNodeWidget)
178
+ input.callFunc("someFunc", 1, 2, 3, {})
179
+ end sub
180
+ `);
181
+ program.validate();
182
+ //TODO: do a better job of handling callFunc() invocations!
183
+ //should have an error
184
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
185
+ });
186
+ });
187
+ describe('argumentTypeMismatch', () => {
188
+ it('param `as object` supports all known types', () => {
189
+ program.setFile('source/file.bs', `
190
+ sub main()
191
+ consoleLog(Direction.up)
192
+ consoleLog(true)
193
+ consoleLog(main)
194
+ consoleLog(1.2)
195
+ consoleLog({} as Video)
196
+ consoleLog("test")
197
+ end sub
198
+
199
+ sub consoleLog(thing as object)
200
+ print thing
201
+ end sub
202
+
203
+ interface Video
204
+ url as string
205
+ end interface
206
+ enum Direction
207
+ up = "up"
208
+ down = "down"
209
+ end enum
210
+ `);
211
+ program.validate();
212
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
213
+ });
214
+ it('`as object` var can be passed to various param types', () => {
215
+ program.setFile('source/file.bs', `
216
+ sub main()
217
+ obj = {} as object
218
+
219
+ printBoolean(obj)
220
+ printClass(obj)
221
+ printDouble(obj)
222
+ printEnum(obj)
223
+ printFloat(obj)
224
+ printFunction(obj)
225
+ printInteger(obj)
226
+ printInterface(obj)
227
+ printLongInteger(obj)
228
+ printString(obj)
229
+ end sub
230
+
231
+ sub printBoolean(value as boolean)
232
+ print value
233
+ end sub
234
+
235
+ class Person
236
+ name as string
237
+ end class
238
+
239
+ sub printClass(value as Person)
240
+ print value
241
+ end sub
242
+
243
+ sub printDouble(value as double)
244
+ print value
245
+ end sub
246
+
247
+ enum Direction
248
+ up = "up"
249
+ end enum
250
+
251
+ sub printEnum(value as Direction)
252
+ print value
253
+ end sub
254
+
255
+ sub printFloat(value as float)
256
+ print value
257
+ end sub
258
+
259
+ sub printFunction(value as function)
260
+ print value
261
+ print value(1)
262
+ end sub
263
+
264
+ interface Video
265
+ url as string
266
+ end interface
267
+
268
+ sub printInterface(value as Video)
269
+ print value
270
+ end sub
271
+
272
+ sub printInteger(value as integer)
273
+ print value
274
+ end sub
275
+
276
+ sub printLongInteger(value as LongInteger)
277
+ print value
278
+ end sub
279
+
280
+ sub printString(value as string)
281
+ print value
282
+ end sub
283
+ `);
284
+ program.validate();
285
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
286
+ });
287
+ it('treats string enums as strings when assigned to string vars', () => {
288
+ program.setFile('source/file.bs', `
289
+ sub main()
290
+ printDirection(Direction.up)
291
+ end sub
292
+
293
+ sub printDirection(theDirection as string)
294
+ print theDirection
295
+ end sub
296
+
297
+ enum Direction
298
+ up = "up"
299
+ down = "down"
300
+ end enum
301
+ `);
302
+ program.validate();
303
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
304
+ });
305
+ it('does not treat strings as a string enum', () => {
306
+ program.setFile('source/file.bs', `
307
+ sub main()
308
+ printDirection("up")
309
+ end sub
310
+
311
+ sub printDirection(theDirection as Direction)
312
+ print theDirection
313
+ end sub
314
+
315
+ enum Direction
316
+ up = "up"
317
+ down = "down"
318
+ end enum
319
+
320
+ `);
321
+ program.validate();
322
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
323
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('string', 'Direction').message
324
+ ]);
325
+ });
326
+ it('supports passing enum type as enum type', () => {
327
+ program.setFile('source/file.bs', `
328
+ sub test(theDirection as Direction)
329
+ printDirection(theDirection)
330
+ end sub
331
+
332
+ sub printDirection(theDirection as Direction)
333
+ print theDirection
334
+ end sub
335
+
336
+ enum Direction
337
+ up = "up"
338
+ down = "down"
339
+ end enum
340
+ `);
341
+ program.validate();
342
+ (0, testHelpers_spec_1.expectDiagnostics)(program, []);
343
+ });
344
+ it('Catches argument type mismatches on function calls', () => {
345
+ program.setFile('source/file.brs', `
346
+ sub a(age as integer)
347
+ end sub
348
+ sub b()
349
+ a("hello")
350
+ end sub
351
+ `);
352
+ program.validate();
353
+ //should have an error
354
+ (0, chai_1.expect)(program.getDiagnostics().map(x => x.message)).to.include(DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('string', 'integer').message);
355
+ });
356
+ it('Catches argument type mismatches on function calls for functions defined in another file', () => {
357
+ program.setFile('source/file.brs', `
358
+ sub a(age as integer)
359
+ end sub
360
+ `);
361
+ program.setFile('source/file2.brs', `
362
+ sub b()
363
+ a("hello")
364
+ foo = "foo"
365
+ a(foo)
366
+ end sub
367
+ `);
368
+ program.validate();
369
+ //should have an error
370
+ (0, chai_1.expect)(program.getDiagnostics().map(x => x.message)).to.include(DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('string', 'integer').message);
371
+ });
372
+ it('catches argument type mismatches on function calls within namespaces', () => {
373
+ program.setFile('source/file.bs', `
374
+ namespace Name.Space
375
+ sub a(param as integer)
376
+ print param
377
+ end sub
378
+
379
+ sub b()
380
+ a("hello")
381
+ foo = "foo"
382
+ a(foo)
383
+ end sub
384
+ end namespace
385
+ `);
386
+ program.validate();
387
+ //should have an error
388
+ (0, chai_1.expect)(program.getDiagnostics().map(x => x.message)).to.include(DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('string', 'integer').message);
389
+ });
390
+ it('catches argument type mismatches on function calls as arguments', () => {
391
+ program.setFile('source/file1.bs', `
392
+ sub a(param as string)
393
+ print param
394
+ end sub
395
+
396
+ function getNum() as integer
397
+ return 1
398
+ end function
399
+
400
+ sub b()
401
+ a(getNum())
402
+ end sub
403
+ `);
404
+ program.validate();
405
+ //should have an error
406
+ (0, chai_1.expect)(program.getDiagnostics().map(x => x.message)).to.include(DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('integer', 'string').message);
407
+ });
408
+ it('catches argument type mismatches on function calls within namespaces across files', () => {
409
+ program.setFile('source/file1.bs', `
410
+ namespace Name.Space
411
+ function getNum() as integer
412
+ return 1
413
+ end function
414
+
415
+ function getStr() as string
416
+ return "hello"
417
+ end function
418
+ end namespace
419
+ `);
420
+ program.setFile('source/file2.bs', `
421
+ namespace Name.Space
422
+ sub needsInt(param as integer)
423
+ print param
424
+ end sub
425
+
426
+ sub someFunc()
427
+ needsInt(getStr())
428
+ needsInt(getNum())
429
+ end sub
430
+ end namespace
431
+ `);
432
+ program.validate();
433
+ //should have an error
434
+ (0, chai_1.expect)(program.getDiagnostics().length).to.equal(1);
435
+ (0, chai_1.expect)(program.getDiagnostics().map(x => x.message)).to.include(DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('string', 'integer').message);
436
+ });
437
+ it('correctly validates correct parameters that are class members', () => {
438
+ program.setFile('source/main.bs', `
439
+ class PiHolder
440
+ pi = 3.14
441
+ function getPi() as float
442
+ return m.pi
443
+ end function
444
+ end class
445
+
446
+ sub takesFloat(fl as float)
447
+ end sub
448
+
449
+ sub someFunc()
450
+ holder = new PiHolder()
451
+ takesFloat(holder.pi)
452
+ takesFloat(holder.getPI())
453
+ end sub`);
454
+ program.validate();
455
+ //should have no error
456
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
457
+ });
458
+ it('correctly validates wrong parameters that are class members', () => {
459
+ program.setFile('source/main.bs', `
460
+ class PiHolder
461
+ pi = 3.14
462
+ name = "hello"
463
+ function getPi() as float
464
+ return m.pi
465
+ end function
466
+ end class
467
+
468
+ sub takesFloat(fl as float)
469
+ end sub
470
+
471
+ sub someFunc()
472
+ holder = new PiHolder()
473
+ takesFloat(holder.name)
474
+ takesFloat(Str(holder.getPI()))
475
+ end sub`);
476
+ program.validate();
477
+ //should have error: holder.name is string
478
+ (0, chai_1.expect)(program.getDiagnostics().length).to.equal(2);
479
+ (0, chai_1.expect)(program.getDiagnostics().map(x => x.message)).to.include(DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('string', 'float').message);
480
+ });
481
+ it('correctly validates correct parameters that are interface members', () => {
482
+ program.setFile('source/main.bs', `
483
+ interface IPerson
484
+ height as float
485
+ name as string
486
+ function getWeight() as float
487
+ function getAddress() as string
488
+ end interface
489
+
490
+ sub takesFloat(fl as float)
491
+ end sub
492
+
493
+ sub someFunc(person as IPerson)
494
+ takesFloat(person.height)
495
+ takesFloat(person.getWeight())
496
+ end sub`);
497
+ program.validate();
498
+ //should have no error
499
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
500
+ });
501
+ it('correctly validates wrong parameters that are interface members', () => {
502
+ program.setFile('source/main.bs', `
503
+ interface IPerson
504
+ isAlive as boolean
505
+ function getAddress() as string
506
+ end interface
507
+
508
+ sub takesFloat(fl as float)
509
+ end sub
510
+
511
+ sub someFunc(person as IPerson)
512
+ takesFloat(person.isAlive)
513
+ takesFloat(person.getAddress())
514
+ end sub
515
+ `);
516
+ program.validate();
517
+ //should have 2 errors: person.name is string (not float) and person.getAddress() is object (not float)
518
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
519
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('boolean', 'float').message,
520
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('string', 'float').message
521
+ ]);
522
+ });
523
+ it('`as object` param allows all types', () => {
524
+ program.setFile('source/main.bs', `
525
+ sub takesObject(obj as Object)
526
+ end sub
527
+
528
+ sub main()
529
+ takesObject(true)
530
+ takesObject(1)
531
+ takesObject(1.2)
532
+ takesObject(1.2#)
533
+ takesObject("text")
534
+ takesObject({})
535
+ takesObject([])
536
+ end sub
537
+ `);
538
+ program.validate();
539
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
540
+ });
541
+ it('allows conversions for arguments', () => {
542
+ program.setFile('source/main.bs', `
543
+ sub takesFloat(fl as float)
544
+ end sub
545
+
546
+ sub someFunc()
547
+ takesFloat(1)
548
+ end sub`);
549
+ program.validate();
550
+ //should have no error
551
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
552
+ });
553
+ it('allows subclasses as arguments', () => {
554
+ program.setFile('source/main.bs', `
555
+
556
+ class Animal
557
+ end class
558
+
559
+ class Dog extends Animal
560
+ end class
561
+
562
+ class Retriever extends Dog
563
+ end class
564
+
565
+ class Lab extends Retriever
566
+ end class
567
+
568
+ sub takesAnimal(thing as Animal)
569
+ end sub
570
+
571
+ sub someFunc()
572
+ fido = new Lab()
573
+ takesAnimal(fido)
574
+ end sub`);
575
+ program.validate();
576
+ //should have no error
577
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
578
+ });
579
+ it('allows subclasses from namespaces as arguments', () => {
580
+ program.setFile('source/main.bs', `
581
+
582
+ class Outside
583
+ end class
584
+
585
+ class ChildOutExtendsInside extends NS.Inside
586
+ end class
587
+
588
+ namespace NS
589
+ class Inside
590
+ end class
591
+
592
+ class ChildInExtendsOutside extends Outside
593
+ end class
594
+
595
+ class ChildInExtendsInside extends Inside
596
+ sub methodTakesInside(i as Inside)
597
+ end sub
598
+ end class
599
+
600
+ sub takesInside(klass as Inside)
601
+ end sub
602
+
603
+ sub testFuncInNamespace()
604
+ takesOutside(new Outside())
605
+ takesOutside(new NS.ChildInExtendsOutside())
606
+
607
+ ' These call NS.takesInside
608
+ takesInside(new NS.Inside())
609
+ takesInside(new Inside())
610
+ takesInside(new NS.ChildInExtendsInside())
611
+ takesInside(new ChildInExtendsInside())
612
+ takesInside(new ChildOutExtendsInside())
613
+
614
+ child = new ChildInExtendsInside()
615
+ child.methodTakesInside(new Inside())
616
+ child.methodTakesInside(new ChildInExtendsInside())
617
+ child.methodTakesInside(new ChildOutExtendsInside())
618
+ end sub
619
+
620
+ end namespace
621
+
622
+ sub takesOutside(klass as Outside)
623
+ end sub
624
+
625
+ sub takesInside(klass as NS.Inside)
626
+ end sub
627
+
628
+ sub testFunc()
629
+ takesOutside(new Outside())
630
+ takesOutside(new NS.ChildInExtendsOutside())
631
+
632
+ takesInside(new NS.Inside())
633
+ takesInside(new NS.ChildInExtendsInside())
634
+ takesInside(new ChildOutExtendsInside())
635
+
636
+ NS.takesInside(new NS.Inside())
637
+ NS.takesInside(new NS.ChildInExtendsInside())
638
+ NS.takesInside(new ChildOutExtendsInside())
639
+
640
+ child = new NS.ChildInExtendsInside()
641
+ child.methodTakesInside(new NS.Inside())
642
+ child.methodTakesInside(new NS.ChildInExtendsInside())
643
+ child.methodTakesInside(new ChildOutExtendsInside())
644
+ end sub`);
645
+ program.validate();
646
+ //should have no error
647
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
648
+ });
649
+ it('respects union types', () => {
650
+ program.setFile('source/main.bs', `
651
+ sub takesStringOrKlass(p as string or Klass)
652
+ end sub
653
+
654
+ class Klass
655
+ end class
656
+
657
+ sub someFunc()
658
+ myKlass = new Klass()
659
+ takesStringOrKlass("test")
660
+ takesStringOrKlass(myKlass)
661
+ takesStringOrKlass(1)
662
+ end sub`);
663
+ program.validate();
664
+ //should have error when passed an integer
665
+ (0, chai_1.expect)(program.getDiagnostics().length).to.equal(1);
666
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
667
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('integer', 'string or Klass').message
668
+ ]);
669
+ });
670
+ it('validates functions assigned to variables', () => {
671
+ program.setFile('source/main.bs', `
672
+ sub someFunc()
673
+ myFunc = function(i as integer, s as string)
674
+ print i+1
675
+ print s.len()
676
+ end function
677
+ myFunc("hello", 2)
678
+ end sub`);
679
+ program.validate();
680
+ //should have error when passed incorrect types
681
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
682
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('string', 'integer').message,
683
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('integer', 'string').message
684
+ ]);
685
+ });
686
+ it('allows any parameter types in a function passed as an argument', () => {
687
+ program.setFile('source/file.brs', `
688
+ function getStrLength(name as string) as integer
689
+ return len(name)
690
+ end function
691
+
692
+ sub tryManyParams(someFunc as function)
693
+ print someFunc(1, 2, "hello", "world")
694
+ end sub
695
+
696
+ sub test()
697
+ tryManyParams(getStrLength)
698
+ end sub
699
+ `);
700
+ program.validate();
701
+ //should have no errors
702
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
703
+ });
704
+ it('allows a inline function as an argument of type function', () => {
705
+ program.setFile('source/file.brs', `
706
+ sub tryManyParams(someFunc as function)
707
+ print someFunc(1, 2, "hello", "world")
708
+ end sub
709
+
710
+ sub test()
711
+ tryManyParams(sub (i as integer)
712
+ print i
713
+ end sub)
714
+ end sub
715
+ `);
716
+ program.validate();
717
+ //should have no errors
718
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
719
+ });
720
+ it('validates when a non-function is used as an argument expecting a function', () => {
721
+ program.setFile('source/file.brs', `
722
+ sub tryManyParams(someFunc as function)
723
+ print someFunc(1, 2, "hello", "world")
724
+ end sub
725
+
726
+ sub test()
727
+ notAFunction = 3.14
728
+ tryManyParams(notAFunction)
729
+ end sub
730
+ `);
731
+ program.validate();
732
+ //should have an error that the argument is not a function
733
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
734
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('float', 'function').message
735
+ ]);
736
+ });
737
+ it('allows a class constructor to be passed as arg to param typed `as function`', () => {
738
+ program.setFile('source/file.bs', `
739
+ sub callSomeFunc(someFunc as function)
740
+ someFunc()
741
+ end sub
742
+
743
+ class MyKlass
744
+ end class
745
+
746
+ sub doStuff()
747
+ callSomeFunc(MyKlass)
748
+ end sub
749
+ `);
750
+ program.validate();
751
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
752
+ });
753
+ it('allows a namespaced class constructor to be passed as arg to param typed `as function`', () => {
754
+ program.setFile('source/file.bs', `
755
+ sub callSomeFunc(someFunc as function)
756
+ someFunc()
757
+ end sub
758
+
759
+ namespace Alpha
760
+ class MyKlass
761
+ end class
762
+
763
+ sub doStuff()
764
+ callSomeFunc(MyKlass)
765
+ end sub
766
+ end namespace
767
+ `);
768
+ program.validate();
769
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
770
+ });
771
+ it('allows any variable to passed as argument to an untyped param with default type invalid', () => {
772
+ program.setFile('source/util.brs', `
773
+ sub doSomething(x = invalid)
774
+ print x
775
+ end sub
776
+
777
+ sub tests()
778
+ doSomething(1)
779
+ doSomething(1.1)
780
+ doSomething("Hello")
781
+ doSomething(true)
782
+ doSomething({test: true})
783
+ end sub
784
+ `);
785
+ program.validate();
786
+ //should have no errors
787
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
788
+ });
789
+ it('allows calling future function and save to same variable', () => {
790
+ program.setFile('source/util.brs', `
791
+ function getSomeInt() as integer
792
+ numVal = getUntypedNum()
793
+ numVal = cInt(numVal)
794
+ return numVal
795
+ end function
796
+
797
+ function getUntypedNum()
798
+ return 1
799
+ end function
800
+ `);
801
+ program.validate();
802
+ //should have no errors
803
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
804
+ });
805
+ it('allows union types of all compatible types as arg', () => {
806
+ program.setFile('source/util.bs', `
807
+ sub printIntNum(num as float or double or integer)
808
+ print cInt(num)
809
+ end sub
810
+ `);
811
+ program.validate();
812
+ //should have no errors
813
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
814
+ });
815
+ it('allows function calls of built-in members of primitives', () => {
816
+ program.setFile('source/util.brs', `
817
+ sub doSomething()
818
+ myStr = "Hello World"
819
+ myStr = myStr.replace("World", "You")
820
+ print myStr
821
+ end sub
822
+ `);
823
+ program.validate();
824
+ //should have no errors
825
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
826
+ });
827
+ it('validates union types of all compatible types as arg - when some do not work', () => {
828
+ program.setFile('source/util.bs', `
829
+ sub printIntNum(maybeNum as float or string)
830
+ print cInt(maybeNum)
831
+ end sub
832
+ `);
833
+ program.validate();
834
+ //should have no errors
835
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
836
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('float or string', 'float').message
837
+ ]);
838
+ });
839
+ it('validates function calls of built-in members of primitives', () => {
840
+ program.setFile('source/util.brs', `
841
+ sub doSomething()
842
+ myStr = "Hello World"
843
+ notAString = 3.14
844
+ myStr = myStr.replace("World", notAString)
845
+ print myStr
846
+ end sub
847
+ `);
848
+ program.validate();
849
+ //should have error - 2nd param should be a string, not a float
850
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
851
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('float', 'string').message
852
+ ]);
853
+ });
854
+ it('validates method calls of classes', () => {
855
+ program.setFile('source/util.bs', `
856
+ class Klass
857
+ sub test(input as string)
858
+ end sub
859
+ end class
860
+
861
+ sub doSomething()
862
+ k = new Klass()
863
+ k.test(3.14)
864
+ end sub
865
+ `);
866
+ program.validate();
867
+ //should have error - param should be a string, not a float
868
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
869
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('float', 'string').message
870
+ ]);
871
+ });
872
+ it('validates inside method calls of classes', () => {
873
+ program.setFile('source/util.bs', `
874
+ class Klass
875
+ sub test(input as string)
876
+ end sub
877
+
878
+ sub otherTest()
879
+ m.test(3.14)
880
+ end sub
881
+ end class
882
+ `);
883
+ program.validate();
884
+ //should have error - param should be a string, not a float
885
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
886
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('float', 'string').message
887
+ ]);
888
+ });
889
+ it('validates calls of a constructor', () => {
890
+ program.setFile('source/util.bs', `
891
+ class Klass
892
+ sub new(name as string)
893
+ end sub
894
+ end class
895
+
896
+ sub createKlass()
897
+ k = new Klass(3.14)
898
+ end sub
899
+ `);
900
+ program.validate();
901
+ //should have error - param should be a string, not a float
902
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
903
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('float', 'string').message
904
+ ]);
905
+ });
906
+ it('validates super calls in a constructor', () => {
907
+ program.setFile('source/util.bs', `
908
+ class Klass
909
+ sub new(name as string)
910
+ end sub
911
+ end class
912
+
913
+ class SubKlass extends Klass
914
+ sub new()
915
+ super(3.14)
916
+ end sub
917
+ end class
918
+ `);
919
+ program.validate();
920
+ //should have error - param should be a string, not a float
921
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
922
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('float', 'string').message
923
+ ]);
924
+ });
925
+ it('validates super calls in a class methods', () => {
926
+ program.setFile('source/util.bs', `
927
+ class Klass
928
+ sub test(name as string)
929
+ end sub
930
+ end class
931
+
932
+ class SubKlass extends Klass
933
+ sub test2()
934
+ super.test(3.14)
935
+ end sub
936
+ end class
937
+ `);
938
+ program.validate();
939
+ //should have error - param should be a string, not a float
940
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
941
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('float', 'string').message
942
+ ]);
943
+ });
944
+ it('validates a function passed as an arg', () => {
945
+ program.setFile('source/util.bs', `
946
+ sub foo()
947
+ getPi = function()
948
+ return 3.14
949
+ end function
950
+ bar(getPi)
951
+ end sub
952
+
953
+
954
+ sub bar(num as integer)
955
+ print num
956
+ end sub
957
+ `);
958
+ program.validate();
959
+ //should have error - param should be a string, not a float
960
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
961
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('function () as dynamic', 'integer').message
962
+ ]);
963
+ });
964
+ it('allows AAs that match an interface to be passed as args', () => {
965
+ program.setFile('source/util.bs', `
966
+ sub doStuff()
967
+ takesMyIface({beta: "hello", charlie: "world"})
968
+ end sub
969
+
970
+ sub takesMyIface(iFace as MyIFace)
971
+ end sub
972
+
973
+ interface MyIFace
974
+ beta as string
975
+ charlie as string
976
+ end interface
977
+ `);
978
+ program.validate();
979
+ //should have error
980
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
981
+ });
982
+ it('validates empty AAs that are passed as args to param expecting interface', () => {
983
+ program.setFile('source/util.bs', `
984
+ sub doStuff()
985
+ takesMyIface({})
986
+ end sub
987
+
988
+ sub takesMyIface(iFace as MyIFace)
989
+ end sub
990
+
991
+ interface MyIFace
992
+ beta as string
993
+ charlie as string
994
+ end interface
995
+ `);
996
+ program.validate();
997
+ //should have error
998
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
999
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('roAssociativeArray', 'MyIFace', {
1000
+ missingFields: [{ name: 'beta', expectedType: StringType_1.StringType.instance }, { name: 'charlie', expectedType: StringType_1.StringType.instance }]
1001
+ }).message
1002
+ ]);
1003
+ });
1004
+ it('includes data on missing fields', () => {
1005
+ program.setFile('source/util.bs', `
1006
+ sub doStuff()
1007
+ takesMyIface({charlie: "hello"})
1008
+ end sub
1009
+
1010
+ sub takesMyIface(iFace as MyIFace)
1011
+ end sub
1012
+
1013
+ interface MyIFace
1014
+ beta as string
1015
+ charlie as integer
1016
+ end interface
1017
+ `);
1018
+ program.validate();
1019
+ //should have error
1020
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1021
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('roAssociativeArray', 'MyIFace', {
1022
+ missingFields: [{ name: 'beta', expectedType: StringType_1.StringType.instance }],
1023
+ fieldMismatches: [{ name: 'charlie', expectedType: IntegerType_1.IntegerType.instance, actualType: StringType_1.StringType.instance }]
1024
+ }).message
1025
+ ]);
1026
+ //The aa should have 'beta' and 'charlie' properties of type string and integer
1027
+ const diagnostics = program.getDiagnostics();
1028
+ (0, chai_1.expect)(diagnostics.length).to.eq(1);
1029
+ const data = diagnostics[0].data;
1030
+ (0, chai_1.expect)(data.missingFields.length).to.eq(1);
1031
+ (0, chai_1.expect)(data.missingFields[0].name).to.eq('beta');
1032
+ (0, testHelpers_spec_1.expectTypeToBe)(data.missingFields[0].expectedType, StringType_1.StringType);
1033
+ (0, chai_1.expect)(data.fieldMismatches.length).to.eq(1);
1034
+ (0, chai_1.expect)(data.fieldMismatches[0].name).to.eq('charlie');
1035
+ (0, testHelpers_spec_1.expectTypeToBe)(data.fieldMismatches[0].expectedType, IntegerType_1.IntegerType);
1036
+ (0, testHelpers_spec_1.expectTypeToBe)(data.fieldMismatches[0].actualType, StringType_1.StringType);
1037
+ });
1038
+ it('allows interfaces that have a superset of properties', () => {
1039
+ program.setFile('source/util.bs', `
1040
+ sub doStuff()
1041
+ takesMyIface({alpha: true, beta: "hello", charlie: 1})
1042
+ end sub
1043
+
1044
+ sub takesMyIface(iFace as MyIFace)
1045
+ end sub
1046
+
1047
+ interface MyIFace
1048
+ beta as string
1049
+ charlie as integer
1050
+ end interface
1051
+ `);
1052
+ program.validate();
1053
+ //should have no errors
1054
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1055
+ });
1056
+ it('allows interfaces that have a superset of properties', () => {
1057
+ program.setFile('source/util.bs', `
1058
+ sub doStuff(otherFace as MyOtherFace)
1059
+ takesMyIface(otherFace)
1060
+ end sub
1061
+
1062
+ sub takesMyIface(iFace as MyIFace)
1063
+ end sub
1064
+
1065
+ interface MyIFace
1066
+ beta as string
1067
+ charlie as integer
1068
+ end interface
1069
+
1070
+ interface MyOtherFace
1071
+ alpha as boolean
1072
+ beta as string
1073
+ charlie as integer
1074
+ end interface
1075
+ `);
1076
+ program.validate();
1077
+ //should have no errors
1078
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1079
+ });
1080
+ it('includes data on missing fields', () => {
1081
+ program.setFile('source/util.bs', `
1082
+ sub doStuff()
1083
+ takesMyIface({charlie: "hello"})
1084
+ end sub
1085
+
1086
+ sub takesMyIface(iFace as MyIFace)
1087
+ end sub
1088
+
1089
+ interface MyIFace
1090
+ beta as string
1091
+ charlie as integer
1092
+ end interface
1093
+ `);
1094
+ program.validate();
1095
+ //should have error
1096
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1097
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('roAssociativeArray', 'MyIFace', {
1098
+ missingFields: [{ name: 'beta', expectedType: StringType_1.StringType.instance }],
1099
+ fieldMismatches: [{ name: 'charlie', expectedType: IntegerType_1.IntegerType.instance, actualType: StringType_1.StringType.instance }]
1100
+ }).message
1101
+ ]);
1102
+ //The aa should have 'beta' and 'charlie' properties of type string and integer
1103
+ const diagnostics = program.getDiagnostics();
1104
+ (0, chai_1.expect)(diagnostics.length).to.eq(1);
1105
+ const data = diagnostics[0].data;
1106
+ (0, chai_1.expect)(data.missingFields.length).to.eq(1);
1107
+ (0, chai_1.expect)(data.missingFields[0].name).to.eq('beta');
1108
+ (0, testHelpers_spec_1.expectTypeToBe)(data.missingFields[0].expectedType, StringType_1.StringType);
1109
+ (0, chai_1.expect)(data.fieldMismatches.length).to.eq(1);
1110
+ (0, chai_1.expect)(data.fieldMismatches[0].name).to.eq('charlie');
1111
+ (0, testHelpers_spec_1.expectTypeToBe)(data.fieldMismatches[0].expectedType, IntegerType_1.IntegerType);
1112
+ (0, testHelpers_spec_1.expectTypeToBe)(data.fieldMismatches[0].actualType, StringType_1.StringType);
1113
+ });
1114
+ describe('array compatibility', () => {
1115
+ it('accepts dynamic when assigning to a roArray', () => {
1116
+ program.setFile('source/util.bs', `
1117
+ sub takesArray(arr as roArray)
1118
+ end sub
1119
+
1120
+ sub doStuff(someArray)
1121
+ takesArray(someArray)
1122
+ end sub
1123
+ `);
1124
+ program.validate();
1125
+ //should have no errors
1126
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1127
+ });
1128
+ it('accepts roArray when assigning to a roArray', () => {
1129
+ program.setFile('source/util.bs', `
1130
+ sub takesArray(arr as roArray)
1131
+ end sub
1132
+
1133
+ sub doStuff(someArray as roArray)
1134
+ takesArray(someArray)
1135
+ end sub
1136
+ `);
1137
+ program.validate();
1138
+ //should have no errors
1139
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1140
+ });
1141
+ it('accepts typed arrays when assigning to a roArray', () => {
1142
+ program.setFile('source/util.bs', `
1143
+ sub takesArray(arr as roArray)
1144
+ end sub
1145
+
1146
+ sub doStuff(someArray as dynamic[])
1147
+ takesArray(someArray)
1148
+ end sub
1149
+ `);
1150
+ program.validate();
1151
+ //should have no errors
1152
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1153
+ });
1154
+ it('accepts roArray when assigning to dynamic[]', () => {
1155
+ program.setFile('source/util.bs', `
1156
+ sub takesArray(arr as dynamic[])
1157
+ end sub
1158
+
1159
+ sub doStuff(someArray as roArray)
1160
+ takesArray(someArray)
1161
+ end sub
1162
+ `);
1163
+ program.validate();
1164
+ //should have no errors
1165
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1166
+ });
1167
+ it('accepts roArray when assigning to typed array', () => {
1168
+ program.setFile('source/util.bs', `
1169
+ sub takesArray(arr as string[])
1170
+ end sub
1171
+
1172
+ sub doStuff(someArray as roArray)
1173
+ takesArray(someArray)
1174
+ end sub
1175
+ `);
1176
+ program.validate();
1177
+ //should have no errors
1178
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1179
+ });
1180
+ it('validates when typed array types are incompatible', () => {
1181
+ program.setFile('source/util.bs', `
1182
+ sub takesArray(arr as string[])
1183
+ end sub
1184
+
1185
+ sub doStuff(someArray as integer[])
1186
+ takesArray(someArray)
1187
+ end sub
1188
+ `);
1189
+ program.validate();
1190
+ //should have errors
1191
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1192
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('Array<integer>', 'Array<string>').message
1193
+ ]);
1194
+ });
1195
+ it('accepts when typed array types are compatible', () => {
1196
+ program.setFile('source/util.bs', `
1197
+ sub takesArray(arr as float[])
1198
+ end sub
1199
+
1200
+ sub doStuff(someArray as integer[])
1201
+ takesArray(someArray)
1202
+ end sub
1203
+ `);
1204
+ program.validate();
1205
+ //should have no errors
1206
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1207
+ });
1208
+ });
1209
+ describe('interface with optional properties', () => {
1210
+ it('allows using interfaces with optional props', () => {
1211
+ program.setFile('source/util.bs', `
1212
+ function takesIFace(iface as MyIFace) as string
1213
+ if invalid <> iface.name
1214
+ return iface.name
1215
+ else if invalid <> iface.data
1216
+ return FormatJson(iface.data)
1217
+ end if
1218
+ return "no"
1219
+ end function
1220
+
1221
+ sub doStuff(iface as MyIFace)
1222
+ print takesIFace(iface)
1223
+ end sub
1224
+
1225
+ interface MyIFace
1226
+ optional name as string
1227
+ optional data
1228
+ end interface
1229
+ `);
1230
+ program.validate();
1231
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1232
+ });
1233
+ it('allows using passing AAs with missing optional properties', () => {
1234
+ program.setFile('source/util.bs', `
1235
+ function takesIFace(iface as MyIFace) as string
1236
+ if invalid <> iface.name
1237
+ return iface.name
1238
+ else if invalid <> iface.data
1239
+ return FormatJson(iface.data)
1240
+ end if
1241
+ return "no"
1242
+ end function
1243
+
1244
+ sub doStuff(iface as MyIFace)
1245
+ print takesIFace({name: "Hello"})
1246
+ end sub
1247
+
1248
+ interface MyIFace
1249
+ optional name as string
1250
+ optional data
1251
+ end interface
1252
+ `);
1253
+ program.validate();
1254
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1255
+ });
1256
+ it('disallows using AAs with bad types for optional properties', () => {
1257
+ program.setFile('source/util.bs', `
1258
+ function takesIFace(iface as MyIFace) as string
1259
+ if invalid <> iface.name
1260
+ return iface.name
1261
+ else if invalid <> iface.data
1262
+ return FormatJson(iface.data)
1263
+ end if
1264
+ return "no"
1265
+ end function
1266
+
1267
+ sub doStuff(iface as MyIFace)
1268
+ print takesIFace({name: 3.14})
1269
+ end sub
1270
+
1271
+ interface MyIFace
1272
+ optional name as string
1273
+ optional data
1274
+ end interface
1275
+ `);
1276
+ program.validate();
1277
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1278
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('roAssociativeArray', 'MyIFace', {
1279
+ fieldMismatches: [{ name: 'name', expectedType: StringType_1.StringType.instance, actualType: types_1.FloatType.instance }]
1280
+ }).message
1281
+ ]);
1282
+ });
1283
+ it('disallows passing classes with bad types for optional properties', () => {
1284
+ program.setFile('source/util.bs', `
1285
+ function takesIFace(iface as MyIFace) as string
1286
+ if invalid <> iface.name
1287
+ return iface.name
1288
+ else if invalid <> iface.data
1289
+ return FormatJson(iface.data)
1290
+ end if
1291
+ return "no"
1292
+ end function
1293
+
1294
+ sub doStuff(iface as MyIFace)
1295
+ k = new MyKlass()
1296
+ print takesIFace(k)
1297
+ end sub
1298
+
1299
+ interface MyIFace
1300
+ optional name as string
1301
+ optional data
1302
+ end interface
1303
+
1304
+ class MyKlass
1305
+ name as float
1306
+ end class
1307
+ `);
1308
+ program.validate();
1309
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1310
+ DiagnosticMessages_1.DiagnosticMessages.argumentTypeMismatch('MyKlass', 'MyIFace', {
1311
+ fieldMismatches: [{ name: 'name', expectedType: StringType_1.StringType.instance, actualType: types_1.FloatType.instance }]
1312
+ }).message
1313
+ ]);
1314
+ });
1315
+ it('allows passing classes as args for interfaces with optional properties', () => {
1316
+ program.setFile('source/util.bs', `
1317
+ function takesIFace(iface as MyIFace) as string
1318
+ if invalid <> iface.name
1319
+ return iface.name
1320
+ else if invalid <> iface.data
1321
+ return FormatJson(iface.data)
1322
+ end if
1323
+ return "no"
1324
+ end function
1325
+
1326
+ sub doStuff(iface as MyIFace)
1327
+ k = new MyKlass()
1328
+ k2 = new MyKlass2()
1329
+ print takesIFace(k)
1330
+ print takesIFace(k2)
1331
+ end sub
1332
+
1333
+ interface MyIFace
1334
+ optional name as string
1335
+ optional data
1336
+ end interface
1337
+
1338
+ class MyKlass
1339
+ data = {}
1340
+ end class
1341
+
1342
+ class MyKlass2
1343
+ data = "test"
1344
+ end class
1345
+ `);
1346
+ program.validate();
1347
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1348
+ });
1349
+ });
1350
+ it('recursive types are allowed', () => {
1351
+ program.setFile('source/util.bs', `
1352
+ interface ChainNode
1353
+ name as string
1354
+ next as ChainNode
1355
+ end interface
1356
+
1357
+ function getChain(cNode as ChainNode) as string
1358
+ output = cNode.name
1359
+ if cNode.next <> invalid
1360
+ output += " - " + getChain(cNode.next)
1361
+ end if
1362
+ return output
1363
+ end function
1364
+ `);
1365
+ program.validate();
1366
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1367
+ });
1368
+ it('recursive types are allowed as array members', () => {
1369
+ program.setFile('source/util.bs', `
1370
+ interface ChainNode
1371
+ name as string
1372
+ nextItems as ChainNode[]
1373
+ end interface
1374
+
1375
+ function getChain(cNode as ChainNode) as string
1376
+ output = cNode.name
1377
+ for each item in cNode.nextItems
1378
+ output += " - " + getChain(item)
1379
+ end for
1380
+ return output
1381
+ end function
1382
+ `);
1383
+ program.validate();
1384
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1385
+ });
1386
+ it('deeply recursive types are allowed', () => {
1387
+ program.setFile('source/util.bs', `
1388
+ interface ChainNode
1389
+ name as string
1390
+ nextItem as ChainNodeWrapper
1391
+ end interface
1392
+
1393
+ interface ChainNodeWrapper
1394
+ node as ChainNode
1395
+ end interface
1396
+
1397
+ function getChain(cNode as ChainNode) as string
1398
+ output = cNode.name
1399
+ if cNode.nextItem <> invalid
1400
+ output += " - " + getChain(cNode.nextItem.node)
1401
+ end if
1402
+ return output
1403
+ end function
1404
+
1405
+ sub useChain()
1406
+ chain3 = {name: "C", nextItem: invalid}
1407
+ wrapper3 = {node: chain3}
1408
+ chain2 = {name: "B", nextItem: wrapper3}
1409
+ wrapper2 = {node: chain2}
1410
+ chain1 = {name: "A", nextItem: wrapper2}
1411
+
1412
+ print getChain(chain1)
1413
+ end sub
1414
+ `);
1415
+ program.validate();
1416
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1417
+ });
1418
+ });
1419
+ describe('cannotFindName', () => {
1420
+ it('finds variables from assignments from member functions of primitive types', () => {
1421
+ program.setFile('source/util.brs', `
1422
+ function lcaseTrim(str)
1423
+ trimmedLowerStr = lcase(str).trim()
1424
+ print trimmedLowerStr
1425
+ end function
1426
+ `);
1427
+ program.validate();
1428
+ //should have no errors
1429
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1430
+ });
1431
+ it('validates when lhs of compound assignment does not exist', () => {
1432
+ program.setFile('source/util.brs', `
1433
+ sub main()
1434
+ expected += chr(10) + " version=""2.0"""
1435
+ end sub
1436
+ `);
1437
+ program.validate();
1438
+ //should have error - cannot find "expected"
1439
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1440
+ DiagnosticMessages_1.DiagnosticMessages.cannotFindName('expected').message
1441
+ ]);
1442
+ });
1443
+ it('does not have a diagnostic for using a variable the result of an assignment with unresolved value', () => {
1444
+ program.setFile('source/util.bs', `
1445
+ sub doStuff()
1446
+ myValue = UndeclaredValue
1447
+ if myValue > 0
1448
+ print "hello"
1449
+ end if
1450
+ end sub
1451
+ `);
1452
+ program.validate();
1453
+ //should have only 1 error - cannot find "UndeclaredValue"
1454
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1455
+ DiagnosticMessages_1.DiagnosticMessages.cannotFindName('UndeclaredValue').message
1456
+ ]);
1457
+ });
1458
+ it('detects assigning to an unknown field in a class', () => {
1459
+ program.setFile('source/main.bs', `
1460
+ class Klass
1461
+ sub new()
1462
+ m.unknown = "hello"
1463
+ end sub
1464
+ end class
1465
+ `);
1466
+ program.validate();
1467
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1468
+ DiagnosticMessages_1.DiagnosticMessages.cannotFindName('unknown', 'Klass.unknown')
1469
+ ]);
1470
+ });
1471
+ it('detects assigning to an unknown field in a primitive', () => {
1472
+ program.setFile('source/main.bs', `
1473
+ sub main()
1474
+ myStr = "hello"
1475
+ myStr.length = 2
1476
+ end sub
1477
+ `);
1478
+ program.validate();
1479
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1480
+ DiagnosticMessages_1.DiagnosticMessages.cannotFindName('length', 'string.length')
1481
+ ]);
1482
+ });
1483
+ it('allows assigning to an unknown field in an AA', () => {
1484
+ program.setFile('source/main.bs', `
1485
+ sub main()
1486
+ myAA = {}
1487
+ myAA.unknown = 4
1488
+ end sub
1489
+ `);
1490
+ program.validate();
1491
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1492
+ });
1493
+ it('allows setting a member of an overriden member of an aa', () => {
1494
+ program.setFile('source/main.bs', `
1495
+ sub makeAA()
1496
+ myAA = {}
1497
+ addItemsToAA(myAA)
1498
+ myAA.items.value = "other string"
1499
+ end sub
1500
+
1501
+ sub addItemsToAA(someAA)
1502
+ someAA.items = {value: "some string"}
1503
+ end sub
1504
+ `);
1505
+ program.validate();
1506
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1507
+ });
1508
+ it('allows accessing a member of an overriden member of an aa', () => {
1509
+ program.setFile('source/main.bs', `
1510
+ sub makeAA()
1511
+ myAA = {}
1512
+ addItemsToAA(myAA)
1513
+ print myAA.items.value.len()
1514
+ end sub
1515
+
1516
+ sub addItemsToAA(someAA)
1517
+ someAA.items = {value: "some string"}
1518
+ end sub
1519
+ `);
1520
+ program.validate();
1521
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1522
+ });
1523
+ it('allows using a member of an overriden member of an aa in a different way', () => {
1524
+ program.setFile('source/main.bs', `
1525
+ sub makeAA()
1526
+ myAA = {}
1527
+ addItemsToAA(myAA)
1528
+ for each item in myAA.items
1529
+ print item
1530
+ end for
1531
+ end sub
1532
+
1533
+ sub addItemsToAA(someAA)
1534
+ someAA.items = [0, 1, 2, 3]
1535
+ end sub
1536
+ `);
1537
+ program.validate();
1538
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1539
+ });
1540
+ });
1541
+ describe('itemCannotBeUsedAsVariable', () => {
1542
+ it('detects assigning to a member of a namespace outside the namespace', () => {
1543
+ program.setFile('source/main.bs', `
1544
+ namespace Alpha
1545
+ const Name = "Alpha"
1546
+ end namespace
1547
+
1548
+ sub main()
1549
+ Alpha.name = "Beta"
1550
+ end sub
1551
+ `);
1552
+ program.validate();
1553
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1554
+ DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('namespace')
1555
+ ]);
1556
+ });
1557
+ it('detects assigning to a member of a namespace inside the namespace', () => {
1558
+ program.setFile('source/main.bs', `
1559
+ namespace Alpha
1560
+ const Name = "Alpha"
1561
+
1562
+ sub inAlpha()
1563
+ alpha.name = "Beta"
1564
+ end sub
1565
+ end namespace
1566
+ `);
1567
+ program.validate();
1568
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1569
+ DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('namespace')
1570
+ ]);
1571
+ });
1572
+ it('detects assigning to a member of a namespace outside the namespace', () => {
1573
+ program.setFile('source/main.bs', `
1574
+ namespace Alpha
1575
+ class Klass
1576
+ end class
1577
+ end namespace
1578
+
1579
+ sub main()
1580
+ myKlass = new Alpha.Klass()
1581
+ Alpha.klass = myKlass
1582
+ end sub
1583
+ `);
1584
+ program.validate();
1585
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1586
+ DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('namespace')
1587
+ ]);
1588
+ });
1589
+ it('detects assigning to a member of a namespace outside the namespace', () => {
1590
+ program.setFile('source/main.bs', `
1591
+ namespace Alpha
1592
+ class Klass
1593
+ function new()
1594
+ end function
1595
+
1596
+ function init()
1597
+ Alpha.innerFunc = someFunc
1598
+ end function
1599
+ end class
1600
+
1601
+ sub innerFunc()
1602
+ end sub
1603
+ end namespace
1604
+
1605
+ sub someFunc()
1606
+ end sub
1607
+ `);
1608
+ program.validate();
1609
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1610
+ DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('namespace')
1611
+ ]);
1612
+ });
1613
+ });
1614
+ describe('returnTypeMismatch', () => {
1615
+ it('finds when a function returns a type that is not what was declared', () => {
1616
+ program.setFile('source/util.bs', `
1617
+ function getPi() as float
1618
+ return "apple" ' get it?
1619
+ end function
1620
+ `);
1621
+ program.validate();
1622
+ //should have error - return value should be a float, not a string
1623
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1624
+ DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('string', 'float').message
1625
+ ]);
1626
+ });
1627
+ it('finds all return statements that do not match', () => {
1628
+ program.setFile('source/util.bs', `
1629
+ function getPi(kind as integer) as float
1630
+ if kind = 1
1631
+ return "apple"
1632
+ else if kind = 2
1633
+ return false
1634
+ else if kind = 3
1635
+ return new Pie("lemon")
1636
+ end if
1637
+ return 3.14
1638
+ end function
1639
+
1640
+ class Pie
1641
+ kind as string
1642
+ sub new(kind as string)
1643
+ m.kind = kind
1644
+ end sub
1645
+ end class
1646
+ `);
1647
+ program.validate();
1648
+ //should have error - return value should be a float, not whatever else
1649
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1650
+ DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('string', 'float').message,
1651
+ DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('boolean', 'float').message,
1652
+ DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('Pie', 'float').message
1653
+ ]);
1654
+ });
1655
+ it('allows returning compatible types', () => {
1656
+ program.setFile('source/util.bs', `
1657
+ function getPi() as float
1658
+ return 3 ' integers are compatible with floats
1659
+ end function
1660
+
1661
+ function getPie() as Pie
1662
+ return new Tart("lemon") ' Tart extends Pie
1663
+ end function
1664
+
1665
+ class Pie
1666
+ kind as string
1667
+ sub new(kind as string)
1668
+ m.kind = kind
1669
+ end sub
1670
+ end class
1671
+
1672
+ class Tart extends Pie
1673
+ size = "small"
1674
+ end class
1675
+ `);
1676
+ program.validate();
1677
+ //should have no errors
1678
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1679
+ });
1680
+ it('detects return types on void functions (subs)', () => {
1681
+ program.setFile('source/util.bs', `
1682
+ sub sayHello(name as string)
1683
+ return "hello " + name ' return should be void in subs
1684
+ end sub
1685
+ `);
1686
+ program.validate();
1687
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1688
+ DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('string', 'void').message
1689
+ ]);
1690
+ });
1691
+ it('detects return types on void functions', () => {
1692
+ program.setFile('source/util.bs', `
1693
+ function sayHello(name as string) as void
1694
+ return "hello " + name ' return should be void in subs
1695
+ end function
1696
+ `);
1697
+ program.validate();
1698
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1699
+ DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('string', 'void').message
1700
+ ]);
1701
+ });
1702
+ it('allows returning enums with the default type that matches the declared return type', () => {
1703
+ program.setFile('source/util.bs', `
1704
+ enum MyEnum
1705
+ val1
1706
+ val2
1707
+ end enum
1708
+
1709
+ function getInt() as integer
1710
+ return MyEnum.val1
1711
+ end function
1712
+ `);
1713
+ program.validate();
1714
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1715
+ });
1716
+ it('allows returning enums passed as a param with the default type that matches the declared return type', () => {
1717
+ program.setFile('source/util.bs', `
1718
+ enum MyEnum
1719
+ val1
1720
+ val2
1721
+ end enum
1722
+
1723
+ function getInt(enumVal as MyEnum) as integer
1724
+ return enumVal
1725
+ end function
1726
+ `);
1727
+ program.validate();
1728
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1729
+ });
1730
+ it('allows returning enums with the default type that matches the declared return type for string enums', () => {
1731
+ program.setFile('source/util.bs', `
1732
+ enum MyEnum
1733
+ val1 = "hello"
1734
+ val2 = "world"
1735
+ end enum
1736
+
1737
+ function getInt() as string
1738
+ return MyEnum.val1
1739
+ end function
1740
+ `);
1741
+ program.validate();
1742
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1743
+ });
1744
+ it('flags returning enums with the default type that does not matches the declared return type', () => {
1745
+ program.setFile('source/util.bs', `
1746
+ enum MyEnum
1747
+ val1 = "hello"
1748
+ val2 = "world"
1749
+ end enum
1750
+
1751
+ function getInt() as integer
1752
+ return MyEnum.val1
1753
+ end function
1754
+ `);
1755
+ program.validate();
1756
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1757
+ DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('MyEnum', 'integer').message
1758
+ ]);
1759
+ });
1760
+ it('flags returning enums passed as params with the default type that does not matches the declared return type', () => {
1761
+ program.setFile('source/util.bs', `
1762
+ enum MyEnum
1763
+ val1 = "hello"
1764
+ val2 = "world"
1765
+ end enum
1766
+
1767
+ function getInt(enumVal as MyEnum) as integer
1768
+ return enumVal
1769
+ end function
1770
+ `);
1771
+ program.validate();
1772
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1773
+ DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('MyEnum', 'integer').message
1774
+ ]);
1775
+ });
1776
+ it('flags returning enums type', () => {
1777
+ program.setFile('source/util.bs', `
1778
+ enum MyEnum
1779
+ val1 = "hello"
1780
+ val2 = "world"
1781
+ end enum
1782
+
1783
+
1784
+ function getInt() as integer
1785
+ return MyEnum
1786
+ end function
1787
+ `);
1788
+ program.validate();
1789
+ (0, chai_1.expect)(program.getDiagnostics().length).to.be.greaterThan(0);
1790
+ });
1791
+ it('allows returning an Enum', () => {
1792
+ program.setFile('source/util.bs', `
1793
+ enum MyEnum
1794
+ val1 = "hello"
1795
+ val2 = "world"
1796
+ end enum
1797
+
1798
+
1799
+ function getInt() as MyEnum
1800
+ return MyEnum.val1
1801
+ end function
1802
+ `);
1803
+ program.validate();
1804
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1805
+ });
1806
+ });
1807
+ describe('assignmentTypeMismatch', () => {
1808
+ it('finds when the type of the lhs is not compatible with the expected type', () => {
1809
+ program.setFile('source/util.bs', `
1810
+ sub doStuff(thing as iThing)
1811
+ thing.name = 123
1812
+ end sub
1813
+
1814
+ interface iThing
1815
+ name as string
1816
+ end interface
1817
+ `);
1818
+ program.validate();
1819
+ //should have error - assignment value should be a string, not a float
1820
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1821
+ DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch('integer', 'string').message
1822
+ ]);
1823
+ });
1824
+ it('allows setting a member with correct type that is a union type', () => {
1825
+ program.setFile('source/util.bs', `
1826
+ sub doStuff(thing as iThing)
1827
+ thing.name = 123
1828
+ end sub
1829
+
1830
+ interface iThing
1831
+ name as string or integer
1832
+ end interface
1833
+ `);
1834
+ program.validate();
1835
+ //should have no error - assignment value should be a string, not a float
1836
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1837
+ });
1838
+ it('finds when the rhs type is not compatible with the lhs, which is a union type', () => {
1839
+ program.setFile('source/util.bs', `
1840
+ sub doStuff(thing as iThing)
1841
+ thing.name = false
1842
+ end sub
1843
+
1844
+ interface iThing
1845
+ name as string or integer
1846
+ end interface
1847
+ `);
1848
+ program.validate();
1849
+ //should have error - assignment value should be a string or integer, not a boolean
1850
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1851
+ DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch('boolean', 'string or integer').message
1852
+ ]);
1853
+ });
1854
+ it('validates when trying to assign to a class method', () => {
1855
+ program.setFile('source/util.bs', `
1856
+ sub doStuff(myThing as Thing)
1857
+ myThing.getPi = 3.14
1858
+ end sub
1859
+
1860
+ class Thing
1861
+ function getPi() as float
1862
+ return 3.14
1863
+ end function
1864
+ end class
1865
+ `);
1866
+ program.validate();
1867
+ //should have error
1868
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1869
+ DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch('float', 'function getPi() as float').message
1870
+ ]);
1871
+ });
1872
+ it('disallows adding new properties to a class', () => {
1873
+ program.setFile('source/util.bs', `
1874
+ sub doStuff(myThing as Thing)
1875
+ myThing.getPi = 3.14
1876
+ end sub
1877
+
1878
+ class Thing
1879
+ end class
1880
+ `);
1881
+ program.validate();
1882
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [DiagnosticMessages_1.DiagnosticMessages.cannotFindName('getPi', 'Thing.getPi')]);
1883
+ });
1884
+ it('validates class constructors', () => {
1885
+ program.setFile('source/util.bs', `
1886
+ class Video
1887
+ sub new(url as integer)
1888
+ m.url = url 'this should be a compile error
1889
+ end sub
1890
+ public url as string
1891
+ end class
1892
+ `);
1893
+ program.validate();
1894
+ //should have errors
1895
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1896
+ DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch('integer', 'string').message
1897
+ ]);
1898
+ });
1899
+ it('validates when assigning to a sgNode', () => {
1900
+ program.setFile('source/util.bs', `
1901
+ sub setLabelText(label as roSGNodeLabel)
1902
+ label.text = 1234
1903
+ end sub
1904
+
1905
+ `);
1906
+ program.validate();
1907
+ //should have errors
1908
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1909
+ DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch('integer', 'string').message
1910
+ ]);
1911
+ });
1912
+ it('allows an assignment to a variable when the declared type does match the rhs type', () => {
1913
+ program.setFile('source/util.bs', `
1914
+ sub setX(value)
1915
+ x as integer = value ' value is dynamic
1916
+ end sub
1917
+
1918
+ sub setY()
1919
+ y as integer = len("hello") ' len returns an integer
1920
+ end sub
1921
+ `);
1922
+ program.validate();
1923
+ //should have errors
1924
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1925
+ });
1926
+ it('validates an assignment to a variable when the declared type does not match the rhs type', () => {
1927
+ program.setFile('source/util.bs', `
1928
+ sub setLabelText(label as roSGNodeLabel)
1929
+ x as integer = label.text
1930
+ end sub
1931
+ `);
1932
+ program.validate();
1933
+ //should have errors
1934
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1935
+ DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch('string', 'integer').message
1936
+ ]);
1937
+ });
1938
+ });
1939
+ describe('operatorTypeMismatch', () => {
1940
+ it('finds when the type of the lhs is not compatible with the rhs type', () => {
1941
+ program.setFile('source/util.bs', `
1942
+ sub doStuff()
1943
+ a = 1 + true
1944
+ b = "hello" * 2
1945
+ end sub
1946
+
1947
+ `);
1948
+ program.validate();
1949
+ //should have errors
1950
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1951
+ DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('+', 'integer', 'boolean').message,
1952
+ DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('*', 'string', 'integer').message
1953
+ ]);
1954
+ });
1955
+ it('allows when the type of the lhs is compatible with the rhs type', () => {
1956
+ program.setFile('source/util.bs', `
1957
+ sub doStuff()
1958
+ a = 10 << 1
1959
+ b = "hello" + "world"
1960
+ c = 78 / 34
1961
+ d = 100 \\ 5
1962
+ thing = new Klass()
1963
+ e = thing <> invalid
1964
+ end sub
1965
+
1966
+ class Klass
1967
+ end class
1968
+ `);
1969
+ program.validate();
1970
+ //should have no errors
1971
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1972
+ });
1973
+ it('allows tests against invalid', () => {
1974
+ program.setFile('source/util.bs', `
1975
+ sub doStuff()
1976
+ thing = new Klass()
1977
+ x = thing <> invalid
1978
+ end sub
1979
+
1980
+ class Klass
1981
+ end class
1982
+ `);
1983
+ program.validate();
1984
+ //should have no errors
1985
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1986
+ });
1987
+ it('disallows equality tests of classes', () => {
1988
+ program.setFile('source/util.bs', `
1989
+ sub doStuff()
1990
+ thing = new Klass()
1991
+ thing2 = new Klass()
1992
+ x = thing = thing2
1993
+ end sub
1994
+
1995
+ class Klass
1996
+ end class
1997
+ `);
1998
+ program.validate();
1999
+ //should have errors
2000
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2001
+ DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('=', 'Klass', 'Klass').message
2002
+ ]);
2003
+ });
2004
+ it('disallows operations between dynamic and custom types', () => {
2005
+ program.setFile('source/util.bs', `
2006
+ sub doStuff(input)
2007
+ thing = new Klass()
2008
+ x = thing + input
2009
+ end sub
2010
+
2011
+ class Klass
2012
+ end class
2013
+ `);
2014
+ program.validate();
2015
+ //should have errors
2016
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2017
+ DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('+', 'Klass', 'dynamic').message
2018
+ ]);
2019
+ });
2020
+ it('allows valid operations on enum members', () => {
2021
+ program.setFile('source/util.bs', `
2022
+ sub makeEasterly(d as Direction)
2023
+ print d + "e"
2024
+ print Direction.north + "east"
2025
+ end sub
2026
+
2027
+ function getTax(itemAmt as ItemCost) as Float
2028
+ return itemAmt * 1.15
2029
+ end function
2030
+
2031
+ enum Direction
2032
+ north = "n"
2033
+ south = "s"
2034
+ end enum
2035
+
2036
+ enum ItemCost
2037
+ x = 99.99
2038
+ y = 29.99
2039
+ end enum
2040
+
2041
+ `);
2042
+ program.validate();
2043
+ //should have no errors
2044
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2045
+ });
2046
+ it('finds invalid operations on enum members', () => {
2047
+ program.setFile('source/util.bs', `
2048
+ enum Direction
2049
+ north = "n"
2050
+ south = "s"
2051
+ end enum
2052
+
2053
+ sub makeEasterly(d as Direction)
2054
+ print d + 2
2055
+ print 3.14 * Direction.north
2056
+ end sub
2057
+ `);
2058
+ program.validate();
2059
+ //should have errors
2060
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2061
+ DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('+', 'Direction', 'integer').message,
2062
+ DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('*', 'float', 'Direction').message
2063
+ ]);
2064
+ });
2065
+ it('validates unary operators', () => {
2066
+ program.setFile('source/util.bs', `
2067
+ sub doStuff()
2068
+ x = - "hello world"
2069
+ end sub
2070
+ `);
2071
+ program.validate();
2072
+ //should have errors
2073
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2074
+ DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('-', 'string').message
2075
+ ]);
2076
+ });
2077
+ it('allows unary on dynamic and union types', () => {
2078
+ program.setFile('source/util.bs', `
2079
+ sub doStuff(x)
2080
+ y = -x
2081
+ print y
2082
+ end sub
2083
+
2084
+ sub doOtherStuff(x as float or integer)
2085
+ y = -x
2086
+ print y
2087
+ end sub
2088
+
2089
+ sub doEventMoreStuff(x as boolean or dynamic)
2090
+ if not x
2091
+ print "ok"
2092
+ end if
2093
+ end sub
2094
+ `);
2095
+ program.validate();
2096
+ //should have no errors
2097
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2098
+ });
2099
+ });
2100
+ describe('memberAccessibilityMismatch', () => {
2101
+ it('should flag when accessing a private member', () => {
2102
+ program.setFile('source/main.bs', `
2103
+ class SomeKlass
2104
+ private name as string
2105
+ end class
2106
+
2107
+ sub foo(x as SomeKlass)
2108
+ print x.name
2109
+ end sub
2110
+ `);
2111
+ program.validate();
2112
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2113
+ DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('name', SymbolTable_1.SymbolTypeFlag.private, 'SomeKlass')
2114
+ ]);
2115
+ });
2116
+ it('should allow accessing a private member in a class', () => {
2117
+ program.setFile('source/main.bs', `
2118
+ class SomeKlass
2119
+ private name as string
2120
+
2121
+ sub foo(x as SomeKlass)
2122
+ print x.name
2123
+ print m.name
2124
+ end sub
2125
+ end class
2126
+ `);
2127
+ program.validate();
2128
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2129
+ });
2130
+ it('should flag when calling a private method outside the class', () => {
2131
+ program.setFile('source/main.bs', `
2132
+ class SomeKlass
2133
+ private sub sayHello()
2134
+ print "Hello"
2135
+ end sub
2136
+ end class
2137
+
2138
+ sub foo(x as SomeKlass)
2139
+ x.sayHello()
2140
+ end sub
2141
+ `);
2142
+ program.validate();
2143
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2144
+ DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('sayHello', SymbolTable_1.SymbolTypeFlag.private, 'SomeKlass')
2145
+ ]);
2146
+ });
2147
+ it('should allow calling a private method in a class', () => {
2148
+ program.setFile('source/main.bs', `
2149
+ class SomeKlass
2150
+ private sub sayHello()
2151
+ print "Hello"
2152
+ end sub
2153
+
2154
+ sub foo(x as SomeKlass)
2155
+ x.sayHello()
2156
+ m.sayHello()
2157
+ end sub
2158
+ end class
2159
+ `);
2160
+ program.validate();
2161
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2162
+ });
2163
+ it('should not allow accessing a private member in a subclass', () => {
2164
+ program.setFile('source/main.bs', `
2165
+ class SomeKlass
2166
+ private name as string
2167
+ end class
2168
+
2169
+ class SubKlass extends SomeKlass
2170
+ sub foo()
2171
+ print m.name
2172
+ end sub
2173
+ end class
2174
+ `);
2175
+ program.validate();
2176
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2177
+ DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('name', SymbolTable_1.SymbolTypeFlag.private, 'SomeKlass')
2178
+ ]);
2179
+ });
2180
+ it('should flag when setting a value on a private member', () => {
2181
+ program.setFile('source/main.bs', `
2182
+ class SomeKlass
2183
+ private name as string
2184
+ end class
2185
+
2186
+ sub foo(x as SomeKlass)
2187
+ x.name = "foo"
2188
+ end sub
2189
+ `);
2190
+ program.validate();
2191
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2192
+ DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('name', SymbolTable_1.SymbolTypeFlag.private, 'SomeKlass')
2193
+ ]);
2194
+ });
2195
+ it('should flag when accessing a protected member', () => {
2196
+ program.setFile('source/main.bs', `
2197
+ class SomeKlass
2198
+ protected name as string
2199
+ end class
2200
+
2201
+ sub foo(x as SomeKlass)
2202
+ print x.name
2203
+ end sub
2204
+ `);
2205
+ program.validate();
2206
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2207
+ DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('name', SymbolTable_1.SymbolTypeFlag.protected, 'SomeKlass')
2208
+ ]);
2209
+ });
2210
+ it('should allow accessing a protected member in a class', () => {
2211
+ program.setFile('source/main.bs', `
2212
+ class SomeKlass
2213
+ protected name as string
2214
+
2215
+ sub foo(x as SomeKlass)
2216
+ print x.name
2217
+ print m.name
2218
+ end sub
2219
+ end class
2220
+ `);
2221
+ program.validate();
2222
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2223
+ });
2224
+ it('should flag when calling a protected method outside the class', () => {
2225
+ program.setFile('source/main.bs', `
2226
+ class SomeKlass
2227
+ protected sub sayHello()
2228
+ print "Hello"
2229
+ end sub
2230
+ end class
2231
+
2232
+ class SubKlass extends SomeKlass
2233
+ end class
2234
+
2235
+ sub foo(x as SomeKlass, y as SubKlass)
2236
+ x.sayHello()
2237
+ y.sayHello()
2238
+ end sub
2239
+ `);
2240
+ program.validate();
2241
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2242
+ DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('sayHello', SymbolTable_1.SymbolTypeFlag.protected, 'SomeKlass'),
2243
+ DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('sayHello', SymbolTable_1.SymbolTypeFlag.protected, 'SomeKlass')
2244
+ ]);
2245
+ });
2246
+ it('should allow calling a protected method in a class', () => {
2247
+ program.setFile('source/main.bs', `
2248
+ class SomeKlass
2249
+ protected sub sayHello()
2250
+ print "Hello"
2251
+ end sub
2252
+ end class
2253
+
2254
+ class SubKlass extends SomeKlass
2255
+ sub foo(x as SomeKlass, y as SubKlass)
2256
+ m.sayHello()
2257
+ x.sayHello()
2258
+ y.sayHello()
2259
+ end sub
2260
+ end class
2261
+ `);
2262
+ program.validate();
2263
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2264
+ });
2265
+ it('should allow accessing a protected member in a subclass', () => {
2266
+ program.setFile('source/main.bs', `
2267
+ class SomeKlass
2268
+ protected name as string
2269
+ end class
2270
+
2271
+ class SubKlass extends SomeKlass
2272
+ sub foo()
2273
+ print m.name
2274
+ end sub
2275
+ end class
2276
+ `);
2277
+ program.validate();
2278
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2279
+ });
2280
+ it('should flag when setting a value on a protected member', () => {
2281
+ program.setFile('source/main.bs', `
2282
+ class SomeKlass
2283
+ protected name as string
2284
+ end class
2285
+
2286
+ class SubKlass extends SomeKlass
2287
+ end class
2288
+
2289
+ sub foo(x as SubKlass)
2290
+ x.name = "foo"
2291
+ end sub
2292
+ `);
2293
+ program.validate();
2294
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2295
+ DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('name', SymbolTable_1.SymbolTypeFlag.protected, 'SomeKlass')
2296
+ ]);
2297
+ });
2298
+ it('should flag when trying to use an inaccessible member in the middle of a chain', () => {
2299
+ program.setFile('source/main.bs', `
2300
+ class SomeKlass
2301
+ protected name as string
2302
+ end class
2303
+
2304
+ sub foo(x as SomeKlass)
2305
+ print x.name.len()
2306
+ end sub
2307
+ `);
2308
+ program.validate();
2309
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2310
+ DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('name', SymbolTable_1.SymbolTypeFlag.protected, 'SomeKlass')
2311
+ ]);
2312
+ });
2313
+ describe('with namespaces', () => {
2314
+ it('protected members are accessible', () => {
2315
+ program.setFile('source/main.bs', `
2316
+ namespace AccessibilityTest
2317
+ class MyClass
2318
+ private data as roAssociativeArray = {}
2319
+ sub new()
2320
+ m.data.AddReplace("key", "value")
2321
+ end sub
2322
+
2323
+ protected sub printData()
2324
+ print m.data
2325
+ end sub
2326
+ end class
2327
+
2328
+ class SubClass extends MyClass
2329
+ sub foo()
2330
+ m.printData()
2331
+ end sub
2332
+ end class
2333
+ end namespace
2334
+ `);
2335
+ program.validate();
2336
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2337
+ });
2338
+ });
2339
+ });
2340
+ describe('revalidation', () => {
2341
+ it('revalidates when a enum defined in a different namespace changes', () => {
2342
+ program.setFile('source/file1.bs', `
2343
+ namespace Alpha
2344
+ function printEnum(enumVal as Alpha.Beta.Charlie.SomeEnum) as string
2345
+ return enumVal.toStr()
2346
+ end function
2347
+ end namespace
2348
+ `);
2349
+ program.setFile('source/file2.bs', `
2350
+ namespace Alpha.Beta.Charlie
2351
+ enum SomeEnum
2352
+ val1 = 1
2353
+ val2 = 2
2354
+ end enum
2355
+ end namespace
2356
+ `);
2357
+ program.validate();
2358
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2359
+ program.setFile('source/file2.bs', `
2360
+ namespace Alpha.Beta.Charlie
2361
+ enum ChangedEnum
2362
+ val1 = 1
2363
+ val2 = 2
2364
+ end enum
2365
+ end namespace
2366
+ `);
2367
+ program.validate();
2368
+ (0, testHelpers_spec_1.expectDiagnosticsIncludes)(program, [DiagnosticMessages_1.DiagnosticMessages.cannotFindName('SomeEnum').message]);
2369
+ });
2370
+ it('revalidates when a class defined in a different namespace changes', () => {
2371
+ program.setFile('source/file1.bs', `
2372
+ namespace Alpha
2373
+ function printEnum(myKlass as Alpha.Beta.Charlie.SomeClass) as string
2374
+ return myKlass.getValue()
2375
+ end function
2376
+ end namespace
2377
+ `);
2378
+ program.setFile('source/file2.bs', `
2379
+ namespace Alpha.Beta.Charlie
2380
+ class SomeClass
2381
+ private myValue as string
2382
+ function getValue() as string
2383
+ return m.myValue
2384
+ end function
2385
+ end class
2386
+ end namespace
2387
+ `);
2388
+ program.validate();
2389
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2390
+ program.setFile('source/file2.bs', `
2391
+ namespace Alpha.Beta.Charlie
2392
+ class SomeClass
2393
+ private myValue as string
2394
+ function getValue(lowerCase as boolean) as string
2395
+ if lowerCase
2396
+ return lcase(m.myValue)
2397
+ end if
2398
+ return m.myValue
2399
+ end function
2400
+ end class
2401
+ end namespace
2402
+ `);
2403
+ program.validate();
2404
+ (0, testHelpers_spec_1.expectDiagnosticsIncludes)(program, [DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(1, 0).message]);
2405
+ });
2406
+ it('validates only parts of files that need revalidation on scope validation', () => {
2407
+ function validateFile(file) {
2408
+ const validateFileEvent = {
2409
+ program: program,
2410
+ file: file
2411
+ };
2412
+ //emit an event to allow plugins to contribute to the file validation process
2413
+ program.plugins.emit('onFileValidate', validateFileEvent);
2414
+ }
2415
+ const commonContents = `
2416
+ sub noValidationForEachScope()
2417
+ k = new KlassInSameFile()
2418
+ print k.value
2419
+ end sub
2420
+
2421
+ class KlassInSameFile
2422
+ value = 1
2423
+ end class
2424
+ `;
2425
+ let commonBs = program.setFile('source/common.bs', commonContents);
2426
+ validateFile(commonBs);
2427
+ (0, chai_1.expect)(commonBs.validationSegmenter.segmentsForValidation.length).to.eq(2); // 1 func, 1 classField
2428
+ (0, chai_1.expect)(commonBs.validationSegmenter.unresolvedSegmentsSymbols.size).to.eq(0);
2429
+ commonBs.validationSegmenter.validatedSegments.forEach(x => (0, chai_1.expect)(x).to.be.false);
2430
+ (0, chai_1.expect)(commonBs.validationSegmenter.singleValidationSegments.size).to.eq(2); // no references needed to other files
2431
+ let common2Contents = `
2432
+ sub doesValidationForEachScope()
2433
+ k = new KlassInDiffFile()
2434
+ print k.value
2435
+ end sub
2436
+
2437
+ function alsoNoValidationForEachScope() as integer
2438
+ return 1
2439
+ end function
2440
+ `;
2441
+ let common2Bs = program.setFile('source/common2.bs', common2Contents);
2442
+ validateFile(common2Bs);
2443
+ (0, chai_1.expect)(common2Bs.validationSegmenter.segmentsForValidation.length).to.eq(2); // 2 func
2444
+ (0, chai_1.expect)(common2Bs.validationSegmenter.unresolvedSegmentsSymbols.size).to.eq(1);
2445
+ commonBs.validationSegmenter.validatedSegments.forEach(x => (0, chai_1.expect)(x).to.be.false);
2446
+ (0, chai_1.expect)(common2Bs.validationSegmenter.singleValidationSegments.size).to.eq(1); // alsoNoValidationForEachScope() does not reference other files
2447
+ let klassContents = `
2448
+ class KlassInDiffFile
2449
+ value = 2
2450
+ end class
2451
+ `;
2452
+ let klassBs = program.setFile('source/klass.bs', klassContents);
2453
+ validateFile(klassBs);
2454
+ (0, chai_1.expect)(klassBs.validationSegmenter.segmentsForValidation.length).to.eq(1); // 1 classField
2455
+ (0, chai_1.expect)(klassBs.validationSegmenter.unresolvedSegmentsSymbols.size).to.eq(0);
2456
+ klassBs.validationSegmenter.validatedSegments.forEach(x => (0, chai_1.expect)(x).to.be.false);
2457
+ (0, chai_1.expect)(klassBs.validationSegmenter.singleValidationSegments.size).to.eq(1); // does not reference other files
2458
+ const widgetFileContents = `
2459
+ sub init()
2460
+ noValidationForEachScope()
2461
+ doesValidationForEachScope()
2462
+ end sub
2463
+
2464
+ sub anotherFunction()
2465
+ print "hello"
2466
+ end sub
2467
+ `;
2468
+ let widgetBs = program.setFile('components/Widget.bs', widgetFileContents);
2469
+ validateFile(widgetBs);
2470
+ (0, chai_1.expect)(widgetBs.validationSegmenter.segmentsForValidation.length).to.eq(2); // 2 funcs
2471
+ (0, chai_1.expect)(widgetBs.validationSegmenter.unresolvedSegmentsSymbols.size).to.eq(1); // 1 func (init)
2472
+ widgetBs.validationSegmenter.validatedSegments.forEach(x => (0, chai_1.expect)(x).to.be.false);
2473
+ (0, chai_1.expect)(widgetBs.validationSegmenter.singleValidationSegments.size).to.eq(1); // 1 func (anotherFunction)
2474
+ const diffKlassContent = `
2475
+ class KlassInDiffFile
2476
+ value = 3
2477
+ end class
2478
+ `;
2479
+ let diffKlassBs = program.setFile('components/diffKlass.bs', diffKlassContent);
2480
+ validateFile(diffKlassBs);
2481
+ (0, chai_1.expect)(diffKlassBs.validationSegmenter.segmentsForValidation.length).to.eq(1); // 1 classField
2482
+ (0, chai_1.expect)(diffKlassBs.validationSegmenter.unresolvedSegmentsSymbols.size).to.eq(0);
2483
+ diffKlassBs.validationSegmenter.validatedSegments.forEach(x => (0, chai_1.expect)(x).to.be.false);
2484
+ (0, chai_1.expect)(diffKlassBs.validationSegmenter.singleValidationSegments.size).to.eq(1);
2485
+ program.setFile('components/Widget.xml', (0, testHelpers_spec_1.trim) `
2486
+ <?xml version="1.0" encoding="utf-8" ?>
2487
+ <component name="Widget" extends="Group">
2488
+ <script uri="Widget.bs"/>
2489
+ <script uri="pkg:/source/common.bs"/>
2490
+ <script uri="pkg:/source/common2.bs"/>
2491
+ <script uri="diffKlass.bs"/>
2492
+ </component>
2493
+ `);
2494
+ //reset files
2495
+ commonBs = program.setFile('source/common.bs', commonContents);
2496
+ common2Bs = program.setFile('source/common2.bs', common2Contents);
2497
+ klassBs = program.setFile('source/klass.bs', klassContents);
2498
+ widgetBs = program.setFile('components/Widget.bs', widgetFileContents);
2499
+ diffKlassBs = program.setFile('components/diffKlass.bs', diffKlassContent);
2500
+ program.validate();
2501
+ // all segments should be validated
2502
+ [commonBs, common2Bs, klassBs, widgetBs, diffKlassBs].forEach(file => {
2503
+ (0, chai_1.expect)(file.validationSegmenter.validatedSegments.size).to.gte(file.validationSegmenter.segmentsForValidation.length);
2504
+ file.validationSegmenter.validatedSegments.forEach(x => (0, chai_1.expect)(x).to.be.true);
2505
+ });
2506
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2507
+ program.setFile('components/Widget.bs', widgetFileContents);
2508
+ program.validate();
2509
+ // Widget.bs has changed. it needs to totally re-validated
2510
+ // and other files in the scope need to revalidate only the unresolved segments - should be source/common2.bs
2511
+ // TODO: how to test this?
2512
+ program.validate();
2513
+ program.setFile('components/diffKlass.bs', diffKlassContent);
2514
+ // diffKlass.bs has changed. it needs to totally re-validated
2515
+ // no other files in scope reference it .. no other files need revalidation
2516
+ // TODO: how to test this?
2517
+ program.validate();
2518
+ program.setFile('source/common.bs', commonContents);
2519
+ // common.bs has changed. it needs to totally re-validated
2520
+ // in source scope, common2.bs still has unresolves, it needs revalidation
2521
+ // in widget scope, widget.bs references it
2522
+ // TODO: how to test this?
2523
+ program.validate();
2524
+ });
2525
+ });
2526
+ });
2527
+ //# sourceMappingURL=ScopeValidator.spec.js.map