brighterscript 0.66.0-alpha.5 → 0.66.0-alpha.7

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 (298) hide show
  1. package/CHANGELOG.md +64 -10
  2. package/README.md +16 -0
  3. package/bsconfig.schema.json +15 -0
  4. package/dist/ActionPipeline.d.ts +10 -0
  5. package/dist/ActionPipeline.js +40 -0
  6. package/dist/ActionPipeline.js.map +1 -0
  7. package/dist/BsConfig.d.ts +15 -1
  8. package/dist/CommentFlagProcessor.d.ts +4 -3
  9. package/dist/CommentFlagProcessor.js.map +1 -1
  10. package/dist/DiagnosticMessages.d.ts +19 -4
  11. package/dist/DiagnosticMessages.js +45 -5
  12. package/dist/DiagnosticMessages.js.map +1 -1
  13. package/dist/LanguageServer.js.map +1 -1
  14. package/dist/PluginInterface.d.ts +11 -2
  15. package/dist/PluginInterface.js +69 -10
  16. package/dist/PluginInterface.js.map +1 -1
  17. package/dist/Program.d.ts +101 -37
  18. package/dist/Program.js +492 -274
  19. package/dist/Program.js.map +1 -1
  20. package/dist/ProgramBuilder.d.ts +10 -4
  21. package/dist/ProgramBuilder.js +44 -54
  22. package/dist/ProgramBuilder.js.map +1 -1
  23. package/dist/Scope.d.ts +27 -13
  24. package/dist/Scope.js +44 -26
  25. package/dist/Scope.js.map +1 -1
  26. package/dist/SymbolTable.d.ts +5 -0
  27. package/dist/SymbolTable.js +15 -2
  28. package/dist/SymbolTable.js.map +1 -1
  29. package/dist/XmlScope.d.ts +7 -4
  30. package/dist/XmlScope.js +47 -8
  31. package/dist/XmlScope.js.map +1 -1
  32. package/dist/astUtils/{AstEditor.d.ts → Editor.d.ts} +6 -1
  33. package/dist/astUtils/{AstEditor.js → Editor.js} +9 -3
  34. package/dist/astUtils/Editor.js.map +1 -0
  35. package/dist/astUtils/{AstEditor.spec.js → Editor.spec.js} +10 -6
  36. package/dist/astUtils/Editor.spec.js.map +1 -0
  37. package/dist/astUtils/creators.d.ts +3 -1
  38. package/dist/astUtils/creators.js +9 -1
  39. package/dist/astUtils/creators.js.map +1 -1
  40. package/dist/astUtils/reflection.d.ts +30 -8
  41. package/dist/astUtils/reflection.js +64 -14
  42. package/dist/astUtils/reflection.js.map +1 -1
  43. package/dist/astUtils/reflection.spec.js +85 -4
  44. package/dist/astUtils/reflection.spec.js.map +1 -1
  45. package/dist/astUtils/visitors.d.ts +3 -3
  46. package/dist/astUtils/visitors.spec.js +7 -7
  47. package/dist/astUtils/visitors.spec.js.map +1 -1
  48. package/dist/bscPlugin/BscPlugin.d.ts +10 -2
  49. package/dist/bscPlugin/BscPlugin.js +24 -4
  50. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  51. package/dist/bscPlugin/FileWriter.d.ts +6 -0
  52. package/dist/bscPlugin/FileWriter.js +24 -0
  53. package/dist/bscPlugin/FileWriter.js.map +1 -0
  54. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +8 -8
  55. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  56. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +4 -4
  57. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
  58. package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +11 -1
  59. package/dist/bscPlugin/completions/CompletionsProcessor.js +112 -58
  60. package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -1
  61. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +151 -6
  62. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -1
  63. package/dist/bscPlugin/fileProviders/FileProvider.d.ts +9 -0
  64. package/dist/bscPlugin/fileProviders/FileProvider.js +51 -0
  65. package/dist/bscPlugin/fileProviders/FileProvider.js.map +1 -0
  66. package/dist/bscPlugin/hover/HoverProcessor.d.ts +1 -7
  67. package/dist/bscPlugin/hover/HoverProcessor.js +2 -8
  68. package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -1
  69. package/dist/bscPlugin/hover/HoverProcessor.spec.js +55 -0
  70. package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -1
  71. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +1 -0
  72. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +43 -0
  73. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
  74. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +22 -0
  75. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -1
  76. package/dist/bscPlugin/serialize/BslibInjector.spec.js +19 -0
  77. package/dist/bscPlugin/serialize/BslibInjector.spec.js.map +1 -0
  78. package/dist/bscPlugin/serialize/BslibManager.d.ts +9 -0
  79. package/dist/bscPlugin/serialize/BslibManager.js +40 -0
  80. package/dist/bscPlugin/serialize/BslibManager.js.map +1 -0
  81. package/dist/bscPlugin/serialize/FileSerializer.d.ts +9 -0
  82. package/dist/bscPlugin/serialize/FileSerializer.js +72 -0
  83. package/dist/bscPlugin/serialize/FileSerializer.js.map +1 -0
  84. package/dist/bscPlugin/transpile/{BrsFilePreTranspileProcessor.d.ts → BrsFileTranspileProcessor.d.ts} +4 -2
  85. package/dist/bscPlugin/transpile/{BrsFilePreTranspileProcessor.js → BrsFileTranspileProcessor.js} +25 -4
  86. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.js.map +1 -0
  87. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.d.ts +1 -0
  88. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js +41 -0
  89. package/dist/bscPlugin/transpile/BrsFileTranspileProcessor.spec.js.map +1 -0
  90. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.d.ts +2 -2
  91. package/dist/bscPlugin/transpile/XmlFilePreTranspileProcessor.js.map +1 -1
  92. package/dist/bscPlugin/validation/BrsFileValidator.js +2 -1
  93. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
  94. package/dist/bscPlugin/validation/ScopeValidator.d.ts +12 -0
  95. package/dist/bscPlugin/validation/ScopeValidator.js +137 -19
  96. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  97. package/dist/bscPlugin/validation/ScopeValidator.spec.js +671 -1
  98. package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -1
  99. package/dist/bscPlugin/validation/XmlFileValidator.js +2 -2
  100. package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -1
  101. package/dist/cli.js +1 -0
  102. package/dist/cli.js.map +1 -1
  103. package/dist/deferred.d.ts +2 -2
  104. package/dist/deferred.js.map +1 -1
  105. package/dist/diagnosticUtils.d.ts +1 -0
  106. package/dist/diagnosticUtils.js +4 -3
  107. package/dist/diagnosticUtils.js.map +1 -1
  108. package/dist/examples/plugins/removePrint.js +1 -1
  109. package/dist/examples/plugins/removePrint.js.map +1 -1
  110. package/dist/files/AssetFile.d.ts +26 -0
  111. package/dist/files/AssetFile.js +26 -0
  112. package/dist/files/AssetFile.js.map +1 -0
  113. package/dist/files/BrsFile.Class.spec.js +40 -40
  114. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  115. package/dist/files/BrsFile.d.ts +42 -15
  116. package/dist/files/BrsFile.js +120 -78
  117. package/dist/files/BrsFile.js.map +1 -1
  118. package/dist/files/BrsFile.spec.js +266 -167
  119. package/dist/files/BrsFile.spec.js.map +1 -1
  120. package/dist/files/Factory.d.ts +25 -0
  121. package/dist/files/Factory.js +22 -0
  122. package/dist/files/Factory.js.map +1 -0
  123. package/dist/files/File.d.ts +106 -0
  124. package/dist/files/File.js +16 -0
  125. package/dist/files/File.js.map +1 -0
  126. package/dist/files/LazyFileData.d.ts +20 -0
  127. package/dist/files/LazyFileData.js +54 -0
  128. package/dist/files/LazyFileData.js.map +1 -0
  129. package/dist/files/LazyFileData.spec.d.ts +1 -0
  130. package/dist/files/LazyFileData.spec.js +27 -0
  131. package/dist/files/LazyFileData.spec.js.map +1 -0
  132. package/dist/files/XmlFile.d.ts +55 -17
  133. package/dist/files/XmlFile.js +88 -47
  134. package/dist/files/XmlFile.js.map +1 -1
  135. package/dist/files/XmlFile.spec.js +64 -57
  136. package/dist/files/XmlFile.spec.js.map +1 -1
  137. package/dist/files/tests/imports.spec.js +21 -8
  138. package/dist/files/tests/imports.spec.js.map +1 -1
  139. package/dist/files/tests/optionalChaning.spec.js +14 -14
  140. package/dist/files/tests/optionalChaning.spec.js.map +1 -1
  141. package/dist/globalCallables.js +2 -6
  142. package/dist/globalCallables.js.map +1 -1
  143. package/dist/index.d.ts +4 -1
  144. package/dist/index.js +4 -1
  145. package/dist/index.js.map +1 -1
  146. package/dist/interfaces.d.ts +326 -85
  147. package/dist/interfaces.js +4 -1
  148. package/dist/interfaces.js.map +1 -1
  149. package/dist/lexer/Lexer.js +1 -1
  150. package/dist/lexer/TokenKind.js +0 -1
  151. package/dist/lexer/TokenKind.js.map +1 -1
  152. package/dist/parser/AstNode.d.ts +2 -2
  153. package/dist/parser/AstNode.js +1 -1
  154. package/dist/parser/AstNode.js.map +1 -1
  155. package/dist/parser/BrsTranspileState.d.ts +3 -2
  156. package/dist/parser/BrsTranspileState.js +3 -2
  157. package/dist/parser/BrsTranspileState.js.map +1 -1
  158. package/dist/parser/Expression.d.ts +1 -1
  159. package/dist/parser/Expression.js +35 -19
  160. package/dist/parser/Expression.js.map +1 -1
  161. package/dist/parser/Parser.js +12 -1
  162. package/dist/parser/Parser.js.map +1 -1
  163. package/dist/parser/Parser.spec.js +18 -2
  164. package/dist/parser/Parser.spec.js.map +1 -1
  165. package/dist/parser/SGParser.d.ts +2 -2
  166. package/dist/parser/SGParser.js +3 -3
  167. package/dist/parser/SGParser.js.map +1 -1
  168. package/dist/parser/SGParser.spec.js +2 -2
  169. package/dist/parser/SGParser.spec.js.map +1 -1
  170. package/dist/parser/SGTypes.d.ts +1 -1
  171. package/dist/parser/Statement.js +1 -1
  172. package/dist/parser/Statement.js.map +1 -1
  173. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +10 -10
  174. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  175. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +10 -10
  176. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -1
  177. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js +24 -24
  178. package/dist/parser/tests/expression/SourceLiteralExpression.spec.js.map +1 -1
  179. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +64 -36
  180. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  181. package/dist/parser/tests/expression/TernaryExpression.spec.js +34 -34
  182. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  183. package/dist/parser/tests/statement/ConstStatement.spec.js +17 -17
  184. package/dist/parser/tests/statement/ConstStatement.spec.js.map +1 -1
  185. package/dist/parser/tests/statement/Continue.spec.js +2 -2
  186. package/dist/parser/tests/statement/Continue.spec.js.map +1 -1
  187. package/dist/parser/tests/statement/Enum.spec.js +26 -26
  188. package/dist/parser/tests/statement/Enum.spec.js.map +1 -1
  189. package/dist/parser/tests/statement/For.spec.js +6 -6
  190. package/dist/parser/tests/statement/For.spec.js.map +1 -1
  191. package/dist/parser/tests/statement/ForEach.spec.js +4 -4
  192. package/dist/parser/tests/statement/ForEach.spec.js.map +1 -1
  193. package/dist/parser/tests/statement/InterfaceStatement.spec.js +18 -10
  194. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
  195. package/dist/parser/tests/statement/PrintStatement.spec.js +10 -10
  196. package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
  197. package/dist/preprocessor/Manifest.d.ts +1 -1
  198. package/dist/preprocessor/Manifest.js +2 -2
  199. package/dist/preprocessor/Manifest.js.map +1 -1
  200. package/dist/roku-types/data.json +111 -149
  201. package/dist/roku-types/index.d.ts +27 -13
  202. package/dist/types/ArrayType.d.ts +2 -1
  203. package/dist/types/ArrayType.js +6 -2
  204. package/dist/types/ArrayType.js.map +1 -1
  205. package/dist/types/ArrayType.spec.js +11 -1
  206. package/dist/types/ArrayType.spec.js.map +1 -1
  207. package/dist/types/AssociativeArrayType.d.ts +11 -0
  208. package/dist/types/AssociativeArrayType.js +52 -0
  209. package/dist/types/AssociativeArrayType.js.map +1 -0
  210. package/dist/types/BaseFunctionType.d.ts +2 -1
  211. package/dist/types/BaseFunctionType.js +1 -1
  212. package/dist/types/BaseFunctionType.js.map +1 -1
  213. package/dist/types/BooleanType.d.ts +2 -1
  214. package/dist/types/BooleanType.js +3 -2
  215. package/dist/types/BooleanType.js.map +1 -1
  216. package/dist/types/BscType.d.ts +3 -3
  217. package/dist/types/BscType.js +26 -12
  218. package/dist/types/BscType.js.map +1 -1
  219. package/dist/types/BscTypeKind.d.ts +2 -0
  220. package/dist/types/BscTypeKind.js +2 -0
  221. package/dist/types/BscTypeKind.js.map +1 -1
  222. package/dist/types/BuiltInInterfaceAdder.d.ts +8 -0
  223. package/dist/types/BuiltInInterfaceAdder.js +88 -23
  224. package/dist/types/BuiltInInterfaceAdder.js.map +1 -1
  225. package/dist/types/ClassType.d.ts +2 -1
  226. package/dist/types/ClassType.js +2 -2
  227. package/dist/types/ClassType.js.map +1 -1
  228. package/dist/types/ComponentType.d.ts +26 -0
  229. package/dist/types/ComponentType.js +83 -0
  230. package/dist/types/ComponentType.js.map +1 -0
  231. package/dist/types/DoubleType.d.ts +2 -1
  232. package/dist/types/DoubleType.js +4 -2
  233. package/dist/types/DoubleType.js.map +1 -1
  234. package/dist/types/DynamicType.d.ts +2 -2
  235. package/dist/types/DynamicType.js +1 -1
  236. package/dist/types/DynamicType.js.map +1 -1
  237. package/dist/types/EnumType.d.ts +3 -2
  238. package/dist/types/EnumType.js +3 -3
  239. package/dist/types/EnumType.js.map +1 -1
  240. package/dist/types/FloatType.d.ts +2 -1
  241. package/dist/types/FloatType.js +4 -2
  242. package/dist/types/FloatType.js.map +1 -1
  243. package/dist/types/FunctionType.d.ts +2 -1
  244. package/dist/types/FunctionType.js +2 -2
  245. package/dist/types/FunctionType.js.map +1 -1
  246. package/dist/types/IntegerType.d.ts +2 -1
  247. package/dist/types/IntegerType.js +4 -2
  248. package/dist/types/IntegerType.js.map +1 -1
  249. package/dist/types/InterfaceType.d.ts +2 -1
  250. package/dist/types/InterfaceType.js +3 -7
  251. package/dist/types/InterfaceType.js.map +1 -1
  252. package/dist/types/InterfaceType.spec.js +25 -2
  253. package/dist/types/InterfaceType.spec.js.map +1 -1
  254. package/dist/types/LongIntegerType.d.ts +2 -1
  255. package/dist/types/LongIntegerType.js +4 -2
  256. package/dist/types/LongIntegerType.js.map +1 -1
  257. package/dist/types/ObjectType.d.ts +2 -2
  258. package/dist/types/ObjectType.js +1 -1
  259. package/dist/types/ObjectType.js.map +1 -1
  260. package/dist/types/ReferenceType.d.ts +2 -0
  261. package/dist/types/ReferenceType.js +45 -1
  262. package/dist/types/ReferenceType.js.map +1 -1
  263. package/dist/types/StringType.d.ts +2 -1
  264. package/dist/types/StringType.js +4 -4
  265. package/dist/types/StringType.js.map +1 -1
  266. package/dist/types/TypedFunctionType.d.ts +7 -1
  267. package/dist/types/TypedFunctionType.js +47 -17
  268. package/dist/types/TypedFunctionType.js.map +1 -1
  269. package/dist/types/TypedFunctionType.spec.js +99 -0
  270. package/dist/types/TypedFunctionType.spec.js.map +1 -1
  271. package/dist/types/UninitializedType.d.ts +2 -1
  272. package/dist/types/UninitializedType.js +1 -1
  273. package/dist/types/UninitializedType.js.map +1 -1
  274. package/dist/types/UnionType.d.ts +2 -2
  275. package/dist/types/UnionType.js +10 -3
  276. package/dist/types/UnionType.js.map +1 -1
  277. package/dist/types/UnionType.spec.js +3 -2
  278. package/dist/types/UnionType.spec.js.map +1 -1
  279. package/dist/types/VoidType.d.ts +2 -1
  280. package/dist/types/VoidType.js +2 -2
  281. package/dist/types/VoidType.js.map +1 -1
  282. package/dist/types/helper.spec.js +15 -0
  283. package/dist/types/helper.spec.js.map +1 -1
  284. package/dist/types/helpers.d.ts +5 -1
  285. package/dist/types/helpers.js +31 -3
  286. package/dist/types/helpers.js.map +1 -1
  287. package/dist/util.d.ts +26 -6
  288. package/dist/util.js +181 -52
  289. package/dist/util.js.map +1 -1
  290. package/dist/validators/ClassValidator.js.map +1 -1
  291. package/package.json +1 -1
  292. package/dist/astUtils/AstEditor.js.map +0 -1
  293. package/dist/astUtils/AstEditor.spec.js.map +0 -1
  294. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +0 -1
  295. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js +0 -31
  296. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js.map +0 -1
  297. /package/dist/astUtils/{AstEditor.spec.d.ts → Editor.spec.d.ts} +0 -0
  298. /package/dist/bscPlugin/{transpile/BrsFilePreTranspileProcessor.spec.d.ts → serialize/BslibInjector.spec.d.ts} +0 -0
