brighterscript 1.0.0-alpha.23 → 1.0.0-alpha.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (536) hide show
  1. package/CHANGELOG.md +585 -218
  2. package/README.md +45 -139
  3. package/bsconfig.schema.json +41 -0
  4. package/dist/ActionPipeline.d.ts +10 -0
  5. package/dist/ActionPipeline.js +40 -0
  6. package/dist/ActionPipeline.js.map +1 -0
  7. package/dist/AstValidationSegmenter.d.ts +25 -0
  8. package/dist/AstValidationSegmenter.js +152 -0
  9. package/dist/AstValidationSegmenter.js.map +1 -0
  10. package/dist/BsConfig.d.ts +39 -4
  11. package/dist/BusyStatusTracker.d.ts +31 -0
  12. package/dist/BusyStatusTracker.js +83 -0
  13. package/dist/BusyStatusTracker.js.map +1 -0
  14. package/dist/Cache.js +3 -3
  15. package/dist/Cache.js.map +1 -1
  16. package/dist/CacheVerifier.d.ts +7 -0
  17. package/dist/CacheVerifier.js +20 -0
  18. package/dist/CacheVerifier.js.map +1 -0
  19. package/dist/CodeActionUtil.d.ts +3 -3
  20. package/dist/CodeActionUtil.js.map +1 -1
  21. package/dist/CommentFlagProcessor.d.ts +3 -2
  22. package/dist/CommentFlagProcessor.js +5 -4
  23. package/dist/CommentFlagProcessor.js.map +1 -1
  24. package/dist/DependencyGraph.d.ts +3 -2
  25. package/dist/DependencyGraph.js +11 -10
  26. package/dist/DependencyGraph.js.map +1 -1
  27. package/dist/DiagnosticCollection.js +9 -5
  28. package/dist/DiagnosticCollection.js.map +1 -1
  29. package/dist/DiagnosticFilterer.d.ts +1 -0
  30. package/dist/DiagnosticFilterer.js +5 -3
  31. package/dist/DiagnosticFilterer.js.map +1 -1
  32. package/dist/DiagnosticMessages.d.ts +79 -15
  33. package/dist/DiagnosticMessages.js +134 -21
  34. package/dist/DiagnosticMessages.js.map +1 -1
  35. package/dist/DiagnosticSeverityAdjuster.d.ts +7 -0
  36. package/dist/DiagnosticSeverityAdjuster.js +41 -0
  37. package/dist/DiagnosticSeverityAdjuster.js.map +1 -0
  38. package/dist/FunctionScope.d.ts +28 -0
  39. package/dist/FunctionScope.js +52 -0
  40. package/dist/FunctionScope.js.map +1 -0
  41. package/dist/KeyedThrottler.d.ts +3 -3
  42. package/dist/KeyedThrottler.js +3 -3
  43. package/dist/KeyedThrottler.js.map +1 -1
  44. package/dist/LanguageServer.d.ts +23 -11
  45. package/dist/LanguageServer.js +222 -87
  46. package/dist/LanguageServer.js.map +1 -1
  47. package/dist/Logger.d.ts +3 -2
  48. package/dist/Logger.js +11 -3
  49. package/dist/Logger.js.map +1 -1
  50. package/dist/PluginInterface.d.ts +21 -3
  51. package/dist/PluginInterface.js +74 -6
  52. package/dist/PluginInterface.js.map +1 -1
  53. package/dist/Program.d.ts +162 -81
  54. package/dist/Program.js +903 -732
  55. package/dist/Program.js.map +1 -1
  56. package/dist/ProgramBuilder.d.ts +22 -12
  57. package/dist/ProgramBuilder.js +132 -104
  58. package/dist/ProgramBuilder.js.map +1 -1
  59. package/dist/Scope.d.ts +95 -134
  60. package/dist/Scope.js +477 -551
  61. package/dist/Scope.js.map +1 -1
  62. package/dist/Stopwatch.js +1 -1
  63. package/dist/Stopwatch.js.map +1 -1
  64. package/dist/SymbolTable.d.ts +95 -29
  65. package/dist/SymbolTable.js +256 -102
  66. package/dist/SymbolTable.js.map +1 -1
  67. package/dist/Throttler.d.ts +12 -0
  68. package/dist/Throttler.js +39 -0
  69. package/dist/Throttler.js.map +1 -1
  70. package/dist/Watcher.d.ts +0 -3
  71. package/dist/Watcher.js +0 -3
  72. package/dist/Watcher.js.map +1 -1
  73. package/dist/XmlScope.d.ts +4 -6
  74. package/dist/XmlScope.js +74 -68
  75. package/dist/XmlScope.js.map +1 -1
  76. package/dist/astUtils/CachedLookups.d.ts +48 -0
  77. package/dist/astUtils/CachedLookups.js +323 -0
  78. package/dist/astUtils/CachedLookups.js.map +1 -0
  79. package/dist/astUtils/{AstEditor.d.ts → Editor.d.ts} +9 -5
  80. package/dist/astUtils/{AstEditor.js → Editor.js} +10 -4
  81. package/dist/astUtils/Editor.js.map +1 -0
  82. package/dist/astUtils/{AstEditor.spec.js → Editor.spec.js} +68 -64
  83. package/dist/astUtils/Editor.spec.js.map +1 -0
  84. package/dist/astUtils/creators.d.ts +10 -10
  85. package/dist/astUtils/creators.js +26 -16
  86. package/dist/astUtils/creators.js.map +1 -1
  87. package/dist/astUtils/creators.spec.js +5 -5
  88. package/dist/astUtils/creators.spec.js.map +1 -1
  89. package/dist/astUtils/reflection.d.ts +132 -100
  90. package/dist/astUtils/reflection.js +225 -166
  91. package/dist/astUtils/reflection.js.map +1 -1
  92. package/dist/astUtils/reflection.spec.js +208 -126
  93. package/dist/astUtils/reflection.spec.js.map +1 -1
  94. package/dist/astUtils/stackedVisitor.spec.js +12 -12
  95. package/dist/astUtils/stackedVisitor.spec.js.map +1 -1
  96. package/dist/astUtils/visitors.d.ts +54 -35
  97. package/dist/astUtils/visitors.js +29 -3
  98. package/dist/astUtils/visitors.js.map +1 -1
  99. package/dist/astUtils/visitors.spec.js +178 -33
  100. package/dist/astUtils/visitors.spec.js.map +1 -1
  101. package/dist/astUtils/xml.d.ts +9 -9
  102. package/dist/astUtils/xml.js +9 -9
  103. package/dist/astUtils/xml.js.map +1 -1
  104. package/dist/bscPlugin/BscPlugin.d.ts +12 -2
  105. package/dist/bscPlugin/BscPlugin.js +41 -3
  106. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  107. package/dist/bscPlugin/CallExpressionInfo.d.ts +36 -0
  108. package/dist/bscPlugin/CallExpressionInfo.js +131 -0
  109. package/dist/bscPlugin/CallExpressionInfo.js.map +1 -0
  110. package/dist/bscPlugin/FileWriter.d.ts +6 -0
  111. package/dist/bscPlugin/FileWriter.js +24 -0
  112. package/dist/bscPlugin/FileWriter.js.map +1 -0
  113. package/dist/bscPlugin/SignatureHelpUtil.d.ts +10 -0
  114. package/dist/bscPlugin/SignatureHelpUtil.js +135 -0
  115. package/dist/bscPlugin/SignatureHelpUtil.js.map +1 -0
  116. package/dist/bscPlugin/codeActions/CodeActionsProcessor.d.ts +1 -1
  117. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +21 -12
  118. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  119. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +86 -12
  120. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
  121. package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +57 -0
  122. package/dist/bscPlugin/completions/CompletionsProcessor.js +544 -0
  123. package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -0
  124. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +1909 -0
  125. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -0
  126. package/dist/bscPlugin/fileProviders/FileProvider.d.ts +9 -0
  127. package/dist/bscPlugin/fileProviders/FileProvider.js +51 -0
  128. package/dist/bscPlugin/fileProviders/FileProvider.js.map +1 -0
  129. package/dist/bscPlugin/hover/HoverProcessor.d.ts +17 -0
  130. package/dist/bscPlugin/hover/HoverProcessor.js +188 -0
  131. package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -0
  132. package/dist/bscPlugin/hover/HoverProcessor.spec.js +513 -0
  133. package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -0
  134. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +3 -1
  135. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +102 -29
  136. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
  137. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +167 -6
  138. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -1
  139. package/dist/bscPlugin/serialize/BslibInjector.spec.d.ts +1 -0
  140. package/dist/bscPlugin/serialize/BslibInjector.spec.js +19 -0
  141. package/dist/bscPlugin/serialize/BslibInjector.spec.js.map +1 -0
  142. package/dist/bscPlugin/serialize/BslibManager.d.ts +9 -0
  143. package/dist/bscPlugin/serialize/BslibManager.js +40 -0
  144. package/dist/bscPlugin/serialize/BslibManager.js.map +1 -0
  145. package/dist/bscPlugin/serialize/FileSerializer.d.ts +9 -0
  146. package/dist/bscPlugin/serialize/FileSerializer.js +72 -0
  147. package/dist/bscPlugin/serialize/FileSerializer.js.map +1 -0
  148. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.d.ts +16 -0
  149. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js +123 -0
  150. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js.map +1 -0
  151. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.d.ts +1 -0
  152. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js +41 -0
  153. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js.map +1 -0
  154. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.d.ts +12 -0
  155. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js +99 -0
  156. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js.map +1 -0
  157. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +22 -1
  158. package/dist/bscPlugin/validation/BrsFileValidator.js +316 -29
  159. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
  160. package/dist/bscPlugin/validation/BrsFileValidator.spec.d.ts +1 -0
  161. package/dist/bscPlugin/validation/BrsFileValidator.spec.js +264 -0
  162. package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +1 -0
  163. package/dist/bscPlugin/validation/ProgramValidator.d.ts +10 -0
  164. package/dist/bscPlugin/validation/ProgramValidator.js +32 -0
  165. package/dist/bscPlugin/validation/ProgramValidator.js.map +1 -0
  166. package/dist/bscPlugin/validation/ScopeValidator.d.ts +56 -8
  167. package/dist/bscPlugin/validation/ScopeValidator.js +514 -116
  168. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  169. package/dist/bscPlugin/validation/ScopeValidator.spec.d.ts +1 -0
  170. package/dist/bscPlugin/validation/ScopeValidator.spec.js +2454 -0
  171. package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -0
  172. package/dist/bscPlugin/validation/XmlFileValidator.d.ts +8 -0
  173. package/dist/bscPlugin/validation/XmlFileValidator.js +44 -0
  174. package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -0
  175. package/dist/cli.js +107 -8
  176. package/dist/cli.js.map +1 -1
  177. package/dist/deferred.d.ts +3 -3
  178. package/dist/deferred.js.map +1 -1
  179. package/dist/diagnosticUtils.d.ts +8 -2
  180. package/dist/diagnosticUtils.js +47 -17
  181. package/dist/diagnosticUtils.js.map +1 -1
  182. package/dist/examples/plugins/removePrint.js +8 -10
  183. package/dist/examples/plugins/removePrint.js.map +1 -1
  184. package/dist/files/AssetFile.d.ts +26 -0
  185. package/dist/files/AssetFile.js +26 -0
  186. package/dist/files/AssetFile.js.map +1 -0
  187. package/dist/files/BrsFile.Class.spec.js +529 -486
  188. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  189. package/dist/files/BrsFile.d.ts +124 -112
  190. package/dist/files/BrsFile.js +819 -1131
  191. package/dist/files/BrsFile.js.map +1 -1
  192. package/dist/files/BrsFile.spec.js +1869 -1277
  193. package/dist/files/BrsFile.spec.js.map +1 -1
  194. package/dist/files/BscFile.d.ts +104 -0
  195. package/dist/files/BscFile.js +16 -0
  196. package/dist/files/BscFile.js.map +1 -0
  197. package/dist/files/Factory.d.ts +25 -0
  198. package/dist/files/Factory.js +22 -0
  199. package/dist/files/Factory.js.map +1 -0
  200. package/dist/files/LazyFileData.d.ts +20 -0
  201. package/dist/files/LazyFileData.js +54 -0
  202. package/dist/files/LazyFileData.js.map +1 -0
  203. package/dist/files/LazyFileData.spec.d.ts +1 -0
  204. package/dist/files/LazyFileData.spec.js +27 -0
  205. package/dist/files/LazyFileData.spec.js.map +1 -0
  206. package/dist/files/XmlFile.d.ts +70 -32
  207. package/dist/files/XmlFile.js +106 -117
  208. package/dist/files/XmlFile.js.map +1 -1
  209. package/dist/files/XmlFile.spec.js +325 -262
  210. package/dist/files/XmlFile.spec.js.map +1 -1
  211. package/dist/files/tests/imports.spec.js +49 -41
  212. package/dist/files/tests/imports.spec.js.map +1 -1
  213. package/dist/files/tests/optionalChaning.spec.js +104 -40
  214. package/dist/files/tests/optionalChaning.spec.js.map +1 -1
  215. package/dist/globalCallables.js +16 -18
  216. package/dist/globalCallables.js.map +1 -1
  217. package/dist/index.d.ts +13 -2
  218. package/dist/index.js +15 -2
  219. package/dist/index.js.map +1 -1
  220. package/dist/interfaces.d.ts +440 -150
  221. package/dist/interfaces.js +27 -0
  222. package/dist/interfaces.js.map +1 -1
  223. package/dist/lexer/Character.spec.js +5 -5
  224. package/dist/lexer/Character.spec.js.map +1 -1
  225. package/dist/lexer/Lexer.d.ts +12 -5
  226. package/dist/lexer/Lexer.js +28 -13
  227. package/dist/lexer/Lexer.js.map +1 -1
  228. package/dist/lexer/Lexer.spec.js +187 -134
  229. package/dist/lexer/Lexer.spec.js.map +1 -1
  230. package/dist/lexer/Token.d.ts +9 -1
  231. package/dist/lexer/Token.js +9 -1
  232. package/dist/lexer/Token.js.map +1 -1
  233. package/dist/lexer/TokenKind.d.ts +9 -0
  234. package/dist/lexer/TokenKind.js +30 -5
  235. package/dist/lexer/TokenKind.js.map +1 -1
  236. package/dist/parser/AstNode.d.ts +162 -0
  237. package/dist/parser/AstNode.js +225 -0
  238. package/dist/parser/AstNode.js.map +1 -0
  239. package/dist/parser/AstNode.spec.d.ts +1 -0
  240. package/dist/parser/AstNode.spec.js +165 -0
  241. package/dist/parser/AstNode.spec.js.map +1 -0
  242. package/dist/parser/BrsTranspileState.d.ts +4 -7
  243. package/dist/parser/BrsTranspileState.js +4 -12
  244. package/dist/parser/BrsTranspileState.js.map +1 -1
  245. package/dist/parser/Expression.d.ts +126 -167
  246. package/dist/parser/Expression.js +524 -394
  247. package/dist/parser/Expression.js.map +1 -1
  248. package/dist/parser/Parser.Class.spec.js +152 -146
  249. package/dist/parser/Parser.Class.spec.js.map +1 -1
  250. package/dist/parser/Parser.d.ts +45 -196
  251. package/dist/parser/Parser.js +470 -926
  252. package/dist/parser/Parser.js.map +1 -1
  253. package/dist/parser/Parser.spec.d.ts +3 -1
  254. package/dist/parser/Parser.spec.js +1034 -805
  255. package/dist/parser/Parser.spec.js.map +1 -1
  256. package/dist/parser/SGParser.d.ts +9 -8
  257. package/dist/parser/SGParser.js +10 -8
  258. package/dist/parser/SGParser.js.map +1 -1
  259. package/dist/parser/SGParser.spec.js +27 -38
  260. package/dist/parser/SGParser.spec.js.map +1 -1
  261. package/dist/parser/SGTypes.d.ts +98 -35
  262. package/dist/parser/SGTypes.js +169 -99
  263. package/dist/parser/SGTypes.js.map +1 -1
  264. package/dist/parser/Statement.d.ts +208 -122
  265. package/dist/parser/Statement.js +599 -364
  266. package/dist/parser/Statement.js.map +1 -1
  267. package/dist/parser/Statement.spec.js +45 -21
  268. package/dist/parser/Statement.spec.js.map +1 -1
  269. package/dist/parser/TranspileState.d.ts +1 -1
  270. package/dist/parser/TranspileState.js +7 -12
  271. package/dist/parser/TranspileState.js.map +1 -1
  272. package/dist/parser/tests/Parser.spec.js +3 -2
  273. package/dist/parser/tests/Parser.spec.js.map +1 -1
  274. package/dist/parser/tests/controlFlow/For.spec.js +33 -23
  275. package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
  276. package/dist/parser/tests/controlFlow/ForEach.spec.js +25 -20
  277. package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
  278. package/dist/parser/tests/controlFlow/If.spec.js +96 -94
  279. package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
  280. package/dist/parser/tests/controlFlow/While.spec.js +22 -16
  281. package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
  282. package/dist/parser/tests/expression/Additive.spec.js +8 -8
  283. package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
  284. package/dist/parser/tests/expression/ArrayLiterals.spec.js +58 -21
  285. package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
  286. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +61 -20
  287. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
  288. package/dist/parser/tests/expression/Boolean.spec.js +8 -8
  289. package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
  290. package/dist/parser/tests/expression/Call.spec.js +129 -21
  291. package/dist/parser/tests/expression/Call.spec.js.map +1 -1
  292. package/dist/parser/tests/expression/Exponential.spec.js +5 -5
  293. package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
  294. package/dist/parser/tests/expression/Function.spec.js +36 -36
  295. package/dist/parser/tests/expression/Function.spec.js.map +1 -1
  296. package/dist/parser/tests/expression/Indexing.spec.js +67 -22
  297. package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
  298. package/dist/parser/tests/expression/Multiplicative.spec.js +9 -9
  299. package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
  300. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +123 -81
  301. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  302. package/dist/parser/tests/expression/PrefixUnary.spec.js +12 -12
  303. package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
  304. package/dist/parser/tests/expression/Primary.spec.js +12 -12
  305. package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
  306. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +10 -10
  307. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -1
  308. package/dist/parser/tests/expression/Relational.spec.js +13 -13
  309. package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
  310. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +24 -24
  311. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
  312. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +221 -81
  313. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  314. package/dist/parser/tests/expression/TernaryExpression.spec.js +287 -105
  315. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  316. package/dist/parser/tests/expression/TypeExpression.spec.d.ts +1 -0
  317. package/dist/parser/tests/expression/TypeExpression.spec.js +127 -0
  318. package/dist/parser/tests/expression/TypeExpression.spec.js.map +1 -0
  319. package/dist/parser/tests/expression/UnaryExpression.spec.d.ts +1 -0
  320. package/dist/parser/tests/expression/UnaryExpression.spec.js +52 -0
  321. package/dist/parser/tests/expression/UnaryExpression.spec.js.map +1 -0
  322. package/dist/parser/tests/statement/AssignmentOperators.spec.js +15 -15
  323. package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
  324. package/dist/parser/tests/statement/ConstStatement.spec.d.ts +1 -0
  325. package/dist/parser/tests/statement/ConstStatement.spec.js +262 -0
  326. package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -0
  327. package/dist/parser/tests/statement/Continue.spec.d.ts +1 -0
  328. package/dist/parser/tests/statement/Continue.spec.js +119 -0
  329. package/dist/parser/tests/statement/Continue.spec.js.map +1 -0
  330. package/dist/parser/tests/statement/Declaration.spec.js +19 -19
  331. package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
  332. package/dist/parser/tests/statement/Dim.spec.js +22 -22
  333. package/dist/parser/tests/statement/Dim.spec.js.map +1 -1
  334. package/dist/parser/tests/statement/Enum.spec.js +111 -300
  335. package/dist/parser/tests/statement/Enum.spec.js.map +1 -1
  336. package/dist/parser/tests/statement/For.spec.js +9 -10
  337. package/dist/parser/tests/statement/For.spec.js.map +1 -1
  338. package/dist/parser/tests/statement/ForEach.spec.js +8 -9
  339. package/dist/parser/tests/statement/ForEach.spec.js.map +1 -1
  340. package/dist/parser/tests/statement/Function.spec.js +44 -35
  341. package/dist/parser/tests/statement/Function.spec.js.map +1 -1
  342. package/dist/parser/tests/statement/Goto.spec.js +5 -5
  343. package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
  344. package/dist/parser/tests/statement/Increment.spec.js +20 -20
  345. package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
  346. package/dist/parser/tests/statement/InterfaceStatement.spec.js +30 -196
  347. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
  348. package/dist/parser/tests/statement/LibraryStatement.spec.js +11 -11
  349. package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
  350. package/dist/parser/tests/statement/Misc.spec.js +16 -78
  351. package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
  352. package/dist/parser/tests/statement/PrintStatement.spec.js +107 -90
  353. package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
  354. package/dist/parser/tests/statement/ReturnStatement.spec.js +14 -12
  355. package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
  356. package/dist/parser/tests/statement/Set.spec.js +48 -35
  357. package/dist/parser/tests/statement/Set.spec.js.map +1 -1
  358. package/dist/parser/tests/statement/Stop.spec.js +6 -6
  359. package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
  360. package/dist/parser/tests/statement/Throw.spec.js +6 -6
  361. package/dist/parser/tests/statement/Throw.spec.js.map +1 -1
  362. package/dist/parser/tests/statement/TryCatch.spec.js +18 -16
  363. package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
  364. package/dist/preprocessor/Manifest.d.ts +1 -1
  365. package/dist/preprocessor/Manifest.js +3 -3
  366. package/dist/preprocessor/Manifest.js.map +1 -1
  367. package/dist/preprocessor/Manifest.spec.js +8 -8
  368. package/dist/preprocessor/Manifest.spec.js.map +1 -1
  369. package/dist/preprocessor/Preprocessor.d.ts +5 -6
  370. package/dist/preprocessor/Preprocessor.js +15 -11
  371. package/dist/preprocessor/Preprocessor.js.map +1 -1
  372. package/dist/preprocessor/Preprocessor.spec.js +25 -25
  373. package/dist/preprocessor/Preprocessor.spec.js.map +1 -1
  374. package/dist/preprocessor/PreprocessorParser.d.ts +1 -1
  375. package/dist/preprocessor/PreprocessorParser.js +7 -1
  376. package/dist/preprocessor/PreprocessorParser.js.map +1 -1
  377. package/dist/preprocessor/PreprocessorParser.spec.js +13 -13
  378. package/dist/preprocessor/PreprocessorParser.spec.js.map +1 -1
  379. package/dist/roku-types/data.json +6544 -10519
  380. package/dist/roku-types/index.d.ts +662 -1934
  381. package/dist/types/ArrayType.d.ts +10 -9
  382. package/dist/types/ArrayType.js +65 -60
  383. package/dist/types/ArrayType.js.map +1 -1
  384. package/dist/types/ArrayType.spec.js +36 -68
  385. package/dist/types/ArrayType.spec.js.map +1 -1
  386. package/dist/types/AssociativeArrayType.d.ts +11 -0
  387. package/dist/types/AssociativeArrayType.js +52 -0
  388. package/dist/types/AssociativeArrayType.js.map +1 -0
  389. package/dist/types/BaseFunctionType.d.ts +9 -0
  390. package/dist/types/BaseFunctionType.js +25 -0
  391. package/dist/types/BaseFunctionType.js.map +1 -0
  392. package/dist/types/BooleanType.d.ts +8 -5
  393. package/dist/types/BooleanType.js +14 -7
  394. package/dist/types/BooleanType.js.map +1 -1
  395. package/dist/types/BooleanType.spec.js +10 -6
  396. package/dist/types/BooleanType.spec.js.map +1 -1
  397. package/dist/types/BscType.d.ts +32 -21
  398. package/dist/types/BscType.js +118 -21
  399. package/dist/types/BscType.js.map +1 -1
  400. package/dist/types/BscTypeKind.d.ts +25 -0
  401. package/dist/types/BscTypeKind.js +30 -0
  402. package/dist/types/BscTypeKind.js.map +1 -0
  403. package/dist/types/BuiltInInterfaceAdder.d.ts +23 -0
  404. package/dist/types/BuiltInInterfaceAdder.js +164 -0
  405. package/dist/types/BuiltInInterfaceAdder.js.map +1 -0
  406. package/dist/types/BuiltInInterfaceAdder.spec.d.ts +1 -0
  407. package/dist/types/BuiltInInterfaceAdder.spec.js +116 -0
  408. package/dist/types/BuiltInInterfaceAdder.spec.js.map +1 -0
  409. package/dist/types/ClassType.d.ts +17 -0
  410. package/dist/types/ClassType.js +58 -0
  411. package/dist/types/ClassType.js.map +1 -0
  412. package/dist/types/ClassType.spec.d.ts +1 -0
  413. package/dist/types/ClassType.spec.js +77 -0
  414. package/dist/types/ClassType.spec.js.map +1 -0
  415. package/dist/types/ComponentType.d.ts +26 -0
  416. package/dist/types/ComponentType.js +83 -0
  417. package/dist/types/ComponentType.js.map +1 -0
  418. package/dist/types/DoubleType.d.ts +8 -5
  419. package/dist/types/DoubleType.js +18 -16
  420. package/dist/types/DoubleType.js.map +1 -1
  421. package/dist/types/DoubleType.spec.js +12 -6
  422. package/dist/types/DoubleType.spec.js.map +1 -1
  423. package/dist/types/DynamicType.d.ts +10 -5
  424. package/dist/types/DynamicType.js +16 -4
  425. package/dist/types/DynamicType.js.map +1 -1
  426. package/dist/types/DynamicType.spec.js +16 -5
  427. package/dist/types/DynamicType.spec.js.map +1 -1
  428. package/dist/types/EnumType.d.ts +30 -12
  429. package/dist/types/EnumType.js +43 -17
  430. package/dist/types/EnumType.js.map +1 -1
  431. package/dist/types/EnumType.spec.d.ts +1 -0
  432. package/dist/types/EnumType.spec.js +33 -0
  433. package/dist/types/EnumType.spec.js.map +1 -0
  434. package/dist/types/FloatType.d.ts +8 -5
  435. package/dist/types/FloatType.js +18 -16
  436. package/dist/types/FloatType.js.map +1 -1
  437. package/dist/types/FloatType.spec.js +4 -6
  438. package/dist/types/FloatType.spec.js.map +1 -1
  439. package/dist/types/FunctionType.d.ts +13 -8
  440. package/dist/types/FunctionType.js +30 -14
  441. package/dist/types/FunctionType.js.map +1 -1
  442. package/dist/types/InheritableType.d.ts +28 -0
  443. package/dist/types/InheritableType.js +152 -0
  444. package/dist/types/InheritableType.js.map +1 -0
  445. package/dist/types/IntegerType.d.ts +8 -5
  446. package/dist/types/IntegerType.js +18 -16
  447. package/dist/types/IntegerType.js.map +1 -1
  448. package/dist/types/IntegerType.spec.js +8 -6
  449. package/dist/types/IntegerType.spec.js.map +1 -1
  450. package/dist/types/InterfaceType.d.ts +12 -13
  451. package/dist/types/InterfaceType.js +20 -48
  452. package/dist/types/InterfaceType.js.map +1 -1
  453. package/dist/types/InterfaceType.spec.js +90 -56
  454. package/dist/types/InterfaceType.spec.js.map +1 -1
  455. package/dist/types/InvalidType.d.ts +7 -5
  456. package/dist/types/InvalidType.js +13 -7
  457. package/dist/types/InvalidType.js.map +1 -1
  458. package/dist/types/InvalidType.spec.js +8 -6
  459. package/dist/types/InvalidType.spec.js.map +1 -1
  460. package/dist/types/LongIntegerType.d.ts +8 -5
  461. package/dist/types/LongIntegerType.js +17 -15
  462. package/dist/types/LongIntegerType.js.map +1 -1
  463. package/dist/types/LongIntegerType.spec.js +10 -6
  464. package/dist/types/LongIntegerType.spec.js.map +1 -1
  465. package/dist/types/NamespaceType.d.ts +12 -0
  466. package/dist/types/NamespaceType.js +28 -0
  467. package/dist/types/NamespaceType.js.map +1 -0
  468. package/dist/types/ObjectType.d.ts +9 -8
  469. package/dist/types/ObjectType.js +21 -11
  470. package/dist/types/ObjectType.js.map +1 -1
  471. package/dist/types/ObjectType.spec.js +3 -3
  472. package/dist/types/ObjectType.spec.js.map +1 -1
  473. package/dist/types/ReferenceType.d.ts +63 -0
  474. package/dist/types/ReferenceType.js +423 -0
  475. package/dist/types/ReferenceType.js.map +1 -0
  476. package/dist/types/ReferenceType.spec.d.ts +1 -0
  477. package/dist/types/ReferenceType.spec.js +137 -0
  478. package/dist/types/ReferenceType.spec.js.map +1 -0
  479. package/dist/types/StringType.d.ts +11 -5
  480. package/dist/types/StringType.js +18 -7
  481. package/dist/types/StringType.js.map +1 -1
  482. package/dist/types/StringType.spec.js +3 -5
  483. package/dist/types/StringType.spec.js.map +1 -1
  484. package/dist/types/TypedFunctionType.d.ts +22 -17
  485. package/dist/types/TypedFunctionType.js +78 -60
  486. package/dist/types/TypedFunctionType.js.map +1 -1
  487. package/dist/types/TypedFunctionType.spec.js +105 -20
  488. package/dist/types/TypedFunctionType.spec.js.map +1 -1
  489. package/dist/types/UninitializedType.d.ts +8 -6
  490. package/dist/types/UninitializedType.js +13 -7
  491. package/dist/types/UninitializedType.js.map +1 -1
  492. package/dist/types/UnionType.d.ts +20 -0
  493. package/dist/types/UnionType.js +123 -0
  494. package/dist/types/UnionType.js.map +1 -0
  495. package/dist/types/UnionType.spec.d.ts +1 -0
  496. package/dist/types/UnionType.spec.js +130 -0
  497. package/dist/types/UnionType.spec.js.map +1 -0
  498. package/dist/types/VoidType.d.ts +8 -5
  499. package/dist/types/VoidType.js +14 -7
  500. package/dist/types/VoidType.js.map +1 -1
  501. package/dist/types/VoidType.spec.js +3 -3
  502. package/dist/types/VoidType.spec.js.map +1 -1
  503. package/dist/types/helper.spec.d.ts +1 -0
  504. package/dist/types/helper.spec.js +145 -0
  505. package/dist/types/helper.spec.js.map +1 -0
  506. package/dist/types/helpers.d.ts +19 -37
  507. package/dist/types/helpers.js +159 -99
  508. package/dist/types/helpers.js.map +1 -1
  509. package/dist/types/index.d.ts +22 -0
  510. package/dist/types/index.js +39 -0
  511. package/dist/types/index.js.map +1 -0
  512. package/dist/util.d.ts +167 -131
  513. package/dist/util.js +890 -350
  514. package/dist/util.js.map +1 -1
  515. package/dist/validators/ClassValidator.d.ts +7 -25
  516. package/dist/validators/ClassValidator.js +103 -194
  517. package/dist/validators/ClassValidator.js.map +1 -1
  518. package/package.json +165 -149
  519. package/dist/astUtils/AstEditor.js.map +0 -1
  520. package/dist/astUtils/AstEditor.spec.js.map +0 -1
  521. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.d.ts +0 -8
  522. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js +0 -40
  523. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +0 -1
  524. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js +0 -32
  525. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js.map +0 -1
  526. package/dist/parser/SGTypes.spec.js +0 -351
  527. package/dist/parser/SGTypes.spec.js.map +0 -1
  528. package/dist/types/CustomType.d.ts +0 -12
  529. package/dist/types/CustomType.js +0 -44
  530. package/dist/types/CustomType.js.map +0 -1
  531. package/dist/types/LazyType.d.ts +0 -16
  532. package/dist/types/LazyType.js +0 -44
  533. package/dist/types/LazyType.js.map +0 -1
  534. /package/dist/astUtils/{AstEditor.spec.d.ts → Editor.spec.d.ts} +0 -0
  535. /package/dist/bscPlugin/{transpile/BrsFilePreTranspileProcessor.spec.d.ts → completions/CompletionsProcessor.spec.d.ts} +0 -0
  536. /package/dist/{parser/SGTypes.spec.d.ts → bscPlugin/hover/HoverProcessor.spec.d.ts} +0 -0
