brighterscript 0.41.2 → 1.0.0-alpha.12

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 (170) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/README.md +2 -2
  3. package/dist/DiagnosticCollection.js +2 -2
  4. package/dist/DiagnosticCollection.js.map +1 -1
  5. package/dist/DiagnosticFilterer.js +2 -2
  6. package/dist/DiagnosticFilterer.js.map +1 -1
  7. package/dist/DiagnosticMessages.d.ts +6 -1
  8. package/dist/DiagnosticMessages.js +5 -0
  9. package/dist/DiagnosticMessages.js.map +1 -1
  10. package/dist/LanguageServer.d.ts +8 -2
  11. package/dist/LanguageServer.js +50 -44
  12. package/dist/LanguageServer.js.map +1 -1
  13. package/dist/Program.d.ts +61 -45
  14. package/dist/Program.js +305 -188
  15. package/dist/Program.js.map +1 -1
  16. package/dist/ProgramBuilder.d.ts +7 -7
  17. package/dist/ProgramBuilder.js +60 -51
  18. package/dist/ProgramBuilder.js.map +1 -1
  19. package/dist/Scope.d.ts +42 -19
  20. package/dist/Scope.js +261 -129
  21. package/dist/Scope.js.map +1 -1
  22. package/dist/SymbolTable.d.ts +73 -0
  23. package/dist/SymbolTable.js +157 -0
  24. package/dist/SymbolTable.js.map +1 -0
  25. package/dist/XmlScope.d.ts +5 -0
  26. package/dist/XmlScope.js +66 -28
  27. package/dist/XmlScope.js.map +1 -1
  28. package/dist/astUtils/creators.d.ts +15 -1
  29. package/dist/astUtils/creators.js +39 -9
  30. package/dist/astUtils/creators.js.map +1 -1
  31. package/dist/astUtils/reflection.d.ts +28 -16
  32. package/dist/astUtils/reflection.js +52 -30
  33. package/dist/astUtils/reflection.js.map +1 -1
  34. package/dist/astUtils/reflection.spec.js +3 -3
  35. package/dist/astUtils/reflection.spec.js.map +1 -1
  36. package/dist/astUtils/visitors.spec.js +12 -13
  37. package/dist/astUtils/visitors.spec.js.map +1 -1
  38. package/dist/astUtils/xml.d.ts +3 -3
  39. package/dist/astUtils/xml.js +2 -2
  40. package/dist/astUtils/xml.js.map +1 -1
  41. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +5 -6
  42. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  43. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +24 -22
  44. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
  45. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.spec.js +2 -2
  46. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.spec.js.map +1 -1
  47. package/dist/examples/plugins/removePrint.js +1 -1
  48. package/dist/examples/plugins/removePrint.js.map +1 -1
  49. package/dist/files/BrsFile.Class.spec.js +356 -41
  50. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  51. package/dist/files/BrsFile.d.ts +55 -37
  52. package/dist/files/BrsFile.js +430 -399
  53. package/dist/files/BrsFile.js.map +1 -1
  54. package/dist/files/BrsFile.spec.js +199 -158
  55. package/dist/files/BrsFile.spec.js.map +1 -1
  56. package/dist/files/XmlFile.d.ts +20 -9
  57. package/dist/files/XmlFile.js +36 -31
  58. package/dist/files/XmlFile.js.map +1 -1
  59. package/dist/files/XmlFile.spec.js +113 -113
  60. package/dist/files/XmlFile.spec.js.map +1 -1
  61. package/dist/files/tests/imports.spec.js +32 -32
  62. package/dist/files/tests/imports.spec.js.map +1 -1
  63. package/dist/globalCallables.js +17 -6
  64. package/dist/globalCallables.js.map +1 -1
  65. package/dist/interfaces.d.ts +155 -39
  66. package/dist/parser/BrsTranspileState.d.ts +7 -0
  67. package/dist/parser/BrsTranspileState.js +10 -1
  68. package/dist/parser/BrsTranspileState.js.map +1 -1
  69. package/dist/parser/Expression.d.ts +23 -12
  70. package/dist/parser/Expression.js +45 -30
  71. package/dist/parser/Expression.js.map +1 -1
  72. package/dist/parser/Parser.Class.spec.js +100 -1
  73. package/dist/parser/Parser.Class.spec.js.map +1 -1
  74. package/dist/parser/Parser.d.ts +118 -5
  75. package/dist/parser/Parser.js +398 -37
  76. package/dist/parser/Parser.js.map +1 -1
  77. package/dist/parser/Parser.spec.js +404 -7
  78. package/dist/parser/Parser.spec.js.map +1 -1
  79. package/dist/parser/SGParser.d.ts +41 -4
  80. package/dist/parser/SGParser.js +185 -174
  81. package/dist/parser/SGParser.js.map +1 -1
  82. package/dist/parser/SGParser.spec.js +17 -4
  83. package/dist/parser/SGParser.spec.js.map +1 -1
  84. package/dist/parser/SGTypes.d.ts +203 -38
  85. package/dist/parser/SGTypes.js +464 -160
  86. package/dist/parser/SGTypes.js.map +1 -1
  87. package/dist/parser/SGTypes.spec.d.ts +1 -0
  88. package/dist/parser/SGTypes.spec.js +351 -0
  89. package/dist/parser/SGTypes.spec.js.map +1 -0
  90. package/dist/parser/Statement.d.ts +37 -26
  91. package/dist/parser/Statement.js +81 -20
  92. package/dist/parser/Statement.js.map +1 -1
  93. package/dist/parser/Statement.spec.js +5 -5
  94. package/dist/parser/Statement.spec.js.map +1 -1
  95. package/dist/parser/TranspileState.d.ts +1 -1
  96. package/dist/parser/TranspileState.js +15 -7
  97. package/dist/parser/TranspileState.js.map +1 -1
  98. package/dist/parser/tests/controlFlow/ForEach.spec.js +5 -4
  99. package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
  100. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +1 -1
  101. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  102. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +1 -1
  103. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -1
  104. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +1 -1
  105. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  106. package/dist/parser/tests/expression/TernaryExpression.spec.js +1 -1
  107. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  108. package/dist/types/ArrayType.d.ts +1 -0
  109. package/dist/types/ArrayType.js +23 -19
  110. package/dist/types/ArrayType.js.map +1 -1
  111. package/dist/types/BooleanType.d.ts +3 -2
  112. package/dist/types/BooleanType.js +6 -3
  113. package/dist/types/BooleanType.js.map +1 -1
  114. package/dist/types/BscType.d.ts +19 -4
  115. package/dist/types/BscType.js +9 -0
  116. package/dist/types/BscType.js.map +1 -1
  117. package/dist/types/CustomType.d.ts +8 -5
  118. package/dist/types/CustomType.js +12 -12
  119. package/dist/types/CustomType.js.map +1 -1
  120. package/dist/types/DoubleType.d.ts +1 -0
  121. package/dist/types/DoubleType.js +11 -11
  122. package/dist/types/DoubleType.js.map +1 -1
  123. package/dist/types/DynamicType.d.ts +1 -0
  124. package/dist/types/DynamicType.js +4 -0
  125. package/dist/types/DynamicType.js.map +1 -1
  126. package/dist/types/FloatType.d.ts +2 -1
  127. package/dist/types/FloatType.js +11 -11
  128. package/dist/types/FloatType.js.map +1 -1
  129. package/dist/types/FunctionType.d.ts +13 -10
  130. package/dist/types/FunctionType.js +34 -18
  131. package/dist/types/FunctionType.js.map +1 -1
  132. package/dist/types/FunctionType.spec.js +8 -2
  133. package/dist/types/FunctionType.spec.js.map +1 -1
  134. package/dist/types/IntegerType.d.ts +2 -1
  135. package/dist/types/IntegerType.js +11 -11
  136. package/dist/types/IntegerType.js.map +1 -1
  137. package/dist/types/InvalidType.d.ts +3 -2
  138. package/dist/types/InvalidType.js +7 -4
  139. package/dist/types/InvalidType.js.map +1 -1
  140. package/dist/types/LazyType.d.ts +17 -0
  141. package/dist/types/LazyType.js +44 -0
  142. package/dist/types/LazyType.js.map +1 -0
  143. package/dist/types/LongIntegerType.d.ts +2 -1
  144. package/dist/types/LongIntegerType.js +11 -11
  145. package/dist/types/LongIntegerType.js.map +1 -1
  146. package/dist/types/ObjectType.d.ts +6 -2
  147. package/dist/types/ObjectType.js +9 -3
  148. package/dist/types/ObjectType.js.map +1 -1
  149. package/dist/types/StringType.d.ts +3 -2
  150. package/dist/types/StringType.js +6 -3
  151. package/dist/types/StringType.js.map +1 -1
  152. package/dist/types/UninitializedType.d.ts +4 -2
  153. package/dist/types/UninitializedType.js +8 -3
  154. package/dist/types/UninitializedType.js.map +1 -1
  155. package/dist/types/VoidType.d.ts +3 -2
  156. package/dist/types/VoidType.js +6 -3
  157. package/dist/types/VoidType.js.map +1 -1
  158. package/dist/types/helpers.d.ts +42 -0
  159. package/dist/types/helpers.js +113 -0
  160. package/dist/types/helpers.js.map +1 -0
  161. package/dist/util.d.ts +68 -15
  162. package/dist/util.js +193 -45
  163. package/dist/util.js.map +1 -1
  164. package/dist/validators/ClassValidator.d.ts +5 -1
  165. package/dist/validators/ClassValidator.js +31 -17
  166. package/dist/validators/ClassValidator.js.map +1 -1
  167. package/package.json +1 -1
  168. package/dist/FunctionScope.d.ts +0 -27
  169. package/dist/FunctionScope.js +0 -49
  170. package/dist/FunctionScope.js.map +0 -1