package/dist/Program.js CHANGED
@@ -6,8 +6,6 @@ const fsExtra = require("fs-extra");
6
6
  const path = require("path");
7
7
  const Scope_1 = require("./Scope");
8
8
  const DiagnosticMessages_1 = require("./DiagnosticMessages");
9
- const BrsFile_1 = require("./files/BrsFile");
10
- const XmlFile_1 = require("./files/XmlFile");
11
9
  const util_1 = require("./util");
12
10
  const XmlScope_1 = require("./XmlScope");
13
11
  const DiagnosticFilterer_1 = require("./DiagnosticFilterer");
@@ -20,8 +18,7 @@ const vscode_uri_1 = require("vscode-uri");
20
18
  const PluginInterface_1 = require("./PluginInterface");
21
19
  const reflection_1 = require("./astUtils/reflection");
22
20
  const BscPlugin_1 = require("./bscPlugin/BscPlugin");
23
- const AstEditor_1 = require("./astUtils/AstEditor");
24
- const roku_deploy_1 = require("roku-deploy");
21
+ const Editor_1 = require("./astUtils/Editor");
25
22
  const CallExpressionInfo_1 = require("./bscPlugin/CallExpressionInfo");
26
23
  const SignatureHelpUtil_1 = require("./bscPlugin/SignatureHelpUtil");
