brighterscript 1.0.0-alpha.44 → 1.0.0-alpha.46

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 (229) hide show
  1. package/bsconfig.schema.json +6 -1
  2. package/dist/AstValidationSegmenter.js +6 -1
  3. package/dist/AstValidationSegmenter.js.map +1 -1
  4. package/dist/BsConfig.d.ts +4 -0
  5. package/dist/BusyStatusTracker.d.ts +37 -7
  6. package/dist/BusyStatusTracker.js +73 -8
  7. package/dist/BusyStatusTracker.js.map +1 -1
  8. package/dist/Cache.d.ts +0 -4
  9. package/dist/Cache.js +0 -6
  10. package/dist/Cache.js.map +1 -1
  11. package/dist/CodeActionUtil.d.ts +6 -1
  12. package/dist/CodeActionUtil.js +3 -0
  13. package/dist/CodeActionUtil.js.map +1 -1
  14. package/dist/CrossScopeValidator.d.ts +1 -1
  15. package/dist/CrossScopeValidator.js +8 -7
  16. package/dist/CrossScopeValidator.js.map +1 -1
  17. package/dist/DiagnosticCollection.d.ts +19 -5
  18. package/dist/DiagnosticCollection.js +71 -23
  19. package/dist/DiagnosticCollection.js.map +1 -1
  20. package/dist/DiagnosticFilterer.d.ts +14 -1
  21. package/dist/DiagnosticFilterer.js +130 -12
  22. package/dist/DiagnosticFilterer.js.map +1 -1
  23. package/dist/DiagnosticManager.d.ts +11 -1
  24. package/dist/DiagnosticManager.js +192 -35
  25. package/dist/DiagnosticManager.js.map +1 -1
  26. package/dist/DiagnosticMessages.d.ts +19 -7
  27. package/dist/DiagnosticMessages.js +21 -9
  28. package/dist/DiagnosticMessages.js.map +1 -1
  29. package/dist/LanguageServer.d.ts +82 -139
  30. package/dist/LanguageServer.js +402 -980
  31. package/dist/LanguageServer.js.map +1 -1
  32. package/dist/Logger.d.ts +9 -4
  33. package/dist/Logger.js +30 -6
  34. package/dist/Logger.js.map +1 -1
  35. package/dist/PluginInterface.d.ts +8 -8
  36. package/dist/PluginInterface.js.map +1 -1
  37. package/dist/Program.d.ts +23 -4
  38. package/dist/Program.js +294 -194
  39. package/dist/Program.js.map +1 -1
  40. package/dist/ProgramBuilder.d.ts +22 -7
  41. package/dist/ProgramBuilder.js +44 -21
  42. package/dist/ProgramBuilder.js.map +1 -1
  43. package/dist/Scope.d.ts +11 -6
  44. package/dist/Scope.js +60 -36
  45. package/dist/Scope.js.map +1 -1
  46. package/dist/SemanticTokenUtils.js +1 -1
  47. package/dist/SemanticTokenUtils.js.map +1 -1
  48. package/dist/astUtils/CachedLookups.js +0 -1
  49. package/dist/astUtils/CachedLookups.js.map +1 -1
  50. package/dist/astUtils/reflection.d.ts +4 -4
  51. package/dist/astUtils/reflection.js +12 -10
  52. package/dist/astUtils/reflection.js.map +1 -1
  53. package/dist/bscPlugin/BscPlugin.d.ts +3 -3
  54. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  55. package/dist/bscPlugin/CallExpressionInfo.js +4 -2
  56. package/dist/bscPlugin/CallExpressionInfo.js.map +1 -1
  57. package/dist/bscPlugin/codeActions/CodeActionsProcessor.d.ts +2 -0
  58. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +147 -0
  59. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  60. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +44 -0
  61. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
  62. package/dist/bscPlugin/completions/CompletionsProcessor.d.ts +1 -1
  63. package/dist/bscPlugin/completions/CompletionsProcessor.js +15 -15
  64. package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -1
  65. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js +82 -5
  66. package/dist/bscPlugin/completions/CompletionsProcessor.spec.js.map +1 -1
  67. package/dist/bscPlugin/hover/HoverProcessor.js +3 -0
  68. package/dist/bscPlugin/hover/HoverProcessor.js.map +1 -1
  69. package/dist/bscPlugin/hover/HoverProcessor.spec.js +44 -0
  70. package/dist/bscPlugin/hover/HoverProcessor.spec.js.map +1 -1
  71. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +4 -0
  72. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
  73. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +17 -0
  74. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -1
  75. package/dist/bscPlugin/validation/BrsFileValidator.js +21 -0
  76. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
  77. package/dist/bscPlugin/validation/BrsFileValidator.spec.js +161 -7
  78. package/dist/bscPlugin/validation/BrsFileValidator.spec.js.map +1 -1
  79. package/dist/bscPlugin/validation/ScopeValidator.d.ts +4 -1
  80. package/dist/bscPlugin/validation/ScopeValidator.js +166 -63
  81. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  82. package/dist/bscPlugin/validation/ScopeValidator.spec.js +21 -9
  83. package/dist/bscPlugin/validation/ScopeValidator.spec.js.map +1 -1
  84. package/dist/common/Sequencer.d.ts +53 -0
  85. package/dist/common/Sequencer.js +233 -0
  86. package/dist/common/Sequencer.js.map +1 -0
  87. package/dist/common/Sequencer.spec.d.ts +1 -0
  88. package/dist/common/Sequencer.spec.js +75 -0
  89. package/dist/common/Sequencer.spec.js.map +1 -0
  90. package/dist/deferred.d.ts +2 -0
  91. package/dist/deferred.js +10 -0
  92. package/dist/deferred.js.map +1 -1
  93. package/dist/examples/plugins/removePrint.d.ts +2 -2
  94. package/dist/examples/plugins/removePrint.js.map +1 -1
  95. package/dist/files/BrsFile.d.ts +1 -1
  96. package/dist/files/BrsFile.js +22 -42
  97. package/dist/files/BrsFile.js.map +1 -1
  98. package/dist/files/BrsFile.spec.js +155 -4
  99. package/dist/files/BrsFile.spec.js.map +1 -1
  100. package/dist/files/BscFile.d.ts +1 -0
  101. package/dist/files/LazyFileData.d.ts +1 -0
  102. package/dist/files/XmlFile.spec.js +1 -1
  103. package/dist/files/XmlFile.spec.js.map +1 -1
  104. package/dist/globalCallables.js +189 -189
  105. package/dist/globalCallables.js.map +1 -1
  106. package/dist/interfaces.d.ts +56 -13
  107. package/dist/interfaces.js.map +1 -1
  108. package/dist/lexer/Lexer.js +1 -1
  109. package/dist/lexer/Lexer.js.map +1 -1
  110. package/dist/logging.d.ts +6 -1
  111. package/dist/logging.js +14 -1
  112. package/dist/logging.js.map +1 -1
  113. package/dist/lsp/ActionQueue.d.ts +35 -0
  114. package/dist/lsp/ActionQueue.js +115 -0
  115. package/dist/lsp/ActionQueue.js.map +1 -0
  116. package/dist/lsp/ActionQueue.spec.d.ts +1 -0
  117. package/dist/lsp/ActionQueue.spec.js +80 -0
  118. package/dist/lsp/ActionQueue.spec.js.map +1 -0
  119. package/dist/lsp/DocumentManager.d.ts +63 -0
  120. package/dist/lsp/DocumentManager.js +122 -0
  121. package/dist/lsp/DocumentManager.js.map +1 -0
  122. package/dist/lsp/DocumentManager.spec.d.ts +1 -0
  123. package/dist/lsp/DocumentManager.spec.js +103 -0
  124. package/dist/lsp/DocumentManager.spec.js.map +1 -0
  125. package/dist/lsp/LspProject.d.ts +231 -0
  126. package/dist/lsp/LspProject.js +3 -0
  127. package/dist/lsp/LspProject.js.map +1 -0
  128. package/dist/lsp/PathFilterer.d.ts +75 -0
  129. package/dist/lsp/PathFilterer.js +196 -0
  130. package/dist/lsp/PathFilterer.js.map +1 -0
  131. package/dist/lsp/PathFilterer.spec.d.ts +1 -0
  132. package/dist/lsp/PathFilterer.spec.js +182 -0
  133. package/dist/lsp/PathFilterer.spec.js.map +1 -0
  134. package/dist/lsp/Project.d.ts +167 -0
  135. package/dist/lsp/Project.js +432 -0
  136. package/dist/lsp/Project.js.map +1 -0
  137. package/dist/lsp/Project.spec.d.ts +1 -0
  138. package/dist/lsp/Project.spec.js +220 -0
  139. package/dist/lsp/Project.spec.js.map +1 -0
  140. package/dist/lsp/ProjectManager.d.ts +221 -0
  141. package/dist/lsp/ProjectManager.js +754 -0
  142. package/dist/lsp/ProjectManager.js.map +1 -0
  143. package/dist/lsp/ProjectManager.spec.d.ts +1 -0
  144. package/dist/lsp/ProjectManager.spec.js +783 -0
  145. package/dist/lsp/ProjectManager.spec.js.map +1 -0
  146. package/dist/lsp/ReaderWriterManager.d.ts +21 -0
  147. package/dist/lsp/ReaderWriterManager.js +60 -0
  148. package/dist/lsp/ReaderWriterManager.js.map +1 -0
  149. package/dist/lsp/worker/MessageHandler.d.ts +99 -0
  150. package/dist/lsp/worker/MessageHandler.js +138 -0
  151. package/dist/lsp/worker/MessageHandler.js.map +1 -0
  152. package/dist/lsp/worker/MessageHandler.spec.d.ts +1 -0
  153. package/dist/lsp/worker/MessageHandler.spec.js +64 -0
  154. package/dist/lsp/worker/MessageHandler.spec.js.map +1 -0
  155. package/dist/lsp/worker/WorkerPool.d.ts +38 -0
  156. package/dist/lsp/worker/WorkerPool.js +78 -0
  157. package/dist/lsp/worker/WorkerPool.js.map +1 -0
  158. package/dist/lsp/worker/WorkerPool.spec.d.ts +1 -0
  159. package/dist/lsp/worker/WorkerPool.spec.js +59 -0
  160. package/dist/lsp/worker/WorkerPool.spec.js.map +1 -0
  161. package/dist/lsp/worker/WorkerThreadProject.d.ts +144 -0
  162. package/dist/lsp/worker/WorkerThreadProject.js +183 -0
  163. package/dist/lsp/worker/WorkerThreadProject.js.map +1 -0
  164. package/dist/lsp/worker/WorkerThreadProject.spec.d.ts +2 -0
  165. package/dist/lsp/worker/WorkerThreadProject.spec.js +68 -0
  166. package/dist/lsp/worker/WorkerThreadProject.spec.js.map +1 -0
  167. package/dist/lsp/worker/WorkerThreadProjectRunner.d.ts +15 -0
  168. package/dist/lsp/worker/WorkerThreadProjectRunner.js +58 -0
  169. package/dist/lsp/worker/WorkerThreadProjectRunner.js.map +1 -0
  170. package/dist/parser/Expression.d.ts +1 -0
  171. package/dist/parser/Expression.js +65 -3
  172. package/dist/parser/Expression.js.map +1 -1
  173. package/dist/parser/Parser.spec.js +12 -0
  174. package/dist/parser/Parser.spec.js.map +1 -1
  175. package/dist/parser/Statement.js +2 -2
  176. package/dist/parser/Statement.js.map +1 -1
  177. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +47 -0
  178. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  179. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +51 -5
  180. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  181. package/dist/parser/tests/expression/TernaryExpression.spec.js +44 -0
  182. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  183. package/dist/roku-types/data.json +880 -756
  184. package/dist/roku-types/index.d.ts +17 -0
  185. package/dist/types/BooleanType.d.ts +0 -2
  186. package/dist/types/BooleanType.js +4 -6
  187. package/dist/types/BooleanType.js.map +1 -1
  188. package/dist/types/BscType.js +5 -0
  189. package/dist/types/BscType.js.map +1 -1
  190. package/dist/types/BuiltInInterfaceAdder.d.ts +1 -0
  191. package/dist/types/BuiltInInterfaceAdder.js +24 -17
  192. package/dist/types/BuiltInInterfaceAdder.js.map +1 -1
  193. package/dist/types/DoubleType.d.ts +0 -2
  194. package/dist/types/DoubleType.js +4 -6
  195. package/dist/types/DoubleType.js.map +1 -1
  196. package/dist/types/DynamicType.d.ts +0 -2
  197. package/dist/types/DynamicType.js +3 -5
  198. package/dist/types/DynamicType.js.map +1 -1
  199. package/dist/types/FloatType.d.ts +0 -2
  200. package/dist/types/FloatType.js +4 -6
  201. package/dist/types/FloatType.js.map +1 -1
  202. package/dist/types/FunctionType.d.ts +0 -2
  203. package/dist/types/FunctionType.js +5 -7
  204. package/dist/types/FunctionType.js.map +1 -1
  205. package/dist/types/IntegerType.d.ts +0 -2
  206. package/dist/types/IntegerType.js +4 -6
  207. package/dist/types/IntegerType.js.map +1 -1
  208. package/dist/types/LongIntegerType.d.ts +0 -2
  209. package/dist/types/LongIntegerType.js +4 -6
  210. package/dist/types/LongIntegerType.js.map +1 -1
  211. package/dist/types/ObjectType.d.ts +3 -3
  212. package/dist/types/ObjectType.js +6 -8
  213. package/dist/types/ObjectType.js.map +1 -1
  214. package/dist/types/StringType.d.ts +0 -2
  215. package/dist/types/StringType.js +4 -6
  216. package/dist/types/StringType.js.map +1 -1
  217. package/dist/types/VoidType.d.ts +0 -2
  218. package/dist/types/VoidType.js +4 -6
  219. package/dist/types/VoidType.js.map +1 -1
  220. package/dist/types/helpers.d.ts +4 -0
  221. package/dist/types/helpers.js +5 -1
  222. package/dist/types/helpers.js.map +1 -1
  223. package/dist/util.d.ts +48 -16
  224. package/dist/util.js +203 -70
  225. package/dist/util.js.map +1 -1
  226. package/dist/validators/ClassValidator.js +2 -2
  227. package/dist/validators/ClassValidator.js.map +1 -1
  228. package/package.json +15 -5
  229. package/CHANGELOG.md +0 -2352
