brighterscript 0.41.6 → 0.44.0

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 (180) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/Cache.d.ts +3 -3
  3. package/dist/Cache.js +10 -6
  4. package/dist/Cache.js.map +1 -1
  5. package/dist/LanguageServer.d.ts +1 -6
  6. package/dist/LanguageServer.js +0 -9
  7. package/dist/LanguageServer.js.map +1 -1
  8. package/dist/PluginInterface.d.ts +3 -3
  9. package/dist/PluginInterface.js +3 -0
  10. package/dist/PluginInterface.js.map +1 -1
  11. package/dist/Program.d.ts +48 -19
  12. package/dist/Program.js +160 -60
  13. package/dist/Program.js.map +1 -1
  14. package/dist/ProgramBuilder.js +3 -3
  15. package/dist/ProgramBuilder.js.map +1 -1
  16. package/dist/Scope.d.ts +6 -5
  17. package/dist/Scope.js +18 -14
  18. package/dist/Scope.js.map +1 -1
  19. package/dist/astUtils/AstEditor.d.ts +27 -0
  20. package/dist/astUtils/AstEditor.js +97 -0
  21. package/dist/astUtils/AstEditor.js.map +1 -0
  22. package/dist/{bscPlugin/semanticTokens/SemanticTokensProcessor.spec.d.ts → astUtils/AstEditor.spec.d.ts} +0 -0
  23. package/dist/astUtils/AstEditor.spec.js +133 -0
  24. package/dist/astUtils/AstEditor.spec.js.map +1 -0
  25. package/dist/astUtils/reflection.d.ts +2 -1
  26. package/dist/astUtils/reflection.js +6 -2
  27. package/dist/astUtils/reflection.js.map +1 -1
  28. package/dist/astUtils/reflection.spec.js +6 -6
  29. package/dist/astUtils/reflection.spec.js.map +1 -1
  30. package/dist/astUtils/visitors.spec.js +13 -16
  31. package/dist/astUtils/visitors.spec.js.map +1 -1
  32. package/dist/bscPlugin/BscPlugin.js +5 -2
  33. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  34. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js +3 -3
  35. package/dist/bscPlugin/codeActions/CodeActionsProcessor.js.map +1 -1
  36. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js +2 -0
  37. package/dist/bscPlugin/codeActions/CodeActionsProcessor.spec.js.map +1 -1
  38. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +8 -0
  39. package/dist/bscPlugin/semanticTokens/{SemanticTokensProcessor.js → BrsFileSemanticTokensProcessor.js} +12 -14
  40. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -0
  41. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.d.ts +1 -0
  42. package/dist/bscPlugin/semanticTokens/{SemanticTokensProcessor.spec.js → BrsFileSemanticTokensProcessor.spec.js} +2 -2
  43. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -0
  44. package/dist/files/BrsFile.Class.spec.js +182 -78
  45. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  46. package/dist/files/BrsFile.d.ts +18 -7
  47. package/dist/files/BrsFile.js +118 -71
  48. package/dist/files/BrsFile.js.map +1 -1
  49. package/dist/files/BrsFile.spec.js +185 -107
  50. package/dist/files/BrsFile.spec.js.map +1 -1
  51. package/dist/files/XmlFile.d.ts +6 -0
  52. package/dist/files/XmlFile.js +15 -9
  53. package/dist/files/XmlFile.js.map +1 -1
  54. package/dist/files/XmlFile.spec.js +44 -40
  55. package/dist/files/XmlFile.spec.js.map +1 -1
  56. package/dist/files/tests/imports.spec.js +6 -4
  57. package/dist/files/tests/imports.spec.js.map +1 -1
  58. package/dist/globalCallables.d.ts +3 -1
  59. package/dist/globalCallables.js +200 -100
  60. package/dist/globalCallables.js.map +1 -1
  61. package/dist/index.d.ts +12 -3
  62. package/dist/index.js +21 -4
  63. package/dist/index.js.map +1 -1
  64. package/dist/interfaces.d.ts +73 -7
  65. package/dist/lexer/Lexer.js +1 -2
  66. package/dist/lexer/Lexer.js.map +1 -1
  67. package/dist/lexer/Lexer.spec.js +462 -462
  68. package/dist/lexer/Lexer.spec.js.map +1 -1
  69. package/dist/parser/Expression.d.ts +1 -1
  70. package/dist/parser/Expression.js +10 -10
  71. package/dist/parser/Expression.js.map +1 -1
  72. package/dist/parser/Parser.Class.spec.js +32 -31
  73. package/dist/parser/Parser.Class.spec.js.map +1 -1
  74. package/dist/parser/Parser.d.ts +13 -1
  75. package/dist/parser/Parser.js +355 -253
  76. package/dist/parser/Parser.js.map +1 -1
  77. package/dist/parser/Parser.spec.js +86 -24
  78. package/dist/parser/Parser.spec.js.map +1 -1
  79. package/dist/parser/Statement.d.ts +2 -2
  80. package/dist/parser/Statement.js +8 -8
  81. package/dist/parser/Statement.js.map +1 -1
  82. package/dist/parser/Statement.spec.js +4 -4
  83. package/dist/parser/Statement.spec.js.map +1 -1
  84. package/dist/parser/tests/Parser.spec.d.ts +3 -3
  85. package/dist/parser/tests/Parser.spec.js +4 -4
  86. package/dist/parser/tests/Parser.spec.js.map +1 -1
  87. package/dist/parser/tests/controlFlow/For.spec.js +40 -40
  88. package/dist/parser/tests/controlFlow/For.spec.js.map +1 -1
  89. package/dist/parser/tests/controlFlow/ForEach.spec.js +22 -21
  90. package/dist/parser/tests/controlFlow/ForEach.spec.js.map +1 -1
  91. package/dist/parser/tests/controlFlow/If.spec.js +100 -99
  92. package/dist/parser/tests/controlFlow/If.spec.js.map +1 -1
  93. package/dist/parser/tests/controlFlow/While.spec.js +25 -25
  94. package/dist/parser/tests/controlFlow/While.spec.js.map +1 -1
  95. package/dist/parser/tests/expression/Additive.spec.js +21 -21
  96. package/dist/parser/tests/expression/Additive.spec.js.map +1 -1
  97. package/dist/parser/tests/expression/ArrayLiterals.spec.js +91 -91
  98. package/dist/parser/tests/expression/ArrayLiterals.spec.js.map +1 -1
  99. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js +102 -102
  100. package/dist/parser/tests/expression/AssociativeArrayLiterals.spec.js.map +1 -1
  101. package/dist/parser/tests/expression/Boolean.spec.js +15 -15
  102. package/dist/parser/tests/expression/Boolean.spec.js.map +1 -1
  103. package/dist/parser/tests/expression/Call.spec.js +22 -21
  104. package/dist/parser/tests/expression/Call.spec.js.map +1 -1
  105. package/dist/parser/tests/expression/Exponential.spec.js +11 -11
  106. package/dist/parser/tests/expression/Exponential.spec.js.map +1 -1
  107. package/dist/parser/tests/expression/Function.spec.js +171 -171
  108. package/dist/parser/tests/expression/Function.spec.js.map +1 -1
  109. package/dist/parser/tests/expression/Indexing.spec.js +50 -50
  110. package/dist/parser/tests/expression/Indexing.spec.js.map +1 -1
  111. package/dist/parser/tests/expression/Multiplicative.spec.js +25 -25
  112. package/dist/parser/tests/expression/Multiplicative.spec.js.map +1 -1
  113. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js +16 -16
  114. package/dist/parser/tests/expression/NullCoalescenceExpression.spec.js.map +1 -1
  115. package/dist/parser/tests/expression/PrefixUnary.spec.js +26 -26
  116. package/dist/parser/tests/expression/PrefixUnary.spec.js.map +1 -1
  117. package/dist/parser/tests/expression/Primary.spec.js +27 -27
  118. package/dist/parser/tests/expression/Primary.spec.js.map +1 -1
  119. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js +3 -2
  120. package/dist/parser/tests/expression/RegexLiteralExpression.spec.js.map +1 -1
  121. package/dist/parser/tests/expression/Relational.spec.js +25 -25
  122. package/dist/parser/tests/expression/Relational.spec.js.map +1 -1
  123. package/dist/parser/tests/expression/TemplateStringExpression.spec.js +7 -7
  124. package/dist/parser/tests/expression/TemplateStringExpression.spec.js.map +1 -1
  125. package/dist/parser/tests/expression/TernaryExpression.spec.js +6 -6
  126. package/dist/parser/tests/expression/TernaryExpression.spec.js.map +1 -1
  127. package/dist/parser/tests/statement/AssignmentOperators.spec.js +15 -15
  128. package/dist/parser/tests/statement/AssignmentOperators.spec.js.map +1 -1
  129. package/dist/parser/tests/statement/Declaration.spec.js +20 -20
  130. package/dist/parser/tests/statement/Declaration.spec.js.map +1 -1
  131. package/dist/parser/tests/statement/Function.spec.js +121 -120
  132. package/dist/parser/tests/statement/Function.spec.js.map +1 -1
  133. package/dist/parser/tests/statement/Goto.spec.js +9 -8
  134. package/dist/parser/tests/statement/Goto.spec.js.map +1 -1
  135. package/dist/parser/tests/statement/Increment.spec.js +22 -22
  136. package/dist/parser/tests/statement/Increment.spec.js.map +1 -1
  137. package/dist/parser/tests/statement/InterfaceStatement.spec.js +12 -0
  138. package/dist/parser/tests/statement/InterfaceStatement.spec.js.map +1 -1
  139. package/dist/parser/tests/statement/LibraryStatement.spec.js +7 -7
  140. package/dist/parser/tests/statement/LibraryStatement.spec.js.map +1 -1
  141. package/dist/parser/tests/statement/Misc.spec.js +71 -70
  142. package/dist/parser/tests/statement/Misc.spec.js.map +1 -1
  143. package/dist/parser/tests/statement/PrintStatement.spec.js +17 -17
  144. package/dist/parser/tests/statement/PrintStatement.spec.js.map +1 -1
  145. package/dist/parser/tests/statement/ReturnStatement.spec.js +33 -33
  146. package/dist/parser/tests/statement/ReturnStatement.spec.js.map +1 -1
  147. package/dist/parser/tests/statement/Set.spec.js +53 -53
  148. package/dist/parser/tests/statement/Set.spec.js.map +1 -1
  149. package/dist/parser/tests/statement/Stop.spec.js +7 -6
  150. package/dist/parser/tests/statement/Stop.spec.js.map +1 -1
  151. package/dist/preprocessor/Chunk.d.ts +1 -1
  152. package/dist/preprocessor/Preprocessor.d.ts +1 -1
  153. package/dist/preprocessor/Preprocessor.js +7 -7
  154. package/dist/preprocessor/Preprocessor.js.map +1 -1
  155. package/dist/types/FunctionType.d.ts +2 -2
  156. package/dist/types/FunctionType.js +3 -3
  157. package/dist/types/FunctionType.js.map +1 -1
  158. package/dist/types/FunctionType.spec.js +2 -2
  159. package/dist/types/FunctionType.spec.js.map +1 -1
  160. package/dist/util.d.ts +17 -1
  161. package/dist/util.js +59 -29
  162. package/dist/util.js.map +1 -1
  163. package/dist/validators/ClassValidator.js +20 -27
  164. package/dist/validators/ClassValidator.js.map +1 -1
  165. package/package.json +2 -1
  166. package/dist/astUtils/index.d.ts +0 -7
  167. package/dist/astUtils/index.js +0 -26
  168. package/dist/astUtils/index.js.map +0 -1
  169. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.d.ts +0 -7
  170. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.js.map +0 -1
  171. package/dist/bscPlugin/semanticTokens/SemanticTokensProcessor.spec.js.map +0 -1
  172. package/dist/lexer/index.d.ts +0 -3
  173. package/dist/lexer/index.js +0 -18
  174. package/dist/lexer/index.js.map +0 -1
  175. package/dist/parser/index.d.ts +0 -3
  176. package/dist/parser/index.js +0 -16
  177. package/dist/parser/index.js.map +0 -1
  178. package/dist/preprocessor/index.d.ts +0 -3
  179. package/dist/preprocessor/index.js +0 -16
  180. package/dist/preprocessor/index.js.map +0 -1