27
24
  const DiagnosticSeverityAdjuster_1 = require("./DiagnosticSeverityAdjuster");
@@ -36,7 +33,14 @@ const LongIntegerType_1 = require("./types/LongIntegerType");
36
33
  const ObjectType_1 = require("./types/ObjectType");
37
34
  const VoidType_1 = require("./types/VoidType");
38
35
  const FunctionType_1 = require("./types/FunctionType");
39
- const startOfSourcePkgPath = `source${path.sep}`;
36
+ const Factory_1 = require("./files/Factory");
37
+ const ActionPipeline_1 = require("./ActionPipeline");
38
+ const LazyFileData_1 = require("./files/LazyFileData");
39
+ const roku_deploy_1 = require("roku-deploy");
40
+ const roku_types_1 = require("./roku-types");
41
+ const ComponentType_1 = require("./types/ComponentType");
42
+ const types_1 = require("./types");
43
+ const BuiltInInterfaceAdder_1 = require("./types/BuiltInInterfaceAdder");
40
44
  const bslibNonAliasedRokuModulesPkgPath = (0, util_1.standardizePath) `source/roku_modules/rokucommunity_bslib/bslib.brs`;
41
45
  const bslibAliasedRokuModulesPkgPath = (0, util_1.standardizePath) `source/roku_modules/bslib/bslib.brs`;
