brighterscript 1.0.0-alpha.50 → 1.0.0-alpha.52

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 (485) hide show
  1. package/README.md +10 -2
  2. package/bsconfig.schema.json +75 -0
  3. package/dist/BsConfig.d.ts +90 -5
  4. package/dist/CodeActionUtil.d.ts +17 -0
  5. package/dist/CodeActionUtil.js.map +1 -1
  6. package/dist/CommentFlagProcessor.d.ts +16 -12
  7. package/dist/CommentFlagProcessor.js +141 -59
  8. package/dist/CommentFlagProcessor.js.map +1 -1
  9. package/dist/CrossScopeValidator.js +13 -5
  10. package/dist/CrossScopeValidator.js.map +1 -1
  11. package/dist/DiagnosticManager.d.ts +1 -0
  12. package/dist/DiagnosticManager.js +25 -9
  13. package/dist/DiagnosticManager.js.map +1 -1
  14. package/dist/DiagnosticMessages.d.ts +61 -17
  15. package/dist/DiagnosticMessages.js +78 -24
  16. package/dist/DiagnosticMessages.js.map +1 -1
  17. package/dist/LanguageServer.d.ts +40 -2
  18. package/dist/LanguageServer.js +154 -5
  19. package/dist/LanguageServer.js.map +1 -1
  20. package/dist/Program.d.ts +66 -1
  21. package/dist/Program.js +205 -13
  22. package/dist/Program.js.map +1 -1
  23. package/dist/ProgramBuilder.d.ts +1 -8
  24. package/dist/ProgramBuilder.js +31 -11
  25. package/dist/ProgramBuilder.js.map +1 -1
  26. package/dist/Scope.d.ts +87 -6
  27. package/dist/Scope.js +76 -31
  28. package/dist/Scope.js.map +1 -1
  29. package/dist/ScopeNamespaceLookup.d.ts +73 -0
  30. package/dist/ScopeNamespaceLookup.js +242 -0
  31. package/dist/ScopeNamespaceLookup.js.map +1 -0
  32. package/dist/SymbolTable.d.ts +9 -2
  33. package/dist/SymbolTable.js +24 -14
  34. package/dist/SymbolTable.js.map +1 -1
  35. package/dist/astUtils/CachedLookups.js +3 -0
  36. package/dist/astUtils/CachedLookups.js.map +1 -1
  37. package/dist/astUtils/reflection.d.ts +4 -1
  38. package/dist/astUtils/reflection.js +24 -4
  39. package/dist/astUtils/reflection.js.map +1 -1
  40. package/dist/astUtils/visitors.d.ts +2 -1
  41. package/dist/astUtils/visitors.js.map +1 -1
  42. package/dist/bscPlugin/BscPlugin.d.ts +5 -2
  43. package/dist/bscPlugin/BscPlugin.js +14 -2
  44. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  45. package/dist/bscPlugin/CallExpressionInfo.d.ts +1 -1
  46. package/dist/bscPlugin/CallExpressionInfo.js +1 -2
  47. package/dist/bscPlugin/CallExpressionInfo.js.map +1 -1
  48. package/dist/bscPlugin/FileWriter.d.ts +13 -0
  49. package/dist/bscPlugin/FileWriter.js +56 -1
  50. package/dist/bscPlugin/FileWriter.js.map +1 -1
  51. package/dist/bscPlugin/codeActions/CodeActionsProcessor.d.ts +106 -5
  52. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +630 -126
  53. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  54. package/dist/bscPlugin/codeActions/FixAllCodeActionsProcessor.d.ts +17 -0
  55. package/dist/bscPlugin/codeActions/FixAllCodeActionsProcessor.js +66 -0
  56. package/dist/bscPlugin/codeActions/FixAllCodeActionsProcessor.js.map +1 -0
  57. package/dist/bscPlugin/codeActions/codeActionHelpers.d.ts +18 -0
  58. package/dist/bscPlugin/codeActions/codeActionHelpers.js +31 -0
  59. package/dist/bscPlugin/codeActions/codeActionHelpers.js.map +1 -0
  60. package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +1 -1
  61. package/dist/bscPlugin/completions/CompletionsProcessor.js +5 -5
  62. package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -1
  63. package/dist/bscPlugin/definition/DefinitionProvider.js +8 -0
  64. package/dist/bscPlugin/definition/DefinitionProvider.js.map +1 -1
  65. package/dist/bscPlugin/hover/HoverProcessor.js +11 -3
  66. package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -1
  67. package/dist/bscPlugin/inlayHints/InlayHintProcessor.d.ts +23 -0
  68. package/dist/bscPlugin/inlayHints/InlayHintProcessor.js +186 -0
  69. package/dist/bscPlugin/inlayHints/InlayHintProcessor.js.map +1 -0
  70. package/dist/bscPlugin/selectionRanges/SelectionRangesProcessor.d.ts +7 -0
  71. package/dist/bscPlugin/selectionRanges/SelectionRangesProcessor.js +77 -0
  72. package/dist/bscPlugin/selectionRanges/SelectionRangesProcessor.js.map +1 -0
  73. package/dist/bscPlugin/serialize/FileSerializer.d.ts +1 -1
  74. package/dist/bscPlugin/serialize/FileSerializer.js +12 -7
  75. package/dist/bscPlugin/serialize/FileSerializer.js.map +1 -1
  76. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.d.ts +7 -0
  77. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js +87 -1
  78. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js.map +1 -1
  79. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +14 -0
  80. package/dist/bscPlugin/validation/BrsFileValidator.js +97 -21
  81. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
  82. package/dist/bscPlugin/validation/ScopeValidator.d.ts +17 -0
  83. package/dist/bscPlugin/validation/ScopeValidator.js +162 -4
  84. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  85. package/dist/bscPlugin/validation/XmlFileValidator.js +14 -0
  86. package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -1
  87. package/dist/cli.js +13 -0
  88. package/dist/cli.js.map +1 -1
  89. package/dist/diagnosticUtils.d.ts +51 -1
  90. package/dist/diagnosticUtils.js +222 -1
  91. package/dist/diagnosticUtils.js.map +1 -1
  92. package/dist/files/BrsFile.d.ts +18 -2
  93. package/dist/files/BrsFile.js +87 -6
  94. package/dist/files/BrsFile.js.map +1 -1
  95. package/dist/files/XmlFile.js +2 -1
  96. package/dist/files/XmlFile.js.map +1 -1
  97. package/dist/interfaces.d.ts +101 -23
  98. package/dist/interfaces.js.map +1 -1
  99. package/dist/lexer/Lexer.js +4 -5
  100. package/dist/lexer/Lexer.js.map +1 -1
  101. package/dist/lexer/Token.d.ts +1 -1
  102. package/dist/lexer/TokenKind.d.ts +8 -0
  103. package/dist/lexer/TokenKind.js +21 -1
  104. package/dist/lexer/TokenKind.js.map +1 -1
  105. package/dist/lsp/LspProject.d.ts +56 -1
  106. package/dist/lsp/Project.d.ts +38 -2
  107. package/dist/lsp/Project.js +135 -4
  108. package/dist/lsp/Project.js.map +1 -1
  109. package/dist/lsp/ProjectManager.d.ts +52 -2
  110. package/dist/lsp/ProjectManager.js +164 -9
  111. package/dist/lsp/ProjectManager.js.map +1 -1
  112. package/dist/lsp/worker/WorkerThreadProject.d.ts +31 -2
  113. package/dist/lsp/worker/WorkerThreadProject.js +19 -0
  114. package/dist/lsp/worker/WorkerThreadProject.js.map +1 -1
  115. package/dist/parser/AstNode.d.ts +3 -1
  116. package/dist/parser/AstNode.js +2 -0
  117. package/dist/parser/AstNode.js.map +1 -1
  118. package/dist/parser/Expression.d.ts +54 -5
  119. package/dist/parser/Expression.js +112 -7
  120. package/dist/parser/Expression.js.map +1 -1
  121. package/dist/parser/Parser.d.ts +24 -1
  122. package/dist/parser/Parser.js +180 -41
  123. package/dist/parser/Parser.js.map +1 -1
  124. package/dist/parser/SGParser.d.ts +1 -0
  125. package/dist/parser/SGParser.js +9 -0
  126. package/dist/parser/SGParser.js.map +1 -1
  127. package/dist/parser/Statement.d.ts +6 -1
  128. package/dist/parser/Statement.js +22 -14
  129. package/dist/parser/Statement.js.map +1 -1
  130. package/dist/parser/TranspileState.d.ts +4 -2
  131. package/dist/parser/TranspileState.js +13 -4
  132. package/dist/parser/TranspileState.js.map +1 -1
  133. package/dist/roku-types/data.json +210 -3
  134. package/dist/types/ArrayType.js +6 -1
  135. package/dist/types/ArrayType.js.map +1 -1
  136. package/dist/types/BooleanType.js +1 -1
  137. package/dist/types/BooleanType.js.map +1 -1
  138. package/dist/types/CallFuncableType.d.ts +1 -1
  139. package/dist/types/ClassType.js +3 -0
  140. package/dist/types/ClassType.js.map +1 -1
  141. package/dist/types/ComponentType.js +3 -0
  142. package/dist/types/ComponentType.js.map +1 -1
  143. package/dist/types/EnumType.js +3 -0
  144. package/dist/types/EnumType.js.map +1 -1
  145. package/dist/types/IntersectionType.js +3 -0
  146. package/dist/types/IntersectionType.js.map +1 -1
  147. package/dist/types/ReferenceType.js +6 -0
  148. package/dist/types/ReferenceType.js.map +1 -1
  149. package/dist/types/TypeStatementType.d.ts +1 -0
  150. package/dist/types/TypeStatementType.js +12 -1
  151. package/dist/types/TypeStatementType.js.map +1 -1
  152. package/dist/types/TypedFunctionType.js +20 -10
  153. package/dist/types/TypedFunctionType.js.map +1 -1
  154. package/dist/types/UnionType.js +3 -0
  155. package/dist/types/UnionType.js.map +1 -1
  156. package/dist/types/helpers.js +6 -0
  157. package/dist/types/helpers.js.map +1 -1
  158. package/dist/util.d.ts +42 -3
  159. package/dist/util.js +131 -7
  160. package/dist/util.js.map +1 -1
  161. package/package.json +25 -26
  162. package/dist/astUtils/CachedLookups.spec.d.ts +0 -1
  163. package/dist/astUtils/CachedLookups.spec.js +0 -39
  164. package/dist/astUtils/CachedLookups.spec.js.map +0 -1
  165. package/dist/astUtils/Editor.spec.d.ts +0 -1
  166. package/dist/astUtils/Editor.spec.js +0 -258
  167. package/dist/astUtils/Editor.spec.js.map +0 -1
  168. package/dist/astUtils/creators.spec.d.ts +0 -1
  169. package/dist/astUtils/creators.spec.js +0 -21
  170. package/dist/astUtils/creators.spec.js.map +0 -1
  171. package/dist/astUtils/reflection.spec.d.ts +0 -1
  172. package/dist/astUtils/reflection.spec.js +0 -392
  173. package/dist/astUtils/reflection.spec.js.map +0 -1
  174. package/dist/astUtils/stackedVisitor.spec.d.ts +0 -1
  175. package/dist/astUtils/stackedVisitor.spec.js +0 -79
  176. package/dist/astUtils/stackedVisitor.spec.js.map +0 -1
  177. package/dist/astUtils/visitors.spec.d.ts +0 -1
  178. package/dist/astUtils/visitors.spec.js +0 -1432
  179. package/dist/astUtils/visitors.spec.js.map +0 -1
  180. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.d.ts +0 -1
  181. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +0 -311
  182. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +0 -1
  183. package/dist/bscPlugin/completions/CompletionsProcessor.spec.d.ts +0 -1
  184. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +0 -2512
  185. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +0 -1
  186. package/dist/bscPlugin/definition/DefinitionProvider.spec.d.ts +0 -1
  187. package/dist/bscPlugin/definition/DefinitionProvider.spec.js +0 -87
  188. package/dist/bscPlugin/definition/DefinitionProvider.spec.js.map +0 -1
  189. package/dist/bscPlugin/hover/HoverProcessor.spec.d.ts +0 -1
  190. package/dist/bscPlugin/hover/HoverProcessor.spec.js +0 -991
  191. package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +0 -1
  192. package/dist/bscPlugin/references/ReferencesProvider.spec.d.ts +0 -1
  193. package/dist/bscPlugin/references/ReferencesProvider.spec.js +0 -51
  194. package/dist/bscPlugin/references/ReferencesProvider.spec.js.map +0 -1
  195. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.d.ts +0 -1
  196. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +0 -564
  197. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +0 -1
  198. package/dist/bscPlugin/serialize/BslibInjector.spec.d.ts +0 -1
  199. package/dist/bscPlugin/serialize/BslibInjector.spec.js +0 -33
  200. package/dist/bscPlugin/serialize/BslibInjector.spec.js.map +0 -1
  201. package/dist/bscPlugin/symbols/DocumentSymbolProcessor.spec.d.ts +0 -1
  202. package/dist/bscPlugin/symbols/DocumentSymbolProcessor.spec.js +0 -291
  203. package/dist/bscPlugin/symbols/DocumentSymbolProcessor.spec.js.map +0 -1
  204. package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.spec.d.ts +0 -1
  205. package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.spec.js +0 -245
  206. package/dist/bscPlugin/symbols/WorkspaceSymbolProcessor.spec.js.map +0 -1
  207. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.d.ts +0 -1
  208. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js +0 -75
  209. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js.map +0 -1
  210. package/dist/bscPlugin/validation/BrsFileValidator.spec.d.ts +0 -1
  211. package/dist/bscPlugin/validation/BrsFileValidator.spec.js +0 -1517
  212. package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +0 -1
  213. package/dist/bscPlugin/validation/ScopeValidator.spec.d.ts +0 -1
  214. package/dist/bscPlugin/validation/ScopeValidator.spec.js +0 -6135
  215. package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +0 -1
  216. package/dist/common/Sequencer.spec.d.ts +0 -1
  217. package/dist/common/Sequencer.spec.js +0 -75
  218. package/dist/common/Sequencer.spec.js.map +0 -1
  219. package/dist/files/BrsFile.Class.spec.d.ts +0 -1
  220. package/dist/files/BrsFile.Class.spec.js +0 -2035
  221. package/dist/files/BrsFile.Class.spec.js.map +0 -1
  222. package/dist/files/BrsFile.spec.d.ts +0 -1
  223. package/dist/files/BrsFile.spec.js +0 -5848
  224. package/dist/files/BrsFile.spec.js.map +0 -1
  225. package/dist/files/LazyFileData.spec.d.ts +0 -1
  226. package/dist/files/LazyFileData.spec.js +0 -27
  227. package/dist/files/LazyFileData.spec.js.map +0 -1
  228. package/dist/files/XmlFile.spec.d.ts +0 -1
  229. package/dist/files/XmlFile.spec.js +0 -1173
  230. package/dist/files/XmlFile.spec.js.map +0 -1
  231. package/dist/files/tests/imports.spec.d.ts +0 -1
  232. package/dist/files/tests/imports.spec.js +0 -251
  233. package/dist/files/tests/imports.spec.js.map +0 -1
  234. package/dist/files/tests/optionalChaning.spec.d.ts +0 -1
  235. package/dist/files/tests/optionalChaning.spec.js +0 -152
  236. package/dist/files/tests/optionalChaning.spec.js.map +0 -1
  237. package/dist/lexer/Character.spec.d.ts +0 -1
  238. package/dist/lexer/Character.spec.js +0 -27
  239. package/dist/lexer/Character.spec.js.map +0 -1
  240. package/dist/lexer/Lexer.spec.d.ts +0 -1
  241. package/dist/lexer/Lexer.spec.js +0 -1345
  242. package/dist/lexer/Lexer.spec.js.map +0 -1
  243. package/dist/lsp/ActionQueue.spec.d.ts +0 -1
  244. package/dist/lsp/ActionQueue.spec.js +0 -80
  245. package/dist/lsp/ActionQueue.spec.js.map +0 -1
  246. package/dist/lsp/DocumentManager.spec.d.ts +0 -1
  247. package/dist/lsp/DocumentManager.spec.js +0 -103
  248. package/dist/lsp/DocumentManager.spec.js.map +0 -1
  249. package/dist/lsp/PathFilterer.spec.d.ts +0 -1
  250. package/dist/lsp/PathFilterer.spec.js +0 -182
  251. package/dist/lsp/PathFilterer.spec.js.map +0 -1
  252. package/dist/lsp/Project.spec.d.ts +0 -1
  253. package/dist/lsp/Project.spec.js +0 -267
  254. package/dist/lsp/Project.spec.js.map +0 -1
  255. package/dist/lsp/ProjectManager.spec.d.ts +0 -1
  256. package/dist/lsp/ProjectManager.spec.js +0 -913
  257. package/dist/lsp/ProjectManager.spec.js.map +0 -1
  258. package/dist/lsp/worker/MessageHandler.spec.d.ts +0 -1
  259. package/dist/lsp/worker/MessageHandler.spec.js +0 -64
  260. package/dist/lsp/worker/MessageHandler.spec.js.map +0 -1
  261. package/dist/lsp/worker/WorkerPool.spec.d.ts +0 -1
  262. package/dist/lsp/worker/WorkerPool.spec.js +0 -59
  263. package/dist/lsp/worker/WorkerPool.spec.js.map +0 -1
  264. package/dist/lsp/worker/WorkerThreadProject.spec.d.ts +0 -2
  265. package/dist/lsp/worker/WorkerThreadProject.spec.js +0 -71
  266. package/dist/lsp/worker/WorkerThreadProject.spec.js.map +0 -1
  267. package/dist/parser/AstNode.spec.d.ts +0 -1
  268. package/dist/parser/AstNode.spec.js +0 -1455
  269. package/dist/parser/AstNode.spec.js.map +0 -1
  270. package/dist/parser/BrightScriptDocParser.spec.d.ts +0 -1
  271. package/dist/parser/BrightScriptDocParser.spec.js +0 -310
  272. package/dist/parser/BrightScriptDocParser.spec.js.map +0 -1
  273. package/dist/parser/Expression.spec.d.ts +0 -1
  274. package/dist/parser/Expression.spec.js +0 -40
  275. package/dist/parser/Expression.spec.js.map +0 -1
  276. package/dist/parser/Parser.Class.spec.d.ts +0 -1
  277. package/dist/parser/Parser.Class.spec.js +0 -520
  278. package/dist/parser/Parser.Class.spec.js.map +0 -1
  279. package/dist/parser/Parser.spec.d.ts +0 -6
  280. package/dist/parser/Parser.spec.js +0 -2802
  281. package/dist/parser/Parser.spec.js.map +0 -1
  282. package/dist/parser/SGParser.spec.d.ts +0 -1
  283. package/dist/parser/SGParser.spec.js +0 -130
  284. package/dist/parser/SGParser.spec.js.map +0 -1
  285. package/dist/parser/Statement.spec.d.ts +0 -1
  286. package/dist/parser/Statement.spec.js +0 -191
  287. package/dist/parser/Statement.spec.js.map +0 -1
  288. package/dist/parser/tests/Parser.spec.d.ts +0 -12
  289. package/dist/parser/tests/Parser.spec.js +0 -29
  290. package/dist/parser/tests/Parser.spec.js.map +0 -1
  291. package/dist/parser/tests/controlFlow/For.spec.d.ts +0 -1
  292. package/dist/parser/tests/controlFlow/For.spec.js +0 -169
  293. package/dist/parser/tests/controlFlow/For.spec.js.map +0 -1
  294. package/dist/parser/tests/controlFlow/ForEach.spec.d.ts +0 -1
  295. package/dist/parser/tests/controlFlow/ForEach.spec.js +0 -140
  296. package/dist/parser/tests/controlFlow/ForEach.spec.js.map +0 -1
  297. package/dist/parser/tests/controlFlow/If.spec.d.ts +0 -1
  298. package/dist/parser/tests/controlFlow/If.spec.js +0 -694
  299. package/dist/parser/tests/controlFlow/If.spec.js.map +0 -1
  300. package/dist/parser/tests/controlFlow/While.spec.d.ts +0 -1
  301. package/dist/parser/tests/controlFlow/While.spec.js +0 -114
  302. package/dist/parser/tests/controlFlow/While.spec.js.map +0 -1
  303. package/dist/parser/tests/expression/Additive.spec.d.ts +0 -1
  304. package/dist/parser/tests/expression/Additive.spec.js +0 -107
  305. package/dist/parser/tests/expression/Additive.spec.js.map +0 -1
  306. package/dist/parser/tests/expression/ArrayLiterals.spec.d.ts +0 -1
  307. package/dist/parser/tests/expression/ArrayLiterals.spec.js +0 -304
  308. package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +0 -1
  309. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.d.ts +0 -1
  310. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +0 -342
  311. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +0 -1
  312. package/dist/parser/tests/expression/Boolean.spec.d.ts +0 -1
  313. package/dist/parser/tests/expression/Boolean.spec.js +0 -90
  314. package/dist/parser/tests/expression/Boolean.spec.js.map +0 -1
  315. package/dist/parser/tests/expression/Call.spec.d.ts +0 -1
  316. package/dist/parser/tests/expression/Call.spec.js +0 -252
  317. package/dist/parser/tests/expression/Call.spec.js.map +0 -1
  318. package/dist/parser/tests/expression/Exponential.spec.d.ts +0 -1
  319. package/dist/parser/tests/expression/Exponential.spec.js +0 -37
  320. package/dist/parser/tests/expression/Exponential.spec.js.map +0 -1
  321. package/dist/parser/tests/expression/Function.spec.d.ts +0 -1
  322. package/dist/parser/tests/expression/Function.spec.js +0 -412
  323. package/dist/parser/tests/expression/Function.spec.js.map +0 -1
  324. package/dist/parser/tests/expression/Indexing.spec.d.ts +0 -1
  325. package/dist/parser/tests/expression/Indexing.spec.js +0 -302
  326. package/dist/parser/tests/expression/Indexing.spec.js.map +0 -1
  327. package/dist/parser/tests/expression/Multiplicative.spec.d.ts +0 -1
  328. package/dist/parser/tests/expression/Multiplicative.spec.js +0 -67
  329. package/dist/parser/tests/expression/Multiplicative.spec.js.map +0 -1
  330. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.d.ts +0 -1
  331. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +0 -346
  332. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +0 -1
  333. package/dist/parser/tests/expression/PrefixUnary.spec.d.ts +0 -1
  334. package/dist/parser/tests/expression/PrefixUnary.spec.js +0 -111
  335. package/dist/parser/tests/expression/PrefixUnary.spec.js.map +0 -1
  336. package/dist/parser/tests/expression/Primary.spec.d.ts +0 -1
  337. package/dist/parser/tests/expression/Primary.spec.js +0 -165
  338. package/dist/parser/tests/expression/Primary.spec.js.map +0 -1
  339. package/dist/parser/tests/expression/RegexLiteralExpression.spec.d.ts +0 -1
  340. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +0 -171
  341. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +0 -1
  342. package/dist/parser/tests/expression/Relational.spec.d.ts +0 -1
  343. package/dist/parser/tests/expression/Relational.spec.js +0 -83
  344. package/dist/parser/tests/expression/Relational.spec.js.map +0 -1
  345. package/dist/parser/tests/expression/SourceLiteralExpression.spec.d.ts +0 -1
  346. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +0 -201
  347. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +0 -1
  348. package/dist/parser/tests/expression/TemplateStringExpression.spec.d.ts +0 -1
  349. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +0 -389
  350. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +0 -1
  351. package/dist/parser/tests/expression/TernaryExpression.spec.d.ts +0 -1
  352. package/dist/parser/tests/expression/TernaryExpression.spec.js +0 -878
  353. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +0 -1
  354. package/dist/parser/tests/expression/TypeExpression.spec.d.ts +0 -1
  355. package/dist/parser/tests/expression/TypeExpression.spec.js +0 -126
  356. package/dist/parser/tests/expression/TypeExpression.spec.js.map +0 -1
  357. package/dist/parser/tests/expression/UnaryExpression.spec.d.ts +0 -1
  358. package/dist/parser/tests/expression/UnaryExpression.spec.js +0 -52
  359. package/dist/parser/tests/expression/UnaryExpression.spec.js.map +0 -1
  360. package/dist/parser/tests/statement/AssignmentOperators.spec.d.ts +0 -1
  361. package/dist/parser/tests/statement/AssignmentOperators.spec.js +0 -79
  362. package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +0 -1
  363. package/dist/parser/tests/statement/ConstStatement.spec.d.ts +0 -1
  364. package/dist/parser/tests/statement/ConstStatement.spec.js +0 -500
  365. package/dist/parser/tests/statement/ConstStatement.spec.js.map +0 -1
  366. package/dist/parser/tests/statement/Continue.spec.d.ts +0 -1
  367. package/dist/parser/tests/statement/Continue.spec.js +0 -119
  368. package/dist/parser/tests/statement/Continue.spec.js.map +0 -1
  369. package/dist/parser/tests/statement/Declaration.spec.d.ts +0 -1
  370. package/dist/parser/tests/statement/Declaration.spec.js +0 -114
  371. package/dist/parser/tests/statement/Declaration.spec.js.map +0 -1
  372. package/dist/parser/tests/statement/Dim.spec.d.ts +0 -1
  373. package/dist/parser/tests/statement/Dim.spec.js +0 -80
  374. package/dist/parser/tests/statement/Dim.spec.js.map +0 -1
  375. package/dist/parser/tests/statement/Enum.spec.d.ts +0 -1
  376. package/dist/parser/tests/statement/Enum.spec.js +0 -744
  377. package/dist/parser/tests/statement/Enum.spec.js.map +0 -1
  378. package/dist/parser/tests/statement/For.spec.d.ts +0 -1
  379. package/dist/parser/tests/statement/For.spec.js +0 -45
  380. package/dist/parser/tests/statement/For.spec.js.map +0 -1
  381. package/dist/parser/tests/statement/ForEach.spec.d.ts +0 -1
  382. package/dist/parser/tests/statement/ForEach.spec.js +0 -36
  383. package/dist/parser/tests/statement/ForEach.spec.js.map +0 -1
  384. package/dist/parser/tests/statement/Function.spec.d.ts +0 -1
  385. package/dist/parser/tests/statement/Function.spec.js +0 -343
  386. package/dist/parser/tests/statement/Function.spec.js.map +0 -1
  387. package/dist/parser/tests/statement/Goto.spec.d.ts +0 -1
  388. package/dist/parser/tests/statement/Goto.spec.js +0 -51
  389. package/dist/parser/tests/statement/Goto.spec.js.map +0 -1
  390. package/dist/parser/tests/statement/Increment.spec.d.ts +0 -1
  391. package/dist/parser/tests/statement/Increment.spec.js +0 -120
  392. package/dist/parser/tests/statement/Increment.spec.js.map +0 -1
  393. package/dist/parser/tests/statement/InterfaceStatement.spec.d.ts +0 -1
  394. package/dist/parser/tests/statement/InterfaceStatement.spec.js +0 -110
  395. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +0 -1
  396. package/dist/parser/tests/statement/LibraryStatement.spec.d.ts +0 -1
  397. package/dist/parser/tests/statement/LibraryStatement.spec.js +0 -74
  398. package/dist/parser/tests/statement/LibraryStatement.spec.js.map +0 -1
  399. package/dist/parser/tests/statement/Misc.spec.d.ts +0 -1
  400. package/dist/parser/tests/statement/Misc.spec.js +0 -292
  401. package/dist/parser/tests/statement/Misc.spec.js.map +0 -1
  402. package/dist/parser/tests/statement/PrintStatement.spec.d.ts +0 -1
  403. package/dist/parser/tests/statement/PrintStatement.spec.js +0 -200
  404. package/dist/parser/tests/statement/PrintStatement.spec.js.map +0 -1
  405. package/dist/parser/tests/statement/ReturnStatement.spec.d.ts +0 -1
  406. package/dist/parser/tests/statement/ReturnStatement.spec.js +0 -97
  407. package/dist/parser/tests/statement/ReturnStatement.spec.js.map +0 -1
  408. package/dist/parser/tests/statement/Set.spec.d.ts +0 -1
  409. package/dist/parser/tests/statement/Set.spec.js +0 -232
  410. package/dist/parser/tests/statement/Set.spec.js.map +0 -1
  411. package/dist/parser/tests/statement/Stop.spec.d.ts +0 -1
  412. package/dist/parser/tests/statement/Stop.spec.js +0 -38
  413. package/dist/parser/tests/statement/Stop.spec.js.map +0 -1
  414. package/dist/parser/tests/statement/Throw.spec.d.ts +0 -1
  415. package/dist/parser/tests/statement/Throw.spec.js +0 -38
  416. package/dist/parser/tests/statement/Throw.spec.js.map +0 -1
  417. package/dist/parser/tests/statement/TryCatch.spec.d.ts +0 -1
  418. package/dist/parser/tests/statement/TryCatch.spec.js +0 -151
  419. package/dist/parser/tests/statement/TryCatch.spec.js.map +0 -1
  420. package/dist/preprocessor/Manifest.spec.d.ts +0 -1
  421. package/dist/preprocessor/Manifest.spec.js +0 -80
  422. package/dist/preprocessor/Manifest.spec.js.map +0 -1
  423. package/dist/types/ArrayType.spec.d.ts +0 -1
  424. package/dist/types/ArrayType.spec.js +0 -58
  425. package/dist/types/ArrayType.spec.js.map +0 -1
  426. package/dist/types/BooleanType.spec.d.ts +0 -1
  427. package/dist/types/BooleanType.spec.js +0 -18
  428. package/dist/types/BooleanType.spec.js.map +0 -1
  429. package/dist/types/BuiltInInterfaceAdder.spec.d.ts +0 -1
  430. package/dist/types/BuiltInInterfaceAdder.spec.js +0 -115
  431. package/dist/types/BuiltInInterfaceAdder.spec.js.map +0 -1
  432. package/dist/types/ClassType.spec.d.ts +0 -1
  433. package/dist/types/ClassType.spec.js +0 -76
  434. package/dist/types/ClassType.spec.js.map +0 -1
  435. package/dist/types/DoubleType.spec.d.ts +0 -1
  436. package/dist/types/DoubleType.spec.js +0 -20
  437. package/dist/types/DoubleType.spec.js.map +0 -1
  438. package/dist/types/DynamicType.spec.d.ts +0 -1
  439. package/dist/types/DynamicType.spec.js +0 -23
  440. package/dist/types/DynamicType.spec.js.map +0 -1
  441. package/dist/types/EnumType.spec.d.ts +0 -1
  442. package/dist/types/EnumType.spec.js +0 -33
  443. package/dist/types/EnumType.spec.js.map +0 -1
  444. package/dist/types/FloatType.spec.d.ts +0 -1
  445. package/dist/types/FloatType.spec.js +0 -12
  446. package/dist/types/FloatType.spec.js.map +0 -1
  447. package/dist/types/IntegerType.spec.d.ts +0 -1
  448. package/dist/types/IntegerType.spec.js +0 -16
  449. package/dist/types/IntegerType.spec.js.map +0 -1
  450. package/dist/types/InterfaceType.spec.d.ts +0 -1
  451. package/dist/types/InterfaceType.spec.js +0 -227
  452. package/dist/types/InterfaceType.spec.js.map +0 -1
  453. package/dist/types/IntersectionType.spec.d.ts +0 -1
  454. package/dist/types/IntersectionType.spec.js +0 -150
  455. package/dist/types/IntersectionType.spec.js.map +0 -1
  456. package/dist/types/InvalidType.spec.d.ts +0 -1
  457. package/dist/types/InvalidType.spec.js +0 -16
  458. package/dist/types/InvalidType.spec.js.map +0 -1
  459. package/dist/types/LongIntegerType.spec.d.ts +0 -1
  460. package/dist/types/LongIntegerType.spec.js +0 -18
  461. package/dist/types/LongIntegerType.spec.js.map +0 -1
  462. package/dist/types/ObjectType.spec.d.ts +0 -1
  463. package/dist/types/ObjectType.spec.js +0 -12
  464. package/dist/types/ObjectType.spec.js.map +0 -1
  465. package/dist/types/ReferenceType.spec.d.ts +0 -1
  466. package/dist/types/ReferenceType.spec.js +0 -151
  467. package/dist/types/ReferenceType.spec.js.map +0 -1
  468. package/dist/types/StringType.spec.d.ts +0 -1
  469. package/dist/types/StringType.spec.js +0 -12
  470. package/dist/types/StringType.spec.js.map +0 -1
  471. package/dist/types/TypedFunctionType.spec.d.ts +0 -1
  472. package/dist/types/TypedFunctionType.spec.js +0 -122
  473. package/dist/types/TypedFunctionType.spec.js.map +0 -1
  474. package/dist/types/UnionType.spec.d.ts +0 -1
  475. package/dist/types/UnionType.spec.js +0 -205
  476. package/dist/types/UnionType.spec.js.map +0 -1
  477. package/dist/types/VoidType.spec.d.ts +0 -1
  478. package/dist/types/VoidType.spec.js +0 -12
  479. package/dist/types/VoidType.spec.js.map +0 -1
  480. package/dist/types/helper.spec.d.ts +0 -1
  481. package/dist/types/helper.spec.js +0 -174
  482. package/dist/types/helper.spec.js.map +0 -1
  483. package/dist/types/roFunctionType.spec.d.ts +0 -1
  484. package/dist/types/roFunctionType.spec.js +0 -20
  485. package/dist/types/roFunctionType.spec.js.map +0 -1