@@ -0,0 +1,2454 @@
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
+ });
1494
+ describe('itemCannotBeUsedAsVariable', () => {
1495
+ it('detects assigning to a member of a namespace outside the namespace', () => {
1496
+ program.setFile('source/main.bs', `
1497
+ namespace Alpha
1498
+ const Name = "Alpha"
1499
+ end namespace
1500
+
1501
+ sub main()
1502
+ Alpha.name = "Beta"
1503
+ end sub
1504
+ `);
1505
+ program.validate();
1506
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1507
+ DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('namespace')
1508
+ ]);
1509
+ });
1510
+ it('detects assigning to a member of a namespace inside the namespace', () => {
1511
+ program.setFile('source/main.bs', `
1512
+ namespace Alpha
1513
+ const Name = "Alpha"
1514
+
1515
+ sub inAlpha()
1516
+ alpha.name = "Beta"
1517
+ end sub
1518
+ end namespace
1519
+ `);
1520
+ program.validate();
1521
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1522
+ DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('namespace')
1523
+ ]);
1524
+ });
1525
+ it('detects assigning to a member of a namespace outside the namespace', () => {
1526
+ program.setFile('source/main.bs', `
1527
+ namespace Alpha
1528
+ class Klass
1529
+ end class
1530
+ end namespace
1531
+
1532
+ sub main()
1533
+ myKlass = new Alpha.Klass()
1534
+ Alpha.klass = myKlass
1535
+ end sub
1536
+ `);
1537
+ program.validate();
1538
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1539
+ DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('namespace')
1540
+ ]);
1541
+ });
1542
+ it('detects assigning to a member of a namespace outside the namespace', () => {
1543
+ program.setFile('source/main.bs', `
1544
+ namespace Alpha
1545
+ class Klass
1546
+ function new()
1547
+ end function
1548
+
1549
+ function init()
1550
+ Alpha.innerFunc = someFunc
1551
+ end function
1552
+ end class
1553
+
1554
+ sub innerFunc()
1555
+ end sub
1556
+ end namespace
1557
+
1558
+ sub someFunc()
1559
+ end sub
1560
+ `);
1561
+ program.validate();
1562
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1563
+ DiagnosticMessages_1.DiagnosticMessages.itemCannotBeUsedAsVariable('namespace')
1564
+ ]);
1565
+ });
1566
+ });
1567
+ describe('returnTypeMismatch', () => {
1568
+ it('finds when a function returns a type that is not what was declared', () => {
1569
+ program.setFile('source/util.bs', `
1570
+ function getPi() as float
1571
+ return "apple" ' get it?
1572
+ end function
1573
+ `);
1574
+ program.validate();
1575
+ //should have error - return value should be a float, not a string
1576
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1577
+ DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('string', 'float').message
1578
+ ]);
1579
+ });
1580
+ it('finds all return statements that do not match', () => {
1581
+ program.setFile('source/util.bs', `
1582
+ function getPi(kind as integer) as float
1583
+ if kind = 1
1584
+ return "apple"
1585
+ else if kind = 2
1586
+ return false
1587
+ else if kind = 3
1588
+ return new Pie("lemon")
1589
+ end if
1590
+ return 3.14
1591
+ end function
1592
+
1593
+ class Pie
1594
+ kind as string
1595
+ sub new(kind as string)
1596
+ m.kind = kind
1597
+ end sub
1598
+ end class
1599
+ `);
1600
+ program.validate();
1601
+ //should have error - return value should be a float, not whatever else
1602
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1603
+ DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('string', 'float').message,
1604
+ DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('boolean', 'float').message,
1605
+ DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('Pie', 'float').message
1606
+ ]);
1607
+ });
1608
+ it('allows returning compatible types', () => {
1609
+ program.setFile('source/util.bs', `
1610
+ function getPi() as float
1611
+ return 3 ' integers are compatible with floats
1612
+ end function
1613
+
1614
+ function getPie() as Pie
1615
+ return new Tart("lemon") ' Tart extends Pie
1616
+ end function
1617
+
1618
+ class Pie
1619
+ kind as string
1620
+ sub new(kind as string)
1621
+ m.kind = kind
1622
+ end sub
1623
+ end class
1624
+
1625
+ class Tart extends Pie
1626
+ size = "small"
1627
+ end class
1628
+ `);
1629
+ program.validate();
1630
+ //should have no errors
1631
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1632
+ });
1633
+ it('detects return types on void functions (subs)', () => {
1634
+ program.setFile('source/util.bs', `
1635
+ sub sayHello(name as string)
1636
+ return "hello " + name ' return should be void in subs
1637
+ end sub
1638
+ `);
1639
+ program.validate();
1640
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1641
+ DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('string', 'void').message
1642
+ ]);
1643
+ });
1644
+ it('detects return types on void functions', () => {
1645
+ program.setFile('source/util.bs', `
1646
+ function sayHello(name as string) as void
1647
+ return "hello " + name ' return should be void in subs
1648
+ end function
1649
+ `);
1650
+ program.validate();
1651
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1652
+ DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('string', 'void').message
1653
+ ]);
1654
+ });
1655
+ it('allows returning enums with the default type that matches the declared return type', () => {
1656
+ program.setFile('source/util.bs', `
1657
+ enum MyEnum
1658
+ val1
1659
+ val2
1660
+ end enum
1661
+
1662
+ function getInt() as integer
1663
+ return MyEnum.val1
1664
+ end function
1665
+ `);
1666
+ program.validate();
1667
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1668
+ });
1669
+ it('allows returning enums passed as a param with the default type that matches the declared return type', () => {
1670
+ program.setFile('source/util.bs', `
1671
+ enum MyEnum
1672
+ val1
1673
+ val2
1674
+ end enum
1675
+
1676
+ function getInt(enumVal as MyEnum) as integer
1677
+ return enumVal
1678
+ end function
1679
+ `);
1680
+ program.validate();
1681
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1682
+ });
1683
+ it('allows returning enums with the default type that matches the declared return type for string enums', () => {
1684
+ program.setFile('source/util.bs', `
1685
+ enum MyEnum
1686
+ val1 = "hello"
1687
+ val2 = "world"
1688
+ end enum
1689
+
1690
+ function getInt() as string
1691
+ return MyEnum.val1
1692
+ end function
1693
+ `);
1694
+ program.validate();
1695
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1696
+ });
1697
+ it('flags returning enums with the default type that does not matches the declared return type', () => {
1698
+ program.setFile('source/util.bs', `
1699
+ enum MyEnum
1700
+ val1 = "hello"
1701
+ val2 = "world"
1702
+ end enum
1703
+
1704
+ function getInt() as integer
1705
+ return MyEnum.val1
1706
+ end function
1707
+ `);
1708
+ program.validate();
1709
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1710
+ DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('MyEnum', 'integer').message
1711
+ ]);
1712
+ });
1713
+ it('flags returning enums passed as params with the default type that does not matches the declared return type', () => {
1714
+ program.setFile('source/util.bs', `
1715
+ enum MyEnum
1716
+ val1 = "hello"
1717
+ val2 = "world"
1718
+ end enum
1719
+
1720
+ function getInt(enumVal as MyEnum) as integer
1721
+ return enumVal
1722
+ end function
1723
+ `);
1724
+ program.validate();
1725
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1726
+ DiagnosticMessages_1.DiagnosticMessages.returnTypeMismatch('MyEnum', 'integer').message
1727
+ ]);
1728
+ });
1729
+ it('flags returning enums type', () => {
1730
+ program.setFile('source/util.bs', `
1731
+ enum MyEnum
1732
+ val1 = "hello"
1733
+ val2 = "world"
1734
+ end enum
1735
+
1736
+
1737
+ function getInt() as integer
1738
+ return MyEnum
1739
+ end function
1740
+ `);
1741
+ program.validate();
1742
+ (0, chai_1.expect)(program.getDiagnostics().length).to.be.greaterThan(0);
1743
+ });
1744
+ it('allows returning an Enum', () => {
1745
+ program.setFile('source/util.bs', `
1746
+ enum MyEnum
1747
+ val1 = "hello"
1748
+ val2 = "world"
1749
+ end enum
1750
+
1751
+
1752
+ function getInt() as MyEnum
1753
+ return MyEnum.val1
1754
+ end function
1755
+ `);
1756
+ program.validate();
1757
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1758
+ });
1759
+ });
1760
+ describe('assignmentTypeMismatch', () => {
1761
+ it('finds when the type of the lhs is not compatible with the expected type', () => {
1762
+ program.setFile('source/util.bs', `
1763
+ sub doStuff(thing as iThing)
1764
+ thing.name = 123
1765
+ end sub
1766
+
1767
+ interface iThing
1768
+ name as string
1769
+ end interface
1770
+ `);
1771
+ program.validate();
1772
+ //should have error - assignment value should be a string, not a float
1773
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1774
+ DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch('integer', 'string').message
1775
+ ]);
1776
+ });
1777
+ it('allows setting a member with correct type that is a union type', () => {
1778
+ program.setFile('source/util.bs', `
1779
+ sub doStuff(thing as iThing)
1780
+ thing.name = 123
1781
+ end sub
1782
+
1783
+ interface iThing
1784
+ name as string or integer
1785
+ end interface
1786
+ `);
1787
+ program.validate();
1788
+ //should have no error - assignment value should be a string, not a float
1789
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1790
+ });
1791
+ it('finds when the rhs type is not compatible with the lhs, which is a union type', () => {
1792
+ program.setFile('source/util.bs', `
1793
+ sub doStuff(thing as iThing)
1794
+ thing.name = false
1795
+ end sub
1796
+
1797
+ interface iThing
1798
+ name as string or integer
1799
+ end interface
1800
+ `);
1801
+ program.validate();
1802
+ //should have error - assignment value should be a string or integer, not a boolean
1803
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1804
+ DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch('boolean', 'string or integer').message
1805
+ ]);
1806
+ });
1807
+ it('validates when trying to assign to a class method', () => {
1808
+ program.setFile('source/util.bs', `
1809
+ sub doStuff(myThing as Thing)
1810
+ myThing.getPi = 3.14
1811
+ end sub
1812
+
1813
+ class Thing
1814
+ function getPi() as float
1815
+ return 3.14
1816
+ end function
1817
+ end class
1818
+ `);
1819
+ program.validate();
1820
+ //should have error
1821
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1822
+ DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch('float', 'function getPi() as float').message
1823
+ ]);
1824
+ });
1825
+ it('disallows adding new properties to a class', () => {
1826
+ program.setFile('source/util.bs', `
1827
+ sub doStuff(myThing as Thing)
1828
+ myThing.getPi = 3.14
1829
+ end sub
1830
+
1831
+ class Thing
1832
+ end class
1833
+ `);
1834
+ program.validate();
1835
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [DiagnosticMessages_1.DiagnosticMessages.cannotFindName('getPi', 'Thing.getPi')]);
1836
+ });
1837
+ it('validates class constructors', () => {
1838
+ program.setFile('source/util.bs', `
1839
+ class Video
1840
+ sub new(url as integer)
1841
+ m.url = url 'this should be a compile error
1842
+ end sub
1843
+ public url as string
1844
+ end class
1845
+ `);
1846
+ program.validate();
1847
+ //should have errors
1848
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1849
+ DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch('integer', 'string').message
1850
+ ]);
1851
+ });
1852
+ it('validates when assigning to a sgNode', () => {
1853
+ program.setFile('source/util.bs', `
1854
+ sub setLabelText(label as roSGNodeLabel)
1855
+ label.text = 1234
1856
+ end sub
1857
+
1858
+ `);
1859
+ program.validate();
1860
+ //should have errors
1861
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1862
+ DiagnosticMessages_1.DiagnosticMessages.assignmentTypeMismatch('integer', 'string').message
1863
+ ]);
1864
+ });
1865
+ });
1866
+ describe('operatorTypeMismatch', () => {
1867
+ it('finds when the type of the lhs is not compatible with the rhs type', () => {
1868
+ program.setFile('source/util.bs', `
1869
+ sub doStuff()
1870
+ a = 1 + true
1871
+ b = "hello" * 2
1872
+ end sub
1873
+
1874
+ `);
1875
+ program.validate();
1876
+ //should have errors
1877
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1878
+ DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('+', 'integer', 'boolean').message,
1879
+ DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('*', 'string', 'integer').message
1880
+ ]);
1881
+ });
1882
+ it('allows when the type of the lhs is compatible with the rhs type', () => {
1883
+ program.setFile('source/util.bs', `
1884
+ sub doStuff()
1885
+ a = 10 << 1
1886
+ b = "hello" + "world"
1887
+ c = 78 / 34
1888
+ d = 100 \\ 5
1889
+ thing = new Klass()
1890
+ e = thing <> invalid
1891
+ end sub
1892
+
1893
+ class Klass
1894
+ end class
1895
+ `);
1896
+ program.validate();
1897
+ //should have no errors
1898
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1899
+ });
1900
+ it('allows tests against invalid', () => {
1901
+ program.setFile('source/util.bs', `
1902
+ sub doStuff()
1903
+ thing = new Klass()
1904
+ x = thing <> invalid
1905
+ end sub
1906
+
1907
+ class Klass
1908
+ end class
1909
+ `);
1910
+ program.validate();
1911
+ //should have no errors
1912
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1913
+ });
1914
+ it('disallows equality tests of classes', () => {
1915
+ program.setFile('source/util.bs', `
1916
+ sub doStuff()
1917
+ thing = new Klass()
1918
+ thing2 = new Klass()
1919
+ x = thing = thing2
1920
+ end sub
1921
+
1922
+ class Klass
1923
+ end class
1924
+ `);
1925
+ program.validate();
1926
+ //should have errors
1927
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1928
+ DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('=', 'Klass', 'Klass').message
1929
+ ]);
1930
+ });
1931
+ it('disallows operations between dynamic and custom types', () => {
1932
+ program.setFile('source/util.bs', `
1933
+ sub doStuff(input)
1934
+ thing = new Klass()
1935
+ x = thing + input
1936
+ end sub
1937
+
1938
+ class Klass
1939
+ end class
1940
+ `);
1941
+ program.validate();
1942
+ //should have errors
1943
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1944
+ DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('+', 'Klass', 'dynamic').message
1945
+ ]);
1946
+ });
1947
+ it('allows valid operations on enum members', () => {
1948
+ program.setFile('source/util.bs', `
1949
+ sub makeEasterly(d as Direction)
1950
+ print d + "e"
1951
+ print Direction.north + "east"
1952
+ end sub
1953
+
1954
+ function getTax(itemAmt as ItemCost) as Float
1955
+ return itemAmt * 1.15
1956
+ end function
1957
+
1958
+ enum Direction
1959
+ north = "n"
1960
+ south = "s"
1961
+ end enum
1962
+
1963
+ enum ItemCost
1964
+ x = 99.99
1965
+ y = 29.99
1966
+ end enum
1967
+
1968
+ `);
1969
+ program.validate();
1970
+ //should have no errors
1971
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
1972
+ });
1973
+ it('finds invalid operations on enum members', () => {
1974
+ program.setFile('source/util.bs', `
1975
+ enum Direction
1976
+ north = "n"
1977
+ south = "s"
1978
+ end enum
1979
+
1980
+ sub makeEasterly(d as Direction)
1981
+ print d + 2
1982
+ print 3.14 * Direction.north
1983
+ end sub
1984
+ `);
1985
+ program.validate();
1986
+ //should have errors
1987
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
1988
+ DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('+', 'Direction', 'integer').message,
1989
+ DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('*', 'float', 'Direction').message
1990
+ ]);
1991
+ });
1992
+ it('validates unary operators', () => {
1993
+ program.setFile('source/util.bs', `
1994
+ sub doStuff()
1995
+ x = - "hello world"
1996
+ end sub
1997
+ `);
1998
+ program.validate();
1999
+ //should have errors
2000
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2001
+ DiagnosticMessages_1.DiagnosticMessages.operatorTypeMismatch('-', 'string').message
2002
+ ]);
2003
+ });
2004
+ it('allows unary on dynamic and union types', () => {
2005
+ program.setFile('source/util.bs', `
2006
+ sub doStuff(x)
2007
+ y = -x
2008
+ print y
2009
+ end sub
2010
+
2011
+ sub doOtherStuff(x as float or integer)
2012
+ y = -x
2013
+ print y
2014
+ end sub
2015
+
2016
+ sub doEventMoreStuff(x as boolean or dynamic)
2017
+ if not x
2018
+ print "ok"
2019
+ end if
2020
+ end sub
2021
+ `);
2022
+ program.validate();
2023
+ //should have no errors
2024
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2025
+ });
2026
+ });
2027
+ describe('memberAccessibilityMismatch', () => {
2028
+ it('should flag when accessing a private member', () => {
2029
+ program.setFile('source/main.bs', `
2030
+ class SomeKlass
2031
+ private name as string
2032
+ end class
2033
+
2034
+ sub foo(x as SomeKlass)
2035
+ print x.name
2036
+ end sub
2037
+ `);
2038
+ program.validate();
2039
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2040
+ DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('name', SymbolTable_1.SymbolTypeFlag.private, 'SomeKlass')
2041
+ ]);
2042
+ });
2043
+ it('should allow accessing a private member in a class', () => {
2044
+ program.setFile('source/main.bs', `
2045
+ class SomeKlass
2046
+ private name as string
2047
+
2048
+ sub foo(x as SomeKlass)
2049
+ print x.name
2050
+ print m.name
2051
+ end sub
2052
+ end class
2053
+ `);
2054
+ program.validate();
2055
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2056
+ });
2057
+ it('should flag when calling a private method outside the class', () => {
2058
+ program.setFile('source/main.bs', `
2059
+ class SomeKlass
2060
+ private sub sayHello()
2061
+ print "Hello"
2062
+ end sub
2063
+ end class
2064
+
2065
+ sub foo(x as SomeKlass)
2066
+ x.sayHello()
2067
+ end sub
2068
+ `);
2069
+ program.validate();
2070
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2071
+ DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('sayHello', SymbolTable_1.SymbolTypeFlag.private, 'SomeKlass')
2072
+ ]);
2073
+ });
2074
+ it('should allow calling a private method in a class', () => {
2075
+ program.setFile('source/main.bs', `
2076
+ class SomeKlass
2077
+ private sub sayHello()
2078
+ print "Hello"
2079
+ end sub
2080
+
2081
+ sub foo(x as SomeKlass)
2082
+ x.sayHello()
2083
+ m.sayHello()
2084
+ end sub
2085
+ end class
2086
+ `);
2087
+ program.validate();
2088
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2089
+ });
2090
+ it('should not allow accessing a private member in a subclass', () => {
2091
+ program.setFile('source/main.bs', `
2092
+ class SomeKlass
2093
+ private name as string
2094
+ end class
2095
+
2096
+ class SubKlass extends SomeKlass
2097
+ sub foo()
2098
+ print m.name
2099
+ end sub
2100
+ end class
2101
+ `);
2102
+ program.validate();
2103
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2104
+ DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('name', SymbolTable_1.SymbolTypeFlag.private, 'SomeKlass')
2105
+ ]);
2106
+ });
2107
+ it('should flag when setting a value on a private member', () => {
2108
+ program.setFile('source/main.bs', `
2109
+ class SomeKlass
2110
+ private name as string
2111
+ end class
2112
+
2113
+ sub foo(x as SomeKlass)
2114
+ x.name = "foo"
2115
+ end sub
2116
+ `);
2117
+ program.validate();
2118
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2119
+ DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('name', SymbolTable_1.SymbolTypeFlag.private, 'SomeKlass')
2120
+ ]);
2121
+ });
2122
+ it('should flag when accessing a protected member', () => {
2123
+ program.setFile('source/main.bs', `
2124
+ class SomeKlass
2125
+ protected name as string
2126
+ end class
2127
+
2128
+ sub foo(x as SomeKlass)
2129
+ print x.name
2130
+ end sub
2131
+ `);
2132
+ program.validate();
2133
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2134
+ DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('name', SymbolTable_1.SymbolTypeFlag.protected, 'SomeKlass')
2135
+ ]);
2136
+ });
2137
+ it('should allow accessing a protected member in a class', () => {
2138
+ program.setFile('source/main.bs', `
2139
+ class SomeKlass
2140
+ protected name as string
2141
+
2142
+ sub foo(x as SomeKlass)
2143
+ print x.name
2144
+ print m.name
2145
+ end sub
2146
+ end class
2147
+ `);
2148
+ program.validate();
2149
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2150
+ });
2151
+ it('should flag when calling a protected method outside the class', () => {
2152
+ program.setFile('source/main.bs', `
2153
+ class SomeKlass
2154
+ protected sub sayHello()
2155
+ print "Hello"
2156
+ end sub
2157
+ end class
2158
+
2159
+ class SubKlass extends SomeKlass
2160
+ end class
2161
+
2162
+ sub foo(x as SomeKlass, y as SubKlass)
2163
+ x.sayHello()
2164
+ y.sayHello()
2165
+ end sub
2166
+ `);
2167
+ program.validate();
2168
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2169
+ DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('sayHello', SymbolTable_1.SymbolTypeFlag.protected, 'SomeKlass'),
2170
+ DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('sayHello', SymbolTable_1.SymbolTypeFlag.protected, 'SomeKlass')
2171
+ ]);
2172
+ });
2173
+ it('should allow calling a protected method in a class', () => {
2174
+ program.setFile('source/main.bs', `
2175
+ class SomeKlass
2176
+ protected sub sayHello()
2177
+ print "Hello"
2178
+ end sub
2179
+ end class
2180
+
2181
+ class SubKlass extends SomeKlass
2182
+ sub foo(x as SomeKlass, y as SubKlass)
2183
+ m.sayHello()
2184
+ x.sayHello()
2185
+ y.sayHello()
2186
+ end sub
2187
+ end class
2188
+ `);
2189
+ program.validate();
2190
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2191
+ });
2192
+ it('should allow accessing a protected member in a subclass', () => {
2193
+ program.setFile('source/main.bs', `
2194
+ class SomeKlass
2195
+ protected name as string
2196
+ end class
2197
+
2198
+ class SubKlass extends SomeKlass
2199
+ sub foo()
2200
+ print m.name
2201
+ end sub
2202
+ end class
2203
+ `);
2204
+ program.validate();
2205
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2206
+ });
2207
+ it('should flag when setting a value on a protected member', () => {
2208
+ program.setFile('source/main.bs', `
2209
+ class SomeKlass
2210
+ protected name as string
2211
+ end class
2212
+
2213
+ class SubKlass extends SomeKlass
2214
+ end class
2215
+
2216
+ sub foo(x as SubKlass)
2217
+ x.name = "foo"
2218
+ end sub
2219
+ `);
2220
+ program.validate();
2221
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2222
+ DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('name', SymbolTable_1.SymbolTypeFlag.protected, 'SomeKlass')
2223
+ ]);
2224
+ });
2225
+ it('should flag when trying to use an inaccessible member in the middle of a chain', () => {
2226
+ program.setFile('source/main.bs', `
2227
+ class SomeKlass
2228
+ protected name as string
2229
+ end class
2230
+
2231
+ sub foo(x as SomeKlass)
2232
+ print x.name.len()
2233
+ end sub
2234
+ `);
2235
+ program.validate();
2236
+ (0, testHelpers_spec_1.expectDiagnostics)(program, [
2237
+ DiagnosticMessages_1.DiagnosticMessages.memberAccessibilityMismatch('name', SymbolTable_1.SymbolTypeFlag.protected, 'SomeKlass')
2238
+ ]);
2239
+ });
2240
+ describe('with namespaces', () => {
2241
+ it('protected members are accessible', () => {
2242
+ program.setFile('source/main.bs', `
2243
+ namespace AccessibilityTest
2244
+ class MyClass
2245
+ private data as roAssociativeArray = {}
2246
+ sub new()
2247
+ m.data.AddReplace("key", "value")
2248
+ end sub
2249
+
2250
+ protected sub printData()
2251
+ print m.data
2252
+ end sub
2253
+ end class
2254
+
2255
+ class SubClass extends MyClass
2256
+ sub foo()
2257
+ m.printData()
2258
+ end sub
2259
+ end class
2260
+ end namespace
2261
+ `);
2262
+ program.validate();
2263
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2264
+ });
2265
+ });
2266
+ });
2267
+ describe('revalidation', () => {
2268
+ it('revalidates when a enum defined in a different namespace changes', () => {
2269
+ program.setFile('source/file1.bs', `
2270
+ namespace Alpha
2271
+ function printEnum(enumVal as Alpha.Beta.Charlie.SomeEnum) as string
2272
+ return enumVal.toStr()
2273
+ end function
2274
+ end namespace
2275
+ `);
2276
+ program.setFile('source/file2.bs', `
2277
+ namespace Alpha.Beta.Charlie
2278
+ enum SomeEnum
2279
+ val1 = 1
2280
+ val2 = 2
2281
+ end enum
2282
+ end namespace
2283
+ `);
2284
+ program.validate();
2285
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2286
+ program.setFile('source/file2.bs', `
2287
+ namespace Alpha.Beta.Charlie
2288
+ enum ChangedEnum
2289
+ val1 = 1
2290
+ val2 = 2
2291
+ end enum
2292
+ end namespace
2293
+ `);
2294
+ program.validate();
2295
+ (0, testHelpers_spec_1.expectDiagnosticsIncludes)(program, [DiagnosticMessages_1.DiagnosticMessages.cannotFindName('SomeEnum').message]);
2296
+ });
2297
+ it('revalidates when a class defined in a different namespace changes', () => {
2298
+ program.setFile('source/file1.bs', `
2299
+ namespace Alpha
2300
+ function printEnum(myKlass as Alpha.Beta.Charlie.SomeClass) as string
2301
+ return myKlass.getValue()
2302
+ end function
2303
+ end namespace
2304
+ `);
2305
+ program.setFile('source/file2.bs', `
2306
+ namespace Alpha.Beta.Charlie
2307
+ class SomeClass
2308
+ private myValue as string
2309
+ function getValue() as string
2310
+ return m.myValue
2311
+ end function
2312
+ end class
2313
+ end namespace
2314
+ `);
2315
+ program.validate();
2316
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2317
+ program.setFile('source/file2.bs', `
2318
+ namespace Alpha.Beta.Charlie
2319
+ class SomeClass
2320
+ private myValue as string
2321
+ function getValue(lowerCase as boolean) as string
2322
+ if lowerCase
2323
+ return lcase(m.myValue)
2324
+ end if
2325
+ return m.myValue
2326
+ end function
2327
+ end class
2328
+ end namespace
2329
+ `);
2330
+ program.validate();
2331
+ (0, testHelpers_spec_1.expectDiagnosticsIncludes)(program, [DiagnosticMessages_1.DiagnosticMessages.mismatchArgumentCount(1, 0).message]);
2332
+ });
2333
+ it('validates only parts of files that need revalidation on scope validation', () => {
2334
+ function validateFile(file) {
2335
+ const validateFileEvent = {
2336
+ program: program,
2337
+ file: file
2338
+ };
2339
+ //emit an event to allow plugins to contribute to the file validation process
2340
+ program.plugins.emit('onFileValidate', validateFileEvent);
2341
+ }
2342
+ const commonContents = `
2343
+ sub noValidationForEachScope()
2344
+ k = new KlassInSameFile()
2345
+ print k.value
2346
+ end sub
2347
+
2348
+ class KlassInSameFile
2349
+ value = 1
2350
+ end class
2351
+ `;
2352
+ let commonBs = program.setFile('source/common.bs', commonContents);
2353
+ validateFile(commonBs);
2354
+ (0, chai_1.expect)(commonBs.validationSegmenter.segmentsForValidation.length).to.eq(2); // 1 func, 1 classField
2355
+ (0, chai_1.expect)(commonBs.validationSegmenter.unresolvedSegmentsSymbols.size).to.eq(0);
2356
+ commonBs.validationSegmenter.validatedSegments.forEach(x => (0, chai_1.expect)(x).to.be.false);
2357
+ (0, chai_1.expect)(commonBs.validationSegmenter.singleValidationSegments.size).to.eq(2); // no references needed to other files
2358
+ let common2Contents = `
2359
+ sub doesValidationForEachScope()
2360
+ k = new KlassInDiffFile()
2361
+ print k.value
2362
+ end sub
2363
+
2364
+ function alsoNoValidationForEachScope() as integer
2365
+ return 1
2366
+ end function
2367
+ `;
2368
+ let common2Bs = program.setFile('source/common2.bs', common2Contents);
2369
+ validateFile(common2Bs);
2370
+ (0, chai_1.expect)(common2Bs.validationSegmenter.segmentsForValidation.length).to.eq(2); // 2 func
2371
+ (0, chai_1.expect)(common2Bs.validationSegmenter.unresolvedSegmentsSymbols.size).to.eq(1);
2372
+ commonBs.validationSegmenter.validatedSegments.forEach(x => (0, chai_1.expect)(x).to.be.false);
2373
+ (0, chai_1.expect)(common2Bs.validationSegmenter.singleValidationSegments.size).to.eq(1); // alsoNoValidationForEachScope() does not reference other files
2374
+ let klassContents = `
2375
+ class KlassInDiffFile
2376
+ value = 2
2377
+ end class
2378
+ `;
2379
+ let klassBs = program.setFile('source/klass.bs', klassContents);
2380
+ validateFile(klassBs);
2381
+ (0, chai_1.expect)(klassBs.validationSegmenter.segmentsForValidation.length).to.eq(1); // 1 classField
2382
+ (0, chai_1.expect)(klassBs.validationSegmenter.unresolvedSegmentsSymbols.size).to.eq(0);
2383
+ klassBs.validationSegmenter.validatedSegments.forEach(x => (0, chai_1.expect)(x).to.be.false);
2384
+ (0, chai_1.expect)(klassBs.validationSegmenter.singleValidationSegments.size).to.eq(1); // does not reference other files
2385
+ const widgetFileContents = `
2386
+ sub init()
2387
+ noValidationForEachScope()
2388
+ doesValidationForEachScope()
2389
+ end sub
2390
+
2391
+ sub anotherFunction()
2392
+ print "hello"
2393
+ end sub
2394
+ `;
2395
+ let widgetBs = program.setFile('components/Widget.bs', widgetFileContents);
2396
+ validateFile(widgetBs);
2397
+ (0, chai_1.expect)(widgetBs.validationSegmenter.segmentsForValidation.length).to.eq(2); // 2 funcs
2398
+ (0, chai_1.expect)(widgetBs.validationSegmenter.unresolvedSegmentsSymbols.size).to.eq(1); // 1 func (init)
2399
+ widgetBs.validationSegmenter.validatedSegments.forEach(x => (0, chai_1.expect)(x).to.be.false);
2400
+ (0, chai_1.expect)(widgetBs.validationSegmenter.singleValidationSegments.size).to.eq(1); // 1 func (anotherFunction)
2401
+ const diffKlassContent = `
2402
+ class KlassInDiffFile
2403
+ value = 3
2404
+ end class
2405
+ `;
2406
+ let diffKlassBs = program.setFile('components/diffKlass.bs', diffKlassContent);
2407
+ validateFile(diffKlassBs);
2408
+ (0, chai_1.expect)(diffKlassBs.validationSegmenter.segmentsForValidation.length).to.eq(1); // 1 classField
2409
+ (0, chai_1.expect)(diffKlassBs.validationSegmenter.unresolvedSegmentsSymbols.size).to.eq(0);
2410
+ diffKlassBs.validationSegmenter.validatedSegments.forEach(x => (0, chai_1.expect)(x).to.be.false);
2411
+ (0, chai_1.expect)(diffKlassBs.validationSegmenter.singleValidationSegments.size).to.eq(1);
2412
+ program.setFile('components/Widget.xml', (0, testHelpers_spec_1.trim) `
2413
+ <?xml version="1.0" encoding="utf-8" ?>
2414
+ <component name="Widget" extends="Group">
2415
+ <script uri="Widget.bs"/>
2416
+ <script uri="pkg:/source/common.bs"/>
2417
+ <script uri="pkg:/source/common2.bs"/>
2418
+ <script uri="diffKlass.bs"/>
2419
+ </component>
2420
+ `);
2421
+ //reset files
2422
+ commonBs = program.setFile('source/common.bs', commonContents);
2423
+ common2Bs = program.setFile('source/common2.bs', common2Contents);
2424
+ klassBs = program.setFile('source/klass.bs', klassContents);
2425
+ widgetBs = program.setFile('components/Widget.bs', widgetFileContents);
2426
+ diffKlassBs = program.setFile('components/diffKlass.bs', diffKlassContent);
2427
+ program.validate();
2428
+ // all segments should be validated
2429
+ [commonBs, common2Bs, klassBs, widgetBs, diffKlassBs].forEach(file => {
2430
+ (0, chai_1.expect)(file.validationSegmenter.validatedSegments.size).to.gte(file.validationSegmenter.segmentsForValidation.length);
2431
+ file.validationSegmenter.validatedSegments.forEach(x => (0, chai_1.expect)(x).to.be.true);
2432
+ });
2433
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
2434
+ program.setFile('components/Widget.bs', widgetFileContents);
2435
+ program.validate();
2436
+ // Widget.bs has changed. it needs to totally re-validated
2437
+ // and other files in the scope need to revalidate only the unresolved segments - should be source/common2.bs
2438
+ // TODO: how to test this?
2439
+ program.validate();
2440
+ program.setFile('components/diffKlass.bs', diffKlassContent);
2441
+ // diffKlass.bs has changed. it needs to totally re-validated
2442
+ // no other files in scope reference it .. no other files need revalidation
2443
+ // TODO: how to test this?
2444
+ program.validate();
2445
+ program.setFile('source/common.bs', commonContents);
2446
+ // common.bs has changed. it needs to totally re-validated
2447
+ // in source scope, common2.bs still has unresolves, it needs revalidation
2448
+ // in widget scope, widget.bs references it
2449
+ // TODO: how to test this?
2450
+ program.validate();
2451
+ });
2452
+ });
2453
+ });
2454
+ //# sourceMappingURL=ScopeValidator.spec.js.map