brighterscript 0.66.0-alpha.3 → 0.66.0-alpha.4

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 (53) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/BusyStatusTracker.d.ts +31 -0
  3. package/dist/BusyStatusTracker.js +83 -0
  4. package/dist/BusyStatusTracker.js.map +1 -0
  5. package/dist/LanguageServer.d.ts +17 -0
  6. package/dist/LanguageServer.js +118 -52
  7. package/dist/LanguageServer.js.map +1 -1
  8. package/dist/Logger.d.ts +1 -1
  9. package/dist/Logger.js.map +1 -1
  10. package/dist/Program.js +10 -4
  11. package/dist/Program.js.map +1 -1
  12. package/dist/Throttler.d.ts +12 -0
  13. package/dist/Throttler.js +39 -0
  14. package/dist/Throttler.js.map +1 -1
  15. package/dist/bscPlugin/validation/ScopeValidator.spec.js +31 -0
  16. package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -1
  17. package/dist/cli.js +9 -1
  18. package/dist/cli.js.map +1 -1
  19. package/dist/deferred.d.ts +1 -1
  20. package/dist/deferred.js.map +1 -1
  21. package/dist/globalCallables.js +9 -1
  22. package/dist/globalCallables.js.map +1 -1
  23. package/dist/index.d.ts +2 -0
  24. package/dist/index.js +2 -0
  25. package/dist/index.js.map +1 -1
  26. package/dist/interfaces.d.ts +4 -0
  27. package/dist/interfaces.js.map +1 -1
  28. package/dist/parser/Expression.d.ts +1 -1
  29. package/dist/types/BooleanType.d.ts +3 -0
  30. package/dist/types/BooleanType.js +5 -0
  31. package/dist/types/BooleanType.js.map +1 -1
  32. package/dist/types/DoubleType.d.ts +3 -0
  33. package/dist/types/DoubleType.js +5 -0
  34. package/dist/types/DoubleType.js.map +1 -1
  35. package/dist/types/EnumType.d.ts +3 -0
  36. package/dist/types/EnumType.js +4 -0
  37. package/dist/types/EnumType.js.map +1 -1
  38. package/dist/types/FloatType.d.ts +3 -0
  39. package/dist/types/FloatType.js +5 -0
  40. package/dist/types/FloatType.js.map +1 -1
  41. package/dist/types/IntegerType.d.ts +3 -0
  42. package/dist/types/IntegerType.js +5 -0
  43. package/dist/types/IntegerType.js.map +1 -1
  44. package/dist/types/LongIntegerType.d.ts +3 -0
  45. package/dist/types/LongIntegerType.js +5 -0
  46. package/dist/types/LongIntegerType.js.map +1 -1
  47. package/dist/types/StringType.d.ts +3 -0
  48. package/dist/types/StringType.js +5 -0
  49. package/dist/types/StringType.js.map +1 -1
  50. package/dist/util.d.ts +1 -2
  51. package/dist/util.js +5 -5
  52. package/dist/util.js.map +1 -1
  53. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -6,6 +6,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
 
8
8
 