@@ -7,47 +7,324 @@ const DiagnosticMessages_1 = require("../../DiagnosticMessages");
7
7
  const Parser_1 = require("../../parser/Parser");
8
8
  const util_1 = require("../../util");
9
9
  const reflection_1 = require("../../astUtils/reflection");
10
+ const visitors_1 = require("../../astUtils/visitors");
10
11
  const TokenKind_1 = require("../../lexer/TokenKind");
12
+ const codeActionHelpers_1 = require("./codeActionHelpers");
13
+ const SGParser_1 = require("../../parser/SGParser");
11
14
  class CodeActionsProcessor {
12
15
  constructor(event) {
13
16
  this.event = event;
14
17
  this.suggestedImports = new Set();
15
18
  }
19
+ /**
20
+ * Processes all diagnostics in the event and emits code actions for each recognized diagnostic code.
21
+ */
16
22
  process() {
23
+ // First pass: individual fixes for each diagnostic at the cursor position
17
24
  for (const diagnostic of this.event.diagnostics) {
18
25
  if (diagnostic.code === DiagnosticMessages_1.DiagnosticCodeMap.cannotFindName || diagnostic.code === DiagnosticMessages_1.DiagnosticCodeMap.cannotFindFunction) {
19
- this.suggestCannotFindName(diagnostic);
26
+ this.suggestCannotFindNameQuickFix(diagnostic);
20
27
  }
21
28
  else if (diagnostic.code === DiagnosticMessages_1.DiagnosticCodeMap.xmlComponentMissingExtendsAttribute) {
22
- this.addMissingExtends(diagnostic);
29
+ this.suggestMissingExtendsQuickFix(diagnostic);
23
30
  }
24
31
  else if (diagnostic.code === DiagnosticMessages_1.DiagnosticCodeMap.voidFunctionMayNotReturnValue) {
25
- this.addVoidFunctionReturnActions(diagnostic);
32
+ this.suggestVoidFunctionReturnQuickFixes([diagnostic]);
26
33
  }
27
34
  else if (diagnostic.code === DiagnosticMessages_1.DiagnosticCodeMap.nonVoidFunctionMustReturnValue) {
28
- this.addNonVoidFunctionReturnActions(diagnostic);
35
+ this.suggestNonVoidFunctionReturnQuickFixes([diagnostic]);
36
+ }
37
+ else if (diagnostic.code === DiagnosticMessages_1.DiagnosticCodeMap.referencedFileDoesNotExist) {
38
+ this.suggestRemoveScriptImportQuickFixes([diagnostic]);
39
+ }
40
+ else if (diagnostic.code === DiagnosticMessages_1.DiagnosticCodeMap.unnecessaryScriptImportInChildFromParent) {
41
+ this.suggestRemoveScriptImportQuickFixes([diagnostic]);
42
+ }
43
+ else if (diagnostic.code === DiagnosticMessages_1.DiagnosticCodeMap.unnecessaryCodebehindScriptImport) {
44
+ this.suggestRemoveScriptImportQuickFixes([diagnostic]);
45
+ }
46
+ else if (diagnostic.code === DiagnosticMessages_1.DiagnosticCodeMap.scriptImportCaseMismatch) {
47
+ this.suggestScriptImportCasingQuickFixes([diagnostic]);
48
+ }
49
+ else if (diagnostic.code === DiagnosticMessages_1.DiagnosticCodeMap.missingOverrideKeyword) {
50
+ this.suggestMissingOverrideQuickFixes([diagnostic]);
51
+ }
52
+ else if (diagnostic.code === DiagnosticMessages_1.DiagnosticCodeMap.cannotUseOverrideKeywordOnConstructorFunction) {
53
+ this.suggestRemoveOverrideFromConstructorQuickFixes([diagnostic]);
54
+ }
55
+ else if ((0, DiagnosticMessages_1.isDiagnosticOfType)(diagnostic, 'mismatchedEndingToken')) {
56
+ this.suggestMismatchedEndingTokenQuickFixes([diagnostic]);
29
57
  }
30
58
  }
59
+ // Second pass: fix-all actions for any code that appeared in the event.
60
+ // Also makes sure that fix-all actions appear after individual fixes
61
+ const eventCodes = new Set(this.event.diagnostics.map(d => d.code));
62
+ const fixAllDiagsByCode = this.collectFixAllDiagnostics(eventCodes);
63
+ // only offer fix-all when there are multiple instances of the same issue in the file
64
+ for (const [code, allInFile] of fixAllDiagsByCode) {
65
+ if (allInFile.length > 1) {
66
+ if (code === DiagnosticMessages_1.DiagnosticCodeMap.voidFunctionMayNotReturnValue) {
67
+ this.suggestVoidFunctionReturnQuickFixes(allInFile);
68
+ }
69
+ else if (code === DiagnosticMessages_1.DiagnosticCodeMap.nonVoidFunctionMustReturnValue) {
70
+ this.suggestNonVoidFunctionReturnQuickFixes(allInFile);
71
+ }
72
+ else if (code === DiagnosticMessages_1.DiagnosticCodeMap.cannotUseOverrideKeywordOnConstructorFunction) {
73
+ this.suggestRemoveOverrideFromConstructorQuickFixes(allInFile);
74
+ }
75
+ else if (code === DiagnosticMessages_1.DiagnosticCodeMap.referencedFileDoesNotExist) {
76
+ this.suggestRemoveScriptImportQuickFixes(allInFile);
77
+ }
78
+ else if (code === DiagnosticMessages_1.DiagnosticCodeMap.unnecessaryScriptImportInChildFromParent) {
79
+ this.suggestRemoveScriptImportQuickFixes(allInFile);
80
+ }
81
+ else if (code === DiagnosticMessages_1.DiagnosticCodeMap.unnecessaryCodebehindScriptImport) {
82
+ this.suggestRemoveScriptImportQuickFixes(allInFile);
83
+ }
84
+ else if (code === DiagnosticMessages_1.DiagnosticCodeMap.scriptImportCaseMismatch) {
85
+ this.suggestScriptImportCasingQuickFixes(allInFile);
86
+ }
87
+ else if (code === DiagnosticMessages_1.DiagnosticCodeMap.missingOverrideKeyword) {
88
+ this.suggestMissingOverrideQuickFixes(allInFile);
89
+ }
90
+ else if (code === DiagnosticMessages_1.DiagnosticCodeMap.mismatchedEndingToken) {
91
+ this.suggestMismatchedEndingTokenQuickFixes(allInFile);
92
+ }
93
+ }
94
+ }
95
+ // Import fix-all aggregates across multiple codes so it runs as its own step
96
+ if (eventCodes.has(DiagnosticMessages_1.DiagnosticCodeMap.cannotFindName) ||
97
+ eventCodes.has(DiagnosticMessages_1.DiagnosticCodeMap.cannotFindFunction)) {
98
+ this.suggestMissingImportsFixAllQuickFix();
99
+ }
100
+ // Suppression actions appear last so real fixes are surfaced first
101
+ for (const diagnostic of this.event.diagnostics) {
102
+ this.suggestDisableDiagnosticQuickFixes(diagnostic);
103
+ }
104
+ this.suggestedImports.clear();
31
105
  }
32
106
  /**
33
- * Generic import suggestion function. Shouldn't be called directly from the main loop, but instead called by more specific diagnostic handlers
107
+ * For any diagnostic with a code, offers two quick-fix actions:
108
+ * - "Disable {code} for this line": adds the code to an existing `bs:disable-line` or
109
+ * `bs:disable-next-line` directive on/above the diagnostic if present, otherwise inserts
110
+ * a new `bs:disable-next-line: {code}` comment on the line above.
111
+ * - "Disable {code} for this file": adds the code to an existing header-level `bs:disable`
112
+ * directive if present, otherwise inserts a new `bs:disable: {code}` at the top of the file.
113
+ *
114
+ * Comment placement and the line-vs-next-line preference are centralized here so they can be
115
+ * revisited without touching the directive parser.
116
+ */
117
+ suggestDisableDiagnosticQuickFixes(diagnostic) {
118
+ var _a;
119
+ const code = diagnostic.code;
120
+ if (code === undefined || code === null) {
121
+ return;
122
+ }
123
+ const file = this.event.file;
124
+ if (!(0, reflection_1.isBrsFile)(file) && !(0, reflection_1.isXmlFile)(file)) {
125
+ return;
126
+ }
127
+ const codeStr = String(code);
128
+ const isXml = (0, reflection_1.isXmlFile)(file);
129
+ //existing.forLine: any line/next-line directive on or above the diagnostic line that the line action could extend
130
+ //existing.forFile: any header-level bs:disable that the file action could extend
131
+ const existing = this.findExistingDisableDirectives(file, (_a = diagnostic.location) === null || _a === void 0 ? void 0 : _a.range.start.line);
132
+ //format helpers wrap the directive body in the right comment syntax (`'` for brs, `<!-- -->` for xml)
133
+ const formatLineDirective = (token, codes) => {
134
+ const body = `bs:disable-${token}: ${codes.join(' ')}`;
135
+ return isXml ? `<!-- ${body} -->` : `' ${body}`;
136
+ };
137
+ const formatBlockDirective = (codes) => {
138
+ const body = `bs:disable: ${codes.join(' ')}`;
139
+ return isXml ? `<!-- ${body} -->` : `' ${body}`;
140
+ };
141
+ // ---- "disable for this line" ----
142
+ //the two lambdas passed to getDiagnosticSuppressionChange are the "extend existing" and "insert fresh" branches:
143
+ // 1) rebuild the existing directive comment with the new code merged into its code list (preserving line vs next-line)
144
+ // 2) insert a fresh `bs:disable-next-line: {code}` on the line above the diagnostic, matching its indent
145
+ const indent = ' '.repeat(diagnostic.location.range.start.character);
146
+ const lineAction = this.getDiagnosticSuppressionChange(existing.forLine, codeStr, () => { var _a; return formatLineDirective(existing.forLine.type, this.mergeCodes((_a = existing.forLine) === null || _a === void 0 ? void 0 : _a.codes, codeStr)); }, () => ({
147
+ position: util_1.util.createPosition(diagnostic.location.range.start.line, 0),
148
+ newText: `${indent}${formatLineDirective('next-line', [codeStr])}\n`
149
+ }));
150
+ if (lineAction) {
151
+ this.event.codeActions.push(CodeActionUtil_1.codeActionUtil.createCodeAction({
152
+ title: `Disable ${code} for this line: ${diagnostic.message}`,
153
+ diagnostics: [diagnostic],
154
+ kind: vscode_languageserver_1.CodeActionKind.QuickFix,
155
+ changes: [lineAction]
156
+ }));
157
+ }
158
+ // ---- "disable for this file" ----
159
+ //same pattern as above, but operating on the header-level bs:disable directive:
160
+ // 1) rebuild the existing header directive with the new code appended
161
+ // 2) insert a fresh `bs:disable: {code}` at the file header (top of brs, or after `<?xml ?>` for xml)
162
+ const fileAction = this.getDiagnosticSuppressionChange(existing.forFile, codeStr, () => { var _a; return formatBlockDirective(this.mergeCodes((_a = existing.forFile) === null || _a === void 0 ? void 0 : _a.codes, codeStr)); }, () => {
163
+ const headerInsert = this.getDisableFileInsertion(file);
164
+ return {
165
+ position: headerInsert.position,
166
+ newText: headerInsert.prefix + formatBlockDirective([codeStr]) + headerInsert.suffix
167
+ };
168
+ });
169
+ if (fileAction) {
170
+ this.event.codeActions.push(CodeActionUtil_1.codeActionUtil.createCodeAction({
171
+ title: `Disable ${code} for this file: ${diagnostic.message}`,
172
+ diagnostics: [diagnostic],
173
+ kind: vscode_languageserver_1.CodeActionKind.QuickFix,
174
+ changes: [fileAction]
175
+ }));
176
+ }
177
+ }
178
+ /**
179
+ * Returns the file change that suppresses `codeStr` via a directive comment, or `null` when no
180
+ * change is needed (the existing directive already covers the code, or already suppresses
181
+ * everything). When `existing` is set, the result is a replace that swaps the directive comment
182
+ * for the text from `buildReplacementText`. When `existing` is null, the result is an insert
183
+ * built from `buildInsert`.
184
+ */
185
+ getDiagnosticSuppressionChange(existing, codeStr, buildReplacementText, buildInsert) {
186
+ if (existing) {
187
+ //existing directive without specific codes already suppresses everything; no-op
188
+ if (existing.codes.length === 0) {
189
+ return null;
190
+ }
191
+ //the new code is already in the directive; no-op
192
+ if (existing.codes.some(c => c.toLowerCase() === codeStr.toLowerCase())) {
193
+ return null;
194
+ }
195
+ return {
196
+ type: 'replace',
197
+ filePath: this.event.file.srcPath,
198
+ range: existing.range,
199
+ newText: buildReplacementText()
200
+ };
201
+ }
202
+ const insert = buildInsert();
203
+ return {
204
+ type: 'insert',
205
+ filePath: this.event.file.srcPath,
206
+ position: insert.position,
207
+ newText: insert.newText
208
+ };
209
+ }
210
+ mergeCodes(existingCodes, newCode) {
211
+ return [...(existingCodes !== null && existingCodes !== void 0 ? existingCodes : []), newCode];
212
+ }
213
+ /**
214
+ * Walks the file's tokens and returns existing `bs:disable-{line,next-line}` and header-level
215
+ * `bs:disable` directives that would cover the diagnostic on `diagLine`. Used so the suppression
216
+ * quick fixes can extend an existing directive instead of stacking new ones.
34
217
  */
35
- suggestImports(diagnostic, key, files) {
218
+ findExistingDisableDirectives(file, diagLine) {
36
219
  var _a, _b, _c, _d, _e;
220
+ const isXml = (0, reflection_1.isXmlFile)(file);
221
+ const tokens = (_b = (_a = file.parser) === null || _a === void 0 ? void 0 : _a.tokens) !== null && _b !== void 0 ? _b : [];
222
+ let inHeader = true;
223
+ let forLine = null;
224
+ let forFile = null;
225
+ for (const token of tokens) {
226
+ const isComment = isXml ? ((_c = token.tokenType) === null || _c === void 0 ? void 0 : _c.name) === 'Comment' : (_d = token.leadingTrivia) === null || _d === void 0 ? void 0 : _d.some(t => t.kind === TokenKind_1.TokenKind.Comment);
227
+ if (!isComment) {
228
+ if (isXml) {
229
+ if (((_e = token.tokenType) === null || _e === void 0 ? void 0 : _e.name) === 'OPEN') {
230
+ inHeader = false;
231
+ }
232
+ }
233
+ else if (token.kind !== TokenKind_1.TokenKind.Newline && token.kind !== TokenKind_1.TokenKind.Whitespace && token.kind !== TokenKind_1.TokenKind.Eof) {
234
+ inHeader = false;
235
+ }
236
+ continue;
237
+ }
238
+ const commentTokens = isXml ? [token] : token.leadingTrivia.filter(t => t.kind === TokenKind_1.TokenKind.Comment);
239
+ for (const commentToken of commentTokens) {
240
+ const tokenRange = isXml ? (0, SGParser_1.rangeFromTokenValue)(commentToken) : commentToken.location.range;
241
+ const tokenText = isXml ? commentToken.image : commentToken.text;
242
+ const parsed = parseDisableComment(tokenText);
243
+ if (!parsed) {
244
+ continue;
245
+ }
246
+ const directive = { type: parsed.directiveType, codes: parsed.codes, range: tokenRange };
247
+ if (!forLine && parsed.directiveType === 'line' && tokenRange.start.line === diagLine) {
248
+ forLine = directive;
249
+ }
250
+ else if (!forLine && parsed.directiveType === 'next-line' && tokenRange.start.line === diagLine - 1) {
251
+ forLine = directive;
252
+ }
253
+ else if (!forFile && parsed.directiveType === 'block' && inHeader) {
254
+ //only header-level `bs:disable` directives are extended for the file-level quick fix
255
+ forFile = directive;
256
+ }
257
+ }
258
+ }
259
+ return { forLine: forLine, forFile: forFile };
260
+ }
261
+ /**
262
+ * Decides where in the file a header-level `bs:disable` directive should be inserted, returning
263
+ * the position plus any prefix/suffix needed so the directive lands on its own line in
264
+ * the header (before the first executable statement / root XML element).
265
+ */
266
+ getDisableFileInsertion(file) {
267
+ var _a;
268
+ if ((0, reflection_1.isXmlFile)(file)) {
269
+ //insert after the `<?xml ?>` declaration if present, otherwise at the very top
270
+ const declCloseToken = (_a = file.parser.tokens) === null || _a === void 0 ? void 0 : _a.find(t => { var _a; return ((_a = t.tokenType) === null || _a === void 0 ? void 0 : _a.name) === 'SPECIAL_CLOSE'; });
271
+ if (declCloseToken) {
272
+ const endLine = declCloseToken.endLine - 1;
273
+ const endColumn = declCloseToken.endColumn;
274
+ return {
275
+ position: util_1.util.createPosition(endLine, endColumn),
276
+ prefix: '\n',
277
+ suffix: ''
278
+ };
279
+ }
280
+ }
281
+ return {
282
+ position: util_1.util.createPosition(0, 0),
283
+ prefix: '',
284
+ suffix: '\n'
285
+ };
286
+ }
287
+ /**
288
+ * Builds a map of diagnostic code → all matching diagnostics in the current file for each
289
+ * code in `eventCodes`. Scope-level codes are not present in `file.getDiagnostics()` so they
290
+ * are sourced from `program.getDiagnostics()` (fetched lazily, only when needed).
291
+ */
292
+ collectFixAllDiagnostics(eventCodes) {
293
+ var _a;
294
+ const fileUri = util_1.util.pathToUri(this.event.file.srcPath);
295
+ const fileDiagnostics = this.event.program.getDiagnostics().filter(d => { var _a; return ((_a = d.location) === null || _a === void 0 ? void 0 : _a.uri) === fileUri; });
296
+ const fileDiagsByCode = new Map();
297
+ for (const d of fileDiagnostics) {
298
+ if (!fileDiagsByCode.has(d.code)) {
299
+ fileDiagsByCode.set(d.code, []);
300
+ }
301
+ fileDiagsByCode.get(d.code).push(d);
302
+ }
303
+ const result = new Map();
304
+ for (const code of eventCodes) {
305
+ result.set(code, (_a = fileDiagsByCode.get(code)) !== null && _a !== void 0 ? _a : []);
306
+ }
307
+ return result;
308
+ }
309
+ /**
310
+ * Generic import suggestion function. Shouldn't be called directly from the main loop, but instead called by more specific diagnostic handlers
311
+ */
312
+ suggestImportQuickFix(diagnostic, key, files) {
313
+ var _a, _b, _c;
37
314
  //skip if we already have this suggestion
38
- if (this.suggestedImports.has(key) || !(0, reflection_1.isBrsFile)(this.event.file)) {
315
+ if (this.suggestedImports.has(key)) {
39
316
  return;
40
317
  }
41
318
  this.suggestedImports.add(key);
42
319
  // eslint-disable-next-line @typescript-eslint/dot-notation
43
320
  const importStatements = this.event.file['_cachedLookups'].importStatements;
44
321
  //find the position of the first import statement, or the top of the file if there is none
45
- const insertPosition = (_e = (_d = (_c = (_b = (_a = importStatements[importStatements.length - 1]) === null || _a === void 0 ? void 0 : _a.tokens.import) === null || _b === void 0 ? void 0 : _b.location) === null || _c === void 0 ? void 0 : _c.range) === null || _d === void 0 ? void 0 : _d.start) !== null && _e !== void 0 ? _e : util_1.util.createPosition(0, 0);
322
+ const insertPosition = (_c = (_b = (_a = importStatements[importStatements.length - 1]) === null || _a === void 0 ? void 0 : _a.tokens.import.location.range) === null || _b === void 0 ? void 0 : _b.start) !== null && _c !== void 0 ? _c : util_1.util.createPosition(0, 0);
46
323
  //find all files that reference this function
47
324
  for (const file of files) {
48
- const destPath = util_1.util.sanitizePkgPath(file.destPath);
325
+ const pkgPath = util_1.util.sanitizePkgPath(file.destPath);
49
326
  this.event.codeActions.push(CodeActionUtil_1.codeActionUtil.createCodeAction({
50
- title: `import "${destPath}"`,
327
+ title: `import "${pkgPath}"`,
51
328
  diagnostics: [diagnostic],
52
329
  isPreferred: false,
53
330
  kind: vscode_languageserver_1.CodeActionKind.QuickFix,
@@ -55,32 +332,93 @@ class CodeActionsProcessor {
55
332
  type: 'insert',
56
333
  filePath: this.event.file.srcPath,
57
334
  position: insertPosition,
58
- newText: `import "${destPath}"\n`
335
+ newText: `import "${pkgPath}"\n`
59
336
  }]
60
337
  }));
61
338
  }
62
339
  }
63
- suggestCannotFindName(diagnostic) {
64
- var _a, _b;
340
+ /**
341
+ * Suggests import statements for an unresolved name (function, class, namespace, or enum).
342
+ */
343
+ suggestCannotFindNameQuickFix(diagnostic) {
344
+ var _a;
65
345
  //skip if not a BrighterScript file
66
- const file = this.event.program.getFile((_a = diagnostic.location) === null || _a === void 0 ? void 0 : _a.uri);
67
- if (!file || file.parseMode !== Parser_1.ParseMode.BrighterScript) {
346
+ if (!(0, reflection_1.isBrsFile)(this.event.file) || this.event.file.parseMode !== Parser_1.ParseMode.BrighterScript) {
68
347
  return;
69
348
  }
70
- const lowerName = ((_b = diagnostic.data.fullName) !== null && _b !== void 0 ? _b : diagnostic.data.name).toLowerCase();
71
- this.suggestImports(diagnostic, lowerName, [
349
+ const lowerName = ((_a = diagnostic.data.fullName) !== null && _a !== void 0 ? _a : diagnostic.data.name).toLowerCase();
350
+ this.suggestImportQuickFix(diagnostic, lowerName, [
72
351
  ...this.event.program.findFilesForFunction(lowerName),
73
352
  ...this.event.program.findFilesForClass(lowerName),
74
353
  ...this.event.program.findFilesForNamespace(lowerName),
75
354
  ...this.event.program.findFilesForEnum(lowerName)
76
355
  ]);
77
356
  }
78
- addMissingExtends(diagnostic) {
79
- var _a, _b, _c;
357
+ /**
358
+ * Scans all import-related diagnostics in the file and emits a single composite
359
+ * "Fix all: Add missing imports" action when 2+ unambiguous imports are needed.
360
+ * Ambiguous names (multiple possible source files) are excluded since we cannot
361
+ * automatically choose one.
362
+ */
363
+ suggestMissingImportsFixAllQuickFix() {
364
+ var _a, _b, _c, _d, _e, _f, _g;
365
+ if (!(0, reflection_1.isBrsFile)(this.event.file) || this.event.file.parseMode !== Parser_1.ParseMode.BrighterScript) {
366
+ return;
367
+ }
368
+ const file = this.event.file;
369
+ // eslint-disable-next-line @typescript-eslint/dot-notation
370
+ const importStatements = file['_cachedLookups'].importStatements;
371
+ const insertPosition = (_c = (_b = (_a = importStatements[importStatements.length - 1]) === null || _a === void 0 ? void 0 : _a.tokens.import.location.range) === null || _b === void 0 ? void 0 : _b.start) !== null && _c !== void 0 ? _c : util_1.util.createPosition(0, 0);
372
+ const changes = [];
373
+ const addedPaths = new Set();
374
+ // cannotFindName/classCouldNotBeFound are scope-level diagnostics, so we must
375
+ // use program.getDiagnostics() (filtered by file) rather than file.getDiagnostics().
376
+ const fileUri = util_1.util.pathToUri(file.srcPath);
377
+ const allFileDiagnostics = this.event.program.getDiagnostics().filter(d => { var _a; return ((_a = d.location) === null || _a === void 0 ? void 0 : _a.uri) === fileUri; });
378
+ for (const diagnostic of allFileDiagnostics) {
379
+ let files = [];
380
+ if (diagnostic.code === DiagnosticMessages_1.DiagnosticCodeMap.cannotFindName || diagnostic.code === DiagnosticMessages_1.DiagnosticCodeMap.cannotFindFunction) {
381
+ const cannotFindNameDiagnostic = diagnostic;
382
+ const lowerName = (_g = ((_e = (_d = cannotFindNameDiagnostic.data) === null || _d === void 0 ? void 0 : _d.fullName) !== null && _e !== void 0 ? _e : (_f = cannotFindNameDiagnostic.data) === null || _f === void 0 ? void 0 : _f.name)) === null || _g === void 0 ? void 0 : _g.toLowerCase();
383
+ if (lowerName) {
384
+ files = [
385
+ ...this.event.program.findFilesForFunction(lowerName),
386
+ ...this.event.program.findFilesForClass(lowerName),
387
+ ...this.event.program.findFilesForNamespace(lowerName),
388
+ ...this.event.program.findFilesForEnum(lowerName)
389
+ ];
390
+ }
391
+ }
392
+ //skip ambiguous names; we can't choose a file automatically
393
+ if (files.length !== 1) {
394
+ continue;
395
+ }
396
+ const pkgPath = util_1.util.sanitizePkgPath(files[0].destPath);
397
+ if (!addedPaths.has(pkgPath)) {
398
+ addedPaths.add(pkgPath);
399
+ changes.push({
400
+ type: 'insert',
401
+ filePath: file.srcPath,
402
+ position: insertPosition,
403
+ newText: `import "${pkgPath}"\n`
404
+ });
405
+ }
406
+ }
407
+ if (changes.length > 1) {
408
+ this.event.codeActions.push(CodeActionUtil_1.codeActionUtil.createCodeAction({
409
+ title: `Fix all: Auto fixable missing imports`,
410
+ kind: vscode_languageserver_1.CodeActionKind.QuickFix,
411
+ changes: changes
412
+ }));
413
+ }
414
+ }
415
+ /**
416
+ * Adds code actions to insert a missing `extends` attribute on an XML component tag.
417
+ * Offers Group, Task, and ContentNode as common choices.
418
+ */
419
+ suggestMissingExtendsQuickFix(diagnostic) {
80
420
  const srcPath = this.event.file.srcPath;
81
- const { componentElement } = this.event.file.parser.ast;
82
- //inject new attribute after the final attribute, or after the `<component` if there are no attributes
83
- const pos = (_c = (_b = ((_a = componentElement.attributes[componentElement.attributes.length - 1]) !== null && _a !== void 0 ? _a : componentElement.tokens.startTagName)) === null || _b === void 0 ? void 0 : _b.location) === null || _c === void 0 ? void 0 : _c.range.end;
421
+ const pos = (0, codeActionHelpers_1.getMissingExtendsInsertPosition)(this.event.file);
84
422
  this.event.codeActions.push(CodeActionUtil_1.codeActionUtil.createCodeAction({
85
423
  title: `Extend "Group"`,
86
424
  diagnostics: [diagnostic],
@@ -116,19 +454,17 @@ class CodeActionsProcessor {
116
454
  }]
117
455
  }));
118
456
  }
119
- addVoidFunctionReturnActions(diagnostic) {
457
+ /**
458
+ * Adds code actions to resolve a `voidFunctionMayNotReturnValue` diagnostic.
459
+ * Offers removing the return value, converting sub→function, or removing an `as void` return type.
460
+ */
461
+ suggestVoidFunctionReturnQuickFixes(diagnostics) {
120
462
  var _a, _b, _c;
121
- this.event.codeActions.push(CodeActionUtil_1.codeActionUtil.createCodeAction({
122
- title: `Remove return value`,
123
- diagnostics: [diagnostic],
124
- kind: vscode_languageserver_1.CodeActionKind.QuickFix,
125
- changes: [{
126
- type: 'delete',
127
- filePath: this.event.file.srcPath,
128
- range: util_1.util.createRange(diagnostic.location.range.start.line, diagnostic.location.range.start.character + 'return'.length, diagnostic.location.range.end.line, diagnostic.location.range.end.character)
129
- }]
130
- }));
131
- if ((0, reflection_1.isBrsFile)(this.event.file)) {
463
+ const changes = diagnostics.map(d => this.getRemoveReturnValueChange(d));
464
+ this.emitOrFixAll(`Remove return value`, `Fix all: Remove void return values`, changes, diagnostics[0]);
465
+ //contextual BrsFile actions only apply to the individual (single-violation) case
466
+ if (changes.length === 1 && (0, reflection_1.isBrsFile)(this.event.file)) {
467
+ const diagnostic = diagnostics[0];
132
468
  const expression = this.event.file.getClosestExpression(diagnostic.location.range.start);
133
469
  const func = expression.findAncestor(reflection_1.isFunctionExpression);
134
470
  //if we're in a sub and we do not have a return type, suggest converting to a function
@@ -145,117 +481,285 @@ class CodeActionsProcessor {
145
481
  kind: vscode_languageserver_1.CodeActionKind.QuickFix,
146
482
  changes: [
147
483
  //function
148
- {
149
- type: 'replace',
150
- filePath: this.event.file.srcPath,
151
- range: func.tokens.functionType.location.range,
152
- newText: functionTypeText
153
- },
484
+ { type: 'replace', filePath: this.event.file.srcPath, range: func.tokens.functionType.location.range, newText: functionTypeText },
154
485
  //end function
155
- {
156
- type: 'replace',
157
- filePath: this.event.file.srcPath,
158
- range: func.tokens.endFunctionType.location.range,
159
- newText: endFunctionTypeText
160
- }
486
+ { type: 'replace', filePath: this.event.file.srcPath, range: func.tokens.endFunctionType.location.range, newText: endFunctionTypeText }
161
487
  ]
162
488
  }));
163
489
  }
164
490
  //function `as void` return type. Suggest removing the return type
165
- if (func.tokens.functionType.kind === TokenKind_1.TokenKind.Function && (0, reflection_1.isVoidType)(func.returnTypeExpression.getType({ flags: 2 /* SymbolTypeFlag.typetime */ }))) {
491
+ if (func.tokens.functionType.kind === TokenKind_1.TokenKind.Function && func.returnTypeExpression && (0, reflection_1.isVoidType)(func.returnTypeExpression.getType({ flags: 2 /* SymbolTypeFlag.typetime */ }))) {
166
492
  this.event.codeActions.push(CodeActionUtil_1.codeActionUtil.createCodeAction({
167
493
  title: `Remove return type from function declaration`,
168
494
  diagnostics: [diagnostic],
169
495
  kind: vscode_languageserver_1.CodeActionKind.QuickFix,
170
- changes: [{
171
- type: 'delete',
172
- filePath: this.event.file.srcPath,
173
- // )| as void|
174
- range: util_1.util.createRange(func.tokens.rightParen.location.range.start.line, func.tokens.rightParen.location.range.start.character + 1, func.returnTypeExpression.location.range.end.line, func.returnTypeExpression.location.range.end.character)
175
- }]
496
+ changes: [this.getRemoveFunctionReturnTypeChange(func)]
176
497
  }));
177
498
  }
178
499
  }
179
500
  }
180
- addNonVoidFunctionReturnActions(diagnostic) {
501
+ /**
502
+ * Adds code actions to resolve a `nonVoidFunctionMustReturnValue` diagnostic.
503
+ * Offers removing the return type from a sub, adding `as void` to a function, or converting function→sub.
504
+ */
505
+ suggestNonVoidFunctionReturnQuickFixes(diagnostics) {
506
+ if (!(0, reflection_1.isBrsFile)(this.event.file)) {
507
+ return;
508
+ }
509
+ const file = this.event.file;
510
+ //find tokens for `as`, `void`, `sub`, `end sub` in the file if possible
511
+ let asText;
512
+ let voidText;
513
+ let subText;
514
+ let endSubText;
515
+ for (const token of file.parser.tokens) {
516
+ if (asText && voidText && subText && endSubText) {
517
+ break;
518
+ }
519
+ if ((token === null || token === void 0 ? void 0 : token.kind) === TokenKind_1.TokenKind.As) {
520
+ asText = token === null || token === void 0 ? void 0 : token.text;
521
+ }
522
+ else if ((token === null || token === void 0 ? void 0 : token.kind) === TokenKind_1.TokenKind.Void) {
523
+ voidText = token === null || token === void 0 ? void 0 : token.text;
524
+ }
525
+ else if ((token === null || token === void 0 ? void 0 : token.kind) === TokenKind_1.TokenKind.Sub) {
526
+ subText = token === null || token === void 0 ? void 0 : token.text;
527
+ }
528
+ else if ((token === null || token === void 0 ? void 0 : token.kind) === TokenKind_1.TokenKind.EndSub) {
529
+ endSubText = token === null || token === void 0 ? void 0 : token.text;
530
+ }
531
+ }
532
+ // Build per-fix-type change arrays, deduplicating by enclosing function so that one
533
+ // function with multiple bare returns only contributes one change.
534
+ const removeReturnTypeChanges = [];
535
+ const addVoidChanges = [];
536
+ const seenFunctions = new Set();
537
+ for (const d of diagnostics) {
538
+ const expr = file.getClosestExpression(d.location.range.start);
539
+ const fn = expr === null || expr === void 0 ? void 0 : expr.findAncestor(reflection_1.isFunctionExpression);
540
+ if (!fn) {
541
+ continue;
542
+ }
543
+ const fnKey = `${fn.location.range.start.line}:${fn.location.range.start.character}`;
544
+ if (seenFunctions.has(fnKey)) {
545
+ continue;
546
+ }
547
+ seenFunctions.add(fnKey);
548
+ if (fn.tokens.functionType.kind === TokenKind_1.TokenKind.Sub && fn.returnTypeExpression && !(0, reflection_1.isVoidType)(fn.returnTypeExpression.getType({ flags: 2 /* SymbolTypeFlag.typetime */ }))) {
549
+ removeReturnTypeChanges.push(this.getRemoveFunctionReturnTypeChange(fn));
550
+ }
551
+ else if (fn.tokens.functionType.kind === TokenKind_1.TokenKind.Function && !fn.returnTypeExpression) {
552
+ addVoidChanges.push({
553
+ type: 'insert',
554
+ filePath: this.event.file.srcPath,
555
+ position: fn.tokens.rightParen.location.range.end,
556
+ newText: ` ${asText !== null && asText !== void 0 ? asText : 'as'} ${voidText !== null && voidText !== void 0 ? voidText : 'void'}`
557
+ });
558
+ }
559
+ }
560
+ this.emitOrFixAll(`Remove return type from sub declaration`, `Fix all: Remove return type from sub declarations`, removeReturnTypeChanges, diagnostics[0]);
561
+ this.emitOrFixAll(`Add void return type to function declaration`, `Fix all: Add void return type to function declarations`, addVoidChanges, diagnostics[0]);
562
+ //'Convert function to sub' has no fix-all variant; only add it for the individual case
563
+ if (addVoidChanges.length === 1 && diagnostics.length === 1) {
564
+ const func = file.getClosestExpression(diagnostics[0].location.range.start).findAncestor(reflection_1.isFunctionExpression);
565
+ this.event.codeActions.push(CodeActionUtil_1.codeActionUtil.createCodeAction({
566
+ title: `Convert function to sub`,
567
+ diagnostics: [diagnostics[0]],
568
+ kind: vscode_languageserver_1.CodeActionKind.QuickFix,
569
+ changes: [
570
+ { type: 'replace', filePath: file.srcPath, range: func.tokens.functionType.location.range, newText: subText !== null && subText !== void 0 ? subText : 'sub' },
571
+ { type: 'replace', filePath: file.srcPath, range: func.tokens.endFunctionType.location.range, newText: endSubText !== null && endSubText !== void 0 ? endSubText : 'end sub' }
572
+ ]
573
+ }));
574
+ }
575
+ }
576
+ // ---- script import fixes ----
577
+ /**
578
+ * Adds code actions to delete one or more unnecessary or broken script import lines.
579
+ */
580
+ suggestRemoveScriptImportQuickFixes(diagnostics) {
581
+ var _a, _b;
582
+ const titles = {
583
+ [DiagnosticMessages_1.DiagnosticCodeMap.unnecessaryScriptImportInChildFromParent]: ['Remove redundant script import', 'Fix all: Remove redundant script imports'],
584
+ [DiagnosticMessages_1.DiagnosticCodeMap.unnecessaryCodebehindScriptImport]: ['Remove unnecessary codebehind import', 'Fix all: Remove unnecessary codebehind imports']
585
+ };
586
+ const [singleTitle, fixAllTitle] = (_b = titles[(_a = diagnostics[0]) === null || _a === void 0 ? void 0 : _a.code]) !== null && _b !== void 0 ? _b : ['Remove script import', 'Fix all: Remove script imports'];
587
+ const changes = diagnostics.map(diagnostic => {
588
+ return {
589
+ type: 'delete',
590
+ filePath: this.event.file.srcPath,
591
+ range: util_1.util.createRange(diagnostic.location.range.start.line, 0, diagnostic.location.range.start.line + 1, 0)
592
+ };
593
+ });
594
+ this.emitOrFixAll(singleTitle, fixAllTitle, changes, diagnostics[0]);
595
+ }
596
+ /**
597
+ * Adds code actions to correct the casing of script import paths to match the actual file name on disk.
598
+ */
599
+ suggestScriptImportCasingQuickFixes(diagnostics) {
181
600
  var _a;
182
- if ((0, reflection_1.isBrsFile)(this.event.file)) {
183
- const expression = this.event.file.getClosestExpression(diagnostic.location.range.start);
184
- const func = expression.findAncestor(reflection_1.isFunctionExpression);
185
- //`sub as <non-void type>`, suggest removing the return type
186
- if (func.tokens.functionType.kind === TokenKind_1.TokenKind.Sub &&
187
- //has a return type
188
- func.returnTypeExpression &&
189
- //is not `as void`
190
- !((0, reflection_1.isVariableExpression)(func.returnTypeExpression.expression) && ((_a = func.returnTypeExpression.expression.tokens.name.text) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'void')) {
191
- this.event.codeActions.push(CodeActionUtil_1.codeActionUtil.createCodeAction({
192
- title: `Remove return type from sub declaration`,
193
- diagnostics: [diagnostic],
194
- kind: vscode_languageserver_1.CodeActionKind.QuickFix,
195
- changes: [{
196
- type: 'delete',
197
- filePath: this.event.file.srcPath,
198
- // )| as void|
199
- range: util_1.util.createRange(func.tokens.rightParen.location.range.start.line, func.tokens.rightParen.location.range.start.character + 1, func.returnTypeExpression.location.range.end.line, func.returnTypeExpression.location.range.end.character)
200
- }]
201
- }));
601
+ const changes = [];
602
+ for (const diagnostic of diagnostics) {
603
+ const correctFilePath = (_a = diagnostic.data) === null || _a === void 0 ? void 0 : _a.correctFilePath;
604
+ if (!correctFilePath) {
605
+ continue;
202
606
  }
203
- //function with no return type.
204
- if (func.tokens.functionType.kind === TokenKind_1.TokenKind.Function && !func.returnTypeExpression) {
205
- //find tokens for `as` and `void` in the file if possible
206
- let asText;
207
- let voidText;
208
- let subText;
209
- let endSubText;
210
- for (const token of this.event.file.parser.tokens) {
211
- if (asText && voidText && subText && endSubText) {
212
- break;
213
- }
214
- if ((token === null || token === void 0 ? void 0 : token.kind) === TokenKind_1.TokenKind.As) {
215
- asText = token === null || token === void 0 ? void 0 : token.text;
216
- }
217
- else if ((token === null || token === void 0 ? void 0 : token.kind) === TokenKind_1.TokenKind.Void) {
218
- voidText = token === null || token === void 0 ? void 0 : token.text;
219
- }
220
- else if ((token === null || token === void 0 ? void 0 : token.kind) === TokenKind_1.TokenKind.Sub) {
221
- subText = token === null || token === void 0 ? void 0 : token.text;
222
- }
223
- else if ((token === null || token === void 0 ? void 0 : token.kind) === TokenKind_1.TokenKind.EndSub) {
224
- endSubText = token === null || token === void 0 ? void 0 : token.text;
225
- }
607
+ changes.push({
608
+ type: 'replace',
609
+ filePath: this.event.file.srcPath,
610
+ range: diagnostic.location.range,
611
+ newText: correctFilePath
612
+ });
613
+ }
614
+ this.emitOrFixAll('Fix script import path casing', 'Fix all: Fix script import path casing', changes, diagnostics[0]);
615
+ }
616
+ // ---- override keyword fixes ----
617
+ /**
618
+ * Adds code actions to insert the missing `override` keyword before a method declaration.
619
+ */
620
+ suggestMissingOverrideQuickFixes(diagnostics) {
621
+ if (!(0, reflection_1.isBrsFile)(this.event.file)) {
622
+ return;
623
+ }
624
+ const file = this.event.file;
625
+ const changes = [];
626
+ for (const diagnostic of diagnostics) {
627
+ let insertPosition;
628
+ file.ast.walk((node) => {
629
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
630
+ if ((0, reflection_1.isMethodStatement)(node) &&
631
+ ((_c = (_b = (_a = node.location) === null || _a === void 0 ? void 0 : _a.range) === null || _b === void 0 ? void 0 : _b.start) === null || _c === void 0 ? void 0 : _c.line) === diagnostic.location.range.start.line &&
632
+ ((_f = (_e = (_d = node.location) === null || _d === void 0 ? void 0 : _d.range) === null || _e === void 0 ? void 0 : _e.start) === null || _f === void 0 ? void 0 : _f.character) === diagnostic.location.range.start.character) {
633
+ insertPosition = (_j = (_h = (_g = node.func.tokens.functionType) === null || _g === void 0 ? void 0 : _g.location) === null || _h === void 0 ? void 0 : _h.range) === null || _j === void 0 ? void 0 : _j.start;
226
634
  }
227
- //suggest converting to `as void`
228
- this.event.codeActions.push(CodeActionUtil_1.codeActionUtil.createCodeAction({
229
- title: `Add void return type to function declaration`,
230
- diagnostics: [diagnostic],
231
- kind: vscode_languageserver_1.CodeActionKind.QuickFix,
232
- changes: [{
233
- type: 'insert',
234
- filePath: this.event.file.srcPath,
235
- position: func.tokens.rightParen.location.range.end,
236
- newText: ` ${asText !== null && asText !== void 0 ? asText : 'as'} ${voidText !== null && voidText !== void 0 ? voidText : 'void'}`
237
- }]
238
- }));
239
- //suggest converting to sub
240
- this.event.codeActions.push(CodeActionUtil_1.codeActionUtil.createCodeAction({
241
- title: `Convert function to sub`,
242
- diagnostics: [diagnostic],
243
- kind: vscode_languageserver_1.CodeActionKind.QuickFix,
244
- changes: [{
245
- type: 'replace',
246
- filePath: this.event.file.srcPath,
247
- range: func.tokens.functionType.location.range,
248
- newText: subText !== null && subText !== void 0 ? subText : 'sub'
249
- }, {
250
- type: 'replace',
251
- filePath: this.event.file.srcPath,
252
- range: func.tokens.endFunctionType.location.range,
253
- newText: endSubText !== null && endSubText !== void 0 ? endSubText : 'end sub'
254
- }]
255
- }));
635
+ }, { walkMode: visitors_1.WalkMode.visitStatementsRecursive });
636
+ if (insertPosition) {
637
+ changes.push({
638
+ type: 'insert',
639
+ filePath: file.srcPath,
640
+ position: insertPosition,
641
+ newText: 'override '
642
+ });
256
643
  }
257
644
  }
645
+ this.emitOrFixAll(`Add missing 'override' keyword`, `Fix all: Add missing 'override' keywords`, changes, diagnostics[0]);
646
+ }
647
+ /**
648
+ * Adds one code action per legal terminator. The first entry of `expected` is marked
649
+ * `isPreferred`, matching the parser's convention of listing the canonical terminator first.
650
+ */
651
+ suggestMismatchedEndingTokenQuickFixes(diagnostics) {
652
+ const { expected, found } = diagnostics[0].data;
653
+ for (let index = 0; index < expected.length; index++) {
654
+ const replacement = expected[index];
655
+ const changes = diagnostics.map(diagnostic => ({
656
+ type: 'replace',
657
+ filePath: this.event.file.srcPath,
658
+ range: diagnostic.location.range,
659
+ newText: replacement
660
+ }));
661
+ this.emitOrFixAll(`Convert '${found}' to '${replacement}'`, `Fix all: Convert '${found}' to '${replacement}'`, changes, diagnostics[0], index === 0);
662
+ }
663
+ }
664
+ /**
665
+ * Adds code actions to remove the invalid `override` keyword from a constructor method.
666
+ */
667
+ suggestRemoveOverrideFromConstructorQuickFixes(diagnostics) {
668
+ const changes = diagnostics.map(d => ({
669
+ type: 'delete',
670
+ filePath: this.event.file.srcPath,
671
+ // delete "override " (the keyword token plus the trailing space before function/sub)
672
+ range: util_1.util.createRange(d.location.range.start.line, d.location.range.start.character, d.location.range.end.line, d.location.range.end.character + 1)
673
+ }));
674
+ this.emitOrFixAll(`Remove 'override' from constructor`, `Fix all: Remove 'override' from constructors`, changes, diagnostics[0]);
675
+ }
676
+ // ---- change helpers ----
677
+ /**
678
+ * Builds a delete change that removes the return value from a `return <expr>` statement,
679
+ * leaving just a bare `return`.
680
+ */
681
+ getRemoveReturnValueChange(diagnostic) {
682
+ return {
683
+ type: 'delete',
684
+ filePath: this.event.file.srcPath,
685
+ range: util_1.util.createRange(diagnostic.location.range.start.line, diagnostic.location.range.start.character + 'return'.length, diagnostic.location.range.end.line, diagnostic.location.range.end.character)
686
+ };
687
+ }
688
+ /**
689
+ * Builds the change that deletes `) as <type>` from a function/sub declaration.
690
+ * Used for both `as void` on a function and any return type on a sub.
691
+ */
692
+ getRemoveFunctionReturnTypeChange(func) {
693
+ return {
694
+ type: 'delete',
695
+ filePath: this.event.file.srcPath,
696
+ // )| as <type>|
697
+ range: util_1.util.createRange(func.tokens.rightParen.location.range.start.line, func.tokens.rightParen.location.range.start.character + 1, func.returnTypeExpression.location.range.end.line, func.returnTypeExpression.location.range.end.character)
698
+ };
699
+ }
700
+ /**
701
+ * Emits a single code action when there is exactly one change, or a "fix all" composite
702
+ * action when there are multiple changes (same pattern as ESLint's "Fix all X problems").
703
+ * Does nothing when the changes array is empty.
704
+ */
705
+ emitOrFixAll(singleTitle, fixAllTitle, changes, diagnostic, isPreferred) {
706
+ if (changes.length === 0) {
707
+ return;
708
+ }
709
+ if (changes.length === 1) {
710
+ this.event.codeActions.push(CodeActionUtil_1.codeActionUtil.createCodeAction(Object.assign(Object.assign({ title: singleTitle, diagnostics: [diagnostic] }, (isPreferred ? { isPreferred: true } : {})), { kind: vscode_languageserver_1.CodeActionKind.QuickFix, changes: changes })));
711
+ }
712
+ else {
713
+ this.event.codeActions.push(CodeActionUtil_1.codeActionUtil.createCodeAction(Object.assign(Object.assign({ title: fixAllTitle }, (isPreferred ? { isPreferred: true } : {})), { kind: vscode_languageserver_1.CodeActionKind.QuickFix, changes: changes })));
714
+ }
258
715
  }
259
716
  }
260
717
  exports.CodeActionsProcessor = CodeActionsProcessor;
718
+ /**
719
+ * Parses a comment's text and returns the directive details if it is one. Recognizes
720
+ * `'`, `rem`, and `<!-- -->` comment styles. Returns `null` for comments that aren't directives.
721
+ * `block` covers `bs:disable`. The `bs:enable` partner isn't surfaced since the quick fix only
722
+ * extends `bs:disable` directives.
723
+ */
724
+ function parseDisableComment(text) {
725
+ let inner = text;
726
+ if (inner.startsWith('<!--')) {
727
+ inner = inner.slice('<!--'.length);
728
+ if (inner.endsWith('-->')) {
729
+ inner = inner.slice(0, -('-->'.length));
730
+ }
731
+ }
732
+ else if (inner.startsWith(`'`)) {
733
+ inner = inner.slice(1);
734
+ }
735
+ else if (/^rem\b/i.test(inner)) {
736
+ inner = inner.slice('rem'.length);
737
+ }
738
+ inner = inner.trimStart();
739
+ const lower = inner.toLowerCase();
740
+ //match longest-prefix first so `bs:disable-line` doesn't get parsed as `bs:disable`
741
+ let directiveType;
742
+ let prefixLength;
743
+ if (lower.startsWith('bs:disable-next-line')) {
744
+ directiveType = 'next-line';
745
+ prefixLength = 'bs:disable-next-line'.length;
746
+ }
747
+ else if (lower.startsWith('bs:disable-line')) {
748
+ directiveType = 'line';
749
+ prefixLength = 'bs:disable-line'.length;
750
+ }
751
+ else if (lower.startsWith('bs:disable')) {
752
+ directiveType = 'block';
753
+ prefixLength = 'bs:disable'.length;
754
+ }
755
+ else {
756
+ return null;
757
+ }
758
+ inner = inner.slice(prefixLength);
759
+ if (inner.startsWith(':')) {
760
+ inner = inner.slice(1);
761
+ }
762
+ const codes = inner.trim().length === 0 ? [] : inner.trim().split(/\s+/);
763
+ return { directiveType: directiveType, codes: codes };
764
+ }
261
765
  //# sourceMappingURL=CodeActionsProcessor.js.map