brighterscript 1.0.0-alpha.1 → 1.0.0-alpha.13

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 (316) hide show
  1. package/CHANGELOG.md +362 -248
  2. package/README.md +2 -2
  3. package/bsconfig.schema.json +1 -1
  4. package/dist/CodeActionUtil.d.ts +11 -2
  5. package/dist/CodeActionUtil.js +17 -3
  6. package/dist/CodeActionUtil.js.map +1 -1
  7. package/dist/CommentFlagProcessor.d.ts +4 -4
  8. package/dist/CommentFlagProcessor.js +5 -3
  9. package/dist/CommentFlagProcessor.js.map +1 -1
  10. package/dist/DependencyGraph.js.map +1 -1
  11. package/dist/DiagnosticCollection.js +2 -2
  12. package/dist/DiagnosticCollection.js.map +1 -1
  13. package/dist/DiagnosticFilterer.js +3 -3
  14. package/dist/DiagnosticFilterer.js.map +1 -1
  15. package/dist/DiagnosticMessages.d.ts +15 -5
  16. package/dist/DiagnosticMessages.js +19 -9
  17. package/dist/DiagnosticMessages.js.map +1 -1
  18. package/dist/LanguageServer.d.ts +11 -10
  19. package/dist/LanguageServer.js +87 -58
  20. package/dist/LanguageServer.js.map +1 -1
  21. package/dist/Logger.d.ts +2 -0
  22. package/dist/Logger.js +5 -3
  23. package/dist/Logger.js.map +1 -1
  24. package/dist/Program.d.ts +76 -46
  25. package/dist/Program.js +254 -180
  26. package/dist/Program.js.map +1 -1
  27. package/dist/ProgramBuilder.d.ts +7 -7
  28. package/dist/ProgramBuilder.js +37 -43
  29. package/dist/ProgramBuilder.js.map +1 -1
  30. package/dist/Scope.d.ts +33 -23
  31. package/dist/Scope.js +222 -147
  32. package/dist/Scope.js.map +1 -1
  33. package/dist/SemanticTokenUtils.d.ts +14 -0
  34. package/dist/SemanticTokenUtils.js +81 -0
  35. package/dist/SemanticTokenUtils.js.map +1 -0
  36. package/dist/SymbolTable.d.ts +9 -3
  37. package/dist/SymbolTable.js +40 -13
  38. package/dist/SymbolTable.js.map +1 -1
  39. package/dist/XmlScope.d.ts +7 -2
  40. package/dist/XmlScope.js +67 -29
  41. package/dist/XmlScope.js.map +1 -1
  42. package/dist/astUtils/AstEditor.d.ts +27 -0
  43. package/dist/astUtils/AstEditor.js +97 -0
  44. package/dist/astUtils/AstEditor.js.map +1 -0
  45. package/dist/astUtils/AstEditor.spec.d.ts +1 -0
  46. package/dist/astUtils/AstEditor.spec.js +133 -0
  47. package/dist/astUtils/AstEditor.spec.js.map +1 -0
  48. package/dist/astUtils/creators.d.ts +15 -1
  49. package/dist/astUtils/creators.js +39 -9
  50. package/dist/astUtils/creators.js.map +1 -1
  51. package/dist/astUtils/creators.spec.js +4 -4
  52. package/dist/astUtils/creators.spec.js.map +1 -1
  53. package/dist/astUtils/index.js +1 -1
  54. package/dist/astUtils/reflection.d.ts +20 -8
  55. package/dist/astUtils/reflection.js +42 -1
  56. package/dist/astUtils/reflection.js.map +1 -1
  57. package/dist/astUtils/reflection.spec.js +115 -115
  58. package/dist/astUtils/reflection.spec.js.map +1 -1
  59. package/dist/astUtils/stackedVisitor.js.map +1 -1
  60. package/dist/astUtils/stackedVisitor.spec.js +13 -13
  61. package/dist/astUtils/stackedVisitor.spec.js.map +1 -1
  62. package/dist/astUtils/visitors.js +1 -1
  63. package/dist/astUtils/visitors.js.map +1 -1
  64. package/dist/astUtils/visitors.spec.js +28 -28
  65. package/dist/astUtils/visitors.spec.js.map +1 -1
  66. package/dist/astUtils/xml.d.ts +4 -3
  67. package/dist/astUtils/xml.js +8 -3
  68. package/dist/astUtils/xml.js.map +1 -1
  69. package/dist/bscPlugin/BscPlugin.d.ts +2 -1
  70. package/dist/bscPlugin/BscPlugin.js +4 -0
  71. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  72. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +5 -6
  73. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  74. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +30 -30
  75. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
  76. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.d.ts +7 -0
  77. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.js +63 -0
  78. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.js.map +1 -0
  79. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.spec.d.ts +1 -0
  80. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.spec.js +45 -0
  81. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.spec.js.map +1 -0
  82. package/dist/diagnosticUtils.d.ts +1 -0
  83. package/dist/diagnosticUtils.js +14 -7
  84. package/dist/diagnosticUtils.js.map +1 -1
  85. package/dist/examples/plugins/removePrint.js +2 -2
  86. package/dist/examples/plugins/removePrint.js.map +1 -1
  87. package/dist/files/BrsFile.Class.spec.js +486 -71
  88. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  89. package/dist/files/BrsFile.d.ts +48 -23
  90. package/dist/files/BrsFile.js +403 -233
  91. package/dist/files/BrsFile.js.map +1 -1
  92. package/dist/files/BrsFile.spec.js +367 -316
  93. package/dist/files/BrsFile.spec.js.map +1 -1
  94. package/dist/files/XmlFile.d.ts +13 -6
  95. package/dist/files/XmlFile.js +27 -21
  96. package/dist/files/XmlFile.js.map +1 -1
  97. package/dist/files/XmlFile.spec.js +274 -228
  98. package/dist/files/XmlFile.spec.js.map +1 -1
  99. package/dist/files/tests/imports.spec.js +49 -49
  100. package/dist/files/tests/imports.spec.js.map +1 -1
  101. package/dist/globalCallables.d.ts +3 -1
  102. package/dist/globalCallables.js +359 -87
  103. package/dist/globalCallables.js.map +1 -1
  104. package/dist/index.js +2 -1
  105. package/dist/index.js.map +1 -1
  106. package/dist/interfaces.d.ts +51 -14
  107. package/dist/lexer/Lexer.d.ts +14 -1
  108. package/dist/lexer/Lexer.js +91 -21
  109. package/dist/lexer/Lexer.js.map +1 -1
  110. package/dist/lexer/Lexer.spec.js +187 -132
  111. package/dist/lexer/Lexer.spec.js.map +1 -1
  112. package/dist/lexer/Token.d.ts +2 -2
  113. package/dist/lexer/TokenKind.d.ts +7 -1
  114. package/dist/lexer/TokenKind.js +51 -3
  115. package/dist/lexer/TokenKind.js.map +1 -1
  116. package/dist/lexer/index.js +2 -1
  117. package/dist/lexer/index.js.map +1 -1
  118. package/dist/parser/BrsTranspileState.d.ts +7 -0
  119. package/dist/parser/BrsTranspileState.js +10 -1
  120. package/dist/parser/BrsTranspileState.js.map +1 -1
  121. package/dist/parser/Expression.d.ts +23 -5
  122. package/dist/parser/Expression.js +124 -75
  123. package/dist/parser/Expression.js.map +1 -1
  124. package/dist/parser/Parser.Class.spec.js +159 -60
  125. package/dist/parser/Parser.Class.spec.js.map +1 -1
  126. package/dist/parser/Parser.d.ts +114 -26
  127. package/dist/parser/Parser.js +471 -126
  128. package/dist/parser/Parser.js.map +1 -1
  129. package/dist/parser/Parser.spec.js +396 -235
  130. package/dist/parser/Parser.spec.js.map +1 -1
  131. package/dist/parser/SGParser.d.ts +41 -4
  132. package/dist/parser/SGParser.js +186 -175
  133. package/dist/parser/SGParser.js.map +1 -1
  134. package/dist/parser/SGParser.spec.js +35 -22
  135. package/dist/parser/SGParser.spec.js.map +1 -1
  136. package/dist/parser/SGTypes.d.ts +206 -38
  137. package/dist/parser/SGTypes.js +470 -161
  138. package/dist/parser/SGTypes.js.map +1 -1
  139. package/dist/parser/SGTypes.spec.d.ts +1 -0
  140. package/dist/parser/SGTypes.spec.js +351 -0
  141. package/dist/parser/SGTypes.spec.js.map +1 -0
  142. package/dist/parser/Statement.d.ts +92 -18
  143. package/dist/parser/Statement.js +287 -58
  144. package/dist/parser/Statement.js.map +1 -1
  145. package/dist/parser/Statement.spec.js +11 -11
  146. package/dist/parser/Statement.spec.js.map +1 -1
  147. package/dist/parser/TranspileState.d.ts +1 -1
  148. package/dist/parser/TranspileState.js +15 -7
  149. package/dist/parser/TranspileState.js.map +1 -1
  150. package/dist/parser/index.js +1 -1
  151. package/dist/parser/tests/Parser.spec.d.ts +8 -7
  152. package/dist/parser/tests/Parser.spec.js +12 -8
  153. package/dist/parser/tests/Parser.spec.js.map +1 -1
  154. package/dist/parser/tests/controlFlow/For.spec.js +50 -50
  155. package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
  156. package/dist/parser/tests/controlFlow/ForEach.spec.js +31 -31
  157. package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
  158. package/dist/parser/tests/controlFlow/If.spec.js +174 -156
  159. package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
  160. package/dist/parser/tests/controlFlow/While.spec.js +32 -32
  161. package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
  162. package/dist/parser/tests/expression/Additive.spec.js +21 -21
  163. package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
  164. package/dist/parser/tests/expression/ArrayLiterals.spec.js +105 -105
  165. package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
  166. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +148 -124
  167. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
  168. package/dist/parser/tests/expression/Boolean.spec.js +17 -17
  169. package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
  170. package/dist/parser/tests/expression/Call.spec.js +30 -30
  171. package/dist/parser/tests/expression/Call.spec.js.map +1 -1
  172. package/dist/parser/tests/expression/Exponential.spec.js +16 -16
  173. package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
  174. package/dist/parser/tests/expression/Function.spec.js +247 -247
  175. package/dist/parser/tests/expression/Function.spec.js.map +1 -1
  176. package/dist/parser/tests/expression/Indexing.spec.js +73 -73
  177. package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
  178. package/dist/parser/tests/expression/Multiplicative.spec.js +36 -36
  179. package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
  180. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +59 -47
  181. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  182. package/dist/parser/tests/expression/PrefixUnary.spec.js +35 -35
  183. package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
  184. package/dist/parser/tests/expression/Primary.spec.js +26 -26
  185. package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
  186. package/dist/parser/tests/expression/RegexLiteralExpression.spec.d.ts +1 -0
  187. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +170 -0
  188. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -0
  189. package/dist/parser/tests/expression/Relational.spec.js +42 -42
  190. package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
  191. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +8 -8
  192. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
  193. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +12 -12
  194. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  195. package/dist/parser/tests/expression/TernaryExpression.spec.js +100 -100
  196. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  197. package/dist/parser/tests/statement/AssignmentOperators.spec.js +35 -35
  198. package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
  199. package/dist/parser/tests/statement/Declaration.spec.js +39 -39
  200. package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
  201. package/dist/parser/tests/statement/Dim.spec.js +21 -21
  202. package/dist/parser/tests/statement/Dim.spec.js.map +1 -1
  203. package/dist/parser/tests/statement/Function.spec.js +192 -192
  204. package/dist/parser/tests/statement/Function.spec.js.map +1 -1
  205. package/dist/parser/tests/statement/Goto.spec.js +11 -11
  206. package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
  207. package/dist/parser/tests/statement/Increment.spec.js +46 -46
  208. package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
  209. package/dist/parser/tests/statement/InterfaceStatement.spec.d.ts +1 -0
  210. package/dist/parser/tests/statement/InterfaceStatement.spec.js +61 -0
  211. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -0
  212. package/dist/parser/tests/statement/LibraryStatement.spec.js +10 -10
  213. package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
  214. package/dist/parser/tests/statement/Misc.spec.js +37 -36
  215. package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
  216. package/dist/parser/tests/statement/PrintStatement.spec.js +30 -30
  217. package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
  218. package/dist/parser/tests/statement/ReturnStatement.spec.js +43 -43
  219. package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
  220. package/dist/parser/tests/statement/Set.spec.js +69 -69
  221. package/dist/parser/tests/statement/Set.spec.js.map +1 -1
  222. package/dist/parser/tests/statement/Stop.spec.js +9 -9
  223. package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
  224. package/dist/parser/tests/statement/Throw.spec.js +5 -5
  225. package/dist/parser/tests/statement/Throw.spec.js.map +1 -1
  226. package/dist/parser/tests/statement/TryCatch.spec.js +13 -13
  227. package/dist/parser/tests/statement/TryCatch.spec.js.map +1 -1
  228. package/dist/preprocessor/Chunk.js.map +1 -1
  229. package/dist/preprocessor/Manifest.d.ts +1 -1
  230. package/dist/preprocessor/Preprocessor.js +1 -1
  231. package/dist/preprocessor/Preprocessor.js.map +1 -1
  232. package/dist/preprocessor/Preprocessor.spec.js +49 -49
  233. package/dist/preprocessor/Preprocessor.spec.js.map +1 -1
  234. package/dist/preprocessor/PreprocessorParser.spec.js +72 -72
  235. package/dist/preprocessor/PreprocessorParser.spec.js.map +1 -1
  236. package/dist/preprocessor/index.js +1 -1
  237. package/dist/types/ArrayType.js +5 -4
  238. package/dist/types/ArrayType.js.map +1 -1
  239. package/dist/types/ArrayType.spec.js +8 -8
  240. package/dist/types/ArrayType.spec.js.map +1 -1
  241. package/dist/types/BooleanType.js +3 -3
  242. package/dist/types/BooleanType.js.map +1 -1
  243. package/dist/types/BooleanType.spec.js +2 -2
  244. package/dist/types/BooleanType.spec.js.map +1 -1
  245. package/dist/types/BscType.d.ts +19 -5
  246. package/dist/types/BscType.js +9 -0
  247. package/dist/types/BscType.js.map +1 -1
  248. package/dist/types/CustomType.d.ts +8 -5
  249. package/dist/types/CustomType.js +17 -6
  250. package/dist/types/CustomType.js.map +1 -1
  251. package/dist/types/DoubleType.js +8 -8
  252. package/dist/types/DoubleType.js.map +1 -1
  253. package/dist/types/DoubleType.spec.js +2 -2
  254. package/dist/types/DoubleType.spec.js.map +1 -1
  255. package/dist/types/DynamicType.js +1 -1
  256. package/dist/types/DynamicType.js.map +1 -1
  257. package/dist/types/DynamicType.spec.js +2 -2
  258. package/dist/types/DynamicType.spec.js.map +1 -1
  259. package/dist/types/FloatType.d.ts +1 -1
  260. package/dist/types/FloatType.js +8 -8
  261. package/dist/types/FloatType.js.map +1 -1
  262. package/dist/types/FloatType.spec.js +2 -2
  263. package/dist/types/FloatType.spec.js.map +1 -1
  264. package/dist/types/FunctionType.d.ts +5 -11
  265. package/dist/types/FunctionType.js +24 -13
  266. package/dist/types/FunctionType.js.map +1 -1
  267. package/dist/types/FunctionType.spec.js +11 -5
  268. package/dist/types/FunctionType.spec.js.map +1 -1
  269. package/dist/types/IntegerType.d.ts +1 -1
  270. package/dist/types/IntegerType.js +8 -8
  271. package/dist/types/IntegerType.js.map +1 -1
  272. package/dist/types/IntegerType.spec.js +2 -2
  273. package/dist/types/IntegerType.spec.js.map +1 -1
  274. package/dist/types/InterfaceType.d.ts +8 -2
  275. package/dist/types/InterfaceType.js +42 -6
  276. package/dist/types/InterfaceType.js.map +1 -1
  277. package/dist/types/InterfaceType.spec.d.ts +1 -0
  278. package/dist/types/InterfaceType.spec.js +174 -0
  279. package/dist/types/InterfaceType.spec.js.map +1 -0
  280. package/dist/types/InvalidType.js +4 -4
  281. package/dist/types/InvalidType.js.map +1 -1
  282. package/dist/types/InvalidType.spec.js +2 -2
  283. package/dist/types/InvalidType.spec.js.map +1 -1
  284. package/dist/types/LazyType.d.ts +9 -7
  285. package/dist/types/LazyType.js +22 -10
  286. package/dist/types/LazyType.js.map +1 -1
  287. package/dist/types/LongIntegerType.d.ts +1 -1
  288. package/dist/types/LongIntegerType.js +8 -8
  289. package/dist/types/LongIntegerType.js.map +1 -1
  290. package/dist/types/LongIntegerType.spec.js +2 -2
  291. package/dist/types/LongIntegerType.spec.js.map +1 -1
  292. package/dist/types/ObjectType.d.ts +7 -4
  293. package/dist/types/ObjectType.js +6 -3
  294. package/dist/types/ObjectType.js.map +1 -1
  295. package/dist/types/ObjectType.spec.js +2 -2
  296. package/dist/types/ObjectType.spec.js.map +1 -1
  297. package/dist/types/StringType.js +3 -3
  298. package/dist/types/StringType.js.map +1 -1
  299. package/dist/types/StringType.spec.js +2 -2
  300. package/dist/types/StringType.spec.js.map +1 -1
  301. package/dist/types/UninitializedType.js +3 -3
  302. package/dist/types/UninitializedType.js.map +1 -1
  303. package/dist/types/VoidType.js +3 -3
  304. package/dist/types/VoidType.js.map +1 -1
  305. package/dist/types/VoidType.spec.js +2 -2
  306. package/dist/types/VoidType.spec.js.map +1 -1
  307. package/dist/types/helpers.d.ts +42 -0
  308. package/dist/types/helpers.js +113 -0
  309. package/dist/types/helpers.js.map +1 -0
  310. package/dist/util.d.ts +77 -17
  311. package/dist/util.js +247 -59
  312. package/dist/util.js.map +1 -1
  313. package/dist/validators/ClassValidator.d.ts +5 -1
  314. package/dist/validators/ClassValidator.js +59 -24
  315. package/dist/validators/ClassValidator.js.map +1 -1
  316. package/package.json +13 -13