@@ -0,0 +1,783 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const chai_1 = require("chai");
4
+ const ProjectManager_1 = require("./ProjectManager");
5
+ const testHelpers_spec_1 = require("../testHelpers.spec");
6
+ const fsExtra = require("fs-extra");
7
+ const util_1 = require("../util");
8
+ const sinon_1 = require("sinon");
9
+ const Project_1 = require("./Project");
10
+ const WorkerThreadProject_1 = require("./worker/WorkerThreadProject");
11
+ const WorkerThreadProject_spec_1 = require("./worker/WorkerThreadProject.spec");
12
+ const DiagnosticMessages_1 = require("../DiagnosticMessages");
13
+ const vscode_languageserver_protocol_1 = require("vscode-languageserver-protocol");
14
+ const PathFilterer_1 = require("./PathFilterer");
15
+ const deferred_1 = require("../deferred");
16
+ const net = require("net");
17
+ const getPort = require("get-port");
18
+ const sinon = (0, sinon_1.createSandbox)();
19
+ describe('ProjectManager', () => {
20
+ let manager;
21
+ let pathFilterer;
22
+ beforeEach(() => {
23
+ pathFilterer = new PathFilterer_1.PathFilterer();
24
+ manager = new ProjectManager_1.ProjectManager({
25
+ pathFilterer: pathFilterer
26
+ });
27
+ fsExtra.emptyDirSync(testHelpers_spec_1.tempDir);
28
+ sinon.restore();
29
+ diagnosticsListeners = [];
30
+ diagnosticsResponses = [];
31
+ manager.on('diagnostics', (event) => {
32
+ var _a;
33
+ if (diagnosticsListeners.length > 0) {
34
+ (_a = diagnosticsListeners.shift()) === null || _a === void 0 ? void 0 : _a(event.diagnostics);
35
+ }
36
+ else {
37
+ diagnosticsResponses.push(event.diagnostics);
38
+ }
39
+ });
40
+ });
41
+ afterEach(() => {
42
+ fsExtra.emptyDirSync(testHelpers_spec_1.tempDir);
43
+ sinon.restore();
44
+ manager.dispose();
45
+ });
46
+ let diagnosticsListeners = [];
47
+ let diagnosticsResponses = [];
48
+ /**
49
+ * Get a promise that resolves when the next diagnostics event is emitted (or pop the earliest unhandled diagnostics list if some are already here)
50
+ */
51
+ function onNextDiagnostics() {
52
+ if (diagnosticsResponses.length > 0) {
53
+ return Promise.resolve(diagnosticsResponses.shift());
54
+ }
55
+ else {
56
+ return new Promise((resolve) => {
57
+ diagnosticsListeners.push(resolve);
58
+ });
59
+ }
60
+ }
61
+ async function setFile(srcPath, contents) {
62
+ //set the namespace first
63
+ await manager.handleFileChanges([{
64
+ srcPath: srcPath,
65
+ type: vscode_languageserver_protocol_1.FileChangeType.Changed,
66
+ fileContents: contents,
67
+ allowStandaloneProject: false
68
+ }]);
69
+ }
70
+ describe('on', () => {
71
+ it('emits events', async () => {
72
+ const stub = sinon.stub();
73
+ const off = manager.on('diagnostics', stub);
74
+ await manager['emit']('diagnostics', { project: undefined, diagnostics: [] });
75
+ (0, chai_1.expect)(stub.callCount).to.eql(1);
76
+ await manager['emit']('diagnostics', { project: undefined, diagnostics: [] });
77
+ (0, chai_1.expect)(stub.callCount).to.eql(2);
78
+ off();
79
+ await manager['emit']('diagnostics', { project: undefined, diagnostics: [] });
80
+ (0, chai_1.expect)(stub.callCount).to.eql(2);
81
+ });
82
+ });
83
+ describe('validation tracking', () => {
84
+ it('tracks validation state', async () => {
85
+ await manager.syncProjects([{
86
+ workspaceFolder: testHelpers_spec_1.rootDir
87
+ }]);
88
+ const project = manager.projects[0];
89
+ //force validation to take a while
90
+ sinon.stub(project['builder'].program, 'validate').callsFake(async () => {
91
+ await util_1.default.sleep(100);
92
+ });
93
+ (0, chai_1.expect)(manager.busyStatusTracker.status).to.eql('idle');
94
+ //run several validations (which cancel the previous)
95
+ void project.validate();
96
+ await util_1.default.sleep(10);
97
+ void project.validate();
98
+ await util_1.default.sleep(10);
99
+ void project.validate();
100
+ await util_1.default.sleep(10);
101
+ //busy status should be active
102
+ (0, chai_1.expect)(manager.busyStatusTracker.status).to.eql('busy');
103
+ });
104
+ });
105
+ describe('getHover', () => {
106
+ it('dedupes identical hover contents', async () => {
107
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/source/main.brs`, `
108
+ sub main()
109
+ end sub
110
+ `);
111
+ await manager.syncProjects([{
112
+ workspaceFolder: testHelpers_spec_1.rootDir
113
+ }]);
114
+ sinon.stub(manager.projects[0], 'getHover').returns(Promise.resolve([{
115
+ contents: ['one', 'two', 'three'],
116
+ range: util_1.default.createRange(1, 1, 1, 1)
117
+ }, {
118
+ contents: ['two', 'three', 'four'],
119
+ range: util_1.default.createRange(2, 2, 2, 2)
120
+ }]));
121
+ const hover = await manager.getHover({
122
+ srcPath: (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/main.brs`,
123
+ position: util_1.default.createPosition(1, 23)
124
+ });
125
+ (0, chai_1.expect)(hover).to.eql({
126
+ contents: ['one', 'two', 'three', 'four'],
127
+ range: util_1.default.createRange(1, 1, 2, 2)
128
+ });
129
+ });
130
+ });
131
+ describe('syncProjects', () => {
132
+ it('does not crash on zero projects', async () => {
133
+ await manager.syncProjects([]);
134
+ });
135
+ it('finds bsconfig in a folder', async () => {
136
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/bsconfig.json`, '');
137
+ await manager.syncProjects([{
138
+ workspaceFolder: testHelpers_spec_1.rootDir
139
+ }]);
140
+ (0, chai_1.expect)(manager.projects[0].projectPath).to.eql((0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}`);
141
+ });
142
+ it('finds bsconfig at root and also in subfolder', async () => {
143
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/bsconfig.json`, '');
144
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/subdir/bsconfig.json`, '');
145
+ await manager.syncProjects([{
146
+ workspaceFolder: testHelpers_spec_1.rootDir
147
+ }]);
148
+ (0, chai_1.expect)(manager.projects.map(x => x.projectPath).sort()).to.eql([
149
+ (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}`,
150
+ (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/subdir`
151
+ ]);
152
+ });
153
+ it('skips excluded bsconfig bsconfig in a folder', async () => {
154
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/bsconfig.json`, '');
155
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/subdir/bsconfig.json`, '');
156
+ await manager.syncProjects([{
157
+ workspaceFolder: testHelpers_spec_1.rootDir,
158
+ excludePatterns: ['subdir/**/*']
159
+ }]);
160
+ (0, chai_1.expect)(manager.projects.map(x => x.projectPath)).to.eql([
161
+ (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}`
162
+ ]);
163
+ });
164
+ it('uses rootDir when manifest found but no brightscript file', async () => {
165
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/subdir/manifest`, '');
166
+ await manager.syncProjects([{
167
+ workspaceFolder: testHelpers_spec_1.rootDir
168
+ }]);
169
+ (0, chai_1.expect)(manager.projects.map(x => x.projectPath)).to.eql([
170
+ (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}`
171
+ ]);
172
+ });
173
+ it('gets diagnostics from plugins added in afterProgramValidate', async () => {
174
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/plugin.js`, `
175
+ module.exports = function () {
176
+ return {
177
+ afterProgramValidate: function(event) {
178
+ var file = event.program.getFile('source/main.brs');
179
+ //add a diagnostic from a plugin
180
+ event.program.diagnostics.register({
181
+ message: 'Test diagnostic',
182
+ code: 'test-123',
183
+ location: {},
184
+ severity: 1
185
+ });
186
+ }
187
+ }
188
+ }
189
+ `);
190
+ fsExtra.outputJsonSync(`${testHelpers_spec_1.rootDir}/bsconfig.json`, {
191
+ plugins: [
192
+ './plugin.js'
193
+ ]
194
+ });
195
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/source/main.brs`, `
196
+ sub test()
197
+ print nameNotDefined
198
+ end sub
199
+ `);
200
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/manifest`, '');
201
+ await manager.syncProjects([{
202
+ workspaceFolder: testHelpers_spec_1.rootDir
203
+ }]);
204
+ (0, testHelpers_spec_1.expectDiagnostics)(await onNextDiagnostics(), [
205
+ DiagnosticMessages_1.DiagnosticMessages.cannotFindName('nameNotDefined').message,
206
+ 'Test diagnostic'
207
+ ]);
208
+ });
209
+ it('uses subdir when manifest and brightscript file found', async () => {
210
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/subdir/manifest`, '');
211
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/subdir/source/main.brs`, '');
212
+ await manager.syncProjects([{
213
+ workspaceFolder: testHelpers_spec_1.rootDir
214
+ }]);
215
+ (0, chai_1.expect)(manager.projects.map(x => x.projectPath)).to.eql([
216
+ (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/subdir`
217
+ ]);
218
+ });
219
+ it('removes stale projects', async () => {
220
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/subdir1/bsconfig.json`, '');
221
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/subdir2/bsconfig.json`, '');
222
+ await manager.syncProjects([{
223
+ workspaceFolder: testHelpers_spec_1.rootDir
224
+ }]);
225
+ (0, chai_1.expect)(manager.projects.map(x => x.projectPath).sort()).to.eql([
226
+ (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/subdir1`,
227
+ (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/subdir2`
228
+ ]);
229
+ fsExtra.removeSync(`${testHelpers_spec_1.rootDir}/subdir1/bsconfig.json`);
230
+ await manager.syncProjects([{
231
+ workspaceFolder: testHelpers_spec_1.rootDir
232
+ }]);
233
+ (0, chai_1.expect)(manager.projects.map(x => x.projectPath).sort()).to.eql([
234
+ (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/subdir2`
235
+ ]);
236
+ });
237
+ it('keeps existing projects on subsequent sync calls', async () => {
238
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/subdir1/bsconfig.json`, '');
239
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/subdir2/bsconfig.json`, '');
240
+ await manager.syncProjects([{
241
+ workspaceFolder: testHelpers_spec_1.rootDir
242
+ }]);
243
+ (0, chai_1.expect)(manager.projects.map(x => x.projectPath).sort()).to.eql([
244
+ (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/subdir1`,
245
+ (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/subdir2`
246
+ ]);
247
+ await manager.syncProjects([{
248
+ workspaceFolder: testHelpers_spec_1.rootDir
249
+ }]);
250
+ (0, chai_1.expect)(manager.projects.map(x => x.projectPath).sort()).to.eql([
251
+ (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/subdir1`,
252
+ (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/subdir2`
253
+ ]);
254
+ });
255
+ });
256
+ describe('getCompletions', () => {
257
+ it('works for quick file changes', async () => {
258
+ //set up the project
259
+ await manager.syncProjects([{
260
+ workspaceFolder: testHelpers_spec_1.rootDir
261
+ }]);
262
+ //add the namespace first
263
+ await setFile((0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/alpha.bs`, `
264
+ namespace alpha
265
+ enum Direction
266
+ up
267
+ end enum
268
+ end namespace
269
+ `);
270
+ //add the baseline file
271
+ await setFile((0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/main.bs`, `
272
+ sub test()
273
+ thing = alpha.Directio
274
+ end sub
275
+ `);
276
+ await manager.onIdle();
277
+ //now for the test. type a char, request completions, type a char, request completions (just like how vscode does it)
278
+ void setFile((0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/main.bs`, `
279
+ sub test()
280
+ thing = alpha.Direction
281
+ end sub
282
+ `);
283
+ // const completionsPromise1 = manager.getCompletions({
284
+ // srcPath: s`${rootDir}/source/main.bs`,
285
+ // position: util.createPosition(2, 43)
286
+ // });
287
+ //request completions
288
+ void setFile((0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/main.bs`, `
289
+ sub test()
290
+ thing = alpha.Direction.
291
+ end sub
292
+ `);
293
+ const completionsPromise2 = manager.getCompletions({
294
+ srcPath: (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/main.bs`,
295
+ position: util_1.default.createPosition(2, 44)
296
+ });
297
+ // //the first set of completions should only have the `alpha.Direction` enum
298
+ // expectCompletionsIncludes(await completionsPromise1, [{
299
+ // label: 'Direction'
300
+ // }]);
301
+ //the next set of completions should only have the alpha.Direction.up enum member
302
+ (0, testHelpers_spec_1.expectCompletionsIncludes)(await completionsPromise2, [{
303
+ label: 'up'
304
+ }]);
305
+ });
306
+ });
307
+ describe('flushDocumentChanges', () => {
308
+ it('does not crash when getting undefined back from projects', async () => {
309
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/source/main.brs`, ``);
310
+ fsExtra.outputJsonSync(`${testHelpers_spec_1.rootDir}/project1/bsconfig.json`, {
311
+ rootDir: testHelpers_spec_1.rootDir
312
+ });
313
+ await manager.syncProjects([{
314
+ workspaceFolder: testHelpers_spec_1.rootDir
315
+ }]);
316
+ sinon.stub(manager.projects[0], 'applyFileChanges').returns(Promise.resolve([
317
+ //return an undefined item, which used to cause a specific crash
318
+ undefined
319
+ ]));
320
+ await manager['flushDocumentChanges']({
321
+ actions: [{
322
+ srcPath: (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/main.brs`,
323
+ type: 'set',
324
+ fileContents: 'sub main():end sub',
325
+ allowStandaloneProject: true
326
+ }]
327
+ });
328
+ });
329
+ });
330
+ describe('handleFileChanges', () => {
331
+ it('only sends files to the project that match the include patterns for that project', async () => {
332
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/source/lib1/a.brs`, ``);
333
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/source/lib2/a.brs`, ``);
334
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/source/lib1/b.brs`, ``);
335
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/source/lib2/b.brs`, ``);
336
+ fsExtra.outputJsonSync(`${testHelpers_spec_1.rootDir}/project1/bsconfig.json`, {
337
+ rootDir: testHelpers_spec_1.rootDir,
338
+ files: [
339
+ 'source/**/a.brs'
340
+ ]
341
+ });
342
+ fsExtra.outputJsonSync(`${testHelpers_spec_1.rootDir}/project2/bsconfig.json`, {
343
+ rootDir: testHelpers_spec_1.rootDir,
344
+ files: [
345
+ 'source/**/b.brs'
346
+ ]
347
+ });
348
+ await manager.syncProjects([{
349
+ workspaceFolder: testHelpers_spec_1.rootDir
350
+ }]);
351
+ let deferred1 = new deferred_1.Deferred();
352
+ let deferred2 = new deferred_1.Deferred();
353
+ const project1 = manager.projects.find(x => x.bsconfigPath.includes('project1'));
354
+ const project2 = manager.projects.find(x => x.bsconfigPath.includes('project2'));
355
+ const project1Stub = sinon.stub(project1, 'applyFileChanges').callsFake(async (...args) => {
356
+ const result = await project1Stub.wrappedMethod.apply(project1, args);
357
+ deferred1.resolve();
358
+ return result;
359
+ });
360
+ const project2Stub = sinon.stub(project2, 'applyFileChanges').callsFake(async (...args) => {
361
+ const result = await project2Stub.wrappedMethod.apply(project1, args);
362
+ deferred2.resolve();
363
+ return result;
364
+ });
365
+ await manager.handleFileChanges([
366
+ { srcPath: `${testHelpers_spec_1.rootDir}/source/lib1/a.brs`, type: vscode_languageserver_protocol_1.FileChangeType.Changed },
367
+ { srcPath: `${testHelpers_spec_1.rootDir}/source/lib2/a.brs`, type: vscode_languageserver_protocol_1.FileChangeType.Changed },
368
+ { srcPath: `${testHelpers_spec_1.rootDir}/source/lib1/b.brs`, type: vscode_languageserver_protocol_1.FileChangeType.Changed },
369
+ { srcPath: `${testHelpers_spec_1.rootDir}/source/lib2/b.brs`, type: vscode_languageserver_protocol_1.FileChangeType.Changed }
370
+ ]);
371
+ //wait for the functions to finish being called
372
+ await Promise.all([
373
+ deferred1.promise,
374
+ deferred2.promise
375
+ ]);
376
+ //project1 should only receive a.brs files
377
+ (0, chai_1.expect)(project1Stub.getCall(0).args[0].map(x => x.srcPath)).to.eql([
378
+ (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/lib1/a.brs`,
379
+ (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/lib2/a.brs`
380
+ ]);
381
+ //project2 should only receive b.brs files
382
+ (0, chai_1.expect)(project2Stub.getCall(0).args[0].map(x => x.srcPath)).to.eql([
383
+ (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/lib1/b.brs`,
384
+ (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/lib2/b.brs`
385
+ ]);
386
+ });
387
+ it('excludes files based on global exclude patterns', async () => {
388
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/source/file1.md`, ``);
389
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/source/file2.brs`, ``);
390
+ fsExtra.outputJsonSync(`${testHelpers_spec_1.rootDir}/bsconfig.json`, {
391
+ files: [
392
+ 'source/**/*.brs'
393
+ ]
394
+ });
395
+ await manager.syncProjects([{
396
+ workspaceFolder: testHelpers_spec_1.rootDir
397
+ }]);
398
+ const stub = sinon.stub(manager, 'handleFileChange').callThrough();
399
+ //register an exclusion filter
400
+ pathFilterer.registerExcludeList(testHelpers_spec_1.rootDir, [
401
+ '**/*.md'
402
+ ]);
403
+ //make sure the .md file is ignored
404
+ await manager.handleFileChanges([
405
+ { srcPath: (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/file1.md`, type: vscode_languageserver_protocol_1.FileChangeType.Created },
406
+ { srcPath: (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/file2.brs`, type: vscode_languageserver_protocol_1.FileChangeType.Created }
407
+ ]);
408
+ await manager.onIdle();
409
+ (0, chai_1.expect)(stub.getCalls().map(x => x.args[0]).map(x => x.srcPath)).to.eql([
410
+ (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/file2.brs`
411
+ ]);
412
+ stub.reset();
413
+ //remove all filters, make sure the markdown file is included
414
+ pathFilterer.clear();
415
+ await manager.handleFileChanges([
416
+ { srcPath: (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/file1.md`, type: vscode_languageserver_protocol_1.FileChangeType.Created },
417
+ { srcPath: (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/file2.brs`, type: vscode_languageserver_protocol_1.FileChangeType.Created }
418
+ ]);
419
+ await manager.onIdle();
420
+ (0, chai_1.expect)(stub.getCalls().flatMap(x => x.args[0]).map(x => x.srcPath)).to.eql([
421
+ (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/file1.md`,
422
+ (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/file2.brs`
423
+ ]);
424
+ });
425
+ it('keeps files from bsconfig.json even if the path matches an exclude list', async () => {
426
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/source/file1.md`, ``);
427
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/source/file2.brs`, ``);
428
+ fsExtra.outputJsonSync(`${testHelpers_spec_1.rootDir}/bsconfig.json`, {
429
+ files: ['source/**/*']
430
+ });
431
+ await manager.syncProjects([{
432
+ workspaceFolder: testHelpers_spec_1.rootDir
433
+ }]);
434
+ const stub = sinon.stub(manager['projects'][0], 'applyFileChanges').callThrough();
435
+ //register an exclusion filter
436
+ pathFilterer.registerExcludeList(testHelpers_spec_1.rootDir, [
437
+ '**/*.md'
438
+ ]);
439
+ //make sure the .md file is included because of its project's files array
440
+ await manager.handleFileChanges([
441
+ { srcPath: `${testHelpers_spec_1.rootDir}/source/file1.md`, type: vscode_languageserver_protocol_1.FileChangeType.Created },
442
+ { srcPath: `${testHelpers_spec_1.rootDir}/source/file2.brs`, type: vscode_languageserver_protocol_1.FileChangeType.Created }
443
+ ]);
444
+ await manager.onIdle();
445
+ (0, chai_1.expect)(stub.getCalls().flatMap(x => x.args[0]).map(x => x.srcPath)).to.eql([
446
+ (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/file1.md`,
447
+ (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/file2.brs`
448
+ ]);
449
+ });
450
+ it('does not create a standalone project for files that exist in a known project', async () => {
451
+ fsExtra.outputFileSync((0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/main.brs`, `sub main() : end sub`);
452
+ await manager.syncProjects([{
453
+ workspaceFolder: testHelpers_spec_1.rootDir
454
+ }]);
455
+ await onNextDiagnostics();
456
+ await manager.handleFileChanges([
457
+ { srcPath: (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/main.brs`, type: vscode_languageserver_protocol_1.FileChangeType.Changed, fileContents: `'test`, allowStandaloneProject: true }
458
+ ]);
459
+ await onNextDiagnostics();
460
+ //there should NOT be a standalone project
461
+ (0, chai_1.expect)(manager['standaloneProjects'].size).to.eql(0);
462
+ });
463
+ it('converts a missing file to a delete', async () => {
464
+ await manager.syncProjects([{
465
+ workspaceFolder: testHelpers_spec_1.rootDir
466
+ }]);
467
+ await onNextDiagnostics();
468
+ let applyFileChangesDeferred = new deferred_1.Deferred();
469
+ const project1 = manager.projects[0];
470
+ const project1Stub = sinon.stub(project1, 'applyFileChanges').callsFake(async (...args) => {
471
+ const result = await project1Stub.wrappedMethod.apply(project1, args);
472
+ applyFileChangesDeferred.resolve(result);
473
+ return result;
474
+ });
475
+ //emit created and changed events for files that don't exist. These turn into delete events
476
+ await manager.handleFileChanges([
477
+ { srcPath: `${testHelpers_spec_1.rootDir}/source/missing1.brs`, type: vscode_languageserver_protocol_1.FileChangeType.Created },
478
+ { srcPath: `${testHelpers_spec_1.rootDir}/source/missing2.brs`, type: vscode_languageserver_protocol_1.FileChangeType.Changed }
479
+ ]);
480
+ //wait for the next set of diagnostics to arrive (signifying the files have been applied)
481
+ const result = await applyFileChangesDeferred.promise;
482
+ //make sure the project has these files
483
+ (0, chai_1.expect)(result.map(x => {
484
+ return { type: x.type, srcPath: x.srcPath };
485
+ })).to.eql([{
486
+ srcPath: (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/missing1.brs`,
487
+ type: 'set'
488
+ }, {
489
+ srcPath: (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/missing2.brs`,
490
+ type: 'set'
491
+ }, {
492
+ srcPath: (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/missing1.brs`,
493
+ type: 'delete'
494
+ }, {
495
+ srcPath: (0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/missing2.brs`,
496
+ type: 'delete'
497
+ }]);
498
+ });
499
+ it('properly syncs changes', async () => {
500
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/source/lib1.brs`, `sub test1():print "alpha":end sub`);
501
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/source/lib2.brs`, `sub test2():print "beta":end sub`);
502
+ await manager.syncProjects([{
503
+ workspaceFolder: testHelpers_spec_1.rootDir
504
+ }]);
505
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(await onNextDiagnostics());
506
+ await manager.handleFileChanges([
507
+ { srcPath: `${testHelpers_spec_1.rootDir}/source/lib1.brs`, fileContents: `sub test1():print alpha:end sub`, type: vscode_languageserver_protocol_1.FileChangeType.Changed },
508
+ { srcPath: `${testHelpers_spec_1.rootDir}/source/lib2.brs`, fileContents: `sub test2()::print beta:end sub`, type: vscode_languageserver_protocol_1.FileChangeType.Changed }
509
+ ]);
510
+ (0, testHelpers_spec_1.expectDiagnostics)(await onNextDiagnostics(), [
511
+ DiagnosticMessages_1.DiagnosticMessages.cannotFindName('alpha').message,
512
+ DiagnosticMessages_1.DiagnosticMessages.cannotFindName('beta').message
513
+ ]);
514
+ await manager.handleFileChanges([
515
+ { srcPath: `${testHelpers_spec_1.rootDir}/source/lib1.brs`, fileContents: `sub test1():print "alpha":end sub`, type: vscode_languageserver_protocol_1.FileChangeType.Changed },
516
+ { srcPath: `${testHelpers_spec_1.rootDir}/source/lib2.brs`, fileContents: `sub test2()::print "beta":end sub`, type: vscode_languageserver_protocol_1.FileChangeType.Changed }
517
+ ]);
518
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(await onNextDiagnostics());
519
+ });
520
+ it('adds all new files in a folder', async () => {
521
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/source/main.brs`, `sub main():print "main":end sub`);
522
+ await manager.syncProjects([{
523
+ workspaceFolder: testHelpers_spec_1.rootDir
524
+ }]);
525
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(await onNextDiagnostics());
526
+ //add a few files to a folder, then register that folder as an "add"
527
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/source/libs/alpha/beta.brs`, `sub beta(): print one: end sub`);
528
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/source/libs/alpha/charlie/delta.brs`, `sub delta():print two:end sub`);
529
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/source/libs/echo/foxtrot.brs`, `sub foxtrot():print three:end sub`);
530
+ await manager.handleFileChanges([
531
+ //register the entire folder as an "add"
532
+ { srcPath: `${testHelpers_spec_1.rootDir}/source/libs`, type: vscode_languageserver_protocol_1.FileChangeType.Created }
533
+ ]);
534
+ (0, testHelpers_spec_1.expectDiagnostics)(await onNextDiagnostics(), [
535
+ DiagnosticMessages_1.DiagnosticMessages.cannotFindName('one').message,
536
+ DiagnosticMessages_1.DiagnosticMessages.cannotFindName('two').message,
537
+ DiagnosticMessages_1.DiagnosticMessages.cannotFindName('three').message
538
+ ]);
539
+ });
540
+ it('removes all files in a folder', async () => {
541
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/source/main.brs`, `sub main():print "main":end sub`);
542
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/source/libs/alpha/beta.brs`, `sub beta(): print one: end sub`);
543
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/source/libs/alpha/charlie/delta.brs`, `sub delta():print two:end sub`);
544
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/source/libs/echo/foxtrot.brs`, `sub foxtrot():print three:end sub`);
545
+ await manager.syncProjects([{
546
+ workspaceFolder: testHelpers_spec_1.rootDir
547
+ }]);
548
+ (0, testHelpers_spec_1.expectDiagnostics)(await onNextDiagnostics(), [
549
+ DiagnosticMessages_1.DiagnosticMessages.cannotFindName('one').message,
550
+ DiagnosticMessages_1.DiagnosticMessages.cannotFindName('two').message,
551
+ DiagnosticMessages_1.DiagnosticMessages.cannotFindName('three').message
552
+ ]);
553
+ await manager.handleFileChanges([
554
+ //register the entire folder as an "add"
555
+ { srcPath: `${testHelpers_spec_1.rootDir}/source/libs`, type: vscode_languageserver_protocol_1.FileChangeType.Deleted }
556
+ ]);
557
+ (0, testHelpers_spec_1.expectZeroDiagnostics)(await onNextDiagnostics());
558
+ });
559
+ });
560
+ describe('threading', () => {
561
+ before(async function workerThreadWarmup() {
562
+ this.timeout(20000);
563
+ await (0, WorkerThreadProject_spec_1.getWakeWorkerThreadPromise)();
564
+ });
565
+ it('spawns a worker thread when threading is enabled', async () => {
566
+ await manager.syncProjects([{
567
+ workspaceFolder: testHelpers_spec_1.rootDir,
568
+ enableThreading: true
569
+ }]);
570
+ (0, chai_1.expect)(manager.projects[0]).instanceof(WorkerThreadProject_1.WorkerThreadProject);
571
+ });
572
+ });
573
+ describe('getProject', () => {
574
+ it('uses .projectPath if param is not a string', async () => {
575
+ await manager.syncProjects([{
576
+ workspaceFolder: testHelpers_spec_1.rootDir
577
+ }]);
578
+ (0, chai_1.expect)(manager['getProject']({
579
+ projectPath: testHelpers_spec_1.rootDir
580
+ })).to.include({
581
+ projectPath: testHelpers_spec_1.rootDir
582
+ });
583
+ });
584
+ });
585
+ describe('createAndActivateProject', () => {
586
+ it('skips creating project if we already have it', async () => {
587
+ await manager.syncProjects([{
588
+ workspaceFolder: testHelpers_spec_1.rootDir
589
+ }]);
590
+ await manager['createAndActivateProject']({
591
+ projectPath: testHelpers_spec_1.rootDir
592
+ });
593
+ (0, chai_1.expect)(manager.projects).to.be.length(1);
594
+ });
595
+ it('uses given projectNumber', async () => {
596
+ await manager['createAndActivateProject']({
597
+ projectPath: testHelpers_spec_1.rootDir,
598
+ workspaceFolder: testHelpers_spec_1.rootDir,
599
+ projectNumber: 3
600
+ });
601
+ (0, chai_1.expect)(manager.projects[0].projectNumber).to.eql(3);
602
+ });
603
+ it('properly tracks a failed run', async () => {
604
+ //force a total crash
605
+ sinon.stub(Project_1.Project.prototype, 'activate').returns(Promise.reject(new Error('Critical failure')));
606
+ let error;
607
+ try {
608
+ await manager['createAndActivateProject']({
609
+ projectPath: testHelpers_spec_1.rootDir,
610
+ workspaceFolder: testHelpers_spec_1.rootDir,
611
+ bsconfigPath: 'subdir1/brsconfig.json'
612
+ });
613
+ }
614
+ catch (e) {
615
+ error = e;
616
+ }
617
+ (0, chai_1.expect)(error).to.include({ message: 'Critical failure' });
618
+ });
619
+ });
620
+ describe('removeProject', () => {
621
+ it('handles undefined', async () => {
622
+ manager['removeProject'](undefined);
623
+ await manager.syncProjects([{
624
+ workspaceFolder: testHelpers_spec_1.rootDir
625
+ }]);
626
+ manager['removeProject'](undefined);
627
+ });
628
+ it('does not crash when removing project that is not there', () => {
629
+ manager['removeProject']({
630
+ projectPath: testHelpers_spec_1.rootDir,
631
+ dispose: () => { }
632
+ });
633
+ });
634
+ });
635
+ describe('getSemanticTokens', () => {
636
+ it('waits until the project is ready', () => {
637
+ });
638
+ });
639
+ describe('standalone projects', () => {
640
+ it('creates a standalone project for files not found in a project', async () => {
641
+ var _a;
642
+ await manager.syncProjects([]);
643
+ await manager.handleFileChanges([{
644
+ srcPath: `${testHelpers_spec_1.rootDir}/source/main.brs`,
645
+ type: vscode_languageserver_protocol_1.FileChangeType.Created,
646
+ fileContents: `sub main():print "main":end sub`,
647
+ allowStandaloneProject: true
648
+ }]);
649
+ await onNextDiagnostics();
650
+ (0, chai_1.expect)((_a = [...manager['standaloneProjects'].values()][0]) === null || _a === void 0 ? void 0 : _a.srcPath).to.eql((0, util_1.standardizePath) `${testHelpers_spec_1.rootDir}/source/main.brs`);
651
+ //it deletes the standalone project when the file is closed
652
+ await manager.handleFileClose({
653
+ srcPath: `${testHelpers_spec_1.rootDir}/source/main.brs`
654
+ });
655
+ (0, chai_1.expect)(manager['standaloneProjects'].size).to.eql(0);
656
+ });
657
+ });
658
+ it('completes promise when project is disposed in the middle of a flow', async function () {
659
+ this.timeout(20000);
660
+ //small plugin to communicate over a socket inside the worker thread.
661
+ //This transpiles from tsc use `require()` for all imports and don't reference external vars
662
+ class Plugin {
663
+ constructor(port, host) {
664
+ this.deferred = this.defer();
665
+ // eslint-disable-next-line
666
+ const net = require('net');
667
+ console.log('Starting server');
668
+ this.server = net.createServer((socket) => {
669
+ console.log('Client connected');
670
+ socket.on('data', (data) => {
671
+ let text = data.toString();
672
+ console.log('message received', JSON.stringify(text));
673
+ //when we get the event to resolve, do it
674
+ if (text === 'resolve') {
675
+ console.log('Resolving promise');
676
+ this.deferred.resolve();
677
+ this.server.close();
678
+ }
679
+ });
680
+ });
681
+ this.server.listen(port, host);
682
+ }
683
+ afterProgramCreate(program) {
684
+ // hijack the function to get workspace symbols, return a promise that resolves in the future
685
+ program.getWorkspaceSymbols = () => {
686
+ return this.deferred.promise;
687
+ };
688
+ }
689
+ defer() {
690
+ let resolve;
691
+ let reject;
692
+ let promise = new Promise((res, rej) => {
693
+ resolve = res;
694
+ reject = rej;
695
+ });
696
+ return {
697
+ resolve: resolve,
698
+ reject: reject,
699
+ promise: promise
700
+ };
701
+ }
702
+ }
703
+ const port = await getPort();
704
+ const host = '127.0.0.1';
705
+ //write a small brighterscript plugin to allow this test to communicate with the thread
706
+ fsExtra.outputFileSync(`${testHelpers_spec_1.rootDir}/plugin.js`, `
707
+ ${Plugin.toString()};
708
+ exports.default = function() {
709
+ return new Plugin(${port}, "${host}");
710
+ };
711
+ `);
712
+ //write a bsconfig that will load this plugin
713
+ fsExtra.outputJsonSync(`${testHelpers_spec_1.rootDir}/bsconfig.json`, {
714
+ plugins: [
715
+ `${testHelpers_spec_1.rootDir}/plugin.js`
716
+ ]
717
+ });
718
+ //wait for the projects to finish syncing/loading
719
+ await manager.syncProjects([{
720
+ workspaceFolder: testHelpers_spec_1.rootDir,
721
+ enableThreading: true
722
+ }]);
723
+ //establish the connection with the plugin
724
+ const connection = net.createConnection({
725
+ host: host,
726
+ port: port
727
+ });
728
+ //do the request to fetch symbols (this will be stalled on purpose by our test plugin)
729
+ let managerGetWorkspaceSymbolPromise = manager.getWorkspaceSymbol();
730
+ //small sleep to let things settle
731
+ await util_1.default.sleep(20);
732
+ //now dispose the project (which should destroy all of the listeners)
733
+ manager['removeProject'](manager.projects[0]);
734
+ //settle again
735
+ await util_1.default.sleep(20);
736
+ console.log('Asking the client to resolve');
737
+ //resolve the request
738
+ connection.write('resolve');
739
+ //now wait to see if we ever get the response back
740
+ let result = await managerGetWorkspaceSymbolPromise;
741
+ //the result should be an empty array, since the only project was rejected in the middle of the request
742
+ (0, chai_1.expect)(result).to.eql([]);
743
+ //test passes if the promise resolves
744
+ });
745
+ it('properly handles reloading when bsconfig.json contents change', async () => {
746
+ fsExtra.outputJsonSync(`${testHelpers_spec_1.rootDir}/bsconfig.json`, {
747
+ files: [
748
+ 'one'
749
+ ]
750
+ });
751
+ //wait for the projects to finish syncing/loading
752
+ await manager.syncProjects([{
753
+ workspaceFolder: testHelpers_spec_1.rootDir,
754
+ enableThreading: false
755
+ }]);
756
+ const stub = sinon.stub(manager, 'reloadProject').callThrough();
757
+ //change the file to new contents
758
+ fsExtra.outputJsonSync(`${testHelpers_spec_1.rootDir}/bsconfig.json`, {
759
+ files: [
760
+ 'two'
761
+ ]
762
+ });
763
+ await manager.handleFileChanges([{
764
+ srcPath: `${testHelpers_spec_1.rootDir}/bsconfig.json`,
765
+ type: vscode_languageserver_protocol_1.FileChangeType.Changed
766
+ }]);
767
+ //the project was reloaded
768
+ (0, chai_1.expect)(stub.callCount).to.eql(1);
769
+ //change the file to the same contents
770
+ fsExtra.outputJsonSync(`${testHelpers_spec_1.rootDir}/bsconfig.json`, {
771
+ files: [
772
+ 'two'
773
+ ]
774
+ });
775
+ await manager.handleFileChanges([{
776
+ srcPath: `${testHelpers_spec_1.rootDir}/bsconfig.json`,
777
+ type: vscode_languageserver_protocol_1.FileChangeType.Changed
778
+ }]);
779
+ //the project was not reloaded this time
780
+ (0, chai_1.expect)(stub.callCount).to.eql(1);
781
+ });
782
+ });
783
+ //# sourceMappingURL=ProjectManager.spec.js.map