package/dist/Program.js CHANGED
@@ -23,9 +23,9 @@ 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 = (0, util_1.standardizePath) `source/roku_modules/rokucommunity_bslib/bslib.brs`;
28
- const bslibAliasedRokuModulesPkgPath = (0, util_1.standardizePath) `source/roku_modules/bslib/bslib.brs`;
26
+ const roku_deploy_1 = require("roku-deploy");
27
+ const bslibNonAliasedRokuModulesPkgPath = `pkg:/source/roku_modules/rokucommunity_bslib/bslib.brs`;
28
+ const bslibAliasedRokuModulesPkgPath = `pkg:/source/roku_modules/bslib/bslib.brs`;
29
29
  class Program {
30
30
  constructor(
31
31
  /**
@@ -47,10 +47,13 @@ class Program {
47
47
  */
48
48
  this.diagnostics = [];
49
49
  /**
50
- * A map of every file loaded into this program, indexed by its original file location
50
+ * A map of every file loaded ino this program, indexed by its lower-case pkgPath
51
51
  */
52
- this.files = {};
53
52
  this.pkgMap = {};
53
+ /**
54
+ * A map of every file loaded into this program, indexed by its lower-case srcPath
55
+ */
56
+ this.files = {};
54
57
  this.scopes = {};
55
58
  /**
56
59
  * A map of every component currently loaded into the program, indexed by the component name.
@@ -86,16 +89,16 @@ class Program {
86
89
  */
87
90
  get bslibPkgPath() {
88
91
  //if there's an aliased (preferred) version of bslib from roku_modules loaded into the program, use that
89
- if (this.getFileByPkgPath(bslibAliasedRokuModulesPkgPath)) {
92
+ if (this.getFile(bslibAliasedRokuModulesPkgPath)) {
90
93
  return bslibAliasedRokuModulesPkgPath;
91
94
  //if there's a non-aliased version of bslib from roku_modules, use that
92
95
  }
93
- else if (this.getFileByPkgPath(bslibNonAliasedRokuModulesPkgPath)) {
96
+ else if (this.getFile(bslibNonAliasedRokuModulesPkgPath)) {
94
97
  return bslibNonAliasedRokuModulesPkgPath;
95
98
  //default to the embedded version
96
99
  }
97
100
  else {
98
- return `source${path.sep}bslib.brs`;
101
+ return `pkg:/source/bslib.brs`;
99
102
  }
100
103
  }
101
104
  get bslibPrefix() {
@@ -106,9 +109,18 @@ class Program {
106
109
  return 'bslib';
107
110
  }
108
111
  }
112
+ /**
113
+ * Get a copy of the list of files currently loaded in the program
114
+ */
115
+ getFiles() {
116
+ return Object.values(this.files);
117
+ }
109
118
  addScope(scope) {
110
119
  this.scopes[scope.name] = scope;
111
- this.plugins.emit('afterScopeCreate', scope);
120
+ this.plugins.emit('afterScopeCreate', {
121
+ program: this,
122
+ scope: scope
123
+ });
112
124
  }
113
125
  /**
114
126
  * Get the component with the specified name
@@ -178,8 +190,8 @@ class Program {
178
190
  */
179
191
  getUnreferencedFiles() {
180
192
  let result = [];
181
- for (let filePath in this.files) {
182
- let file = this.files[filePath];
193
+ for (let key in this.files) {
194
+ const file = this.files[key];
183
195
  if (!this.fileIsIncludedInAnyScope(file)) {
184
196
  //no scopes reference this file. add it to the list
185
197
  result.push(file);
@@ -219,13 +231,10 @@ class Program {
219
231
  /**
220
232
  * Determine if the specified file is loaded in this program right now.
221
233
  * @param filePath
234
+ * @param normalizePath should the provided path be normalized before use
222
235
  */
223
- hasFile(filePath) {
224
- filePath = (0, util_1.standardizePath) `${filePath}`;
225
- return this.files[filePath] !== undefined;
226
- }
227
- getPkgPath(...args) {
228
- throw new Error('Not implemented');
236
+ hasFile(filePath, normalizePath = true) {
237
+ return !!this.getFile(filePath, normalizePath);
229
238
  }
230
239
  /**
231
240
  * roku filesystem is case INsensitive, so find the scope by key case insensitive
@@ -235,9 +244,6 @@ class Program {
235
244
  if (!scopeName) {
236
245
  return undefined;
237
246
  }
238
- //most scopes are xml file pkg paths. however, the ones that are not are single names like "global" and "scope",
239
- //so it's safe to run the standardizePkgPath method
240
- scopeName = (0, util_1.standardizePath) `${scopeName}`;
241
247
  let key = Object.keys(this.scopes).find(x => x.toLowerCase() === scopeName.toLowerCase());
242
248
  return this.scopes[key];
243
249
  }
@@ -254,65 +260,94 @@ class Program {
254
260
  var _a;
255
261
  return (_a = this.getComponent(componentName)) === null || _a === void 0 ? void 0 : _a.scope;
256
262
  }
257
- addOrReplaceFile(fileParam, fileContents) {
258
- assert.ok(fileParam, 'fileEntry is required');
263
+ /**
264
+ * Update internal maps with this file reference
265
+ */
266
+ assignFile(file) {
267
+ this.files[file.srcPath.toLowerCase()] = file;
268
+ this.pkgMap[file.pkgPath.toLowerCase()] = file;
269
+ }
270
+ /**
271
+ * Remove this file from internal maps
272
+ */
273
+ unassignFile(file) {
274
+ delete this.files[file.srcPath.toLowerCase()];
275
+ delete this.pkgMap[file.pkgPath.toLowerCase()];
276
+ }
277
+ setFile(fileParam, fileContents) {
278
+ assert.ok(fileParam, 'fileParam is required');
259
279
  let srcPath;
260
280
  let pkgPath;
261
281
  if (typeof fileParam === 'string') {
262
- srcPath = (0, util_1.standardizePath) `${this.options.rootDir}/${fileParam}`;
263
- pkgPath = (0, util_1.standardizePath) `${fileParam}`;
282
+ //is a pkg path
283
+ if (fileParam.startsWith('pkg:/')) {
284
+ //srcPath is the pkgPath relative to the rootDir
285
+ srcPath = (0, util_1.standardizePath) `${this.options.rootDir}/${fileParam.substring(5)}`;
286
+ pkgPath = fileParam;
287
+ //is a srcPath (absolute path to src file location)
288
+ }
289
+ else if (path.isAbsolute(fileParam)) {
290
+ srcPath = util_1.util.standardizePath(fileParam);
291
+ //assume the file path is a sub path of rootDir
292
+ pkgPath = util_1.util.sanitizePkgPath(roku_deploy_1.util.stringReplaceInsensitive(srcPath, this.options.rootDir, ''));
293
+ //is destPath (path relative to rootDir and `pkg:/`)
294
+ }
295
+ else {
296
+ srcPath = (0, util_1.standardizePath) `${this.options.rootDir}/${fileParam}`;
297
+ pkgPath = util_1.util.sanitizePkgPath(fileParam);
298
+ }
299
+ //is a FileObj
264
300
  }
265
301
  else {
266
302
  srcPath = (0, util_1.standardizePath) `${fileParam.src}`;
267
- pkgPath = (0, util_1.standardizePath) `${fileParam.dest}`;
303
+ pkgPath = util_1.util.sanitizePkgPath(fileParam.dest);
268
304
  }
269
- let file = this.logger.time(Logger_1.LogLevel.debug, ['Program.addOrReplaceFile()', chalk_1.default.green(srcPath)], () => {
270
- assert.ok(srcPath, 'fileEntry.src is required');
271
- assert.ok(pkgPath, 'fileEntry.dest is required');
305
+ const lowerPkgPath = pkgPath.toLowerCase();
306
+ return this.logger.time(Logger_1.LogLevel.debug, ['program.setFile()', chalk_1.default.green(srcPath)], () => {
307
+ assert.ok(srcPath, 'srcPath is required');
308
+ assert.ok(pkgPath, 'pkgPath is required');
272
309
  //if the file is already loaded, remove it
273
310
  if (this.hasFile(srcPath)) {
274
311
  this.removeFile(srcPath);
275
312
  }
276
313
  let fileExtension = path.extname(srcPath).toLowerCase();
277
314
  let file;
315
+ const beforeFileParseEvent = {
316
+ program: this,
317
+ srcPath: srcPath,
318
+ source: fileContents
319
+ };
278
320
  if (fileExtension === '.brs' || fileExtension === '.bs') {
279
321
  let brsFile = new BrsFile_1.BrsFile(srcPath, pkgPath, this);
280
322
  //add file to the `source` dependency list
281
- if (brsFile.pkgPath.startsWith(startOfSourcePkgPath)) {
323
+ if (brsFile.pkgPath.startsWith('pkg:/source/')) {
282
324
  this.createSourceScope();
283
325
  this.dependencyGraph.addDependency('scope:source', brsFile.dependencyGraphKey);
284
326
  }
285
327
  //add the file to the program
286
- this.files[srcPath] = brsFile;
287
- this.pkgMap[brsFile.pkgPath.toLowerCase()] = brsFile;
288
- let sourceObj = {
289
- pathAbsolute: srcPath,
290
- source: fileContents
291
- };
292
- this.plugins.emit('beforeFileParse', sourceObj);
328
+ this.assignFile(brsFile);
329
+ this.plugins.emit('beforeFileParse', beforeFileParseEvent);
293
330
  this.logger.time(Logger_1.LogLevel.debug, ['parse', chalk_1.default.green(srcPath)], () => {
294
- brsFile.parse(sourceObj.source);
331
+ brsFile.parse(beforeFileParseEvent.source);
295
332
  });
296
333
  file = brsFile;
297
334
  brsFile.attachDependencyGraph(this.dependencyGraph);
298
- this.plugins.emit('afterFileValidate', brsFile);
335
+ this.plugins.emit('afterFileParse', {
336
+ program: this,
337
+ file: brsFile
338
+ });
299
339
  }
300
340
  else if (
301
341
  //is xml file
302
342
  fileExtension === '.xml' &&
303
343
  //resides in the components folder (Roku will only parse xml files in the components folder)
304
- pkgPath.toLowerCase().startsWith(util_1.util.pathSepNormalize(`components/`))) {
344
+ lowerPkgPath.startsWith('pkg:/components/')) {
305
345
  let xmlFile = new XmlFile_1.XmlFile(srcPath, pkgPath, this);
346
+ this.assignFile(xmlFile);
306
347
  //add the file to the program
307
- this.files[srcPath] = xmlFile;
308
- this.pkgMap[xmlFile.pkgPath.toLowerCase()] = xmlFile;
309
- let sourceObj = {
310
- pathAbsolute: srcPath,
311
- source: fileContents
312
- };
313
- this.plugins.emit('beforeFileParse', sourceObj);
348
+ this.plugins.emit('beforeFileParse', beforeFileParseEvent);
314
349
  this.logger.time(Logger_1.LogLevel.debug, ['parse', chalk_1.default.green(srcPath)], () => {
315
- xmlFile.parse(sourceObj.source);
350
+ xmlFile.parse(beforeFileParseEvent.source);
316
351
  });
317
352
  file = xmlFile;
318
353
  //create a new scope for this xml file
@@ -320,12 +355,15 @@ class Program {
320
355
  this.addScope(scope);
321
356
  //register this compoent now that we have parsed it and know its component name
322
357
  this.registerComponent(xmlFile, scope);
323
- this.plugins.emit('afterFileValidate', xmlFile);
358
+ this.plugins.emit('afterFileParse', {
359
+ program: this,
360
+ file: xmlFile
361
+ });
324
362
  }
325
363
  else {
326
364
  //TODO do we actually need to implement this? Figure out how to handle img paths
327
- // let genericFile = this.files[pathAbsolute] = <any>{
328
- // pathAbsolute: pathAbsolute,
365
+ // let genericFile = this.files[srcPath] = <any>{
366
+ // srcPath: srcPath,
329
367
  // pkgPath: pkgPath,
330
368
  // wasProcessed: true
331
369
  // } as File;
@@ -333,7 +371,6 @@ class Program {
333
371
  }
334
372
  return file;
335
373
  });
336
- return file;
337
374
  }
338
375
  /**
339
376
  * Ensure source scope is created.
@@ -346,80 +383,79 @@ class Program {
346
383
  this.addScope(sourceScope);
347
384
  }
348
385
  }
349
- /**
350
- * Find the file by its absolute path. This is case INSENSITIVE, since
351
- * Roku is a case insensitive file system. It is an error to have multiple files
352
- * with the same path with only case being different.
353
- * @param pathAbsolute
354
- */
355
- getFileByPathAbsolute(pathAbsolute) {
356
- pathAbsolute = (0, util_1.standardizePath) `${pathAbsolute}`;
357
- for (let filePath in this.files) {
358
- if (filePath.toLowerCase() === pathAbsolute.toLowerCase()) {
359
- return this.files[filePath];
360
- }
361
- }
362
- }
363
- /**
364
- * Get a list of files for the given (platform-normalized) pkgPath array.
365
- * Missing files are just ignored.
366
- */
367
- getFilesByPkgPaths(pkgPaths) {
368
- return pkgPaths
369
- .map(pkgPath => this.getFileByPkgPath(pkgPath))
370
- .filter(file => file !== undefined);
371
- }
372
- /**
373
- * Get a file with the specified (platform-normalized) pkg path.
374
- * If not found, return undefined
375
- */
376
- getFileByPkgPath(pkgPath) {
377
- return this.pkgMap[pkgPath.toLowerCase()];
378
- }
379
386
  /**
380
387
  * Remove a set of files from the program
381
- * @param absolutePaths
388
+ * @param srcPaths
382
389
  */
383
- removeFiles(absolutePaths) {
384
- for (let pathAbsolute of absolutePaths) {
385
- this.removeFile(pathAbsolute);
390
+ removeFiles(srcPaths) {
391
+ for (let srcPath of srcPaths) {
392
+ this.removeFile(srcPath);
386
393
  }
387
394
  }
388
395
  /**
389
396
  * Remove a file from the program
390
- * @param pathAbsolute
397
+ * @param filePath can be a srcPath, a pkgPath, or a destPath (same as pkgPath but without `pkg:/`)
398
+ * @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
399
+
391
400
  */
392
- removeFile(pathAbsolute) {
393
- this.logger.debug('Program.removeFile()', pathAbsolute);
394
- if (!path.isAbsolute(pathAbsolute)) {
395
- throw new Error(`Path must be absolute: "${pathAbsolute}"`);
396
- }
397
- let file = this.getFile(pathAbsolute);
401
+ removeFile(filePath, normalizePath = true) {
402
+ this.logger.debug('Program.removeFile()', filePath);
403
+ let file = this.getFile(filePath, normalizePath);
398
404
  if (file) {
399
- this.plugins.emit('beforeFileDispose', file);
405
+ this.plugins.emit('beforeFileDispose', {
406
+ program: this,
407
+ file: file
408
+ });
400
409
  //if there is a scope named the same as this file's path, remove it (i.e. xml scopes)
401
410
  let scope = this.scopes[file.pkgPath];
402
411
  if (scope) {
403
- this.plugins.emit('beforeScopeDispose', scope);
412
+ this.plugins.emit('beforeScopeDispose', {
413
+ program: this,
414
+ scope: scope
415
+ });
404
416
  scope.dispose();
405
417
  //notify dependencies of this scope that it has been removed
406
418
  this.dependencyGraph.remove(scope.dependencyGraphKey);
407
419
  delete this.scopes[file.pkgPath];
408
- this.plugins.emit('afterScopeDispose', scope);
420
+ this.plugins.emit('afterScopeDispose', {
421
+ program: this,
422
+ scope: scope
423
+ });
409
424
  }
410
425
  //remove the file from the program
411
- delete this.files[file.pathAbsolute];
412
- delete this.pkgMap[file.pkgPath.toLowerCase()];
426
+ this.unassignFile(file);
413
427
  this.dependencyGraph.remove(file.dependencyGraphKey);
414
428
  //if this is a pkg:/source file, notify the `source` scope that it has changed
415
- if (file.pkgPath.startsWith(startOfSourcePkgPath)) {
429
+ if (file.pkgPath.startsWith('pkg:/source/')) {
416
430
  this.dependencyGraph.removeDependency('scope:source', file.dependencyGraphKey);
417
431
  }
418
432
  //if this is a component, remove it from our components map
419
433
  if ((0, reflection_1.isXmlFile)(file)) {
420
434
  this.unregisterComponent(file);
421
435
  }
422
- this.plugins.emit('afterFileDispose', file);
436
+ this.plugins.emit('afterFileDispose', {
437
+ program: this,
438
+ file: file
439
+ });
440
+ }
441
+ }
442
+ /**
443
+ * Remove all files from the program that are in the specified folder path (recursive)
444
+ * @param folderSrcPath The absolute path to the folder on disk
445
+ * @param normalizePath should the provided path be normalized before use?
446
+ */
447
+ removeFilesInFolder(folderSrcPath, normalizePath = true) {
448
+ if (normalizePath) {
449
+ folderSrcPath = util_1.util.standardizePath(folderSrcPath);
450
+ }
451
+ const lowerFolderSrcPath = folderSrcPath.toLowerCase();
452
+ for (const key in this.files) {
453
+ const file = this.files[key];
454
+ const lowerSrcPath = file.srcPath.toLowerCase();
455
+ //if the file path starts with the parent path and the file path does not exactly match the folder path
456
+ if (lowerSrcPath.toLowerCase().startsWith(lowerFolderSrcPath) && lowerSrcPath !== lowerFolderSrcPath) {
457
+ this.removeFile(file.srcPath, false);
458
+ }
423
459
  }
424
460
  }
425
461
  /**
@@ -428,53 +464,86 @@ class Program {
428
464
  */
429
465
  validate() {
430
466
  this.logger.time(Logger_1.LogLevel.log, ['Validating project'], () => {
467
+ var _a;
431
468
  this.diagnostics = [];
432
- this.plugins.emit('beforeProgramValidate', this);
433
- this.logger.time(Logger_1.LogLevel.info, ['Validate all scopes'], () => {
434
- for (let scopeName in this.scopes) {
435
- let scope = this.scopes[scopeName];
436
- scope.validate();
437
- }
469
+ this.plugins.emit('beforeProgramValidate', {
470
+ program: this
438
471
  });
439
- //find any files NOT loaded into a scope
440
- for (let filePath in this.files) {
441
- let file = this.files[filePath];
472
+ //validate every file
473
+ for (const file of Object.values(this.files)) {
474
+ //find any files NOT loaded into a scope
442
475
  if (!this.fileIsIncludedInAnyScope(file)) {
443
476
  this.logger.debug('Program.validate(): fileNotReferenced by any scope', () => chalk_1.default.green(file === null || file === void 0 ? void 0 : file.pkgPath));
444
477
  //the file is not loaded in any scope
445
478
  this.diagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.fileNotReferencedByAnyOtherFile()), { file: file, range: util_1.util.createRange(0, 0, 0, Number.MAX_VALUE) }));
446
479
  }
480
+ //for every unvalidated file, validate it
481
+ if (!file.isValidated) {
482
+ this.plugins.emit('beforeFileValidate', {
483
+ program: this,
484
+ file: file
485
+ });
486
+ //call file.validate() IF the file has that function defined
487
+ (_a = file.validate) === null || _a === void 0 ? void 0 : _a.call(file);
488
+ file.isValidated = true;
489
+ this.plugins.emit('afterFileValidate', {
490
+ program: this,
491
+ file: file
492
+ });
493
+ }
447
494
  }
495
+ this.logger.time(Logger_1.LogLevel.info, ['Validate all scopes'], () => {
496
+ for (let scope of Object.values(this.scopes)) {
497
+ //only validate unvalidated scopes
498
+ if (!scope.isValidated) {
499
+ this.plugins.emit('beforeScopeValidate', {
500
+ program: this,
501
+ scope: scope
502
+ });
503
+ scope.validate();
504
+ scope.isValidated = true;
505
+ this.plugins.emit('afterScopeValidate', {
506
+ program: this,
507
+ scope: scope
508
+ });
509
+ }
510
+ }
511
+ });
448
512
  this.detectDuplicateComponentNames();
449
- this.plugins.emit('afterProgramValidate', this);
513
+ this.plugins.emit('afterProgramValidate', {
514
+ program: this
515
+ });
450
516
  });
451
517
  }
452
518
  /**
453
519
  * Flag all duplicate component names
454
520
  */
455
521
  detectDuplicateComponentNames() {
456
- const componentsByName = Object.keys(this.files).reduce((map, filePath) => {
457
- var _a;
458
- const file = this.files[filePath];
522
+ var _a;
523
+ const componentsByName = new Map();
524
+ for (const key in this.files) {
525
+ const file = this.files[key];
459
526
  //if this is an XmlFile, and it has a valid `componentName` property
460
- if ((0, reflection_1.isXmlFile)(file) && ((_a = file.componentName) === null || _a === void 0 ? void 0 : _a.text)) {
461
- let lowerName = file.componentName.text.toLowerCase();
462
- if (!map[lowerName]) {
463
- map[lowerName] = [];
527
+ if ((0, reflection_1.isXmlFile)(file)) {
528
+ const componentNameLower = (_a = file.componentName) === null || _a === void 0 ? void 0 : _a.text.toLowerCase();
529
+ if (componentNameLower) {
530
+ if (!componentsByName.has(componentNameLower)) {
531
+ componentsByName.set(componentNameLower, [file]);
532
+ }
533
+ else {
534
+ componentsByName.get(componentNameLower).push(file);
535
+ }
464
536
  }
465
- map[lowerName].push(file);
466
537
  }
467
- return map;
468
- }, {});
469
- for (let name in componentsByName) {
470
- const xmlFiles = componentsByName[name];
538
+ }
539
+ for (const xmlFiles of componentsByName.values()) {
471
540
  //add diagnostics for every duplicate component with this name
472
541
  if (xmlFiles.length > 1) {
473
542
  for (let xmlFile of xmlFiles) {
474
543
  const { componentName } = xmlFile;
475
544
  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 => {
476
545
  return {
477
- location: vscode_languageserver_1.Location.create(vscode_uri_1.URI.file(xmlFile.pathAbsolute).toString(), x.componentName.range),
546
+ location: vscode_languageserver_1.Location.create(vscode_uri_1.URI.file(xmlFile.srcPath).toString(), x.componentName.range),
478
547
  message: 'Also defined here'
479
548
  };
480
549
  }) }));
@@ -483,11 +552,11 @@ class Program {
483
552
  }
484
553
  }
485
554
  /**
486
- * Determine if the given file is included in at least one scope in this program
555
+ * Determine at least one scope has the file
487
556
  */
488
557
  fileIsIncludedInAnyScope(file) {
489
- for (let scopeName in this.scopes) {
490
- if (this.scopes[scopeName].hasFile(file)) {
558
+ for (let scope of Object.values(this.scopes)) {
559
+ if (scope.hasFile(file)) {
491
560
  return true;
492
561
  }
493
562
  }
@@ -495,11 +564,19 @@ class Program {
495
564
  }
496
565
  /**
497
566
  * Get the file at the given path
498
- * @param pathAbsolute
567
+ * @param filePath can be a srcPath, a pkgPath, or a destPath (same as pkgPath but without `pkg:/`)
568
+ * @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
499
569
  */
500
- getFile(pathAbsolute) {
501
- pathAbsolute = (0, util_1.standardizePath) `${pathAbsolute}`;
502
- return this.files[pathAbsolute];
570
+ getFile(filePath, normalizePath = true) {
571
+ if (typeof filePath !== 'string') {
572
+ return undefined;
573
+ }
574
+ else if (path.isAbsolute(filePath)) {
575
+ return this.files[(normalizePath ? util_1.util.standardizePath(filePath) : filePath).toLowerCase()];
576
+ }
577
+ else {
578
+ return this.pkgMap[(normalizePath ? util_1.util.sanitizePkgPath(filePath) : filePath).toLowerCase()];
579
+ }
503
580
  }
504
581
  /**
505
582
  * Get a list of all scopes the file is loaded into
@@ -548,9 +625,12 @@ class Program {
548
625
  let funcNames = new Set();
549
626
  let currentScope = scope;
550
627
  while ((0, reflection_1.isXmlScope)(currentScope)) {
551
- 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 : []) {
552
- if (!filterName || name === filterName) {
553
- funcNames.add(name);
628
+ for (let member of (_b = (_a = currentScope.xmlFile.ast.component) === null || _a === void 0 ? void 0 : _a.interfaceMembers) !== null && _b !== void 0 ? _b : []) {
629
+ if ((0, reflection_1.isSGInterfaceFunction)(member)) {
630
+ const name = member.name;
631
+ if (!filterName || name === filterName) {
632
+ funcNames.add(name);
633
+ }
554
634
  }
555
635
  }
556
636
  currentScope = currentScope.getParentScope();
@@ -573,17 +653,17 @@ class Program {
573
653
  }
574
654
  /**
575
655
  * Find all available completion items at the given position
576
- * @param pathAbsolute
656
+ * @param srcPath The absolute path to the source file on disk
577
657
  * @param lineIndex
578
658
  * @param columnIndex
579
659
  */
580
- getCompletions(pathAbsolute, position) {
581
- let file = this.getFile(pathAbsolute);
660
+ getCompletions(srcPath, position) {
661
+ let file = this.getFile(srcPath);
582
662
  if (!file) {
583
663
  return [];
584
664
  }
585
665
  let result = [];
586
- if ((0, reflection_1.isBrsFile)(file) && file.isPositionNextToTokenKind(position, lexer_1.TokenKind.Callfunc)) {
666
+ if ((0, reflection_1.isBrsFile)(file) && file.parser.isPositionNextToTokenKind(position, lexer_1.TokenKind.Callfunc)) {
587
667
  // is next to a @. callfunc invocation - must be an interface method
588
668
  for (const scope of this.getScopes().filter((s) => (0, reflection_1.isXmlScope)(s))) {
589
669
  let fileLinks = this.getStatementsForXmlFile(scope);
@@ -599,7 +679,12 @@ class Program {
599
679
  //if there are no scopes, include the global scope so we at least get the built-in functions
600
680
  scopes = scopes.length > 0 ? scopes : [this.globalScope];
601
681
  //get the completions from all scopes for this file
602
- let allCompletions = util_1.util.flatMap(scopes.map(ctx => file.getCompletions(position, ctx)), c => c);
682
+ let allCompletions = util_1.util.flatMap(scopes.map(ctx => {
683
+ ctx.linkSymbolTable();
684
+ const completions = file.getCompletions(position, ctx);
685
+ ctx.unlinkSymbolTable();
686
+ return completions;
687
+ }), c => c);
603
688
  //only keep completions common to every scope for this file
604
689
  let keyCounts = {};
605
690
  for (let completion of allCompletions) {
@@ -615,21 +700,22 @@ class Program {
615
700
  * Goes through each file and builds a list of workspace symbols for the program. Used by LanguageServer's onWorkspaceSymbol functionality
616
701
  */
617
702
  getWorkspaceSymbols() {
618
- const results = Object.keys(this.files).map(key => {
703
+ const result = [];
704
+ for (const key in this.files) {
619
705
  const file = this.files[key];
620
706
  if ((0, reflection_1.isBrsFile)(file)) {
621
- return file.getWorkspaceSymbols();
707
+ result.push(...file.getWorkspaceSymbols());
622
708
  }
623
- return [];
624
- });
625
- return util_1.util.flatMap(results, c => c);
709
+ }
710
+ return result;
626
711
  }
627
712
  /**
628
713
  * Given a position in a file, if the position is sitting on some type of identifier,
629
714
  * go to the definition of that identifier (where this thing was first defined)
715
+ * @param srcPath The absolute path to the source file on disk
630
716
  */
631
- getDefinition(pathAbsolute, position) {
632
- let file = this.getFile(pathAbsolute);
717
+ getDefinition(srcPath, position) {
718
+ let file = this.getFile(srcPath);
633
719
  if (!file) {
634
720
  return [];
635
721
  }
@@ -645,9 +731,12 @@ class Program {
645
731
  return results;
646
732
  }
647
733
  }
648
- getHover(pathAbsolute, position) {
734
+ /**
735
+ * @param srcPath The absolute path to the source file on disk
736
+ */
737
+ getHover(srcPath, position) {
649
738
  //find the file
650
- let file = this.getFile(pathAbsolute);
739
+ let file = this.getFile(srcPath);
651
740
  if (!file) {
652
741
  return null;
653
742
  }
@@ -655,10 +744,11 @@ class Program {
655
744
  }
656
745
  /**
657
746
  * Compute code actions for the given file and range
747
+ * @param srcPath The absolute path to the source file on disk
658
748
  */
659
- getCodeActions(pathAbsolute, range) {
749
+ getCodeActions(srcPath, range) {
660
750
  const codeActions = [];
661
- const file = this.getFile(pathAbsolute);
751
+ const file = this.getFile(srcPath);
662
752
  if (file) {
663
753
  const diagnostics = this
664
754
  //get all current diagnostics (filtered by diagnostic filters)
@@ -702,7 +792,7 @@ class Program {
702
792
  return [];
703
793
  }
704
794
  const results = new Map();
705
- let functionScope = file.getFunctionScopeAtPosition(position);
795
+ let functionExpression = file.getFunctionExpressionAtPosition(position);
706
796
  let identifierInfo = this.getPartialStatementInfo(file, position);
707
797
  if (identifierInfo.statementType === '') {
708
798
  // just general function calls
@@ -720,10 +810,12 @@ class Program {
720
810
  else if (identifierInfo.statementType === '.') {
721
811
  //if m class reference.. then
722
812
  //only get statements from the class I am in..
723
- if (functionScope) {
724
- let myClass = file.getClassFromMReference(position, file.getTokenAt(position), functionScope);
725
- if (myClass) {
726
- for (let scope of this.getScopesForFile(myClass.file)) {
813
+ if (functionExpression) {
814
+ const currentToken = file.parser.getTokenAt(position);
815
+ for (let scope of this.getScopesForFile(file)) {
816
+ scope.linkSymbolTable();
817
+ let myClass = file.getClassFromToken(currentToken, functionExpression, scope);
818
+ if (myClass) {
727
819
  let classes = scope.getClassHierarchy(myClass.item.getName(parser_1.ParseMode.BrighterScript).toLowerCase());
728
820
  //and anything from any class in scope to a non m class
729
821
  for (let statement of [...classes].filter((i) => (0, reflection_1.isClassMethodStatement)(i.item))) {
@@ -734,6 +826,7 @@ class Program {
734
826
  }
735
827
  }
736
828
  }
829
+ scope.unlinkSymbolTable();
737
830
  }
738
831
  }
739
832
  if (identifierInfo.dotPart) {
@@ -794,12 +887,12 @@ class Program {
794
887
  if (!itemCounts.isArgStartFound) {
795
888
  //try to get sig help based on the name
796
889
  index = position.character;
797
- let currentToken = file.getTokenAt(position);
890
+ let currentToken = file.parser.getTokenAt(position);
798
891
  if (currentToken && currentToken.kind !== lexer_1.TokenKind.Comment) {
799
892
  name = file.getPartialVariableName(currentToken, [lexer_1.TokenKind.New]);
800
893
  if (!name) {
801
894
  //try the previous token, incase we're on a bracket
802
- currentToken = file.getPreviousToken(currentToken);
895
+ currentToken = file.parser.getPreviousToken(currentToken);
803
896
  name = file.getPartialVariableName(currentToken, [lexer_1.TokenKind.New]);
804
897
  }
805
898
  if (name === null || name === void 0 ? void 0 : name.indexOf('.')) {
@@ -906,9 +999,12 @@ class Program {
906
999
  }
907
1000
  return itemCounts;
908
1001
  }
909
- getReferences(pathAbsolute, position) {
1002
+ /**
1003
+ * @param srcPath The absolute path to the source file on disk
1004
+ */
1005
+ getReferences(srcPath, position) {
910
1006
  //find the file
911
- let file = this.getFile(pathAbsolute);
1007
+ let file = this.getFile(srcPath);
912
1008
  if (!file) {
913
1009
  return null;
914
1010
  }
@@ -926,8 +1022,8 @@ class Program {
926
1022
  */
927
1023
  let resultPkgPaths = {};
928
1024
  //restrict to only .brs files
929
- for (let key in this.files) {
930
- let file = this.files[key];
1025
+ for (const key in this.files) {
1026
+ const file = this.files[key];
931
1027
  if (
932
1028
  //is a BrightScript or BrighterScript file
933
1029
  (file.extension === '.bs' || file.extension === '.brs') &&
@@ -935,14 +1031,12 @@ class Program {
935
1031
  lowerSourcePkgPath !== file.pkgPath.toLowerCase()) {
936
1032
  //add the relative path
937
1033
  let relativePath = util_1.util.getRelativePath(sourcePkgPath, file.pkgPath).replace(/\\/g, '/');
938
- let pkgPathStandardized = file.pkgPath.replace(/\\/g, '/');
939
- let filePkgPath = `pkg:/${pkgPathStandardized}`;
940
- let lowerFilePkgPath = filePkgPath.toLowerCase();
941
- if (!resultPkgPaths[lowerFilePkgPath]) {
942
- resultPkgPaths[lowerFilePkgPath] = true;
1034
+ const lowerPkgPath = file.pkgPath.toLowerCase();
1035
+ if (!resultPkgPaths[lowerPkgPath]) {
1036
+ resultPkgPaths[lowerPkgPath] = true;
943
1037
  result.push({
944
1038
  label: relativePath,
945
- detail: file.pathAbsolute,
1039
+ detail: file.srcPath,
946
1040
  kind: vscode_languageserver_1.CompletionItemKind.File,
947
1041
  textEdit: {
948
1042
  newText: relativePath,
@@ -951,11 +1045,11 @@ class Program {
951
1045
  });
952
1046
  //add the absolute path
953
1047
  result.push({
954
- label: filePkgPath,
955
- detail: file.pathAbsolute,
1048
+ label: file.pkgPath,
1049
+ detail: file.srcPath,
956
1050
  kind: vscode_languageserver_1.CompletionItemKind.File,
957
1051
  textEdit: {
958
- newText: filePkgPath,
1052
+ newText: file.pkgPath,
959
1053
  range: scriptImport.filePathRange
960
1054
  }
961
1055
  });
@@ -967,50 +1061,64 @@ class Program {
967
1061
  /**
968
1062
  * Transpile a single file and get the result as a string.
969
1063
  * This does not write anything to the file system.
1064
+ * @param srcPath The absolute path to the source file on disk
970
1065
  */
971
- getTranspiledFileContents(pathAbsolute) {
972
- let file = this.getFile(pathAbsolute);
1066
+ getTranspiledFileContents(srcPath) {
1067
+ let file = this.getFile(srcPath);
973
1068
  let result = file.transpile();
974
- return Object.assign(Object.assign({}, result), { pathAbsolute: file.pathAbsolute, pkgPath: file.pkgPath });
1069
+ return Object.assign(Object.assign({}, result), { srcPath: file.srcPath, pkgPath: file.pkgPath });
975
1070
  }
976
1071
  async transpile(fileEntries, stagingFolderPath) {
977
- // map fileEntries using their path as key, to avoid excessive "find()" operations
1072
+ // map fileEntries using their path as key to avoid excessive "find()" operations
978
1073
  const mappedFileEntries = fileEntries.reduce((collection, entry) => {
979
1074
  collection[(0, util_1.standardizePath) `${entry.src}`] = entry;
980
1075
  return collection;
981
1076
  }, {});
982
- const entries = Object.values(this.files).map(file => {
983
- let filePathObj = mappedFileEntries[(0, util_1.standardizePath) `${file.pathAbsolute}`];
1077
+ const entries = [];
1078
+ for (const key in this.files) {
1079
+ const file = this.files[key];
1080
+ let filePathObj = mappedFileEntries[(0, util_1.standardizePath) `${file.srcPath}`];
984
1081
  if (!filePathObj) {
985
1082
  //this file has been added in-memory, from a plugin, for example
986
1083
  filePathObj = {
987
1084
  //add an interpolated src path (since it doesn't actually exist in memory)
988
- src: `bsc:/${file.pkgPath}`,
1085
+ src: `bsc-in-memory:/${util_1.util.removeProtocol(file.pkgPath)}`,
989
1086
  dest: file.pkgPath
990
1087
  };
991
1088
  }
992
- //replace the file extension
993
- let outputPath = filePathObj.dest.replace(/\.bs$/gi, '.brs');
1089
+ //prep the output path
1090
+ let outputPath = filePathObj.dest
1091
+ //replace any leading protocol
1092
+ .replace(/^[-a-z_]+:\//, '')
1093
+ //change any .bs file extension to .brs
1094
+ .replace(/\.bs$/gi, '.brs');
994
1095
  //prepend the staging folder path
995
1096
  outputPath = (0, util_1.standardizePath) `${stagingFolderPath}/${outputPath}`;
996
- return {
1097
+ entries.push({
997
1098
  file: file,
998
1099
  outputPath: outputPath
999
- };
1100
+ });
1101
+ }
1102
+ this.plugins.emit('beforeProgramTranspile', {
1103
+ program: this,
1104
+ entries: entries
1000
1105
  });
1001
- this.plugins.emit('beforeProgramTranspile', this, entries);
1002
1106
  const promises = entries.map(async (entry) => {
1003
1107
  //skip transpiling typedef files
1004
1108
  if ((0, reflection_1.isBrsFile)(entry.file) && entry.file.isTypedef) {
1005
1109
  return;
1006
1110
  }
1007
- this.plugins.emit('beforeFileTranspile', entry);
1111
+ this.plugins.emit('beforeFileTranspile', {
1112
+ program: this,
1113
+ file: entry.file,
1114
+ outputPath: entry.outputPath
1115
+ });
1008
1116
  const { file, outputPath } = entry;
1009
1117
  const result = file.transpile();
1010
1118
  //make sure the full dir path exists
1011
1119
  await fsExtra.ensureDir(path.dirname(outputPath));
1012
1120
  if (await fsExtra.pathExists(outputPath)) {
1013
- throw new Error(`Error while transpiling "${file.pathAbsolute}". A file already exists at "${outputPath}" and will not be overwritten.`);
1121
+ throw new Error(`Error while transpiling "${file.srcPath}". A file already exists at "${outputPath}" and will not be overwritten.`);
1014
1122
  }
1015
1123
  const writeMapPromise = result.map ? fsExtra.writeFile(`${outputPath}.map`, result.map.toString()) : null;
1016
1124
  await Promise.all([
@@ -1022,14 +1130,21 @@ class Program {
1022
1130
  const typedefPath = outputPath.replace(/\.brs$/i, '.d.bs');
1023
1131
  await fsExtra.writeFile(typedefPath, typedef);
1024
1132
  }
1025
- this.plugins.emit('afterFileTranspile', entry);
1133
+ this.plugins.emit('afterFileTranspile', {
1134
+ program: this,
1135
+ file: entry.file,
1136
+ outputPath: entry.outputPath
1137
+ });
1026
1138
  });
1027
1139
  //if there's no bslib file already loaded into the program, copy it to the staging directory
1028
- if (!this.getFileByPkgPath(bslibAliasedRokuModulesPkgPath) && !this.getFileByPkgPath((0, util_1.standardizePath) `source/bslib.brs`)) {
1140
+ if (!this.getFile(bslibAliasedRokuModulesPkgPath) && !this.getFile(`pkg:/source/bslib.brs`)) {
1029
1141
  promises.push(util_1.util.copyBslibToStaging(stagingFolderPath));
1030
1142
  }
1031
1143
  await Promise.all(promises);
1032
- this.plugins.emit('afterProgramTranspile', this, entries);
1144
+ this.plugins.emit('afterProgramTranspile', {
1145
+ program: this,
1146
+ entries: entries
1147
+ });
1033
1148
  }
1034
1149
  /**
1035
1150
  * Find a list of files in the program that have a function with the given name (case INsensitive)
@@ -1088,11 +1203,13 @@ class Program {
1088
1203
  return this._manifest;
1089
1204
  }
1090
1205
  dispose() {
1091
- for (let filePath in this.files) {
1092
- this.files[filePath].dispose();
1206
+ var _a, _b;
1207
+ for (const key in this.files) {
1208
+ const file = this.files[key];
1209
+ (_a = file.dispose) === null || _a === void 0 ? void 0 : _a.call(file);
1093
1210
  }
1094
1211
  for (let name in this.scopes) {
1095
- this.scopes[name].dispose();
1212
+ (_b = this.scopes[name]) === null || _b === void 0 ? void 0 : _b.dispose();
1096
1213
  }
1097
1214
  this.globalScope.dispose();
1098
1215
  this.dependencyGraph.dispose();