package/dist/Program.js CHANGED
@@ -23,9 +23,10 @@ const reflection_1 = require("./astUtils/reflection");
23
23
  const parser_1 = require("./parser");
24
24
  const lexer_1 = require("./lexer");
25
25
  const BscPlugin_1 = require("./bscPlugin/BscPlugin");
26
- const startOfSourcePkgPath = `source${path.sep}`;
27
- const bslibNonAliasedRokuModulesPkgPath = util_1.standardizePath `source/roku_modules/rokucommunity_bslib/bslib.brs`;
28
- const bslibAliasedRokuModulesPkgPath = util_1.standardizePath `source/roku_modules/bslib/bslib.brs`;
26
+ const roku_deploy_1 = require("roku-deploy");
27
+ const AstEditor_1 = require("./astUtils/AstEditor");
28
+ const bslibNonAliasedRokuModulesPkgPath = `pkg:/source/roku_modules/rokucommunity_bslib/bslib.brs`;
29
+ const bslibAliasedRokuModulesPkgPath = `pkg:/source/roku_modules/bslib/bslib.brs`;
29
30
  class Program {
30
31
  constructor(
31
32
  /**
@@ -47,10 +48,13 @@ class Program {
47
48
  */
48
49
  this.diagnostics = [];
49
50
  /**
50
- * A map of every file loaded into this program, indexed by its original file location
51
+ * A map of every file loaded ino this program, indexed by its lower-case pkgPath
51
52
  */
52
- this.files = {};
53
53
  this.pkgMap = {};
54
+ /**
55
+ * A map of every file loaded into this program, indexed by its lower-case srcPath
56
+ */
57
+ this.files = {};
54
58
  this.scopes = {};
55
59
  /**
56
60
  * A map of every component currently loaded into the program, indexed by the component name.
@@ -86,16 +90,16 @@ class Program {
86
90
  */
87
91
  get bslibPkgPath() {
88
92
  //if there's an aliased (preferred) version of bslib from roku_modules loaded into the program, use that
89
- if (this.getFileByPkgPath(bslibAliasedRokuModulesPkgPath)) {
93
+ if (this.getFile(bslibAliasedRokuModulesPkgPath)) {
90
94
  return bslibAliasedRokuModulesPkgPath;
91
95
  //if there's a non-aliased version of bslib from roku_modules, use that
92
96
  }
93
- else if (this.getFileByPkgPath(bslibNonAliasedRokuModulesPkgPath)) {
97
+ else if (this.getFile(bslibNonAliasedRokuModulesPkgPath)) {
94
98
  return bslibNonAliasedRokuModulesPkgPath;
95
99
  //default to the embedded version
96
100
  }
97
101
  else {
98
- return `source${path.sep}bslib.brs`;
102
+ return `pkg:/source/bslib.brs`;
99
103
  }
100
104
  }
101
105
  get bslibPrefix() {
@@ -106,6 +110,12 @@ class Program {
106
110
  return 'bslib';
107
111
  }
108
112
  }
113
+ /**
114
+ * Get a copy of the list of files currently loaded in the program
115
+ */
116
+ getFiles() {
117
+ return Object.values(this.files);
118
+ }
109
119
  addScope(scope) {
110
120
  this.scopes[scope.name] = scope;
111
121
  this.plugins.emit('afterScopeCreate', {
@@ -181,8 +191,8 @@ class Program {
181
191
  */
182
192
  getUnreferencedFiles() {
183
193
  let result = [];
184
- for (let filePath in this.files) {
185
- let file = this.files[filePath];
194
+ for (let key in this.files) {
195
+ const file = this.files[key];
186
196
  if (!this.fileIsIncludedInAnyScope(file)) {
187
197
  //no scopes reference this file. add it to the list
188
198
  result.push(file);
@@ -222,13 +232,10 @@ class Program {
222
232
  /**
223
233
  * Determine if the specified file is loaded in this program right now.
224
234
  * @param filePath
235
+ * @param normalizePath should the provided path be normalized before use
225
236
  */
226
- hasFile(filePath) {
227
- filePath = util_1.standardizePath `${filePath}`;
228
- return this.files[filePath] !== undefined;
229
- }
230
- getPkgPath(...args) {
231
- throw new Error('Not implemented');
237
+ hasFile(filePath, normalizePath = true) {
238
+ return !!this.getFile(filePath, normalizePath);
232
239
  }
233
240
  /**
234
241
  * roku filesystem is case INsensitive, so find the scope by key case insensitive
@@ -238,9 +245,6 @@ class Program {
238
245
  if (!scopeName) {
239
246
  return undefined;
240
247
  }
241
- //most scopes are xml file pkg paths. however, the ones that are not are single names like "global" and "scope",
242
- //so it's safe to run the standardizePkgPath method
243
- scopeName = util_1.standardizePath `${scopeName}`;
244
248
  let key = Object.keys(this.scopes).find(x => x.toLowerCase() === scopeName.toLowerCase());
245
249
  return this.scopes[key];
246
250
  }
@@ -257,21 +261,52 @@ class Program {
257
261
  var _a;
258
262
  return (_a = this.getComponent(componentName)) === null || _a === void 0 ? void 0 : _a.scope;
259
263
  }
260
- addOrReplaceFile(fileParam, fileContents) {
261
- assert.ok(fileParam, 'fileEntry is required');
264
+ /**
265
+ * Update internal maps with this file reference
266
+ */
267
+ assignFile(file) {
268
+ this.files[file.srcPath.toLowerCase()] = file;
269
+ this.pkgMap[file.pkgPath.toLowerCase()] = file;
270
+ }
271
+ /**
272
+ * Remove this file from internal maps
273
+ */
274
+ unassignFile(file) {
275
+ delete this.files[file.srcPath.toLowerCase()];
276
+ delete this.pkgMap[file.pkgPath.toLowerCase()];
277
+ }
278
+ setFile(fileParam, fileContents) {
279
+ assert.ok(fileParam, 'fileParam is required');
262
280
  let srcPath;
263
281
  let pkgPath;
264
282
  if (typeof fileParam === 'string') {
265
- srcPath = util_1.standardizePath `${this.options.rootDir}/${fileParam}`;
266
- pkgPath = util_1.standardizePath `${fileParam}`;
283
+ //is a pkg path
284
+ if (fileParam.startsWith('pkg:/')) {
285
+ //srcPath is the pkgPath relative to the rootDir
286
+ srcPath = (0, util_1.standardizePath) `${this.options.rootDir}/${fileParam.substring(5)}`;
287
+ pkgPath = fileParam;
288
+ //is a srcPath (absolute path to src file location)
289
+ }
290
+ else if (path.isAbsolute(fileParam)) {
291
+ srcPath = util_1.util.standardizePath(fileParam);
292
+ //assume the file path is a sub path of rootDir
293
+ pkgPath = util_1.util.sanitizePkgPath(roku_deploy_1.util.stringReplaceInsensitive(srcPath, this.options.rootDir, ''));
294
+ //is destPath (path relative to rootDir and `pkg:/`)
295
+ }
296
+ else {
297
+ srcPath = (0, util_1.standardizePath) `${this.options.rootDir}/${fileParam}`;
298
+ pkgPath = util_1.util.sanitizePkgPath(fileParam);
299
+ }
300
+ //is a FileObj
267
301
  }
268
302
  else {
269
- srcPath = util_1.standardizePath `${fileParam.src}`;
270
- pkgPath = util_1.standardizePath `${fileParam.dest}`;
303
+ srcPath = (0, util_1.standardizePath) `${fileParam.src}`;
304
+ pkgPath = util_1.util.sanitizePkgPath(fileParam.dest);
271
305
  }
272
- return this.logger.time(Logger_1.LogLevel.debug, ['Program.addOrReplaceFile()', chalk_1.default.green(srcPath)], () => {
273
- assert.ok(srcPath, 'fileEntry.src is required');
274
- assert.ok(pkgPath, 'fileEntry.dest is required');
306
+ const lowerPkgPath = pkgPath.toLowerCase();
307
+ return this.logger.time(Logger_1.LogLevel.debug, ['program.setFile()', chalk_1.default.green(srcPath)], () => {
308
+ assert.ok(srcPath, 'srcPath is required');
309
+ assert.ok(pkgPath, 'pkgPath is required');
275
310
  //if the file is already loaded, remove it
276
311
  if (this.hasFile(srcPath)) {
277
312
  this.removeFile(srcPath);
@@ -280,19 +315,18 @@ class Program {
280
315
  let file;
281
316
  const beforeFileParseEvent = {
282
317
  program: this,
283
- pathAbsolute: srcPath,
318
+ srcPath: srcPath,
284
319
  source: fileContents
285
320
  };
286
321
  if (fileExtension === '.brs' || fileExtension === '.bs') {
287
322
  let brsFile = new BrsFile_1.BrsFile(srcPath, pkgPath, this);
288
323
  //add file to the `source` dependency list
289
- if (brsFile.pkgPath.startsWith(startOfSourcePkgPath)) {
324
+ if (brsFile.pkgPath.startsWith('pkg:/source/')) {
290
325
  this.createSourceScope();
291
326
  this.dependencyGraph.addDependency('scope:source', brsFile.dependencyGraphKey);
292
327
  }
293
328
  //add the file to the program
294
- this.files[srcPath] = brsFile;
295
- this.pkgMap[brsFile.pkgPath.toLowerCase()] = brsFile;
329
+ this.assignFile(brsFile);
296
330
  this.plugins.emit('beforeFileParse', beforeFileParseEvent);
297
331
  this.logger.time(Logger_1.LogLevel.debug, ['parse', chalk_1.default.green(srcPath)], () => {
298
332
  brsFile.parse(beforeFileParseEvent.source);
@@ -308,11 +342,10 @@ class Program {
308
342
  //is xml file
309
343
  fileExtension === '.xml' &&
310
344
  //resides in the components folder (Roku will only parse xml files in the components folder)
311
- pkgPath.toLowerCase().startsWith(util_1.util.pathSepNormalize(`components/`))) {
345
+ lowerPkgPath.startsWith('pkg:/components/')) {
312
346
  let xmlFile = new XmlFile_1.XmlFile(srcPath, pkgPath, this);
347
+ this.assignFile(xmlFile);
313
348
  //add the file to the program
314
- this.files[srcPath] = xmlFile;
315
- this.pkgMap[xmlFile.pkgPath.toLowerCase()] = xmlFile;
316
349
  this.plugins.emit('beforeFileParse', beforeFileParseEvent);
317
350
  this.logger.time(Logger_1.LogLevel.debug, ['parse', chalk_1.default.green(srcPath)], () => {
318
351
  xmlFile.parse(beforeFileParseEvent.source);
@@ -330,8 +363,8 @@ class Program {
330
363
  }
331
364
  else {
332
365
  //TODO do we actually need to implement this? Figure out how to handle img paths
333
- // let genericFile = this.files[pathAbsolute] = <any>{
334
- // pathAbsolute: pathAbsolute,
366
+ // let genericFile = this.files[srcPath] = <any>{
367
+ // srcPath: srcPath,
335
368
  // pkgPath: pkgPath,
336
369
  // wasProcessed: true
337
370
  // } as File;
@@ -351,55 +384,24 @@ class Program {
351
384
  this.addScope(sourceScope);
352
385
  }
353
386
  }
354
- /**
355
- * Find the file by its absolute path. This is case INSENSITIVE, since
356
- * Roku is a case insensitive file system. It is an error to have multiple files
357
- * with the same path with only case being different.
358
- * @param pathAbsolute
359
- */
360
- getFileByPathAbsolute(pathAbsolute) {
361
- pathAbsolute = util_1.standardizePath `${pathAbsolute}`;
362
- for (let filePath in this.files) {
363
- if (filePath.toLowerCase() === pathAbsolute.toLowerCase()) {
364
- return this.files[filePath];
365
- }
366
- }
367
- }
368
- /**
369
- * Get a list of files for the given (platform-normalized) pkgPath array.
370
- * Missing files are just ignored.
371
- */
372
- getFilesByPkgPaths(pkgPaths) {
373
- return pkgPaths
374
- .map(pkgPath => this.getFileByPkgPath(pkgPath))
375
- .filter(file => file !== undefined);
376
- }
377
- /**
378
- * Get a file with the specified (platform-normalized) pkg path.
379
- * If not found, return undefined
380
- */
381
- getFileByPkgPath(pkgPath) {
382
- return this.pkgMap[pkgPath.toLowerCase()];
383
- }
384
387
  /**
385
388
  * Remove a set of files from the program
386
- * @param absolutePaths
389
+ * @param srcPaths
387
390
  */
388
- removeFiles(absolutePaths) {
389
- for (let pathAbsolute of absolutePaths) {
390
- this.removeFile(pathAbsolute);
391
+ removeFiles(srcPaths) {
392
+ for (let srcPath of srcPaths) {
393
+ this.removeFile(srcPath);
391
394
  }
392
395
  }
393
396
  /**
394
397
  * Remove a file from the program
395
- * @param pathAbsolute
398
+ * @param filePath can be a srcPath, a pkgPath, or a destPath (same as pkgPath but without `pkg:/`)
399
+ * @param normalizePath should this function repair and standardize the path? Passing false should have a performance boost if you can guarantee your path is already sanitized
400
+
396
401
  */
397
- removeFile(pathAbsolute) {
398
- this.logger.debug('Program.removeFile()', pathAbsolute);
399
- if (!path.isAbsolute(pathAbsolute)) {
400
- throw new Error(`Path must be absolute: "${pathAbsolute}"`);
401
- }
402
- let file = this.getFile(pathAbsolute);
402
+ removeFile(filePath, normalizePath = true) {
403
+ this.logger.debug('Program.removeFile()', filePath);
404
+ let file = this.getFile(filePath, normalizePath);
403
405
  if (file) {
404
406
  this.plugins.emit('beforeFileDispose', {
405
407
  program: this,
@@ -422,15 +424,14 @@ class Program {
422
424
  });
423
425
  }
424
426
  //remove the file from the program
425
- delete this.files[file.pathAbsolute];
426
- delete this.pkgMap[file.pkgPath.toLowerCase()];
427
+ this.unassignFile(file);
427
428
  this.dependencyGraph.remove(file.dependencyGraphKey);
428
429
  //if this is a pkg:/source file, notify the `source` scope that it has changed
429
- if (file.pkgPath.startsWith(startOfSourcePkgPath)) {
430
+ if (file.pkgPath.startsWith('pkg:/source/')) {
430
431
  this.dependencyGraph.removeDependency('scope:source', file.dependencyGraphKey);
431
432
  }
432
433
  //if this is a component, remove it from our components map
433
- if (reflection_1.isXmlFile(file)) {
434
+ if ((0, reflection_1.isXmlFile)(file)) {
434
435
  this.unregisterComponent(file);
435
436
  }
436
437
  this.plugins.emit('afterFileDispose', {
@@ -439,6 +440,25 @@ class Program {
439
440
  });
440
441
  }
441
442
  }
443
+ /**
444
+ * Remove all files from the program that are in the specified folder path (recursive)
445
+ * @param folderSrcPath The absolute path to the folder on disk
446
+ * @param normalizePath should the provided path be normalized before use?
447
+ */
448
+ removeFilesInFolder(folderSrcPath, normalizePath = true) {
449
+ if (normalizePath) {
450
+ folderSrcPath = util_1.util.standardizePath(folderSrcPath);
451
+ }
452
+ const lowerFolderSrcPath = folderSrcPath.toLowerCase();
453
+ for (const key in this.files) {
454
+ const file = this.files[key];
455
+ const lowerSrcPath = file.srcPath.toLowerCase();
456
+ //if the file path starts with the parent path and the file path does not exactly match the folder path
457
+ if (lowerSrcPath.toLowerCase().startsWith(lowerFolderSrcPath) && lowerSrcPath !== lowerFolderSrcPath) {
458
+ this.removeFile(file.srcPath, false);
459
+ }
460
+ }
461
+ }
442
462
  /**
443
463
  * Traverse the entire project, and validate all scopes
444
464
  * @param force - if true, then all scopes are force to validate, even if they aren't marked as dirty
@@ -500,28 +520,31 @@ class Program {
500
520
  * Flag all duplicate component names
501
521
  */
502
522
  detectDuplicateComponentNames() {
503
- const componentsByName = Object.keys(this.files).reduce((map, filePath) => {
504
- var _a;
505
- const file = this.files[filePath];
523
+ var _a;
524
+ const componentsByName = new Map();
525
+ for (const key in this.files) {
526
+ const file = this.files[key];
506
527
  //if this is an XmlFile, and it has a valid `componentName` property
507
- if (reflection_1.isXmlFile(file) && ((_a = file.componentName) === null || _a === void 0 ? void 0 : _a.text)) {
508
- let lowerName = file.componentName.text.toLowerCase();
509
- if (!map[lowerName]) {
510
- map[lowerName] = [];
528
+ if ((0, reflection_1.isXmlFile)(file)) {
529
+ const componentNameLower = (_a = file.componentName) === null || _a === void 0 ? void 0 : _a.text.toLowerCase();
530
+ if (componentNameLower) {
531
+ if (!componentsByName.has(componentNameLower)) {
532
+ componentsByName.set(componentNameLower, [file]);
533
+ }
534
+ else {
535
+ componentsByName.get(componentNameLower).push(file);
536
+ }
511
537
  }
512
- map[lowerName].push(file);
513
538
  }
514
- return map;
515
- }, {});
516
- for (let name in componentsByName) {
517
- const xmlFiles = componentsByName[name];
539
+ }
540
+ for (const xmlFiles of componentsByName.values()) {
518
541
  //add diagnostics for every duplicate component with this name
519
542
  if (xmlFiles.length > 1) {
520
543
  for (let xmlFile of xmlFiles) {
521
544
  const { componentName } = xmlFile;
522
545
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.duplicateComponentName(componentName.text)), { range: xmlFile.componentName.range, file: xmlFile, relatedInformation: xmlFiles.filter(x => x !== xmlFile).map(x => {
523
546
  return {
524
- location: vscode_languageserver_1.Location.create(vscode_uri_1.URI.file(xmlFile.pathAbsolute).toString(), x.componentName.range),
547
+ location: vscode_languageserver_1.Location.create(vscode_uri_1.URI.file(xmlFile.srcPath).toString(), x.componentName.range),
525
548
  message: 'Also defined here'
526
549
  };
527
550
  }) }));
@@ -542,11 +565,19 @@ class Program {
542
565
  }
543
566
  /**
544
567
  * Get the file at the given path
545
- * @param pathAbsolute
568
+ * @param filePath can be a srcPath, a pkgPath, or a destPath (same as pkgPath but without `pkg:/`)
569
+ * @param normalizePath should this function repair and standardize the path? Passing false should have a performance boost if you can guarantee your path is already sanitized
546
570
  */
547
- getFile(pathAbsolute) {
548
- pathAbsolute = util_1.standardizePath `${pathAbsolute}`;
549
- return this.files[pathAbsolute];
571
+ getFile(filePath, normalizePath = true) {
572
+ if (typeof filePath !== 'string') {
573
+ return undefined;
574
+ }
575
+ else if (path.isAbsolute(filePath)) {
576
+ return this.files[(normalizePath ? util_1.util.standardizePath(filePath) : filePath).toLowerCase()];
577
+ }
578
+ else {
579
+ return this.pkgMap[(normalizePath ? util_1.util.sanitizePkgPath(filePath) : filePath).toLowerCase()];
580
+ }
550
581
  }
551
582
  /**
552
583
  * Get a list of all scopes the file is loaded into
@@ -571,7 +602,7 @@ class Program {
571
602
  //look through all files in scope for matches
572
603
  for (const scope of this.getScopesForFile(originFile)) {
573
604
  for (const file of scope.getAllFiles()) {
574
- if (reflection_1.isXmlFile(file) || filesSearched.has(file)) {
605
+ if ((0, reflection_1.isXmlFile)(file) || filesSearched.has(file)) {
575
606
  continue;
576
607
  }
577
608
  filesSearched.add(file);
@@ -594,17 +625,20 @@ class Program {
594
625
  //get all function names for the xml file and parents
595
626
  let funcNames = new Set();
596
627
  let currentScope = scope;
597
- while (reflection_1.isXmlScope(currentScope)) {
598
- for (let name of (_b = (_a = currentScope.xmlFile.ast.component.api) === null || _a === void 0 ? void 0 : _a.functions.map((f) => f.name)) !== null && _b !== void 0 ? _b : []) {
599
- if (!filterName || name === filterName) {
600
- funcNames.add(name);
628
+ while ((0, reflection_1.isXmlScope)(currentScope)) {
629
+ for (let member of (_b = (_a = currentScope.xmlFile.ast.component) === null || _a === void 0 ? void 0 : _a.interfaceMembers) !== null && _b !== void 0 ? _b : []) {
630
+ if ((0, reflection_1.isSGInterfaceFunction)(member)) {
631
+ const name = member.name;
632
+ if (!filterName || name === filterName) {
633
+ funcNames.add(name);
634
+ }
601
635
  }
602
636
  }
603
637
  currentScope = currentScope.getParentScope();
604
638
  }
605
639
  //look through all files in scope for matches
606
640
  for (const file of scope.getOwnFiles()) {
607
- if (reflection_1.isXmlFile(file) || filesSearched.has(file)) {
641
+ if ((0, reflection_1.isXmlFile)(file) || filesSearched.has(file)) {
608
642
  continue;
609
643
  }
610
644
  filesSearched.add(file);
@@ -620,19 +654,19 @@ class Program {
620
654
  }
621
655
  /**
622
656
  * Find all available completion items at the given position
623
- * @param pathAbsolute
657
+ * @param srcPath The absolute path to the source file on disk
624
658
  * @param lineIndex
625
659
  * @param columnIndex
626
660
  */
627
- getCompletions(pathAbsolute, position) {
628
- let file = this.getFile(pathAbsolute);
661
+ getCompletions(srcPath, position) {
662
+ let file = this.getFile(srcPath);
629
663
  if (!file) {
630
664
  return [];
631
665
  }
632
666
  let result = [];
633
- if (reflection_1.isBrsFile(file) && file.isPositionNextToTokenKind(position, lexer_1.TokenKind.Callfunc)) {
667
+ if ((0, reflection_1.isBrsFile)(file) && file.parser.isPositionNextToTokenKind(position, lexer_1.TokenKind.Callfunc)) {
634
668
  // is next to a @. callfunc invocation - must be an interface method
635
- for (const scope of this.getScopes().filter((s) => reflection_1.isXmlScope(s))) {
669
+ for (const scope of this.getScopes().filter((s) => (0, reflection_1.isXmlScope)(s))) {
636
670
  let fileLinks = this.getStatementsForXmlFile(scope);
637
671
  for (let fileLink of fileLinks) {
638
672
  result.push(scope.createCompletionFromFunctionStatement(fileLink.item));
@@ -646,7 +680,12 @@ class Program {
646
680
  //if there are no scopes, include the global scope so we at least get the built-in functions
647
681
  scopes = scopes.length > 0 ? scopes : [this.globalScope];
648
682
  //get the completions from all scopes for this file
649
- let allCompletions = util_1.util.flatMap(scopes.map(ctx => file.getCompletions(position, ctx)), c => c);
683
+ let allCompletions = util_1.util.flatMap(scopes.map(ctx => {
684
+ ctx.linkSymbolTable();
685
+ const completions = file.getCompletions(position, ctx);
686
+ ctx.unlinkSymbolTable();
687
+ return completions;
688
+ }), c => c);
650
689
  //only keep completions common to every scope for this file
651
690
  let keyCounts = {};
652
691
  for (let completion of allCompletions) {
@@ -662,25 +701,26 @@ class Program {
662
701
  * Goes through each file and builds a list of workspace symbols for the program. Used by LanguageServer's onWorkspaceSymbol functionality
663
702
  */
664
703
  getWorkspaceSymbols() {
665
- const results = Object.keys(this.files).map(key => {
704
+ const result = [];
705
+ for (const key in this.files) {
666
706
  const file = this.files[key];
667
- if (reflection_1.isBrsFile(file)) {
668
- return file.getWorkspaceSymbols();
707
+ if ((0, reflection_1.isBrsFile)(file)) {
708
+ result.push(...file.getWorkspaceSymbols());
669
709
  }
670
- return [];
671
- });
672
- return util_1.util.flatMap(results, c => c);
710
+ }
711
+ return result;
673
712
  }
674
713
  /**
675
714
  * Given a position in a file, if the position is sitting on some type of identifier,
676
715
  * go to the definition of that identifier (where this thing was first defined)
716
+ * @param srcPath The absolute path to the source file on disk
677
717
  */
678
- getDefinition(pathAbsolute, position) {
679
- let file = this.getFile(pathAbsolute);
718
+ getDefinition(srcPath, position) {
719
+ let file = this.getFile(srcPath);
680
720
  if (!file) {
681
721
  return [];
682
722
  }
683
- if (reflection_1.isBrsFile(file)) {
723
+ if ((0, reflection_1.isBrsFile)(file)) {
684
724
  return file.getDefinition(position);
685
725
  }
686
726
  else {
@@ -692,9 +732,12 @@ class Program {
692
732
  return results;
693
733
  }
694
734
  }
695
- getHover(pathAbsolute, position) {
735
+ /**
736
+ * @param srcPath The absolute path to the source file on disk
737
+ */
738
+ getHover(srcPath, position) {
696
739
  //find the file
697
- let file = this.getFile(pathAbsolute);
740
+ let file = this.getFile(srcPath);
698
741
  if (!file) {
699
742
  return null;
700
743
  }
@@ -702,10 +745,11 @@ class Program {
702
745
  }
703
746
  /**
704
747
  * Compute code actions for the given file and range
748
+ * @param srcPath The absolute path to the source file on disk
705
749
  */
706
- getCodeActions(pathAbsolute, range) {
750
+ getCodeActions(srcPath, range) {
707
751
  const codeActions = [];
708
- const file = this.getFile(pathAbsolute);
752
+ const file = this.getFile(srcPath);
709
753
  if (file) {
710
754
  const diagnostics = this
711
755
  //get all current diagnostics (filtered by diagnostic filters)
@@ -726,10 +770,26 @@ class Program {
726
770
  }
727
771
  return codeActions;
728
772
  }
773
+ /**
774
+ * Get semantic tokens for the specified file
775
+ */
776
+ getSemanticTokens(srcPath) {
777
+ const file = this.getFile(srcPath);
778
+ if (file) {
779
+ const result = [];
780
+ this.plugins.emit('onGetSemanticTokens', {
781
+ program: this,
782
+ file: file,
783
+ scopes: this.getScopesForFile(file),
784
+ semanticTokens: result
785
+ });
786
+ return result;
787
+ }
788
+ }
729
789
  getSignatureHelp(filepath, position) {
730
790
  var _a;
731
791
  let file = this.getFile(filepath);
732
- if (!file || !reflection_1.isBrsFile(file)) {
792
+ if (!file || !(0, reflection_1.isBrsFile)(file)) {
733
793
  return [];
734
794
  }
735
795
  const results = new Map();
@@ -752,12 +812,14 @@ class Program {
752
812
  //if m class reference.. then
753
813
  //only get statements from the class I am in..
754
814
  if (functionExpression) {
755
- let myClass = file.getClassFromMReference(position, file.getTokenAt(position), functionExpression);
756
- if (myClass) {
757
- for (let scope of this.getScopesForFile(myClass.file)) {
815
+ const currentToken = file.parser.getTokenAt(position);
816
+ for (let scope of this.getScopesForFile(file)) {
817
+ scope.linkSymbolTable();
818
+ let myClass = file.getClassFromToken(currentToken, functionExpression, scope);
819
+ if (myClass) {
758
820
  let classes = scope.getClassHierarchy(myClass.item.getName(parser_1.ParseMode.BrighterScript).toLowerCase());
759
821
  //and anything from any class in scope to a non m class
760
- for (let statement of [...classes].filter((i) => reflection_1.isClassMethodStatement(i.item))) {
822
+ for (let statement of [...classes].filter((i) => (0, reflection_1.isClassMethodStatement)(i.item))) {
761
823
  let sigHelp = statement.file.getSignatureHelpForStatement(statement.item);
762
824
  if (sigHelp && !results.has[sigHelp.key]) {
763
825
  results.set(sigHelp.key, sigHelp);
@@ -765,6 +827,7 @@ class Program {
765
827
  }
766
828
  }
767
829
  }
830
+ scope.unlinkSymbolTable();
768
831
  }
769
832
  }
770
833
  if (identifierInfo.dotPart) {
@@ -786,7 +849,7 @@ class Program {
786
849
  }
787
850
  }
788
851
  else if (identifierInfo.statementType === '@.') {
789
- for (const scope of this.getScopes().filter((s) => reflection_1.isXmlScope(s))) {
852
+ for (const scope of this.getScopes().filter((s) => (0, reflection_1.isXmlScope)(s))) {
790
853
  let fileLinks = this.getStatementsForXmlFile(scope, identifierInfo.name);
791
854
  for (let fileLink of fileLinks) {
792
855
  let sigHelp = fileLink.file.getSignatureHelpForStatement(fileLink.item);
@@ -825,12 +888,12 @@ class Program {
825
888
  if (!itemCounts.isArgStartFound) {
826
889
  //try to get sig help based on the name
827
890
  index = position.character;
828
- let currentToken = file.getTokenAt(position);
891
+ let currentToken = file.parser.getTokenAt(position);
829
892
  if (currentToken && currentToken.kind !== lexer_1.TokenKind.Comment) {
830
893
  name = file.getPartialVariableName(currentToken, [lexer_1.TokenKind.New]);
831
894
  if (!name) {
832
895
  //try the previous token, incase we're on a bracket
833
- currentToken = file.getPreviousToken(currentToken);
896
+ currentToken = file.parser.getPreviousToken(currentToken);
834
897
  name = file.getPartialVariableName(currentToken, [lexer_1.TokenKind.New]);
835
898
  }
836
899
  if (name === null || name === void 0 ? void 0 : name.indexOf('.')) {
@@ -937,9 +1000,12 @@ class Program {
937
1000
  }
938
1001
  return itemCounts;
939
1002
  }
940
- getReferences(pathAbsolute, position) {
1003
+ /**
1004
+ * @param srcPath The absolute path to the source file on disk
1005
+ */
1006
+ getReferences(srcPath, position) {
941
1007
  //find the file
942
- let file = this.getFile(pathAbsolute);
1008
+ let file = this.getFile(srcPath);
943
1009
  if (!file) {
944
1010
  return null;
945
1011
  }
@@ -957,8 +1023,8 @@ class Program {
957
1023
  */
958
1024
  let resultPkgPaths = {};
959
1025
  //restrict to only .brs files
960
- for (let key in this.files) {
961
- let file = this.files[key];
1026
+ for (const key in this.files) {
1027
+ const file = this.files[key];
962
1028
  if (
963
1029
  //is a BrightScript or BrighterScript file
964
1030
  (file.extension === '.bs' || file.extension === '.brs') &&
@@ -966,14 +1032,12 @@ class Program {
966
1032
  lowerSourcePkgPath !== file.pkgPath.toLowerCase()) {
967
1033
  //add the relative path
968
1034
  let relativePath = util_1.util.getRelativePath(sourcePkgPath, file.pkgPath).replace(/\\/g, '/');
969
- let pkgPathStandardized = file.pkgPath.replace(/\\/g, '/');
970
- let filePkgPath = `pkg:/${pkgPathStandardized}`;
971
- let lowerFilePkgPath = filePkgPath.toLowerCase();
972
- if (!resultPkgPaths[lowerFilePkgPath]) {
973
- resultPkgPaths[lowerFilePkgPath] = true;
1035
+ const lowerPkgPath = file.pkgPath.toLowerCase();
1036
+ if (!resultPkgPaths[lowerPkgPath]) {
1037
+ resultPkgPaths[lowerPkgPath] = true;
974
1038
  result.push({
975
1039
  label: relativePath,
976
- detail: file.pathAbsolute,
1040
+ detail: file.srcPath,
977
1041
  kind: vscode_languageserver_1.CompletionItemKind.File,
978
1042
  textEdit: {
979
1043
  newText: relativePath,
@@ -982,11 +1046,11 @@ class Program {
982
1046
  });
983
1047
  //add the absolute path
984
1048
  result.push({
985
- label: filePkgPath,
986
- detail: file.pathAbsolute,
1049
+ label: file.pkgPath,
1050
+ detail: file.srcPath,
987
1051
  kind: vscode_languageserver_1.CompletionItemKind.File,
988
1052
  textEdit: {
989
- newText: filePkgPath,
1053
+ newText: file.pkgPath,
990
1054
  range: scriptImport.filePathRange
991
1055
  }
992
1056
  });
@@ -998,76 +1062,84 @@ class Program {
998
1062
  /**
999
1063
  * Transpile a single file and get the result as a string.
1000
1064
  * This does not write anything to the file system.
1065
+ * @param srcPath The absolute path to the source file on disk
1001
1066
  */
1002
- getTranspiledFileContents(pathAbsolute) {
1003
- let file = this.getFile(pathAbsolute);
1067
+ getTranspiledFileContents(srcPath) {
1068
+ let file = this.getFile(srcPath);
1004
1069
  let result = file.transpile();
1005
- return Object.assign(Object.assign({}, result), { pathAbsolute: file.pathAbsolute, pkgPath: file.pkgPath });
1070
+ return Object.assign(Object.assign({}, result), { srcPath: file.srcPath, pkgPath: file.pkgPath });
1006
1071
  }
1007
1072
  async transpile(fileEntries, stagingFolderPath) {
1008
- // map fileEntries using their path as key, to avoid excessive "find()" operations
1073
+ // map fileEntries using their path as key to avoid excessive "find()" operations
1009
1074
  const mappedFileEntries = fileEntries.reduce((collection, entry) => {
1010
- collection[util_1.standardizePath `${entry.src}`] = entry;
1075
+ collection[(0, util_1.standardizePath) `${entry.src}`] = entry;
1011
1076
  return collection;
1012
1077
  }, {});
1013
- const entries = Object.values(this.files).map(file => {
1014
- let filePathObj = mappedFileEntries[util_1.standardizePath `${file.pathAbsolute}`];
1078
+ const entries = [];
1079
+ for (const key in this.files) {
1080
+ const file = this.files[key];
1081
+ let filePathObj = mappedFileEntries[(0, util_1.standardizePath) `${file.srcPath}`];
1015
1082
  if (!filePathObj) {
1016
1083
  //this file has been added in-memory, from a plugin, for example
1017
1084
  filePathObj = {
1018
1085
  //add an interpolated src path (since it doesn't actually exist in memory)
1019
- src: `bsc:/${file.pkgPath}`,
1086
+ src: `bsc-in-memory:/${util_1.util.removeProtocol(file.pkgPath)}`,
1020
1087
  dest: file.pkgPath
1021
1088
  };
1022
1089
  }
1023
- //replace the file extension
1024
- let outputPath = filePathObj.dest.replace(/\.bs$/gi, '.brs');
1090
+ //prep the output path
1091
+ let outputPath = filePathObj.dest
1092
+ //replace any leading protocol
1093
+ .replace(/^[-a-z_]+:\//, '')
1094
+ //change any .bs file extension to .brs
1095
+ .replace(/\.bs$/gi, '.brs');
1025
1096
  //prepend the staging folder path
1026
- outputPath = util_1.standardizePath `${stagingFolderPath}/${outputPath}`;
1027
- return {
1097
+ outputPath = (0, util_1.standardizePath) `${stagingFolderPath}/${outputPath}`;
1098
+ entries.push({
1028
1099
  file: file,
1029
- outputPath: outputPath
1030
- };
1031
- });
1100
+ program: this,
1101
+ outputPath: outputPath,
1102
+ editor: new AstEditor_1.AstEditor()
1103
+ });
1104
+ }
1032
1105
  this.plugins.emit('beforeProgramTranspile', {
1033
1106
  program: this,
1034
1107
  entries: entries
1035
1108
  });
1036
1109
  const promises = entries.map(async (entry) => {
1037
1110
  //skip transpiling typedef files
1038
- if (reflection_1.isBrsFile(entry.file) && entry.file.isTypedef) {
1111
+ if ((0, reflection_1.isBrsFile)(entry.file) && entry.file.isTypedef) {
1039
1112
  return;
1040
1113
  }
1041
- this.plugins.emit('beforeFileTranspile', {
1042
- program: this,
1043
- file: entry.file,
1044
- outputPath: entry.outputPath
1045
- });
1114
+ this.plugins.emit('beforeFileTranspile', entry);
1046
1115
  const { file, outputPath } = entry;
1116
+ //if we have any edits, assume the file needs to be transpiled
1117
+ if (entry.editor.hasChanges) {
1118
+ //use the `editor` because it'll track the previous value for us and revert later on
1119
+ entry.editor.setProperty(file, 'needsTranspiled', true);
1120
+ }
1047
1121
  const result = file.transpile();
1048
1122
  //make sure the full dir path exists
1049
1123
  await fsExtra.ensureDir(path.dirname(outputPath));
1050
1124
  if (await fsExtra.pathExists(outputPath)) {
1051
- throw new Error(`Error while transpiling "${file.pathAbsolute}". A file already exists at "${outputPath}" and will not be overwritten.`);
1125
+ throw new Error(`Error while transpiling "${file.srcPath}". A file already exists at "${outputPath}" and will not be overwritten.`);
1052
1126
  }
1053
1127
  const writeMapPromise = result.map ? fsExtra.writeFile(`${outputPath}.map`, result.map.toString()) : null;
1054
1128
  await Promise.all([
1055
1129
  fsExtra.writeFile(outputPath, result.code),
1056
1130
  writeMapPromise
1057
1131
  ]);
1058
- if (reflection_1.isBrsFile(file) && this.options.emitDefinitions) {
1132
+ if ((0, reflection_1.isBrsFile)(file) && this.options.emitDefinitions) {
1059
1133
  const typedef = file.getTypedef();
1060
1134
  const typedefPath = outputPath.replace(/\.brs$/i, '.d.bs');
1061
1135
  await fsExtra.writeFile(typedefPath, typedef);
1062
1136
  }
1063
- this.plugins.emit('afterFileTranspile', {
1064
- program: this,
1065
- file: entry.file,
1066
- outputPath: entry.outputPath
1067
- });
1137
+ this.plugins.emit('afterFileTranspile', entry);
1138
+ //undo all `editor` edits that may have been applied to this file.
1139
+ entry.editor.undoAll();
1068
1140
  });
1069
1141
  //if there's no bslib file already loaded into the program, copy it to the staging directory
1070
- if (!this.getFileByPkgPath(bslibAliasedRokuModulesPkgPath) && !this.getFileByPkgPath(util_1.standardizePath `source/bslib.brs`)) {
1142
+ if (!this.getFile(bslibAliasedRokuModulesPkgPath) && !this.getFile(`pkg:/source/bslib.brs`)) {
1071
1143
  promises.push(util_1.util.copyBslibToStaging(stagingFolderPath));
1072
1144
  }
1073
1145
  await Promise.all(promises);
@@ -1084,7 +1156,7 @@ class Program {
1084
1156
  const lowerFunctionName = functionName.toLowerCase();
1085
1157
  //find every file with this function defined
1086
1158
  for (const file of Object.values(this.files)) {
1087
- if (reflection_1.isBrsFile(file)) {
1159
+ if ((0, reflection_1.isBrsFile)(file)) {
1088
1160
  //TODO handle namespace-relative function calls
1089
1161
  //if the file has a function with this name
1090
1162
  if (file.parser.references.functionStatementLookup.get(lowerFunctionName) !== undefined) {
@@ -1102,7 +1174,7 @@ class Program {
1102
1174
  const lowerClassName = className.toLowerCase();
1103
1175
  //find every file with this class defined
1104
1176
  for (const file of Object.values(this.files)) {
1105
- if (reflection_1.isBrsFile(file)) {
1177
+ if ((0, reflection_1.isBrsFile)(file)) {
1106
1178
  //TODO handle namespace-relative classes
1107
1179
  //if the file has a function with this name
1108
1180
  if (file.parser.references.classStatementLookup.get(lowerClassName) !== undefined) {
@@ -1124,7 +1196,7 @@ class Program {
1124
1196
  try {
1125
1197
  //we only load this manifest once, so do it sync to improve speed downstream
1126
1198
  contents = fsExtra.readFileSync(manifestPath, 'utf-8');
1127
- this._manifest = Manifest_1.parseManifest(contents);
1199
+ this._manifest = (0, Manifest_1.parseManifest)(contents);
1128
1200
  }
1129
1201
  catch (err) {
1130
1202
  this._manifest = new Map();
@@ -1133,11 +1205,13 @@ class Program {
1133
1205
  return this._manifest;
1134
1206
  }
1135
1207
  dispose() {
1136
- for (let filePath in this.files) {
1137
- this.files[filePath].dispose();
1208
+ var _a, _b;
1209
+ for (const key in this.files) {
1210
+ const file = this.files[key];
1211
+ (_a = file.dispose) === null || _a === void 0 ? void 0 : _a.call(file);
1138
1212
  }
1139
1213
  for (let name in this.scopes) {
1140
- this.scopes[name].dispose();
1214
+ (_b = this.scopes[name]) === null || _b === void 0 ? void 0 : _b.dispose();
1141
1215
  }
1142
1216
  this.globalScope.dispose();
1143
1217
  this.dependencyGraph.dispose();