@@ -3,13 +3,13 @@ import type { CompletionItem, Hover, Position } from 'vscode-languageserver';
3
3
  import { Location, SignatureInformation, DocumentSymbol, SymbolInformation } from 'vscode-languageserver';
4
4
  import type { Scope } from '../Scope';
5
5
  import { FunctionScope } from '../FunctionScope';
6
- import type { Callable, CommentFlag, FunctionCall, BsDiagnostic, FileReference } from '../interfaces';
7
- import type { Token } from '../lexer';
8
- import { TokenKind } from '../lexer';
9
- import { Parser, ParseMode } from '../parser';
6
+ import type { Callable, CommentFlag, FunctionCall, BsDiagnostic, FileReference, FileLink } from '../interfaces';
7
+ import type { Token } from '../lexer/Token';
8
+ import { TokenKind } from '../lexer/TokenKind';
9
+ import { Parser, ParseMode } from '../parser/Parser';
10
10
  import type { FunctionExpression, Expression } from '../parser/Expression';
11
11
  import type { ClassStatement, Statement } from '../parser/Statement';
12
- import type { FileLink, Program, SignatureInfoObj } from '../Program';
12
+ import type { Program, SignatureInfoObj } from '../Program';
13
13
  import type { DependencyGraph } from '../DependencyGraph';