9
+ ## [0.66.0-alpha.4](https://github.com/rokucommunity/brighterscript/compare/v0.66.0-alpha.3...v0.66.0-alpha.4) - 2023-07-26
10
+ ### Changed
11
+ - all changes from [v0.65.4](https://github.com/rokucommunity/brighterscript/compare/v0.65.3...v0.65.4)
12
+ ### Fixes
13
+ - assignment from return of member functions of primitive types ([#855](https://github.com/rokucommunity/brighterscript/pull/855))
14
+ - using invalid as a default param value (now sets type to dynamic) ([#855](https://github.com/rokucommunity/brighterscript/pull/855))
15
+ - missing `Roku_Event_Dispatcher()` global callable (from library `Roku_Event_Dispatcher.brs`) ([#855](https://github.com/rokucommunity/brighterscript/pull/855))
16
+ - `FormatJson()` function signature ([#855](https://github.com/rokucommunity/brighterscript/pull/855))
17
+
18
+
19
+
9
20
  ## [0.66.0-alpha.3](https://github.com/rokucommunity/brighterscript/compare/v0.66.0-alpha.2...v0.66.0-alpha.3) - 2023-07-24
10
21
  ## Fixed
11
22
  - performance fixes ([#834](https://github.com/rokucommunity/brighterscript/pull/834))
@@ -41,6 +52,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
41
52
 
42
53
 
43
54
 
55
+ ## [0.65.4](https://github.com/rokucommunity/brighterscript/compare/v0.65.3...v0.65.4) - 2023-07-24
56
+ ### Changed
57
+ - Install `v8-profiler-next` on demand instead of being a dependency ([#854](https://github.com/rokucommunity/brighterscript/pull/854))
58
+
59
+
60
+
61
+ ## [0.65.3](https://github.com/rokucommunity/brighterscript/compare/v0.65.2...v0.65.3) - 2023-07-22
62
+ ### Changed
63
+ - Show busy spinner for lsp builds. Remove `build-status` event in favor of new `busy-status` ([#852](https://github.com/rokucommunity/brighterscript/pull/852))
64
+ - upgrade to [roku-deploy@3.10.3](https://github.com/rokucommunity/roku-deploy/blob/master/CHANGELOG.md#3103---2023-07-22). Notable changes since 3.10.2:
65
+ - Bump word-wrap from 1.2.3 to 1.2.4 ([roku-deploy#117](https://github.com/rokucommunity/roku-deploy/pull/117))
66
+ - Bump word-wrap from 1.2.3 to 1.2.4 ([#851](https://github.com/rokucommunity/brighterscript/pull/851))
67
+
68
+
69
+
70
+ ## [0.65.2](https://github.com/rokucommunity/brighterscript/compare/v0.65.1...v0.65.2) - 2023-07-17
71
+ ### Added
72
+ - beforeProgramDispose event ([#844](https://github.com/rokucommunity/brighterscript/pull/844)), ([#845](https://github.com/rokucommunity/brighterscript/pull/845))
73
+ - profiling support to the cli via the `--profile` flag ([#833](https://github.com/rokucommunity/brighterscript/pull/833))
74
+ ### Changed
75
+ - Make component ready on afterScopeCreate ([#843](https://github.com/rokucommunity/brighterscript/pull/843))
76
+ - Add project index to language server log entries ([#836](https://github.com/rokucommunity/brighterscript/pull/836))
77
+ - Prevent crashing when diagnostic is missing range. ([#832](https://github.com/rokucommunity/brighterscript/pull/832))
78
+ - Prevent crash when diagnostic is missing range ([#831](https://github.com/rokucommunity/brighterscript/pull/831))
79
+ - Add baseline interface docs ([#829](https://github.com/rokucommunity/brighterscript/pull/829))
80
+
81
+
82
+
44
83
  ## [0.65.1](https://github.com/rokucommunity/brighterscript/compare/v0.65.0...v0.65.1) - 2023-06-09
45
84
  ### Fixed
46
85
  - injection of duplicate super calls into classes ([#823](https://github.com/rokucommunity/brighterscript/pull/823))
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Tracks the busy/idle status of various sync or async tasks
3
+ * Reports the overall status to the client
4
+ */
5
+ export declare class BusyStatusTracker {
6
+ /**
7
+ * @readonly
8
+ */
9
+ activeRuns: Set<{
10
+ label?: string;
11
+ startTime?: Date;
12
+ }>;
13
+ /**
14
+ * Start a new piece of work
15
+ */
16
+ run<T, R = T | Promise<T>>(callback: (finalize?: FinalizeBuildStatusRun) => R, label?: string): R;
17
+ private emitter;
18
+ on(eventName: 'change', handler: (status: BusyStatus) => void): () => void;
19
+ private emit;
20
+ destroy(): void;
21
+ /**
22
+ * The current status of the busy tracker.
23
+ * @readonly
24
+ */
25
+ get status(): BusyStatus;
26
+ }
27
+ export declare type FinalizeBuildStatusRun = (status?: BusyStatus) => void;
28
+ export declare enum BusyStatus {
29
+ busy = "busy",
30
+ idle = "idle"
31
+ }
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BusyStatus = exports.BusyStatusTracker = void 0;
4
+ const eventemitter3_1 = require("eventemitter3");
5
+ /**
6
+ * Tracks the busy/idle status of various sync or async tasks
7
+ * Reports the overall status to the client
8
+ */
9
+ class BusyStatusTracker {
10
+ constructor() {
11
+ /**
12
+ * @readonly
13
+ */
14
+ this.activeRuns = new Set();
15
+ this.emitter = new eventemitter3_1.EventEmitter();
16
+ }
17
+ /**
18
+ * Start a new piece of work
19
+ */
20
+ run(callback, label) {
21
+ const run = {
22
+ label: label,
23
+ startTime: new Date()
24
+ };
25
+ this.activeRuns.add(run);
26
+ if (this.activeRuns.size === 1) {
27
+ this.emit('change', BusyStatus.busy);
28
+ }
29
+ let isFinalized = false;
30
+ const finalizeRun = () => {
31
+ if (isFinalized === false) {
32
+ isFinalized = true;
33
+ this.activeRuns.delete(run);
34
+ if (this.activeRuns.size <= 0) {
35
+ this.emit('change', BusyStatus.idle);
36
+ }
37
+ }
38
+ };
39
+ let result;
40
+ //call the callback function
41
+ try {
42
+ result = callback(finalizeRun);
43
+ //if the result is a promise, don't finalize until it completes
44
+ if (typeof (result === null || result === void 0 ? void 0 : result.then) === 'function') {
45
+ return Promise.resolve(result).finally(finalizeRun).then(() => result);
46
+ }
47
+ else {
48
+ finalizeRun();
49
+ return result;
50
+ }
51
+ }
52
+ catch (e) {
53
+ finalizeRun();
54
+ throw e;
55
+ }
56
+ }
57
+ on(eventName, handler) {
58
+ this.emitter.on(eventName, handler);
59
+ return () => {
60
+ this.emitter.off(eventName, handler);
61
+ };
62
+ }
63
+ emit(eventName, value) {
64
+ this.emitter.emit(eventName, value);
65
+ }
66
+ destroy() {
67
+ this.emitter.removeAllListeners();
68
+ }
69
+ /**
70
+ * The current status of the busy tracker.
71
+ * @readonly
72
+ */
73
+ get status() {
74
+ return this.activeRuns.size === 0 ? BusyStatus.idle : BusyStatus.busy;
75
+ }
76
+ }
77
+ exports.BusyStatusTracker = BusyStatusTracker;
78
+ var BusyStatus;
79
+ (function (BusyStatus) {
80
+ BusyStatus["busy"] = "busy";
81
+ BusyStatus["idle"] = "idle";
82
+ })(BusyStatus = exports.BusyStatus || (exports.BusyStatus = {}));
83
+ //# sourceMappingURL=BusyStatusTracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BusyStatusTracker.js","sourceRoot":"","sources":["../src/BusyStatusTracker.ts"],"names":[],"mappings":";;;AAAA,iDAA6C;AAE7C;;;GAGG;AACH,MAAa,iBAAiB;IAA9B;QACI;;WAEG;QACI,eAAU,GAAG,IAAI,GAAG,EAGvB,CAAC;QA4CG,YAAO,GAAG,IAAI,4BAAY,EAAsB,CAAC;IAwB7D,CAAC;IAlEG;;OAEG;IACI,GAAG,CAAwB,QAAkD,EAAE,KAAc;QAChG,MAAM,GAAG,GAAG;YACR,KAAK,EAAE,KAAK;YACZ,SAAS,EAAE,IAAI,IAAI,EAAE;SACxB,CAAC;QACF,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEzB,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,EAAE;YAC5B,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;SACxC;QAED,IAAI,WAAW,GAAG,KAAK,CAAC;QACxB,MAAM,WAAW,GAAG,GAAG,EAAE;YACrB,IAAI,WAAW,KAAK,KAAK,EAAE;gBACvB,WAAW,GAAG,IAAI,CAAC;gBACnB,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAC5B,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,EAAE;oBAC3B,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;iBACxC;aACJ;QACL,CAAC,CAAC;QAEF,IAAI,MAA0B,CAAC;QAC/B,4BAA4B;QAC5B,IAAI;YACA,MAAM,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;YAC/B,+DAA+D;YAC/D,IAAI,OAAO,CAAC,MAAc,aAAd,MAAM,uBAAN,MAAM,CAAU,IAAI,CAAA,KAAK,UAAU,EAAE;gBAC7C,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAQ,CAAC;aACjF;iBAAM;gBACH,WAAW,EAAE,CAAC;gBACd,OAAO,MAAM,CAAC;aACjB;SACJ;QAAC,OAAO,CAAC,EAAE;YACR,WAAW,EAAE,CAAC;YACd,MAAM,CAAC,CAAC;SACX;IACL,CAAC;IAIM,EAAE,CAAC,SAAmB,EAAE,OAAqC;QAChE,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACpC,OAAO,GAAG,EAAE;YACR,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACzC,CAAC,CAAC;IACN,CAAC;IAEO,IAAI,CAAC,SAAmB,EAAE,KAAiB;QAC/C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACxC,CAAC;IAEM,OAAO;QACV,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE,CAAC;IACtC,CAAC;IAED;;;OAGG;IACH,IAAW,MAAM;QACb,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;IAC1E,CAAC;CACJ;AA3ED,8CA2EC;AAID,IAAY,UAGX;AAHD,WAAY,UAAU;IAClB,2BAAa,CAAA;IACb,2BAAa,CAAA;AACjB,CAAC,EAHW,UAAU,GAAV,kBAAU,KAAV,kBAAU,QAGrB"}
@@ -3,6 +3,7 @@ import type { InitializeParams, ServerCapabilities, ExecuteCommandParams, Worksp
3
3
  import { FileChangeType } from 'vscode-languageserver/node';
4
4
  import { ProgramBuilder } from './ProgramBuilder';
5
5
  import { Throttler } from './Throttler';
6
+ import { BusyStatusTracker } from './BusyStatusTracker';
6
7
  export declare class LanguageServer {
7
8
  private connection;
8
9
  projects: Project[];
@@ -34,7 +35,10 @@ export declare class LanguageServer {
34
35
  private sendDiagnosticsThrottler;
35
36
  private boundValidateAll;
36
37
  private validateAllThrottled;
38
+ busyStatusTracker: BusyStatusTracker;
37
39
  run(): void;
40
+ private busyStatusIndex;
41
+ private sendBusyStatus;
38
42
  /**
39
43
  * Called when the client starts initialization
40
44
  */
@@ -84,6 +88,11 @@ export declare class LanguageServer {
84
88
  * A unique project counter to help distinguish log entries in lsp mode
85
89
  */
86
90
  private projectCounter;
91
+ /**
92
+ * @param projectPath path to the project
93
+ * @param workspacePath path to the workspace in which all project should reside or are referenced by
94
+ * @param projectNumber an optional project number to assign to the project. Used when reloading projects that should keep the same number
95
+ */
87
96
  private createProject;
88
97
  private createStandaloneFileProject;
89
98
  private getProjects;
@@ -143,6 +152,7 @@ export declare class LanguageServer {
143
152
  private onDefinition;
144
153
  private onSignatureHelp;
145
154
  private onReferences;
155
+ private onValidateSettled;
146
156
  private onFullSemanticTokens;
147
157
  private diagnosticCollection;
148
158
  private sendDiagnostics;
@@ -151,6 +161,10 @@ export declare class LanguageServer {
151
161
  dispose(): void;
152
162
  }
153
163
  export interface Project {
164
+ /**
165
+ * A unique number for this project, generated during this current language server session. Mostly used so we can identify which project is doing logging
166
+ */
167
+ projectNumber: number;
154
168
  firstRunPromise: Promise<any>;
155
169
  builder: ProgramBuilder;
156
170
  /**
@@ -169,3 +183,6 @@ export interface Project {
169
183
  export declare enum CustomCommands {
170
184
  TranspileFile = "TranspileFile"
171
185
  }
186
+ export declare enum NotificationName {
187
+ busyStatus = "busyStatus"
188
+ }
@@ -6,7 +6,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  return c > 3 && r && Object.defineProperty(target, key, r), r;
7
7
  };
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.CustomCommands = exports.LanguageServer = void 0;
9
+ exports.NotificationName = exports.CustomCommands = exports.LanguageServer = void 0;
10
10
  require("array-flat-polyfill");
11
11
  const fastGlob = require("fast-glob");
12
12
  const path = require("path");
@@ -24,6 +24,7 @@ const KeyedThrottler_1 = require("./KeyedThrottler");
24
24
  const DiagnosticCollection_1 = require("./DiagnosticCollection");
25
25
  const reflection_1 = require("./astUtils/reflection");
26
26
  const SemanticTokenUtils_1 = require("./SemanticTokenUtils");
27
+ const BusyStatusTracker_1 = require("./BusyStatusTracker");
27
28
  class LanguageServer {
28
29
  constructor() {
29
30
  this.connection = undefined;
@@ -53,6 +54,8 @@ class LanguageServer {
53
54
  this.validateThrottler = new Throttler_1.Throttler(0);
54
55
  this.sendDiagnosticsThrottler = new Throttler_1.Throttler(0);
55
56
  this.boundValidateAll = this.validateAll.bind(this);
57
+ this.busyStatusTracker = new BusyStatusTracker_1.BusyStatusTracker();
58
+ this.busyStatusIndex = -1;
56
59
  /**
57
60
  * A unique project counter to help distinguish log entries in lsp mode
58
61
  */
@@ -70,6 +73,10 @@ class LanguageServer {
70
73
  // Create a connection for the server. The connection uses Node's IPC as a transport.
71
74
  // Also include all preview / proposed LSP features.
72
75
  this.connection = this.createConnection();
76
+ // Send the current status of the busyStatusTracker anytime it changes
77
+ this.busyStatusTracker.on('change', (status) => {
78
+ this.sendBusyStatus(status);
79
+ });
73
80
  //listen to all of the output log events and pipe them into the debug channel in the extension
74
81
  this.loggerSubscription = Logger_1.Logger.subscribe((text) => {
75
82
  this.connection.tracer.log(text);
@@ -124,6 +131,15 @@ class LanguageServer {
124
131
  // Listen on the connection
125
132
  this.connection.listen();
126
133
  }
134
+ sendBusyStatus(status) {
135
+ this.busyStatusIndex = ++this.busyStatusIndex <= 0 ? 0 : this.busyStatusIndex;
136
+ this.connection.sendNotification(NotificationName.busyStatus, {
137
+ status: status,
138
+ timestamp: Date.now(),
139
+ index: this.busyStatusIndex,
140
+ activeRuns: [...this.busyStatusTracker.activeRuns]
141
+ });
142
+ }
127
143
  /**
128
144
  * Called when the client starts initialization
129
145
  */
@@ -326,7 +342,6 @@ class LanguageServer {
326
342
  if (waitForFirstProject) {
327
343
  await this.initialProjectsCreated;
328
344
  }
329
- let status;
330
345
  for (let project of this.getProjects()) {
331
346
  try {
332
347
  await project.firstRunPromise;
@@ -339,7 +354,6 @@ class LanguageServer {
339
354
  this.sendCriticalFailure(`BrighterScript language server failed to start: \n${e.message}`);
340
355
  }
341
356
  }
342
- this.connection.sendNotification('build-status', status ? status : 'success');
343
357
  }
344
358
  /**
345
359
  * Event handler for when the program wants to load file contents.
@@ -394,7 +408,12 @@ class LanguageServer {
394
408
  //no config file could be found
395
409
  return undefined;
396
410
  }
397
- async createProject(projectPath, workspacePath = projectPath) {
411
+ /**
412
+ * @param projectPath path to the project
413
+ * @param workspacePath path to the workspace in which all project should reside or are referenced by
414
+ * @param projectNumber an optional project number to assign to the project. Used when reloading projects that should keep the same number
415
+ */
416
+ async createProject(projectPath, workspacePath = projectPath, projectNumber) {
398
417
  workspacePath !== null && workspacePath !== void 0 ? workspacePath : (workspacePath = projectPath);
399
418
  let project = this.projects.find((x) => x.projectPath === projectPath);
400
419
  //skip this project if we already have it
@@ -402,7 +421,7 @@ class LanguageServer {
402
421
  return;
403
422
  }
404
423
  let builder = new ProgramBuilder_1.ProgramBuilder();
405
- const projectNumber = this.projectCounter++;
424
+ projectNumber !== null && projectNumber !== void 0 ? projectNumber : (projectNumber = this.projectCounter++);
406
425
  builder.logger.prefix = `[prj${projectNumber}]`;
407
426
  builder.logger.log(`Created project #${projectNumber} for: "${projectPath}"`);
408
427
  //flush diagnostics every time the program finishes validating
@@ -426,21 +445,11 @@ class LanguageServer {
426
445
  //config file doesn't exist...let `brighterscript` resolve the default way
427
446
  configFilePath = undefined;
428
447
  }
429
- let firstRunPromise = builder.run({
430
- cwd: cwd,
431
- project: configFilePath,
432
- watch: false,
433
- createPackage: false,
434
- deploy: false,
435
- copyToStaging: false,
436
- showDiagnosticsInConsole: false
437
- });
438
- firstRunPromise.catch((err) => {
439
- console.error(err);
440
- });
448
+ const firstRunDeferred = new deferred_1.Deferred();
441
449
  let newProject = {
450
+ projectNumber: projectNumber,
442
451
  builder: builder,
443
- firstRunPromise: firstRunPromise,
452
+ firstRunPromise: firstRunDeferred.promise,
444
453
  projectPath: projectPath,
445
454
  workspacePath: workspacePath,
446
455
  isFirstRunComplete: false,
@@ -449,19 +458,31 @@ class LanguageServer {
449
458
  isStandaloneFileProject: false
450
459
  };
451
460
  this.projects.push(newProject);
452
- await firstRunPromise.then(() => {
461
+ try {
462
+ await builder.run({
463
+ cwd: cwd,
464
+ project: configFilePath,
465
+ watch: false,
466
+ createPackage: false,
467
+ deploy: false,
468
+ copyToStaging: false,
469
+ showDiagnosticsInConsole: false
470
+ });
453
471
  newProject.isFirstRunComplete = true;
454
472
  newProject.isFirstRunSuccessful = true;
455
- }).catch(() => {
473
+ firstRunDeferred.resolve();
474
+ }
475
+ catch (e) {
476
+ builder.logger.error(e);
477
+ firstRunDeferred.reject(e);
456
478
  newProject.isFirstRunComplete = true;
457
479
  newProject.isFirstRunSuccessful = false;
458
- }).then(() => {
459
- //if we found a deprecated brsconfig.json, add a diagnostic warning the user
460
- if (configFilePath && path.basename(configFilePath) === 'brsconfig.json') {
461
- builder.addDiagnostic(configFilePath, Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.brsConfigJsonIsDeprecated()), { range: util_1.util.createRange(0, 0, 0, 0) }));
462
- return this.sendDiagnostics();
463
- }
464
- });
480
+ }
481
+ //if we found a deprecated brsconfig.json, add a diagnostic warning the user
482
+ if (configFilePath && path.basename(configFilePath) === 'brsconfig.json') {
483
+ builder.addDiagnostic(configFilePath, Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.brsConfigJsonIsDeprecated()), { range: util_1.util.createRange(0, 0, 0, 0) }));
484
+ return this.sendDiagnostics();
485
+ }
465
486
  }
466
487
  async createStandaloneFileProject(srcPath) {
467
488
  //skip this workspace if we already have it
@@ -494,6 +515,7 @@ class LanguageServer {
494
515
  console.error(err);
495
516
  });
496
517
  let newProject = {
518
+ projectNumber: this.projectCounter++,
497
519
  builder: builder,
498
520
  firstRunPromise: firstRunPromise,
499
521
  projectPath: srcPath,
@@ -595,7 +617,7 @@ class LanguageServer {
595
617
  if (project.isStandaloneFileProject === false) {
596
618
  this.removeProject(project);
597
619
  //create a new workspace/brs program
598
- await this.createProject(project.projectPath, project.workspacePath);
620
+ await this.createProject(project.projectPath, project.workspacePath, project.projectNumber);
599
621
  //handle temp workspace
600
622
  }
601
623
  else {
@@ -676,7 +698,6 @@ class LanguageServer {
676
698
  async onDidChangeWatchedFiles(params) {
677
699
  //ensure programs are initialized
678
700
  await this.waitAllProjectFirstRuns();
679
- this.connection.sendNotification('build-status', 'building');
680
701
  let projects = this.getProjects();
681
702
  //convert all file paths to absolute paths
682
703
  let changes = params.changes.map(x => {
@@ -745,7 +766,6 @@ class LanguageServer {
745
766
  //give every workspace the chance to handle file changes
746
767
  await Promise.all(projects.map((project) => this.handleFileChanges(project, changes)));
747
768
  }
748
- this.connection.sendNotification('build-status', 'success');
749
769
  }
750
770
  /**
751
771
  * This only operates on files that match the specified files globs, so it is safe to throw
@@ -870,7 +890,6 @@ class LanguageServer {
870
890
  //throttle file processing. first call is run immediately, and then the last call is processed.
871
891
  await this.keyedThrottler.run(filePath, () => {
872
892
  var _a;
873
- this.connection.sendNotification('build-status', 'building');
874
893
  let documentText = document.getText();
875
894
  for (const project of this.getProjects()) {
876
895
  //only add or replace existing files. All of the files in the project should
@@ -899,13 +918,15 @@ class LanguageServer {
899
918
  await this.synchronizeStandaloneProjects();
900
919
  let projects = this.getProjects();
901
920
  //validate all programs
902
- await Promise.all(projects.map((x) => x.builder.program.validate()));
921
+ await Promise.all(projects.map((project) => {
922
+ project.builder.program.validate();
923
+ return project;
924
+ }));
903
925
  }
904
926
  catch (e) {
905
927
  this.connection.console.error(e);
906
928
  this.sendCriticalFailure(`Critical error validating project: ${e.message}${(_a = e.stack) !== null && _a !== void 0 ? _a : ''}`);
907
929
  }
908
- this.connection.sendNotification('build-status', 'success');
909
930
  }
910
931
  async onWorkspaceSymbol(params) {
911
932
  await this.waitAllProjectFirstRuns();
@@ -973,15 +994,20 @@ class LanguageServer {
973
994
  })), c => c);
974
995
  return results.filter((r) => r);
975
996
  }
997
+ onValidateSettled() {
998
+ return Promise.all([
999
+ //wait for the validator to start running (or timeout if it never did)
1000
+ this.validateThrottler.onRunOnce(100),
1001
+ //wait for the validator to stop running (or resolve immediately if it's already idle)
1002
+ this.validateThrottler.onIdleOnce(true)
1003
+ ]);
1004
+ }
976
1005
  async onFullSemanticTokens(params) {
977
1006
  await this.waitAllProjectFirstRuns();
978
- await Promise.all([
979
- //wait for the file to settle (in case there are multiple file changes in quick succession)
980
- this.keyedThrottler.onIdleOnce(util_1.util.uriToPath(params.textDocument.uri), true),
981
- // wait for the validation to finish before providing semantic tokens. program.validate() populates and then caches AstNode.parent properties.
982
- // If we don't wait, then fetching semantic tokens can cause some invalid cache
983
- this.validateThrottler.onIdleOnce(false)
984
- ]);
1007
+ //wait for the file to settle (in case there are multiple file changes in quick succession)
1008
+ await this.keyedThrottler.onIdleOnce(util_1.util.uriToPath(params.textDocument.uri), true);
1009
+ //wait for the validation cycle to settle
1010
+ await this.onValidateSettled();
985
1011
  const srcPath = util_1.util.uriToPath(params.textDocument.uri);
986
1012
  for (const project of this.projects) {
987
1013
  //find the first program that has this file, since it would be incredibly inefficient to generate semantic tokens for the same file multiple times.
@@ -1038,22 +1064,35 @@ __decorate([
1038
1064
  AddStackToErrorMessage
1039
1065
  ], LanguageServer.prototype, "onInitialize", null);
1040
1066
  __decorate([
1041
- AddStackToErrorMessage
1067
+ TrackBusyStatus
1068
+ ], LanguageServer.prototype, "getProjectPaths", null);
1069
+ __decorate([
1070
+ TrackBusyStatus
1071
+ ], LanguageServer.prototype, "syncProjects", null);
1072
+ __decorate([
1073
+ AddStackToErrorMessage,
1074
+ TrackBusyStatus
1042
1075
  ], LanguageServer.prototype, "onInitialized", null);
1043
1076
  __decorate([
1044
- AddStackToErrorMessage
1077
+ TrackBusyStatus
1078
+ ], LanguageServer.prototype, "createProject", null);
1079
+ __decorate([
1080
+ AddStackToErrorMessage,
1081
+ TrackBusyStatus
1045
1082
  ], LanguageServer.prototype, "onCompletion", null);
1046
1083
  __decorate([
1047
1084
  AddStackToErrorMessage
1048
1085
  ], LanguageServer.prototype, "onCompletionResolve", null);
1049
1086
  __decorate([
1050
- AddStackToErrorMessage
1087
+ AddStackToErrorMessage,
1088
+ TrackBusyStatus
1051
1089
  ], LanguageServer.prototype, "onCodeAction", null);
1052
1090
  __decorate([
1053
1091
  AddStackToErrorMessage
1054
1092
  ], LanguageServer.prototype, "onDidChangeConfiguration", null);
1055
1093
  __decorate([
1056
- AddStackToErrorMessage
1094
+ AddStackToErrorMessage,
1095
+ TrackBusyStatus
1057
1096
  ], LanguageServer.prototype, "onDidChangeWatchedFiles", null);
1058
1097
  __decorate([
1059
1098
  AddStackToErrorMessage
@@ -1062,34 +1101,49 @@ __decorate([
1062
1101
  AddStackToErrorMessage
1063
1102
  ], LanguageServer.prototype, "onDocumentClose", null);
1064
1103
  __decorate([
1065
- AddStackToErrorMessage
1104
+ AddStackToErrorMessage,
1105
+ TrackBusyStatus
1066
1106
  ], LanguageServer.prototype, "validateTextDocument", null);
1067
1107
  __decorate([
1068
- AddStackToErrorMessage
1108
+ TrackBusyStatus
1109
+ ], LanguageServer.prototype, "validateAll", null);
1110
+ __decorate([
1111
+ AddStackToErrorMessage,
1112
+ TrackBusyStatus
1069
1113
  ], LanguageServer.prototype, "onWorkspaceSymbol", null);
1070
1114
  __decorate([
1071
- AddStackToErrorMessage
1115
+ AddStackToErrorMessage,
1116
+ TrackBusyStatus
1072
1117
  ], LanguageServer.prototype, "onDocumentSymbol", null);
1073
1118
  __decorate([
1074
- AddStackToErrorMessage
1119
+ AddStackToErrorMessage,
1120
+ TrackBusyStatus
1075
1121
  ], LanguageServer.prototype, "onDefinition", null);
1076
1122
  __decorate([
1077
- AddStackToErrorMessage
1123
+ AddStackToErrorMessage,
1124
+ TrackBusyStatus
1078
1125
  ], LanguageServer.prototype, "onSignatureHelp", null);
1079
1126
  __decorate([
1080
- AddStackToErrorMessage
1127
+ AddStackToErrorMessage,
1128
+ TrackBusyStatus
1081
1129
  ], LanguageServer.prototype, "onReferences", null);
1082
1130
  __decorate([
1083
- AddStackToErrorMessage
1131
+ AddStackToErrorMessage,
1132
+ TrackBusyStatus
1084
1133
  ], LanguageServer.prototype, "onFullSemanticTokens", null);
1085
1134
  __decorate([
1086
- AddStackToErrorMessage
1135
+ AddStackToErrorMessage,
1136
+ TrackBusyStatus
1087
1137
  ], LanguageServer.prototype, "onExecuteCommand", null);
1088
1138
  exports.LanguageServer = LanguageServer;
1089
1139
  var CustomCommands;
1090
1140
  (function (CustomCommands) {
1091
1141
  CustomCommands["TranspileFile"] = "TranspileFile";
1092
1142
  })(CustomCommands = exports.CustomCommands || (exports.CustomCommands = {}));
1143
+ var NotificationName;
1144
+ (function (NotificationName) {
1145
+ NotificationName["busyStatus"] = "busyStatus";
1146
+ })(NotificationName = exports.NotificationName || (exports.NotificationName = {}));
1093
1147
  /**
1094
1148
  * Wraps a method. If there's an error (either sync or via a promise),
1095
1149
  * this appends the error's stack trace at the end of the error message so that the connection will
@@ -1121,4 +1175,16 @@ function AddStackToErrorMessage(target, propertyKey, descriptor) {
1121
1175
  }
1122
1176
  };
1123
1177
  }
1178
+ /**
1179
+ * An annotation used to wrap the method in a busyStatus tracking call
1180
+ */
1181
+ function TrackBusyStatus(target, propertyKey, descriptor) {
1182
+ let originalMethod = descriptor.value;
1183
+ //wrapping the original method
1184
+ descriptor.value = function value(...args) {
1185
+ return this.busyStatusTracker.run(() => {
1186
+ return originalMethod.apply(this, args);
1187
+ }, originalMethod.name);
1188
+ };
1189
+ }
1124
1190
  //# sourceMappingURL=LanguageServer.js.map