42
46
  class Program {
@@ -46,6 +50,10 @@ class Program {
46
50
  */
47
51
  options, logger, plugins) {
48
52
  this.options = options;
53
+ /**
54
+ * An editor that plugins can use to modify program-level things during the build flow. Don't use this to edit files (they have their own `.editor`)
55
+ */
56
+ this.editor = new Editor_1.Editor();
49
57
  /**
50
58
  * A graph of all files and their dependencies.
51
59
  * For example:
@@ -64,7 +72,16 @@ class Program {
64
72
  * A map of every file loaded into this program, indexed by its original file location
65
73
  */
66
74
  this.files = {};
67
- this.pkgMap = {};
75
+ /**
76
+ * A map of every file loaded into this program, indexed by its destPath
77
+ */
78
+ this.destMap = new Map();
79
+ /**
80
+ * Plugins can contribute multiple virtual files for a single physical file.
81
+ * This collection links the virtual files back to the physical file that produced them.
82
+ * The key is the standardized and lower-cased srcPath
83
+ */
84
+ this.fileClusters = new Map();
68
85
  this.scopes = {};
69
86
  /**
70
87
  * A map of every component currently loaded into the program, indexed by the component name.
@@ -73,6 +90,12 @@ class Program {
73
90
  * but if you do, only ever use the component at index 0.
74
91
  */
75
92
  this.components = {};
93
+ /**
94
+ * Keeps a set of all the components that need to have their types updated during the current validation cycle
95
+ */
96
+ this.componentSymbolsToUpdate = new Set();
97
+ this.getTranspiledFileContentsPipeline = new ActionPipeline_1.ActionPipeline();
98
+ this.buildPipeline = new ActionPipeline_1.ActionPipeline();
76
99
  this.options = util_1.util.normalizeConfig(options);
77
100
  this.logger = logger || new Logger_1.Logger(options.logLevel);
78
101
  this.plugins = plugins || new PluginInterface_1.default([], { logger: this.logger });
@@ -81,6 +104,7 @@ class Program {
81
104
  //normalize the root dir path
82
105
  this.options.rootDir = util_1.util.getRootDir(this.options);
83
106
  this.createGlobalScope();
107
+ this.fileFactory = new Factory_1.FileFactory(this);
84
108
  }
85
109
  createGlobalScope() {
86
110
  //create the 'global' scope
@@ -96,12 +120,37 @@ class Program {
96
120
  //TODO we might need to fix this because the isValidated clears stuff now
97
121
  this.globalScope.isValidated = true;
98
122
  }
123
+ recursivelyAddNodeToSymbolTable(nodeData) {
124
+ if (!nodeData) {
125
+ return;
126
+ }
127
+ let nodeType;
128
+ const nodeName = util_1.util.getSgNodeTypeName(nodeData.name);
129
+ if (!this.globalScope.symbolTable.hasSymbol(nodeName, SymbolTable_1.SymbolTypeFlag.typetime)) {
130
+ let parentNode;
131
+ if (nodeData.extends) {
132
+ const parentNodeData = roku_types_1.nodes[nodeData.extends.name.toLowerCase()];
133
+ try {
134
+ parentNode = this.recursivelyAddNodeToSymbolTable(parentNodeData);
135
+ }
136
+ catch (error) {
137
+ console.log(error, nodeData);
138
+ }
139
+ }
140
+ nodeType = new ComponentType_1.ComponentType(nodeData.name, parentNode);
141
+ nodeType.addBuiltInInterfaces();
142
+ this.globalScope.symbolTable.addSymbol(nodeName, { description: nodeData.description }, nodeType, SymbolTable_1.SymbolTypeFlag.typetime);
143
+ }
144
+ else {
145
+ nodeType = this.globalScope.symbolTable.getSymbolType(nodeName, { flags: SymbolTable_1.SymbolTypeFlag.typetime });
146
+ }
147
+ return nodeType;
148
+ }
99
149
  /**
100
150
  * Do all setup required for the global symbol table.
101
151
  */
102
152
  populateGlobalSymbolTable() {
103
153
  //Setup primitive types in global symbolTable
104
- //TODO: Need to handle Array types
105
154
  this.globalScope.symbolTable.addSymbol('boolean', undefined, BooleanType_1.BooleanType.instance, SymbolTable_1.SymbolTypeFlag.typetime);
106
155
  this.globalScope.symbolTable.addSymbol('double', undefined, DoubleType_1.DoubleType.instance, SymbolTable_1.SymbolTypeFlag.typetime);
107
156
  this.globalScope.symbolTable.addSymbol('dynamic', undefined, DynamicType_1.DynamicType.instance, SymbolTable_1.SymbolTypeFlag.typetime);
@@ -112,9 +161,27 @@ class Program {
112
161
  this.globalScope.symbolTable.addSymbol('object', undefined, new ObjectType_1.ObjectType(), SymbolTable_1.SymbolTypeFlag.typetime);
113
162
  this.globalScope.symbolTable.addSymbol('string', undefined, StringType_1.StringType.instance, SymbolTable_1.SymbolTypeFlag.typetime);
114
163
  this.globalScope.symbolTable.addSymbol('void', undefined, VoidType_1.VoidType.instance, SymbolTable_1.SymbolTypeFlag.typetime);
115
- for (let pair of globalCallables_1.globalCallableMap) {
116
- let [key, callable] = pair;
117
- this.globalScope.symbolTable.addSymbol(key, undefined, callable.type, SymbolTable_1.SymbolTypeFlag.runtime);
164
+ BuiltInInterfaceAdder_1.BuiltInInterfaceAdder.getLookupTable = () => this.globalScope.symbolTable;
165
+ for (const callable of globalCallables_1.globalCallables) {
166
+ this.globalScope.symbolTable.addSymbol(callable.name, { description: callable.shortDescription }, callable.type, SymbolTable_1.SymbolTypeFlag.runtime);
167
+ }
168
+ for (const componentData of Object.values(roku_types_1.components)) {
169
+ const nodeType = new types_1.InterfaceType(componentData.name);
170
+ nodeType.addBuiltInInterfaces();
171
+ this.globalScope.symbolTable.addSymbol(componentData.name, { description: componentData.description }, nodeType, SymbolTable_1.SymbolTypeFlag.typetime);
172
+ }
173
+ for (const ifaceData of Object.values(roku_types_1.interfaces)) {
174
+ const nodeType = new types_1.InterfaceType(ifaceData.name);
175
+ nodeType.addBuiltInInterfaces();
176
+ this.globalScope.symbolTable.addSymbol(ifaceData.name, { description: ifaceData.description }, nodeType, SymbolTable_1.SymbolTypeFlag.typetime);
177
+ }
178
+ for (const eventData of Object.values(roku_types_1.events)) {
179
+ const nodeType = new types_1.InterfaceType(eventData.name);
180
+ nodeType.addBuiltInInterfaces();
181
+ this.globalScope.symbolTable.addSymbol(eventData.name, { description: eventData.description }, nodeType, SymbolTable_1.SymbolTypeFlag.typetime);
182
+ }
183
+ for (const nodeData of Object.values(roku_types_1.nodes)) {
184
+ this.recursivelyAddNodeToSymbolTable(nodeData);
118
185
  }
119
186
  }
120
187
  /**
@@ -131,7 +198,7 @@ class Program {
131
198
  //default to the embedded version
132
199
  }
133
200
  else {
134
- return `source${path.sep}bslib.brs`;
201
+ return `${this.options.bslibDestinationDir}${path.sep}bslib.brs`;
135
202
  }
136
203
  }
137
204
  get bslibPrefix() {
@@ -152,7 +219,7 @@ class Program {
152
219
  var _a;
153
220
  if (componentName) {
154
221
  //return the first compoment in the list with this name
155
- //(components are ordered in this list by pkgPath to ensure consistency)
222
+ //(components are ordered in this list by destPath to ensure consistency)
156
223
  return (_a = this.components[componentName.toLowerCase()]) === null || _a === void 0 ? void 0 : _a[0];
157
224
  }
158
225
  else {
@@ -163,8 +230,7 @@ class Program {
163
230
  * Register (or replace) the reference to a component in the component map
164
231
  */
165
232
  registerComponent(xmlFile, scope) {
166
- var _a, _b;
167
- const key = ((_b = (_a = xmlFile.componentName) === null || _a === void 0 ? void 0 : _a.text) !== null && _b !== void 0 ? _b : xmlFile.pkgPath).toLowerCase();
233
+ const key = this.getComponentKey(xmlFile);
168
234
  if (!this.components[key]) {
169
235
  this.components[key] = [];
170
236
  }
@@ -173,8 +239,8 @@ class Program {
173
239
  scope: scope
174
240
  });
175
241
  this.components[key].sort((a, b) => {
176
- const pathA = a.file.pkgPath.toLowerCase();
177
- const pathB = b.file.pkgPath.toLowerCase();
242
+ const pathA = a.file.destPath.toLowerCase();
243
+ const pathB = b.file.destPath.toLowerCase();
178
244
  if (pathA < pathB) {
179
245
  return -1;
180
246
  }
@@ -184,13 +250,13 @@ class Program {
184
250
  return 0;
185
251
  });
186
252
  this.syncComponentDependencyGraph(this.components[key]);
253
+ this.addDeferredComponentTypeSymbolCreation(xmlFile);
187
254
  }
188
255
  /**
189
256
  * Remove the specified component from the components map
190
257
  */
191
258
  unregisterComponent(xmlFile) {
192
- var _a, _b;
193
- const key = ((_b = (_a = xmlFile.componentName) === null || _a === void 0 ? void 0 : _a.text) !== null && _b !== void 0 ? _b : xmlFile.pkgPath).toLowerCase();
259
+ const key = this.getComponentKey(xmlFile);
194
260
  const arr = this.components[key] || [];
195
261
  for (let i = 0; i < arr.length; i++) {
196
262
  if (arr[i].file === xmlFile) {
@@ -199,6 +265,44 @@ class Program {
199
265
  }
200
266
  }
201
267
  this.syncComponentDependencyGraph(arr);
268
+ this.addDeferredComponentTypeSymbolCreation(xmlFile);
269
+ }
270
+ /**
271
+ * Adds a component described in an XML to the set of components that needs to be updated this validation cycle.
272
+ * @param xmlFile XML file with <component> tag
273
+ */
274
+ addDeferredComponentTypeSymbolCreation(xmlFile) {
275
+ var _a;
276
+ this.componentSymbolsToUpdate.add({ componentKey: this.getComponentKey(xmlFile), componentName: (_a = xmlFile.componentName) === null || _a === void 0 ? void 0 : _a.text });
277
+ }
278
+ getComponentKey(xmlFile) {
279
+ var _a, _b;
280
+ return ((_b = (_a = xmlFile.componentName) === null || _a === void 0 ? void 0 : _a.text) !== null && _b !== void 0 ? _b : xmlFile.pkgPath).toLowerCase();
281
+ }
282
+ /**
283
+ * Updates the global symbol table with the first component in this.components to have the same name as the component in the file
284
+ * @param componentKey key getting a component from `this.components`
285
+ * @param componentName the unprefixed name of the component that will be added (e.g. 'MyLabel' NOT 'roSgNodeMyLabel')
286
+ */
287
+ updateComponentSymbolInGlobalScope(componentKey, componentName) {
288
+ const symbolName = componentName ? util_1.util.getSgNodeTypeName(componentName) : undefined;
289
+ if (!symbolName) {
290
+ return;
291
+ }
292
+ const components = this.components[componentKey] || [];
293
+ // Remove any existing symbols that match
294
+ this.globalScope.symbolTable.removeSymbol(symbolName);
295
+ // There is a component that can be added - use it.
296
+ if (components.length > 0) {
297
+ const componentScope = components[0].scope;
298
+ // TODO: May need to link symbol tables to get correct types for callfuncs
299
+ // componentScope.linkSymbolTable();
300
+ const componentType = componentScope.getComponentType();
301
+ if (componentType) {
302
+ this.globalScope.symbolTable.addSymbol(symbolName, {}, componentType, SymbolTable_1.SymbolTypeFlag.typetime);
303
+ }
304
+ // TODO: Remember to unlink! componentScope.unlinkSymbolTable();
305
+ }
202
306
  }
203
307
  /**
204
308
  * re-attach the dependency graph with a new key for any component who changed
@@ -212,6 +316,7 @@ class Program {
212
316
  //attach (or re-attach) the dependencyGraph for every component whose position changed
213
317
  if (file.dependencyGraphIndex !== i) {
214
318
  file.dependencyGraphIndex = i;
319
+ this.dependencyGraph.addOrReplace(file.dependencyGraphKey, file.dependencies);
215
320
  file.attachDependencyGraph(this.dependencyGraph);
216
321
  scope.attachDependencyGraph(this.dependencyGraph);
217
322
  }
@@ -248,7 +353,7 @@ class Program {
248
353
  //get the diagnostics from all unreferenced files
249
354
  let unreferencedFiles = this.getUnreferencedFiles();
250
355
  for (let file of unreferencedFiles) {
251
- diagnostics.push(...file.getDiagnostics());
356
+ diagnostics.push(...file.diagnostics);
252
357
  }
253
358
  const filteredDiagnostics = this.logger.time(Logger_1.LogLevel.debug, ['filter diagnostics'], () => {
254
359
  //filter out diagnostics based on our diagnostic filters
@@ -273,11 +378,9 @@ class Program {
273
378
  hasFile(filePath, normalizePath = true) {
274
379
  return !!this.getFile(filePath, normalizePath);
275
380
  }
276
- getPkgPath(...args) {
277
- throw new Error('Not implemented');
278
- }
279
381
  /**
280
382
  * roku filesystem is case INsensitive, so find the scope by key case insensitive
383
+ * @param scopeName xml scope names are their `destPath`. Source scope is stored with the key `"source"`
281
384
  */
282
385
  getScopeByName(scopeName) {
283
386
  if (!scopeName) {
@@ -306,8 +409,14 @@ class Program {
306
409
  * Update internal maps with this file reference
307
410
  */
308
411
  assignFile(file) {
412
+ const fileAddEvent = {
413
+ file: file,
414
+ program: this
415
+ };
416
+ this.plugins.emit('beforeFileAdd', fileAddEvent);
309
417
  this.files[file.srcPath.toLowerCase()] = file;
310
- this.pkgMap[file.pkgPath.toLowerCase()] = file;
418
+ this.destMap.set(file.destPath.toLowerCase(), file);
419
+ this.plugins.emit('afterFileAdd', fileAddEvent);
311
420
  return file;
312
421
  }
313
422
  /**
@@ -315,104 +424,102 @@ class Program {
315
424
  */
316
425
  unassignFile(file) {
317
426
  delete this.files[file.srcPath.toLowerCase()];
318
- delete this.pkgMap[file.pkgPath.toLowerCase()];
427
+ this.destMap.delete(file.destPath.toLowerCase());
319
428
  return file;
320
429
  }
321
- setFile(fileParam, fileContents) {
430
+ setFile(fileParam, fileData) {
322
431
  //normalize the file paths
323
- const { srcPath, pkgPath } = this.getPaths(fileParam, this.options.rootDir);
432
+ const { srcPath, destPath } = this.getPaths(fileParam, this.options.rootDir);
324
433
  let file = this.logger.time(Logger_1.LogLevel.debug, ['Program.setFile()', chalk_1.default.green(srcPath)], () => {
434
+ var _a, _b, _c;
325
435
  //if the file is already loaded, remove it
326
436
  if (this.hasFile(srcPath)) {
327
437
  this.removeFile(srcPath);
328
438
  }
329
- let fileExtension = path.extname(srcPath).toLowerCase();
330
- let file;
331
- if (fileExtension === '.brs' || fileExtension === '.bs') {
332
- //add the file to the program
333
- const brsFile = this.assignFile(new BrsFile_1.BrsFile(srcPath, pkgPath, this));
334
- //add file to the `source` dependency list
335
- if (brsFile.pkgPath.startsWith(startOfSourcePkgPath)) {
336
- this.createSourceScope();
337
- this.dependencyGraph.addDependency('scope:source', brsFile.dependencyGraphKey);
338
- }
339
- let beforeFileParseEvent = {
340
- program: this,
341
- srcPath: srcPath,
342
- source: fileContents
343
- };
344
- this.plugins.emit('beforeFileParse', beforeFileParseEvent);
345
- this.logger.time(Logger_1.LogLevel.debug, ['parse', chalk_1.default.green(srcPath)], () => {
346
- brsFile.parse(beforeFileParseEvent.source);
347
- });
348
- //notify plugins that this file has finished parsing
349
- this.plugins.emit('afterFileParse', {
350
- program: this,
351
- file: brsFile
352
- });
353
- file = brsFile;
354
- brsFile.attachDependencyGraph(this.dependencyGraph);
439
+ const data = new LazyFileData_1.LazyFileData(fileData);
440
+ const event = new ProvideFileEventInternal(this, srcPath, destPath, data, this.fileFactory);
441
+ this.plugins.emit('beforeProvideFile', event);
442
+ this.plugins.emit('provideFile', event);
443
+ this.plugins.emit('afterProvideFile', event);
444
+ //if no files were provided, create a AssetFile to represent it.
445
+ if (event.files.length === 0) {
446
+ event.files.push(this.fileFactory.AssetFile({
447
+ srcPath: event.srcPath,
448
+ destPath: event.destPath,
449
+ pkgPath: event.destPath,
450
+ data: data
451
+ }));
355
452
  }
356
- else if (
357
- //is xml file
358
- fileExtension === '.xml' &&
359
- //resides in the components folder (Roku will only parse xml files in the components folder)
360
- pkgPath.toLowerCase().startsWith(util_1.util.pathSepNormalize(`components/`))) {
361
- //add the file to the program
362
- const xmlFile = this.assignFile(new XmlFile_1.XmlFile(srcPath, pkgPath, this));
363
- let event = {
364
- program: this,
365
- srcPath: srcPath,
366
- source: fileContents
367
- };
368
- this.plugins.emit('beforeFileParse', event);
369
- this.logger.time(Logger_1.LogLevel.debug, ['parse', chalk_1.default.green(srcPath)], () => {
370
- xmlFile.parse(event.source);
371
- });
372
- //notify plugins that this file has finished parsing
373
- this.plugins.emit('afterFileParse', {
374
- program: this,
375
- file: xmlFile
376
- });
377
- file = xmlFile;
378
- //create a new scope for this xml file
379
- let scope = new XmlScope_1.XmlScope(xmlFile, this);
380
- this.addScope(scope);
381
- //register this compoent now that we have parsed it and know its component name
382
- this.registerComponent(xmlFile, scope);
383
- //notify plugins that the scope is created and the component is registered
384
- this.plugins.emit('afterScopeCreate', {
385
- program: this,
386
- scope: scope
387
- });
453
+ //find the file instance for the srcPath that triggered this action.
454
+ const primaryFile = event.files.find(x => x.srcPath === srcPath);
455
+ if (!primaryFile) {
456
+ throw new Error(`No file provided for srcPath '${srcPath}'. Instead, received ${JSON.stringify(event.files.map(x => ({
457
+ type: x.type,
458
+ srcPath: x.srcPath,
459
+ destPath: x.destPath
460
+ })))}`);
388
461
  }
389
- else {
390
- //TODO do we actually need to implement this? Figure out how to handle img paths
391
- // let genericFile = this.files[srcPath] = <any>{
392
- // srcPath: srcPath,
393
- // pkgPath: pkgPath,
394
- // wasProcessed: true
395
- // } as File;
396
- // file = <any>genericFile;
462
+ //link the virtual files to the primary file
463
+ this.fileClusters.set((_a = primaryFile.srcPath) === null || _a === void 0 ? void 0 : _a.toLowerCase(), event.files);
464
+ for (const file of event.files) {
465
+ file.srcPath = (0, util_1.standardizePath)(file.srcPath);
466
+ if (file.destPath) {
467
+ file.destPath = (0, util_1.standardizePath) `${util_1.util.replaceCaseInsensitive(file.destPath, this.options.rootDir, '')}`;
468
+ }
469
+ if (file.pkgPath) {
470
+ file.pkgPath = (0, util_1.standardizePath) `${util_1.util.replaceCaseInsensitive(file.pkgPath, this.options.rootDir, '')}`;
471
+ }
472
+ else {
473
+ file.pkgPath = file.destPath;
474
+ }
475
+ file.excludeFromOutput = file.excludeFromOutput === true;
476
+ //set the dependencyGraph key for every file to its destPath
477
+ file.dependencyGraphKey = file.destPath.toLowerCase();
478
+ this.assignFile(file);
479
+ //register a callback anytime this file's dependencies change
480
+ if (typeof file.onDependenciesChanged === 'function') {
481
+ (_b = file.disposables) !== null && _b !== void 0 ? _b : (file.disposables = []);
482
+ file.disposables.push(this.dependencyGraph.onchange(file.dependencyGraphKey, file.onDependenciesChanged.bind(file)));
483
+ }
484
+ //register this file (and its dependencies) with the dependency graph
485
+ this.dependencyGraph.addOrReplace(file.dependencyGraphKey, (_c = file.dependencies) !== null && _c !== void 0 ? _c : []);
486
+ //if this is a `source` file, add it to the source scope's dependency list
487
+ if (this.isSourceBrsFile(file)) {
488
+ this.createSourceScope();
489
+ this.dependencyGraph.addDependency('scope:source', file.dependencyGraphKey);
490
+ }
491
+ //if this is an xml file in the components folder, register it as a component
492
+ if (this.isComponentsXmlFile(file)) {
493
+ //create a new scope for this xml file
494
+ let scope = new XmlScope_1.XmlScope(file, this);
495
+ this.addScope(scope);
496
+ //register this compoent now that we have parsed it and know its component name
497
+ this.registerComponent(file, scope);
498
+ //notify plugins that the scope is created and the component is registered
499
+ this.plugins.emit('afterScopeCreate', {
500
+ program: this,
501
+ scope: scope
502
+ });
503
+ }
397
504
  }
398
- return file;
505
+ return primaryFile;
399
506
  });
400
507
  return file;
401
508
  }
402
509
  /**
403
- * Given a srcPath, a pkgPath, or both, resolve whichever is missing, relative to rootDir.
510
+ * Given a srcPath, a destPath, or both, resolve whichever is missing, relative to rootDir.
404
511
  * @param fileParam an object representing file paths
405
512
  * @param rootDir must be a pre-normalized path
406
513
  */
407
514
  getPaths(fileParam, rootDir) {
408
515
  let srcPath;
409
- let pkgPath;
516
+ let destPath;
410
517
  assert.ok(fileParam, 'fileParam is required');
411
- //lift the srcPath and pkgPath vars from the incoming param
518
+ //lift the path vars from the incoming param
412
519
  if (typeof fileParam === 'string') {
413
520
  fileParam = this.removePkgPrefix(fileParam);
414
521
  srcPath = (0, util_1.standardizePath) `${path.resolve(rootDir, fileParam)}`;
415
- pkgPath = (0, util_1.standardizePath) `${util_1.util.replaceCaseInsensitive(srcPath, rootDir, '')}`;
522
+ destPath = (0, util_1.standardizePath) `${util_1.util.replaceCaseInsensitive(srcPath, rootDir, '')}`;
416
523
  }
417
524
  else {
418
525
  let param = fileParam;
@@ -423,30 +530,30 @@ class Program {
423
530
  srcPath = (0, util_1.standardizePath) `${param.srcPath}`;
424
531
  }
425
532
  if (param.dest) {
426
- pkgPath = (0, util_1.standardizePath) `${this.removePkgPrefix(param.dest)}`;
533
+ destPath = (0, util_1.standardizePath) `${this.removePkgPrefix(param.dest)}`;
427
534
  }
428
535
  if (param.pkgPath) {
429
- pkgPath = (0, util_1.standardizePath) `${this.removePkgPrefix(param.pkgPath)}`;
536
+ destPath = (0, util_1.standardizePath) `${this.removePkgPrefix(param.pkgPath)}`;
430
537
  }
431
538
  }
432
- //if there's no srcPath, use the pkgPath to build an absolute srcPath
539
+ //if there's no srcPath, use the destPath to build an absolute srcPath
433
540
  if (!srcPath) {
434
- srcPath = (0, util_1.standardizePath) `${rootDir}/${pkgPath}`;
541
+ srcPath = (0, util_1.standardizePath) `${rootDir}/${destPath}`;
435
542
  }
436
543
  //coerce srcPath to an absolute path
437
544
  if (!path.isAbsolute(srcPath)) {
438
545
  srcPath = util_1.util.standardizePath(srcPath);
439
546
  }
440
- //if there's no pkgPath, compute relative path from rootDir
441
- if (!pkgPath) {
442
- pkgPath = (0, util_1.standardizePath) `${util_1.util.replaceCaseInsensitive(srcPath, rootDir, '')}`;
547
+ //if destPath isn't set, compute it from the other paths
548
+ if (!destPath) {
549
+ destPath = (0, util_1.standardizePath) `${util_1.util.replaceCaseInsensitive(srcPath, rootDir, '')}`;
443
550
  }
444
551
  assert.ok(srcPath, 'fileEntry.src is required');
445
- assert.ok(pkgPath, 'fileEntry.dest is required');
552
+ assert.ok(destPath, 'fileEntry.dest is required');
446
553
  return {
447
554
  srcPath: srcPath,
448
- //remove leading slash from pkgPath
449
- pkgPath: pkgPath.replace(/^[\/\\]+/, '')
555
+ //remove leading slash
556
+ destPath: destPath.replace(/^[\/\\]+/, '')
450
557
  };
451
558
  }
452
559
  /**
@@ -455,6 +562,18 @@ class Program {
455
562
  removePkgPrefix(path) {
456
563
  return path.replace(/^pkg:\//i, '');
457
564
  }
565
+ /**
566
+ * Is this file a .brs file found somewhere within the `pkg:/source/` folder?
567
+ */
568
+ isSourceBrsFile(file) {
569
+ return !!/^(pkg:\/)?source[\/\\]/.exec(file.destPath);
570
+ }
571
+ /**
572
+ * Is this file a .brs file found somewhere within the `pkg:/source/` folder?
573
+ */
574
+ isComponentsXmlFile(file) {
575
+ return (0, reflection_1.isXmlFile)(file) && !!/^(pkg:\/)?components[\/\\]/.exec(file.destPath);
576
+ }
458
577
  /**
459
578
  * Ensure source scope is created.
460
579
  * Note: automatically called internally, and no-op if it exists already.
@@ -482,46 +601,55 @@ class Program {
482
601
  }
483
602
  /**
484
603
  * Remove a file from the program
485
- * @param filePath can be a srcPath, a pkgPath, or a destPath (same as pkgPath but without `pkg:/`)
604
+ * @param filePath can be a srcPath, a destPath, or a destPath with leading `pkg:/`
486
605
  * @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
487
606
  */
488
607
  removeFile(filePath, normalizePath = true) {
608
+ var _a, _b, _c, _d;
489
609
  this.logger.debug('Program.removeFile()', filePath);
490
- let file = this.getFile(filePath, normalizePath);
491
- if (file) {
492
- const fileDisposeEvent = {
493
- program: this,
494
- file: file
495
- };
496
- this.plugins.emit('beforeFileDispose', fileDisposeEvent);
610
+ const paths = this.getPaths(filePath, this.options.rootDir);
611
+ //there can be one or more File entries for a single srcPath, so get all of them and remove them all
612
+ const files = (_b = this.fileClusters.get((_a = paths.srcPath) === null || _a === void 0 ? void 0 : _a.toLowerCase())) !== null && _b !== void 0 ? _b : [this.getFile(filePath, normalizePath)];
613
+ for (const file of files) {
614
+ //if a file has already been removed, nothing more needs to be done here
615
+ if (!file || !this.hasFile(file.srcPath)) {
616
+ continue;
617
+ }
618
+ const event = { file: file, program: this };
619
+ this.plugins.emit('beforeFileRemove', event);
497
620
  //if there is a scope named the same as this file's path, remove it (i.e. xml scopes)
498
- let scope = this.scopes[file.pkgPath];
621
+ let scope = this.scopes[file.destPath];
499
622
  if (scope) {
500
623
  const scopeDisposeEvent = {
501
624
  program: this,
502
625
  scope: scope
503
626
  };
504
627
  this.plugins.emit('beforeScopeDispose', scopeDisposeEvent);
628
+ this.plugins.emit('onScopeDispose', scopeDisposeEvent);
505
629
  scope.dispose();
506
630
  //notify dependencies of this scope that it has been removed
507
631
  this.dependencyGraph.remove(scope.dependencyGraphKey);
508
- delete this.scopes[file.pkgPath];
632
+ delete this.scopes[file.destPath];
509
633
  this.plugins.emit('afterScopeDispose', scopeDisposeEvent);
510
634
  }
511
635
  //remove the file from the program
512
636
  this.unassignFile(file);
513
637
  this.dependencyGraph.remove(file.dependencyGraphKey);
514
638
  //if this is a pkg:/source file, notify the `source` scope that it has changed
515
- if (file.pkgPath.startsWith(startOfSourcePkgPath)) {
639
+ if (this.isSourceBrsFile(file)) {
516
640
  this.dependencyGraph.removeDependency('scope:source', file.dependencyGraphKey);
517
641
  }
518
642
  //if this is a component, remove it from our components map
519
643
  if ((0, reflection_1.isXmlFile)(file)) {
520
644
  this.unregisterComponent(file);
521
645
  }
646
+ //dispose any disposable things on the file
647
+ for (const disposable of (_c = file === null || file === void 0 ? void 0 : file.disposables) !== null && _c !== void 0 ? _c : []) {
648
+ disposable();
649
+ }
522
650
  //dispose file
523
- file === null || file === void 0 ? void 0 : file.dispose();
524
- this.plugins.emit('afterFileDispose', fileDisposeEvent);
651
+ (_d = file === null || file === void 0 ? void 0 : file.dispose) === null || _d === void 0 ? void 0 : _d.call(file);
652
+ this.plugins.emit('afterFileRemove', event);
525
653
  }
526
654
  }
527
655
  /**
@@ -534,6 +662,7 @@ class Program {
534
662
  program: this
535
663
  };
536
664
  this.plugins.emit('beforeProgramValidate', programValidateEvent);
665
+ this.plugins.emit('onProgramValidate', programValidateEvent);
537
666
  //validate every file
538
667
  for (const file of Object.values(this.files)) {
539
668
  //for every unvalidated file, validate it
@@ -549,6 +678,13 @@ class Program {
549
678
  this.plugins.emit('afterFileValidate', validateFileEvent);
550
679
  }
551
680
  }
681
+ // Build component types for any component that changes
682
+ this.logger.time(Logger_1.LogLevel.info, ['Build component types'], () => {
683
+ for (let { componentKey, componentName } of this.componentSymbolsToUpdate) {
684
+ this.updateComponentSymbolInGlobalScope(componentKey, componentName);
685
+ }
686
+ this.componentSymbolsToUpdate.clear();
687
+ });
552
688
  this.logger.time(Logger_1.LogLevel.info, ['Validate all scopes'], () => {
553
689
  for (let scopeName in this.scopes) {
554
690
  let scope = this.scopes[scopeName];
@@ -611,12 +747,13 @@ class Program {
611
747
  getFile(filePath, normalizePath = true) {
612
748
  if (typeof filePath !== 'string') {
613
749
  return undefined;
750
+ //is the path absolute (or the `virtual:` prefix)
614
751
  }
615
- else if (path.isAbsolute(filePath)) {
752
+ else if (/^(?:(?:virtual:[\/\\])|(?:\w:)|(?:[\/\\]))/gmi.exec(filePath)) {
616
753
  return this.files[(normalizePath ? util_1.util.standardizePath(filePath) : filePath).toLowerCase()];
617
754
  }
618
755
  else {
619
- return this.pkgMap[(normalizePath ? util_1.util.standardizePath(filePath) : filePath).toLowerCase()];
756
+ return this.destMap.get((normalizePath ? util_1.util.standardizePath(filePath) : filePath).toLowerCase());
620
757
  }
621
758
  }
622
759
  /**
@@ -658,7 +795,8 @@ class Program {
658
795
  //look through all files in scope for matches
659
796
  for (const scope of this.getScopesForFile(originFile)) {
660
797
  for (const file of scope.getAllFiles()) {
661
- if ((0, reflection_1.isXmlFile)(file) || filesSearched.has(file)) {
798
+ //skip non-brs files, or files we've already processed
799
+ if (!(0, reflection_1.isBrsFile)(file) || filesSearched.has(file)) {
662
800
  continue;
663
801
  }
664
802
  filesSearched.add(file);
@@ -691,7 +829,8 @@ class Program {
691
829
  }
692
830
  //look through all files in scope for matches
693
831
  for (const file of scope.getOwnFiles()) {
694
- if ((0, reflection_1.isXmlFile)(file) || filesSearched.has(file)) {
832
+ //skip non-brs files, or files we've already processed
833
+ if (!(0, reflection_1.isBrsFile)(file) || filesSearched.has(file)) {
695
834
  continue;
696
835
  }
697
836
  filesSearched.add(file);
@@ -840,10 +979,12 @@ class Program {
840
979
  getReferences(srcPath, position) {
841
980
  //find the file
842
981
  let file = this.getFile(srcPath);
843
- if (!file) {
982
+ if ((0, reflection_1.isBrsFile)(file) || (0, reflection_1.isXmlFile)(file)) {
983
+ return file.getReferences(position);
984
+ }
985
+ else {
844
986
  return null;
845
987
  }
846
- return file.getReferences(position);
847
988
  }
848
989
  /**
849
990
  * Transpile a single file and get the result as a string.
@@ -854,168 +995,211 @@ class Program {
854
995
  * @param filePath can be a srcPath or a destPath
855
996
  */
856
997
  async getTranspiledFileContents(filePath) {
857
- let fileMap = await roku_deploy_1.rokuDeploy.getFilePaths(this.options.files, this.options.rootDir);
858
- //remove files currently loaded in the program, we will transpile those instead (even if just for source maps)
859
- let filteredFileMap = [];
860
- for (let fileEntry of fileMap) {
861
- if (this.hasFile(fileEntry.src) === false) {
862
- filteredFileMap.push(fileEntry);
998
+ const file = this.getFile(filePath);
999
+ return this.getTranspiledFileContentsPipeline.run(async () => {
1000
+ const result = {
1001
+ destPath: file.destPath,
1002
+ pkgPath: file.pkgPath,
1003
+ srcPath: file.srcPath
1004
+ };
1005
+ const expectedPkgPath = file.pkgPath.toLowerCase();
1006
+ const expectedMapPath = `${expectedPkgPath}.map`;
1007
+ const expectedTypedefPkgPath = expectedPkgPath.replace(/\.brs$/i, '.d.bs');
1008
+ //add a temporary plugin to tap into the file writing process
1009
+ const plugin = this.plugins.addFirst({
1010
+ name: 'getTranspiledFileContents',
1011
+ beforeWriteFile: (event) => {
1012
+ const pkgPath = event.file.pkgPath.toLowerCase();
1013
+ switch (pkgPath) {
1014
+ //this is the actual transpiled file
1015
+ case expectedPkgPath:
1016
+ result.code = event.file.data.toString();
1017
+ break;
1018
+ //this is the sourcemap
1019
+ case expectedMapPath:
1020
+ result.map = event.file.data.toString();
1021
+ break;
1022
+ //this is the typedef
1023
+ case expectedTypedefPkgPath:
1024
+ result.typedef = event.file.data.toString();
1025
+ break;
1026
+ default:
1027
+ //no idea what this file is. just ignore it
1028
+ }
1029
+ //mark every file as processed so it they don't get written to the output directory
1030
+ event.processedFiles.add(event.file);
1031
+ }
1032
+ });
1033
+ try {
1034
+ //now that the plugin has been registered, run the build with just this file
1035
+ await this.build({
1036
+ files: [file]
1037
+ });
1038
+ }
1039
+ finally {
1040
+ this.plugins.remove(plugin);
863
1041
  }
1042
+ return result;
1043
+ });
1044
+ }
1045
+ /**
1046
+ * Get the absolute output path for a file
1047
+ */
1048
+ getOutputPath(file, stagingDir = this.getStagingDir()) {
1049
+ return (0, util_1.standardizePath) `${stagingDir}/${file.pkgPath}`;
1050
+ }
1051
+ getStagingDir(stagingDir) {
1052
+ var _a, _b;
1053
+ let result = (_a = stagingDir !== null && stagingDir !== void 0 ? stagingDir : this.options.stagingDir) !== null && _a !== void 0 ? _a : this.options.stagingDir;
1054
+ if (!result) {
1055
+ result = roku_deploy_1.rokuDeploy.getOptions(this.options).stagingDir;
864
1056
  }
865
- const { entries, astEditor } = this.beforeProgramTranspile(fileMap, this.options.stagingDir);
866
- const result = this._getTranspiledFileContents(this.getFile(filePath));
867
- this.afterProgramTranspile(entries, astEditor);
1057
+ result = (0, util_1.standardizePath) `${path.resolve((_b = this.options.cwd) !== null && _b !== void 0 ? _b : process.cwd(), result !== null && result !== void 0 ? result : '/')}`;
868
1058
  return result;
869
1059
  }
870
1060
  /**
871
- * Internal function used to transpile files.
872
- * This does not write anything to the file system
1061
+ * Prepare the program for building
1062
+ * @param files the list of files that should be prepared
873
1063
  */
874
- _getTranspiledFileContents(file, outputPath) {
875
- const editor = new AstEditor_1.AstEditor();
876
- this.plugins.emit('beforeFileTranspile', {
877
- program: this,
878
- file: file,
879
- outputPath: outputPath,
880
- editor: editor
881
- });
882
- //if we have any edits, assume the file needs to be transpiled
883
- if (editor.hasChanges) {
884
- //use the `editor` because it'll track the previous value for us and revert later on
885
- editor.setProperty(file, 'needsTranspiled', true);
886
- }
887
- //transpile the file
888
- const result = file.transpile();
889
- //generate the typedef if enabled
890
- let typedef;
891
- if ((0, reflection_1.isBrsFile)(file) && this.options.emitDefinitions) {
892
- typedef = file.getTypedef();
893
- }
894
- const event = {
1064
+ async prepare(files) {
1065
+ const programEvent = {
895
1066
  program: this,
896
- file: file,
897
- outputPath: outputPath,
898
- editor: editor,
899
- code: result.code,
900
- map: result.map,
901
- typedef: typedef
902
- };
903
- this.plugins.emit('afterFileTranspile', event);
904
- //undo all `editor` edits that may have been applied to this file.
905
- editor.undoAll();
906
- return {
907
- srcPath: file.srcPath,
908
- pkgPath: file.pkgPath,
909
- code: event.code,
910
- map: event.map,
911
- typedef: event.typedef
1067
+ editor: this.editor,
1068
+ files: files
912
1069
  };
913
- }
914
- beforeProgramTranspile(fileEntries, stagingDir) {
915
- // map fileEntries using their path as key, to avoid excessive "find()" operations
916
- const mappedFileEntries = fileEntries.reduce((collection, entry) => {
917
- collection[(0, util_1.standardizePath) `${entry.src}`] = entry;
918
- return collection;
919
- }, {});
920
- const getOutputPath = (file) => {
921
- let filePathObj = mappedFileEntries[(0, util_1.standardizePath) `${file.srcPath}`];
922
- if (!filePathObj) {
923
- //this file has been added in-memory, from a plugin, for example
924
- filePathObj = {
925
- //add an interpolated src path (since it doesn't actually exist in memory)
926
- src: `bsc:/${file.pkgPath}`,
927
- dest: file.pkgPath
928
- };
1070
+ //assign an editor to every file
1071
+ for (const file of files) {
1072
+ //if the file doesn't have an editor yet, assign one now
1073
+ if (!file.editor) {
1074
+ file.editor = new Editor_1.Editor();
929
1075
  }
930
- //replace the file extension
931
- let outputPath = filePathObj.dest.replace(/\.bs$/gi, '.brs');
932
- //prepend the staging folder path
933
- outputPath = (0, util_1.standardizePath) `${stagingDir}/${outputPath}`;
934
- return outputPath;
935
- };
936
- const entries = Object.values(this.files).map(file => {
937
- return {
1076
+ }
1077
+ files.sort((a, b) => {
1078
+ if (a.pkgPath < b.pkgPath) {
1079
+ return -1;
1080
+ }
1081
+ else if (a.pkgPath > b.pkgPath) {
1082
+ return 1;
1083
+ }
1084
+ else {
1085
+ return 1;
1086
+ }
1087
+ });
1088
+ await this.plugins.emitAsync('beforePrepareProgram', programEvent);
1089
+ await this.plugins.emitAsync('prepareProgram', programEvent);
1090
+ const stagingDir = this.getStagingDir();
1091
+ const entries = [];
1092
+ for (const file of files) {
1093
+ //if the file doesn't have an editor yet, assign one now
1094
+ if (!file.editor) {
1095
+ file.editor = new Editor_1.Editor();
1096
+ }
1097
+ const event = {
1098
+ program: this,
938
1099
  file: file,
939
- outputPath: getOutputPath(file)
1100
+ editor: file.editor,
1101
+ outputPath: this.getOutputPath(file, stagingDir)
940
1102
  };
941
- //sort the entries to make transpiling more deterministic
942
- }).sort((a, b) => {
943
- return a.file.srcPath < b.file.srcPath ? -1 : 1;
1103
+ await this.plugins.emitAsync('beforePrepareFile', event);
1104
+ await this.plugins.emitAsync('prepareFile', event);
1105
+ await this.plugins.emitAsync('afterPrepareFile', event);
1106
+ //TODO remove this in v1
1107
+ entries.push(event);
1108
+ }
1109
+ await this.plugins.emitAsync('afterPrepareProgram', programEvent);
1110
+ return files;
1111
+ }
1112
+ /**
1113
+ * Generate the contents of every file
1114
+ */
1115
+ async serialize(files) {
1116
+ const allFiles = new Map();
1117
+ const serializeProgramEvent = await this.plugins.emitAsync('beforeSerializeProgram', {
1118
+ program: this,
1119
+ files: files,
1120
+ result: allFiles
944
1121
  });
945
- const astEditor = new AstEditor_1.AstEditor();
946
- this.plugins.emit('beforeProgramTranspile', {
1122
+ await this.plugins.emitAsync('onSerializeProgram', {
947
1123
  program: this,
948
- entries: entries,
949
- editor: astEditor
1124
+ files: files,
1125
+ result: allFiles
950
1126
  });
951
- return {
952
- entries: entries,
953
- getOutputPath: getOutputPath,
954
- astEditor: astEditor
955
- };
956
- }
957
- async transpile(fileEntries, stagingDir) {
958
- const { entries, getOutputPath, astEditor } = this.beforeProgramTranspile(fileEntries, stagingDir);
959
- const processedFiles = new Set();
960
- const transpileFile = async (srcPath, outputPath) => {
961
- //find the file in the program
962
- const file = this.getFile(srcPath);
963
- //mark this file as processed so we don't process it more than once
964
- processedFiles.add(outputPath === null || outputPath === void 0 ? void 0 : outputPath.toLowerCase());
965
- //skip transpiling typedef files
966
- if ((0, reflection_1.isBrsFile)(file) && file.isTypedef) {
967
- return;
968
- }
969
- const fileTranspileResult = this._getTranspiledFileContents(file, outputPath);
970
- //make sure the full dir path exists
971
- await fsExtra.ensureDir(path.dirname(outputPath));
972
- if (await fsExtra.pathExists(outputPath)) {
973
- throw new Error(`Error while transpiling "${file.srcPath}". A file already exists at "${outputPath}" and will not be overwritten.`);
974
- }
975
- const writeMapPromise = fileTranspileResult.map ? fsExtra.writeFile(`${outputPath}.map`, fileTranspileResult.map.toString()) : null;
976
- await Promise.all([
977
- fsExtra.writeFile(outputPath, fileTranspileResult.code),
978
- writeMapPromise
979
- ]);
980
- if (fileTranspileResult.typedef) {
981
- const typedefPath = outputPath.replace(/\.brs$/i, '.d.bs');
982
- await fsExtra.writeFile(typedefPath, fileTranspileResult.typedef);
983
- }
984
- };
985
- let promises = entries.map(async (entry) => {
986
- var _a;
987
- return transpileFile((_a = entry === null || entry === void 0 ? void 0 : entry.file) === null || _a === void 0 ? void 0 : _a.srcPath, entry.outputPath);
1127
+ //sort the entries to make transpiling more deterministic
1128
+ files = serializeProgramEvent.files.sort((a, b) => {
1129
+ return a.srcPath < b.srcPath ? -1 : 1;
988
1130
  });
989
- //if there's no bslib file already loaded into the program, copy it to the staging directory
990
- if (!this.getFile(bslibAliasedRokuModulesPkgPath) && !this.getFile((0, util_1.standardizePath) `source/bslib.brs`)) {
991
- promises.push(util_1.util.copyBslibToStaging(stagingDir));
1131
+ // serialize each file
1132
+ for (const file of files) {
1133
+ const event = {
1134
+ program: this,
1135
+ file: file,
1136
+ result: allFiles
1137
+ };
1138
+ await this.plugins.emitAsync('beforeSerializeFile', event);
1139
+ await this.plugins.emitAsync('serializeFile', event);
1140
+ await this.plugins.emitAsync('afterSerializeFile', event);
992
1141
  }
993
- await Promise.all(promises);
994
- //transpile any new files that plugins added since the start of this transpile process
995
- do {
996
- promises = [];
997
- for (const key in this.files) {
998
- const file = this.files[key];
999
- //this is a new file
1000
- const outputPath = getOutputPath(file);
1001
- if (!processedFiles.has(outputPath === null || outputPath === void 0 ? void 0 : outputPath.toLowerCase())) {
1002
- promises.push(transpileFile(file === null || file === void 0 ? void 0 : file.srcPath, outputPath));
1003
- }
1004
- }
1005
- if (promises.length > 0) {
1006
- this.logger.info(`Transpiling ${promises.length} new files`);
1007
- await Promise.all(promises);
1008
- }
1009
- } while (promises.length > 0);
1010
- this.afterProgramTranspile(entries, astEditor);
1142
+ this.plugins.emit('afterSerializeProgram', {
1143
+ program: this,
1144
+ files: files,
1145
+ result: allFiles
1146
+ });
1147
+ return allFiles;
1011
1148
  }
1012
- afterProgramTranspile(entries, astEditor) {
1013
- this.plugins.emit('afterProgramTranspile', {
1149
+ /**
1150
+ * Write the entire project to disk
1151
+ */
1152
+ async write(stagingDir, files) {
1153
+ const programEvent = await this.plugins.emitAsync('beforeWriteProgram', {
1014
1154
  program: this,
1015
- entries: entries,
1016
- editor: astEditor
1155
+ files: files,
1156
+ stagingDir: stagingDir
1157
+ });
1158
+ //empty the staging directory
1159
+ await fsExtra.emptyDir(stagingDir);
1160
+ const serializedFiles = [...files]
1161
+ .map(([, serializedFiles]) => serializedFiles)
1162
+ .flat();
1163
+ //write all the files to disk (asynchronously)
1164
+ await Promise.all(serializedFiles.map(async (file) => {
1165
+ const event = await this.plugins.emitAsync('beforeWriteFile', {
1166
+ program: this,
1167
+ file: file,
1168
+ outputPath: this.getOutputPath(file, stagingDir),
1169
+ processedFiles: new Set()
1170
+ });
1171
+ await this.plugins.emitAsync('writeFile', event);
1172
+ await this.plugins.emitAsync('afterWriteFile', event);
1173
+ }));
1174
+ await this.plugins.emitAsync('afterWriteProgram', programEvent);
1175
+ }
1176
+ /**
1177
+ * Build the project. This transpiles/transforms/copies all files and moves them to the staging directory
1178
+ * @param options the list of options used to build the program
1179
+ */
1180
+ async build(options) {
1181
+ //run a single build at a time
1182
+ await this.buildPipeline.run(async () => {
1183
+ var _a;
1184
+ const stagingDir = this.getStagingDir(options === null || options === void 0 ? void 0 : options.stagingDir);
1185
+ const event = await this.plugins.emitAsync('beforeBuildProgram', {
1186
+ program: this,
1187
+ editor: this.editor,
1188
+ files: (_a = options === null || options === void 0 ? void 0 : options.files) !== null && _a !== void 0 ? _a : Object.values(this.files)
1189
+ });
1190
+ //prepare the program (and files) for building
1191
+ event.files = await this.prepare(event.files);
1192
+ //stage the entire program
1193
+ const serializedFilesByFile = await this.serialize(event.files);
1194
+ await this.write(stagingDir, serializedFilesByFile);
1195
+ await this.plugins.emitAsync('afterBuildProgram', event);
1196
+ //undo all edits for the program
1197
+ this.editor.undoAll();
1198
+ //undo all edits for each file
1199
+ for (const file of event.files) {
1200
+ file.editor.undoAll();
1201
+ }
1017
1202
  });
1018
- astEditor.undoAll();
1019
1203
  }
1020
1204
  /**
1021
1205
  * Find a list of files in the program that have a function with the given name (case INsensitive)
@@ -1090,6 +1274,7 @@ class Program {
1090
1274
  * Get a map of the manifest information
1091
1275
  */
1092
1276
  getManifest() {
1277
+ var _a, _b;
1093
1278
  if (!this._manifest) {
1094
1279
  //load the manifest file.
1095
1280
  //TODO update this to get the manifest from the files array or require it in the options...we shouldn't assume the location of the manifest
@@ -1098,7 +1283,27 @@ class Program {
1098
1283
  try {
1099
1284
  //we only load this manifest once, so do it sync to improve speed downstream
1100
1285
  contents = fsExtra.readFileSync(manifestPath, 'utf-8');
1101
- this._manifest = (0, Manifest_1.parseManifest)(contents);
1286
+ let parsedManifest = (0, Manifest_1.parseManifest)(contents);
1287
+ // Lift the bs_consts defined in the manifest
1288
+ let bsConsts = (0, Manifest_1.getBsConst)(parsedManifest, false);
1289
+ // Override or delete any bs_consts defined in the bs config
1290
+ for (const key in (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.manifest) === null || _b === void 0 ? void 0 : _b.bs_const) {
1291
+ const value = this.options.manifest.bs_const[key];
1292
+ if (value === null) {
1293
+ bsConsts.delete(key);
1294
+ }
1295
+ else {
1296
+ bsConsts.set(key, value);
1297
+ }
1298
+ }
1299
+ // convert the new list of bs consts back into a string for the rest of the down stream systems to use
1300
+ let constString = '';
1301
+ for (const [key, value] of bsConsts) {
1302
+ constString += `${constString !== '' ? ';' : ''}${key}=${value.toString()}`;
1303
+ }
1304
+ // Set the updated bs_const value
1305
+ parsedManifest.set('bs_const', constString);
1306
+ this._manifest = parsedManifest;
1102
1307
  }
1103
1308
  catch (err) {
1104
1309
  this._manifest = new Map();
@@ -1107,16 +1312,29 @@ class Program {
1107
1312
  return this._manifest;
1108
1313
  }
1109
1314
  dispose() {
1315
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1110
1316
  this.plugins.emit('beforeProgramDispose', { program: this });
1111
1317
  for (let filePath in this.files) {
1112
- this.files[filePath].dispose();
1318
+ (_b = (_a = this.files[filePath]) === null || _a === void 0 ? void 0 : _a.dispose) === null || _b === void 0 ? void 0 : _b.call(_a);
1113
1319
  }
1114
1320
  for (let name in this.scopes) {
1115
- this.scopes[name].dispose();
1321
+ (_d = (_c = this.scopes[name]) === null || _c === void 0 ? void 0 : _c.dispose) === null || _d === void 0 ? void 0 : _d.call(_c);
1116
1322
  }
1117
- this.globalScope.dispose();
1118
- this.dependencyGraph.dispose();
1323
+ (_f = (_e = this.globalScope) === null || _e === void 0 ? void 0 : _e.dispose) === null || _f === void 0 ? void 0 : _f.call(_e);
1324
+ (_h = (_g = this.dependencyGraph) === null || _g === void 0 ? void 0 : _g.dispose) === null || _h === void 0 ? void 0 : _h.call(_g);
1119
1325
  }
1120
1326
  }
1121
1327
  exports.Program = Program;
1328
+ class ProvideFileEventInternal {
1329
+ constructor(program, srcPath, destPath, data, fileFactory) {
1330
+ var _a;
1331
+ this.program = program;
1332
+ this.srcPath = srcPath;
1333
+ this.destPath = destPath;
1334
+ this.data = data;
1335
+ this.fileFactory = fileFactory;
1336
+ this.files = [];
1337
+ this.srcExtension = (_a = path.extname(srcPath)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
1338
+ }
1339
+ }
1122
1340
  //# sourceMappingURL=Program.js.map