14
14
  /**
15
15
  * Holds all details about this file within the scope of the whole program
@@ -34,6 +34,11 @@ export declare class BrsFile {
34
34
  * The key used to identify this file in the dependency graph
35
35
  */
36
36
  dependencyGraphKey: string;
37
+ /**
38
+ * Indicates whether this file needs to be validated.
39
+ * Files are only ever validated a single time
40
+ */
41
+ isValidated: boolean;
37
42
  /**
38
43
  * The all-lowercase extension for this file (including the leading dot)
39
44
  */
@@ -57,7 +62,7 @@ export declare class BrsFile {
57
62
  /**
58
63
  * The AST for this file
59
64
  */
60
- get ast(): import("../parser").Body;
65
+ get ast(): import("../parser/Statement").Body;
61
66
  private documentSymbols;
62
67
  private workspaceSymbols;
63
68
  /**
@@ -103,7 +108,9 @@ export declare class BrsFile {
103
108
  * @param fileContents
104
109
  */
105
110
  parse(fileContents: string): void;
106
- findAndValidateImportAndImportStatements(): void;
111
+ private registerImports;
112
+ validate(): void;
113
+ private validateImportStatements;
107
114
  /**
108
115
  * Find a class. This scans all scopes for this file, and returns the first matching class that is found.
109
116
  * Returns undefined if not found.
@@ -192,6 +199,10 @@ export declare class BrsFile {
192
199
  getDefinition(position: Position): Location[];
193
200
  getClassMemberDefinitions(textToSearchFor: string, file: BrsFile): Location[];
194
201
  getHover(position: Position): Hover;
202
+ /**
203
+ * Build a hover documentation for a callable.
204
+ */
205
+ private getCallableDocumentation;
195
206
  getSignatureHelpForNamespaceMethods(callableName: string, dottedGetText: string, scope: Scope): {
196
207
  key: string;
197
208
  signature: SignatureInformation;
@@ -7,8 +7,9 @@ const chalk_1 = require("chalk");
7
7
  const path = require("path");
8
8
  const DiagnosticMessages_1 = require("../DiagnosticMessages");
9
9
  const FunctionScope_1 = require("../FunctionScope");
10
- const lexer_1 = require("../lexer");
11
- const parser_1 = require("../parser");
10
+ const Lexer_1 = require("../lexer/Lexer");
11
+ const TokenKind_1 = require("../lexer/TokenKind");
12
+ const Parser_1 = require("../parser/Parser");
12
13
  const DynamicType_1 = require("../types/DynamicType");
13
14
  const FunctionType_1 = require("../types/FunctionType");
14
15
  const VoidType_1 = require("../types/VoidType");
@@ -36,7 +37,12 @@ class BrsFile {
36
37
  /**
37
38
  * The parseMode used for the parser for this file
38
39
  */
39
- this.parseMode = parser_1.ParseMode.BrightScript;
40
+ this.parseMode = Parser_1.ParseMode.BrightScript;
41
+ /**
42
+ * Indicates whether this file needs to be validated.
43
+ * Files are only ever validated a single time
44
+ */
45
+ this.isValidated = false;
40
46
  this.diagnostics = [];
41
47
  this.commentFlags = [];
42
48
  this.callables = [];
@@ -57,7 +63,7 @@ class BrsFile {
57
63
  //all BrighterScript files need to be transpiled
58
64
  if ((_a = this.extension) === null || _a === void 0 ? void 0 : _a.endsWith('.bs')) {
59
65
  this.needsTranspiled = true;
60
- this.parseMode = parser_1.ParseMode.BrighterScript;
66
+ this.parseMode = Parser_1.ParseMode.BrighterScript;
61
67
  }
62
68
  this.isTypedef = this.extension === '.d.bs';
63
69
  if (!this.isTypedef) {
@@ -145,11 +151,13 @@ class BrsFile {
145
151
  this.diagnostics = [];
146
152
  //if we have a typedef file, skip parsing this file
147
153
  if (this.hasTypedef) {
154
+ //skip validation since the typedef is shadowing this file
155
+ this.isValidated = true;
148
156
  return;
149
157
  }
150
158
  //tokenize the input file
151
159
  let lexer = this.program.logger.time(Logger_1.LogLevel.debug, ['lexer.lex', chalk_1.default.green(this.pathAbsolute)], () => {
152
- return lexer_1.Lexer.scan(fileContents, {
160
+ return Lexer_1.Lexer.scan(fileContents, {
153
161
  includeWhitespace: false
154
162
  });
155
163
  });
@@ -172,32 +180,50 @@ class BrsFile {
172
180
  //if the preprocessor generated tokens, use them.
173
181
  let tokens = preprocessor.processedTokens.length > 0 ? preprocessor.processedTokens : lexer.tokens;
174
182
  this.program.logger.time(Logger_1.LogLevel.debug, ['parser.parse', chalk_1.default.green(this.pathAbsolute)], () => {
175
- this._parser = parser_1.Parser.parse(tokens, {
183
+ this._parser = Parser_1.Parser.parse(tokens, {
176
184
  mode: this.parseMode,
177
185
  logger: this.program.logger
178
186
  });
179
187
  });
180
188
  //absorb all lexing/preprocessing/parsing diagnostics
181
189
  this.diagnostics.push(...lexer.diagnostics, ...preprocessor.diagnostics, ...this._parser.diagnostics);
182
- //notify AST ready
183
- this.program.plugins.emit('afterFileParse', this);
184
190
  //extract all callables from this file
185
191
  this.findCallables();
186
192
  //find all places where a sub/function is being called
187
193
  this.findFunctionCalls();
188
- this.findAndValidateImportAndImportStatements();
194
+ //register all import statements for use in the rest of the program
195
+ this.registerImports();
189
196
  //attach this file to every diagnostic
190
197
  for (let diagnostic of this.diagnostics) {
191
198
  diagnostic.file = this;
192
199
  }
193
200
  }
194
201
  catch (e) {
195
- this._parser = new parser_1.Parser();
202
+ this._parser = new Parser_1.Parser();
196
203
  this.diagnostics.push(Object.assign({ file: this, range: util_1.util.createRange(0, 0, 0, Number.MAX_VALUE) }, DiagnosticMessages_1.DiagnosticMessages.genericParserMessage('Critical error parsing file: ' + JSON.stringify((0, serialize_error_1.serializeError)(e)))));
197
204
  }
198
205
  }
199
- findAndValidateImportAndImportStatements() {
200
- var _a;
206
+ registerImports() {
207
+ var _a, _b, _c, _d;
208
+ for (const statement of (_c = (_b = (_a = this.parser) === null || _a === void 0 ? void 0 : _a.references) === null || _b === void 0 ? void 0 : _b.importStatements) !== null && _c !== void 0 ? _c : []) {
209
+ //register import statements
210
+ if ((0, reflection_1.isImportStatement)(statement) && statement.filePathToken) {
211
+ this.ownScriptImports.push({
212
+ filePathRange: statement.filePathToken.range,
213
+ pkgPath: util_1.util.getPkgPathFromTarget(this.pkgPath, statement.filePath),
214
+ sourceFile: this,
215
+ text: (_d = statement.filePathToken) === null || _d === void 0 ? void 0 : _d.text
216
+ });
217
+ }
218
+ }
219
+ }
220
+ validate() {
221
+ //only validate the file if it was actually parsed (skip files containing typedefs)
222
+ if (!this.hasTypedef) {
223
+ this.validateImportStatements();
224
+ }
225
+ }
226
+ validateImportStatements() {
201
227
  let topOfFileIncludeStatements = [];
202
228
  for (let stmt of this.ast.statements) {
203
229
  //skip comments
@@ -218,15 +244,6 @@ class BrsFile {
218
244
  ...this._parser.references.importStatements
219
245
  ];
220
246
  for (let result of statements) {
221
- //register import statements
222
- if ((0, reflection_1.isImportStatement)(result) && result.filePathToken) {
223
- this.ownScriptImports.push({
224
- filePathRange: result.filePathToken.range,
225
- pkgPath: util_1.util.getPkgPathFromTarget(this.pkgPath, result.filePath),
226
- sourceFile: this,
227
- text: (_a = result.filePathToken) === null || _a === void 0 ? void 0 : _a.text
228
- });
229
- }
230
247
  //if this statement is not one of the top-of-file statements,
231
248
  //then add a diagnostic explaining that it is invalid
232
249
  if (!topOfFileIncludeStatements.includes(result)) {
@@ -284,7 +301,7 @@ class BrsFile {
284
301
  const processor = new CommentFlagProcessor_1.CommentFlagProcessor(this, ['rem', `'`], DiagnosticMessages_1.diagnosticCodes, [DiagnosticMessages_1.DiagnosticCodeMap.unknownDiagnosticCode]);
285
302
  this.commentFlags = [];
286
303
  for (let token of tokens) {
287
- if (token.kind === lexer_1.TokenKind.Comment) {
304
+ if (token.kind === TokenKind_1.TokenKind.Comment) {
288
305
  processor.tryAdd(token.text, token.range);
289
306
  }
290
307
  }
@@ -374,9 +391,9 @@ class BrsFile {
374
391
  }
375
392
  functionType.setName(assignment.name.text);
376
393
  for (let param of assignment.value.parameters) {
377
- let isRequired = !param.defaultValue;
394
+ let isOptional = !!param.defaultValue;
378
395
  //TODO compute optional parameters
379
- functionType.addParameter(param.name.text, param.type, isRequired);
396
+ functionType.addParameter(param.name.text, param.type, isOptional);
380
397
  }
381
398
  return functionType;
382
399
  //literal
@@ -436,8 +453,8 @@ class BrsFile {
436
453
  isRestArgument: false
437
454
  };
438
455
  params.push(callableParam);
439
- let isRequired = !param.defaultValue;
440
- functionType.addParameter(callableParam.name, callableParam.type, isRequired);
456
+ let isOptional = !!param.defaultValue;
457
+ functionType.addParameter(callableParam.name, callableParam.type, isOptional);
441
458
  }
442
459
  this.callables.push({
443
460
  isSub: statement.func.functionType.text.toLowerCase() === 'sub',
@@ -570,10 +587,10 @@ class BrsFile {
570
587
  //if cursor is within a comment, disable completions
571
588
  let currentToken = this.getTokenAt(position);
572
589
  const tokenKind = currentToken === null || currentToken === void 0 ? void 0 : currentToken.kind;
573
- if (tokenKind === lexer_1.TokenKind.Comment) {
590
+ if (tokenKind === TokenKind_1.TokenKind.Comment) {
574
591
  return [];
575
592
  }
576
- else if (tokenKind === lexer_1.TokenKind.StringLiteral || tokenKind === lexer_1.TokenKind.TemplateStringQuasi) {
593
+ else if (tokenKind === TokenKind_1.TokenKind.StringLiteral || tokenKind === TokenKind_1.TokenKind.TemplateStringQuasi) {
577
594
  const match = /^("?)(pkg|libpkg):/.exec(currentToken.text);
578
595
  if (match) {
579
596
  const [, openingQuote, fileProtocol] = match;
@@ -605,7 +622,7 @@ class BrsFile {
605
622
  let functionScope = this.getFunctionScopeAtPosition(position);
606
623
  if (!functionScope) {
607
624
  //we aren't in any function scope, so return the keyword completions and namespaces
608
- if (this.getTokenBefore(currentToken, lexer_1.TokenKind.New)) {
625
+ if (this.getTokenBefore(currentToken, TokenKind_1.TokenKind.New)) {
609
626
  // there's a new keyword, so only class types are viable here
610
627
  return [...this.getGlobalClassStatementCompletions(currentToken, this.parseMode)];
611
628
  }
@@ -614,17 +631,17 @@ class BrsFile {
614
631
  }
615
632
  }
616
633
  const classNameCompletions = this.getGlobalClassStatementCompletions(currentToken, this.parseMode);
617
- const newToken = this.getTokenBefore(currentToken, lexer_1.TokenKind.New);
634
+ const newToken = this.getTokenBefore(currentToken, TokenKind_1.TokenKind.New);
618
635
  if (newToken) {
619
636
  //we are after a new keyword; so we can only be namespaces or classes at this point
620
637
  result.push(...classNameCompletions);
621
638
  result.push(...namespaceCompletions);
622
639
  return result;
623
640
  }
624
- if (this.tokenFollows(currentToken, lexer_1.TokenKind.Goto)) {
641
+ if (this.tokenFollows(currentToken, TokenKind_1.TokenKind.Goto)) {
625
642
  return this.getLabelCompletion(functionScope);
626
643
  }
627
- if (this.isPositionNextToTokenKind(position, lexer_1.TokenKind.Dot)) {
644
+ if (this.isPositionNextToTokenKind(position, TokenKind_1.TokenKind.Dot)) {
628
645
  if (namespaceCompletions.length > 0) {
629
646
  //if we matched a namespace, after a dot, it can't be anything else but something from our namespace completions
630
647
  return namespaceCompletions;
@@ -670,7 +687,7 @@ class BrsFile {
670
687
  kind: (0, reflection_1.isFunctionType)(variable.type) ? vscode_languageserver_1.CompletionItemKind.Function : vscode_languageserver_1.CompletionItemKind.Variable
671
688
  });
672
689
  }
673
- if (this.parseMode === parser_1.ParseMode.BrighterScript) {
690
+ if (this.parseMode === Parser_1.ParseMode.BrighterScript) {
674
691
  //include the first part of namespaces
675
692
  let namespaces = scope.getAllNamespaceStatements();
676
693
  for (let stmt of namespaces) {
@@ -700,7 +717,7 @@ class BrsFile {
700
717
  let classStatement = this.getClassFromMReference(position, currentToken, functionScope);
701
718
  let results = new Map();
702
719
  if (classStatement) {
703
- let classes = scope.getClassHierarchy(classStatement.item.getName(parser_1.ParseMode.BrighterScript).toLowerCase());
720
+ let classes = scope.getClassHierarchy(classStatement.item.getName(Parser_1.ParseMode.BrighterScript).toLowerCase());
704
721
  for (let cs of classes) {
705
722
  for (let member of [...(_b = (_a = cs === null || cs === void 0 ? void 0 : cs.item) === null || _a === void 0 ? void 0 : _a.fields) !== null && _b !== void 0 ? _b : [], ...(_d = (_c = cs === null || cs === void 0 ? void 0 : cs.item) === null || _c === void 0 ? void 0 : _c.methods) !== null && _d !== void 0 ? _d : []]) {
706
723
  if (!results.has(member.name.text.toLowerCase())) {
@@ -716,21 +733,21 @@ class BrsFile {
716
733
  }
717
734
  getClassFromMReference(position, currentToken, functionScope) {
718
735
  let previousToken = this.getPreviousToken(currentToken);
719
- if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === lexer_1.TokenKind.Dot) {
736
+ if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === TokenKind_1.TokenKind.Dot) {
720
737
  previousToken = this.getPreviousToken(previousToken);
721
738
  }
722
- if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === lexer_1.TokenKind.Identifier && (previousToken === null || previousToken === void 0 ? void 0 : previousToken.text.toLowerCase()) === 'm' && (0, reflection_1.isClassMethodStatement)(functionScope.func.functionStatement)) {
739
+ if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === TokenKind_1.TokenKind.Identifier && (previousToken === null || previousToken === void 0 ? void 0 : previousToken.text.toLowerCase()) === 'm' && (0, reflection_1.isClassMethodStatement)(functionScope.func.functionStatement)) {
723
740
  return { item: this.parser.references.classStatements.find((cs) => util_1.util.rangeContains(cs.range, position)), file: this };
724
741
  }
725
742
  return undefined;
726
743
  }
727
744
  getGlobalClassStatementCompletions(currentToken, parseMode) {
728
745
  var _a;
729
- if (parseMode === parser_1.ParseMode.BrightScript) {
746
+ if (parseMode === Parser_1.ParseMode.BrightScript) {
730
747
  return [];
731
748
  }
732
749
  let results = new Map();
733
- let completionName = (_a = this.getPartialVariableName(currentToken, [lexer_1.TokenKind.New])) === null || _a === void 0 ? void 0 : _a.toLowerCase();
750
+ let completionName = (_a = this.getPartialVariableName(currentToken, [TokenKind_1.TokenKind.New])) === null || _a === void 0 ? void 0 : _a.toLowerCase();
734
751
  if (completionName === null || completionName === void 0 ? void 0 : completionName.includes('.')) {
735
752
  return [];
736
753
  }
@@ -752,17 +769,17 @@ class BrsFile {
752
769
  }
753
770
  getNamespaceCompletions(currentToken, parseMode, scope) {
754
771
  //BrightScript does not support namespaces, so return an empty list in that case
755
- if (parseMode === parser_1.ParseMode.BrightScript) {
772
+ if (parseMode === Parser_1.ParseMode.BrightScript) {
756
773
  return [];
757
774
  }
758
- let completionName = this.getPartialVariableName(currentToken, [lexer_1.TokenKind.New]);
775
+ let completionName = this.getPartialVariableName(currentToken, [TokenKind_1.TokenKind.New]);
759
776
  if (!completionName) {
760
777
  return [];
761
778
  }
762
779
  //remove any trailing identifer and then any trailing dot, to give us the
763
780
  //name of its immediate parent namespace
764
781
  let closestParentNamespaceName = completionName.replace(/\.([a-z0-9_]*)?$/gi, '');
765
- let newToken = this.getTokenBefore(currentToken, lexer_1.TokenKind.New);
782
+ let newToken = this.getTokenBefore(currentToken, TokenKind_1.TokenKind.New);
766
783
  let result = new Map();
767
784
  for (let [, namespace] of scope.namespaceLookup) {
768
785
  //completionName = "NameA."
@@ -811,11 +828,11 @@ class BrsFile {
811
828
  return undefined;
812
829
  }
813
830
  let location;
814
- const nameParts = this.getPartialVariableName(token, [lexer_1.TokenKind.New]).split('.');
831
+ const nameParts = this.getPartialVariableName(token, [TokenKind_1.TokenKind.New]).split('.');
815
832
  const endName = nameParts[nameParts.length - 1].toLowerCase();
816
833
  const namespaceName = nameParts.slice(0, -1).join('.').toLowerCase();
817
834
  const statementHandler = (statement) => {
818
- if (!location && statement.getName(parser_1.ParseMode.BrighterScript).toLowerCase() === namespaceName) {
835
+ if (!location && statement.getName(Parser_1.ParseMode.BrighterScript).toLowerCase() === namespaceName) {
819
836
  const namespaceItemStatementHandler = (statement) => {
820
837
  if (!location && statement.name.text.toLowerCase() === endName) {
821
838
  const uri = util_1.util.pathToUri(file.pathAbsolute);
@@ -841,7 +858,7 @@ class BrsFile {
841
858
  * Given a current token, walk
842
859
  */
843
860
  getPartialVariableName(currentToken, excludeTokens = null) {
844
- let identifierAndDotKinds = [lexer_1.TokenKind.Identifier, ...lexer_1.AllowedLocalIdentifiers, lexer_1.TokenKind.Dot];
861
+ let identifierAndDotKinds = [TokenKind_1.TokenKind.Identifier, ...TokenKind_1.AllowedLocalIdentifiers, TokenKind_1.TokenKind.Dot];
845
862
  //consume tokens backwards until we find something other than a dot or an identifier
846
863
  let tokens = [];
847
864
  const parser = this.parser;
@@ -867,17 +884,17 @@ class BrsFile {
867
884
  const previousToken = this.getPreviousToken(closestToken);
868
885
  const previousTokenKind = previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind;
869
886
  //next to matched token
870
- if (!closestToken || closestToken.kind === lexer_1.TokenKind.Eof) {
887
+ if (!closestToken || closestToken.kind === TokenKind_1.TokenKind.Eof) {
871
888
  return false;
872
889
  }
873
890
  else if (closestToken.kind === tokenKind) {
874
891
  return true;
875
892
  }
876
- else if (closestToken.kind === lexer_1.TokenKind.Newline || previousTokenKind === lexer_1.TokenKind.Newline) {
893
+ else if (closestToken.kind === TokenKind_1.TokenKind.Newline || previousTokenKind === TokenKind_1.TokenKind.Newline) {
877
894
  return false;
878
895
  //next to an identifier, which is next to token kind
879
896
  }
880
- else if (closestToken.kind === lexer_1.TokenKind.Identifier && previousTokenKind === tokenKind) {
897
+ else if (closestToken.kind === TokenKind_1.TokenKind.Identifier && previousTokenKind === tokenKind) {
881
898
  return true;
882
899
  }
883
900
  else {
@@ -888,7 +905,7 @@ class BrsFile {
888
905
  const index = this.parser.tokens.indexOf(currentToken);
889
906
  for (let i = index - 1; i >= 0; i--) {
890
907
  currentToken = this.parser.tokens[i];
891
- if (currentToken.kind === lexer_1.TokenKind.Newline) {
908
+ if (currentToken.kind === TokenKind_1.TokenKind.Newline) {
892
909
  break;
893
910
  }
894
911
  else if (currentToken.kind === tokenKind) {
@@ -908,7 +925,7 @@ class BrsFile {
908
925
  let tokens = [];
909
926
  for (let i = this.parser.tokens.indexOf(currentToken); direction === -1 ? i >= 0 : i === this.parser.tokens.length; i += direction) {
910
927
  currentToken = this.parser.tokens[i];
911
- if (currentToken.kind === lexer_1.TokenKind.Newline || currentToken.kind === tokenKind) {
928
+ if (currentToken.kind === TokenKind_1.TokenKind.Newline || currentToken.kind === tokenKind) {
912
929
  break;
913
930
  }
914
931
  tokens.push(currentToken);
@@ -1052,7 +1069,7 @@ class BrsFile {
1052
1069
  else {
1053
1070
  return;
1054
1071
  }
1055
- const name = (0, reflection_1.isClassFieldStatement)(statement) ? statement.name.text : statement.getName(parser_1.ParseMode.BrighterScript);
1072
+ const name = (0, reflection_1.isClassFieldStatement)(statement) ? statement.name.text : statement.getName(Parser_1.ParseMode.BrighterScript);
1056
1073
  return vscode_languageserver_1.DocumentSymbol.create(name, '', symbolKind, statement.range, statement.range, children);
1057
1074
  }
1058
1075
  /**
@@ -1086,9 +1103,9 @@ class BrsFile {
1086
1103
  else {
1087
1104
  return symbols;
1088
1105
  }
1089
- const name = statement.getName(parser_1.ParseMode.BrighterScript);
1106
+ const name = statement.getName(Parser_1.ParseMode.BrighterScript);
1090
1107
  const uri = util_1.util.pathToUri(this.pathAbsolute);
1091
- const symbol = vscode_languageserver_1.SymbolInformation.create(name, symbolKind, statement.range, uri, containerStatement === null || containerStatement === void 0 ? void 0 : containerStatement.getName(parser_1.ParseMode.BrighterScript));
1108
+ const symbol = vscode_languageserver_1.SymbolInformation.create(name, symbolKind, statement.range, uri, containerStatement === null || containerStatement === void 0 ? void 0 : containerStatement.getName(Parser_1.ParseMode.BrighterScript));
1092
1109
  symbols.push(symbol);
1093
1110
  return symbols;
1094
1111
  }
@@ -1102,8 +1119,8 @@ class BrsFile {
1102
1119
  const token = this.getTokenAt(position);
1103
1120
  // While certain other tokens are allowed as local variables (AllowedLocalIdentifiers: https://github.com/rokucommunity/brighterscript/blob/master/src/lexer/TokenKind.ts#L418), these are converted by the parser to TokenKind.Identifier by the time we retrieve the token using getTokenAt
1104
1121
  let definitionTokenTypes = [
1105
- lexer_1.TokenKind.Identifier,
1106
- lexer_1.TokenKind.StringLiteral
1122
+ TokenKind_1.TokenKind.Identifier,
1123
+ TokenKind_1.TokenKind.StringLiteral
1107
1124
  ];
1108
1125
  //throw out invalid tokens and the wrong kind of tokens
1109
1126
  if (!token || !definitionTokenTypes.includes(token.kind)) {
@@ -1111,7 +1128,7 @@ class BrsFile {
1111
1128
  }
1112
1129
  let textToSearchFor = token.text.toLowerCase();
1113
1130
  const previousToken = this.getTokenAt({ line: token.range.start.line, character: token.range.start.character });
1114
- if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === lexer_1.TokenKind.Callfunc) {
1131
+ if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === TokenKind_1.TokenKind.Callfunc) {
1115
1132
  for (const scope of this.program.getScopes()) {
1116
1133
  //to only get functions defined in interface methods
1117
1134
  const callable = scope.getAllCallables().find((c) => c.callable.name.toLowerCase() === textToSearchFor); // eslint-disable-line @typescript-eslint/no-loop-func
@@ -1121,7 +1138,7 @@ class BrsFile {
1121
1138
  }
1122
1139
  return results;
1123
1140
  }
1124
- let classToken = this.getTokenBefore(token, lexer_1.TokenKind.Class);
1141
+ let classToken = this.getTokenBefore(token, TokenKind_1.TokenKind.Class);
1125
1142
  if (classToken) {
1126
1143
  let cs = this.parser.references.classStatements.find((cs) => cs.classKeyword.range === classToken.range);
1127
1144
  if (cs === null || cs === void 0 ? void 0 : cs.parentClassName) {
@@ -1133,7 +1150,7 @@ class BrsFile {
1133
1150
  }
1134
1151
  return results;
1135
1152
  }
1136
- if (token.kind === lexer_1.TokenKind.StringLiteral) {
1153
+ if (token.kind === TokenKind_1.TokenKind.StringLiteral) {
1137
1154
  // We need to strip off the quotes but only if present
1138
1155
  const startIndex = textToSearchFor.startsWith('"') ? 1 : 0;
1139
1156
  let endIndex = textToSearchFor.length;
@@ -1153,7 +1170,7 @@ class BrsFile {
1153
1170
  results.push(vscode_languageserver_1.Location.create(uri, varDeclaration.nameRange));
1154
1171
  }
1155
1172
  }
1156
- if (this.tokenFollows(token, lexer_1.TokenKind.Goto)) {
1173
+ if (this.tokenFollows(token, TokenKind_1.TokenKind.Goto)) {
1157
1174
  for (const label of functionScope.labelStatements) {
1158
1175
  if (label.name.toLocaleLowerCase() === textToSearchFor) {
1159
1176
  const uri = util_1.util.pathToUri(this.pathAbsolute);
@@ -1170,7 +1187,7 @@ class BrsFile {
1170
1187
  continue;
1171
1188
  }
1172
1189
  filesSearched.add(file);
1173
- if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === lexer_1.TokenKind.Dot && file.parseMode === parser_1.ParseMode.BrighterScript) {
1190
+ if ((previousToken === null || previousToken === void 0 ? void 0 : previousToken.kind) === TokenKind_1.TokenKind.Dot && file.parseMode === Parser_1.ParseMode.BrighterScript) {
1174
1191
  results.push(...this.getClassMemberDefinitions(textToSearchFor, file));
1175
1192
  const namespaceDefinition = this.getNamespaceDefinitions(token, file);
1176
1193
  if (namespaceDefinition) {
@@ -1214,14 +1231,15 @@ class BrsFile {
1214
1231
  return results;
1215
1232
  }
1216
1233
  getHover(position) {
1234
+ const fence = (code) => util_1.util.mdFence(code, 'brightscript');
1217
1235
  //get the token at the position
1218
1236
  let token = this.getTokenAt(position);
1219
1237
  let hoverTokenTypes = [
1220
- lexer_1.TokenKind.Identifier,
1221
- lexer_1.TokenKind.Function,
1222
- lexer_1.TokenKind.EndFunction,
1223
- lexer_1.TokenKind.Sub,
1224
- lexer_1.TokenKind.EndSub
1238
+ TokenKind_1.TokenKind.Identifier,
1239
+ TokenKind_1.TokenKind.Function,
1240
+ TokenKind_1.TokenKind.EndFunction,
1241
+ TokenKind_1.TokenKind.Sub,
1242
+ TokenKind_1.TokenKind.EndSub
1225
1243
  ];
1226
1244
  //throw out invalid tokens and the wrong kind of tokens
1227
1245
  if (!token || !hoverTokenTypes.includes(token.kind)) {
@@ -1247,7 +1265,7 @@ class BrsFile {
1247
1265
  return {
1248
1266
  range: token.range,
1249
1267
  //append the variable name to the front for scope
1250
- contents: typeText
1268
+ contents: fence(typeText)
1251
1269
  };
1252
1270
  }
1253
1271
  }
@@ -1255,7 +1273,7 @@ class BrsFile {
1255
1273
  if (labelStatement.name.toLocaleLowerCase() === lowerTokenText) {
1256
1274
  return {
1257
1275
  range: token.range,
1258
- contents: `${labelStatement.name}: label`
1276
+ contents: fence(`${labelStatement.name}: label`)
1259
1277
  };
1260
1278
  }
1261
1279
  }
@@ -1269,12 +1287,41 @@ class BrsFile {
1269
1287
  if (callable) {
1270
1288
  return {
1271
1289
  range: token.range,
1272
- contents: callable.type.toString()
1290
+ contents: this.getCallableDocumentation(callable)
1273
1291
  };
1274
1292
  }
1275
1293
  }
1276
1294
  }
1277
1295
  }
1296
+ /**
1297
+ * Build a hover documentation for a callable.
1298
+ */
1299
+ getCallableDocumentation(callable) {
1300
+ var _a;
1301
+ const comments = [];
1302
+ const tokens = callable.file.parser.tokens;
1303
+ const idx = tokens.indexOf((_a = callable.functionStatement) === null || _a === void 0 ? void 0 : _a.func.functionType);
1304
+ for (let i = idx - 1; i >= 0; i--) {
1305
+ const token = tokens[i];
1306
+ //skip whitespace and newline chars
1307
+ if (token.kind === TokenKind_1.TokenKind.Comment) {
1308
+ comments.push(token);
1309
+ }
1310
+ else if (token.kind === TokenKind_1.TokenKind.Newline || token.kind === TokenKind_1.TokenKind.Whitespace) {
1311
+ //skip these tokens
1312
+ continue;
1313
+ //any other token means there are no more comments
1314
+ }
1315
+ else {
1316
+ break;
1317
+ }
1318
+ }
1319
+ let result = util_1.util.mdFence(callable.type.toString(), 'brightscript');
1320
+ if (comments.length > 0) {
1321
+ result += '\n***\n' + comments.reverse().map(x => x.text.replace(/^('|rem)/i, '')).join('\n');
1322
+ }
1323
+ return result;
1324
+ }
1278
1325
  getSignatureHelpForNamespaceMethods(callableName, dottedGetText, scope) {
1279
1326
  var _a;
1280
1327
  if (!dottedGetText) {
@@ -1321,12 +1368,12 @@ class BrsFile {
1321
1368
  }
1322
1369
  }
1323
1370
  const kind = currentToken.kind;
1324
- if (kind === lexer_1.TokenKind.Comment) {
1371
+ if (kind === TokenKind_1.TokenKind.Comment) {
1325
1372
  // Strip off common leading characters to make it easier to read
1326
1373
  const commentText = currentToken.text.replace(/^[' *\/]+/, '');
1327
1374
  functionComments.unshift(commentText);
1328
1375
  }
1329
- else if (kind === lexer_1.TokenKind.Newline) {
1376
+ else if (kind === TokenKind_1.TokenKind.Newline) {
1330
1377
  if (functionComments.length === 0) {
1331
1378
  continue;
1332
1379
  }
@@ -1385,7 +1432,7 @@ class BrsFile {
1385
1432
  const classConstructor = this.getClassMethod(classStatement, 'new');
1386
1433
  let sigHelp = classConstructor ? this.getSignatureHelpForStatement(classConstructor) : undefined;
1387
1434
  if (sigHelp) {
1388
- sigHelp.key = classStatement.getName(parser_1.ParseMode.BrighterScript);
1435
+ sigHelp.key = classStatement.getName(Parser_1.ParseMode.BrighterScript);
1389
1436
  sigHelp.signature.label = sigHelp.signature.label.replace(/(function|sub) new/, sigHelp.key);
1390
1437
  }
1391
1438
  return sigHelp;
@@ -1462,7 +1509,7 @@ exports.BrsFile = BrsFile;
1462
1509
  * List of completions for all valid keywords/reserved words.
1463
1510
  * Build this list once because it won't change for the lifetime of this process
1464
1511
  */
1465
- exports.KeywordCompletions = Object.keys(lexer_1.Keywords)
1512
+ exports.KeywordCompletions = Object.keys(TokenKind_1.Keywords)
1466
1513
  //remove any keywords with whitespace
1467
1514
  .filter(x => !x.includes(' '))
1468
1515
  //create completions