brighterscript 1.0.0-alpha.52 → 1.0.0-alpha.53

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 (163) hide show
  1. package/README.md +5 -3
  2. package/bsconfig.schema.json +151 -0
  3. package/dist/BsConfig.d.ts +158 -44
  4. package/dist/BsConfig.js +24 -0
  5. package/dist/BsConfig.js.map +1 -1
  6. package/dist/BusyStatusTracker.js +3 -0
  7. package/dist/BusyStatusTracker.js.map +1 -1
  8. package/dist/CrossScopeValidator.js +5 -0
  9. package/dist/CrossScopeValidator.js.map +1 -1
  10. package/dist/DiagnosticFilterer.d.ts +17 -1
  11. package/dist/DiagnosticFilterer.js +69 -6
  12. package/dist/DiagnosticFilterer.js.map +1 -1
  13. package/dist/DiagnosticManager.d.ts +11 -1
  14. package/dist/DiagnosticManager.js +22 -3
  15. package/dist/DiagnosticManager.js.map +1 -1
  16. package/dist/DiagnosticMessages.d.ts +93 -4
  17. package/dist/DiagnosticMessages.js +91 -5
  18. package/dist/DiagnosticMessages.js.map +1 -1
  19. package/dist/LanguageServer.d.ts +15 -3
  20. package/dist/LanguageServer.js +53 -6
  21. package/dist/LanguageServer.js.map +1 -1
  22. package/dist/Logger.d.ts +7 -7
  23. package/dist/Logger.js +2 -2
  24. package/dist/Logger.js.map +1 -1
  25. package/dist/PluginInterface.js +2 -1
  26. package/dist/PluginInterface.js.map +1 -1
  27. package/dist/Program.d.ts +106 -9
  28. package/dist/Program.js +273 -23
  29. package/dist/Program.js.map +1 -1
  30. package/dist/ProgramBuilder.js +6 -0
  31. package/dist/ProgramBuilder.js.map +1 -1
  32. package/dist/RokuConstants.d.ts +123 -0
  33. package/dist/RokuConstants.js +87 -0
  34. package/dist/RokuConstants.js.map +1 -0
  35. package/dist/ScopeNamespaceLookup.js.map +1 -1
  36. package/dist/Stopwatch.js +2 -2
  37. package/dist/Stopwatch.js.map +1 -1
  38. package/dist/SymbolTable.d.ts +1 -0
  39. package/dist/SymbolTable.js +20 -12
  40. package/dist/SymbolTable.js.map +1 -1
  41. package/dist/Throttler.d.ts +1 -1
  42. package/dist/Throttler.js.map +1 -1
  43. package/dist/astUtils/reflection.d.ts +6 -1
  44. package/dist/astUtils/reflection.js +15 -4
  45. package/dist/astUtils/reflection.js.map +1 -1
  46. package/dist/astUtils/visitors.d.ts +1 -1
  47. package/dist/astUtils/visitors.js +2 -0
  48. package/dist/astUtils/visitors.js.map +1 -1
  49. package/dist/bscPlugin/BscPlugin.d.ts +2 -2
  50. package/dist/bscPlugin/BscPlugin.js +1 -1
  51. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  52. package/dist/bscPlugin/CallExpressionInfo.js.map +1 -1
  53. package/dist/bscPlugin/SignatureHelpUtil.js.map +1 -1
  54. package/dist/bscPlugin/codeActions/FixAllCodeActionsProcessor.d.ts +3 -3
  55. package/dist/bscPlugin/codeActions/FixAllCodeActionsProcessor.js.map +1 -1
  56. package/dist/bscPlugin/completions/CompletionsProcessor.js +2 -3
  57. package/dist/bscPlugin/completions/CompletionsProcessor.js.map +1 -1
  58. package/dist/bscPlugin/definition/DefinitionProvider.d.ts +67 -2
  59. package/dist/bscPlugin/definition/DefinitionProvider.js +244 -5
  60. package/dist/bscPlugin/definition/DefinitionProvider.js.map +1 -1
  61. package/dist/bscPlugin/references/ReferencesProvider.js +7 -1
  62. package/dist/bscPlugin/references/ReferencesProvider.js.map +1 -1
  63. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +40 -6
  64. package/dist/bscPlugin/validation/BrsFileValidator.js +109 -18
  65. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -1
  66. package/dist/bscPlugin/validation/ProgramValidator.d.ts +10 -0
  67. package/dist/bscPlugin/validation/ProgramValidator.js +54 -0
  68. package/dist/bscPlugin/validation/ProgramValidator.js.map +1 -1
  69. package/dist/bscPlugin/validation/ScopeValidator.js +55 -30
  70. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -1
  71. package/dist/bscPlugin/validation/XmlFileValidator.d.ts +18 -0
  72. package/dist/bscPlugin/validation/XmlFileValidator.js +51 -0
  73. package/dist/bscPlugin/validation/XmlFileValidator.js.map +1 -1
  74. package/dist/cli.js.map +1 -1
  75. package/dist/diagnosticUtils.d.ts +1 -1
  76. package/dist/diagnosticUtils.js.map +1 -1
  77. package/dist/files/BrsFile.d.ts +2 -2
  78. package/dist/files/BrsFile.js +2 -2
  79. package/dist/files/BrsFile.js.map +1 -1
  80. package/dist/files/XmlFile.d.ts +51 -1
  81. package/dist/files/XmlFile.js +264 -0
  82. package/dist/files/XmlFile.js.map +1 -1
  83. package/dist/formatUtils.d.ts +20 -0
  84. package/dist/formatUtils.js +38 -0
  85. package/dist/formatUtils.js.map +1 -0
  86. package/dist/globalCallables.d.ts +1 -1
  87. package/dist/globalCallables.js +4 -1
  88. package/dist/globalCallables.js.map +1 -1
  89. package/dist/interfaces.d.ts +60 -5
  90. package/dist/interfaces.js.map +1 -1
  91. package/dist/lexer/Lexer.d.ts +26 -0
  92. package/dist/lexer/Lexer.js +140 -15
  93. package/dist/lexer/Lexer.js.map +1 -1
  94. package/dist/lexer/TokenKind.d.ts +27 -0
  95. package/dist/lexer/TokenKind.js +77 -3
  96. package/dist/lexer/TokenKind.js.map +1 -1
  97. package/dist/lsp/ActionQueue.js +1 -2
  98. package/dist/lsp/ActionQueue.js.map +1 -1
  99. package/dist/lsp/DocumentManager.js +4 -0
  100. package/dist/lsp/DocumentManager.js.map +1 -1
  101. package/dist/lsp/LspProject.d.ts +2 -2
  102. package/dist/lsp/Project.d.ts +2 -2
  103. package/dist/lsp/Project.js +2 -0
  104. package/dist/lsp/Project.js.map +1 -1
  105. package/dist/lsp/ProjectManager.d.ts +7 -2
  106. package/dist/lsp/ProjectManager.js +3 -1
  107. package/dist/lsp/ProjectManager.js.map +1 -1
  108. package/dist/lsp/worker/MessageHandler.d.ts +1 -0
  109. package/dist/lsp/worker/MessageHandler.js +9 -0
  110. package/dist/lsp/worker/MessageHandler.js.map +1 -1
  111. package/dist/lsp/worker/WorkerPool.d.ts +51 -17
  112. package/dist/lsp/worker/WorkerPool.js +118 -40
  113. package/dist/lsp/worker/WorkerPool.js.map +1 -1
  114. package/dist/lsp/worker/WorkerThreadProject.d.ts +16 -3
  115. package/dist/lsp/worker/WorkerThreadProject.js +50 -10
  116. package/dist/lsp/worker/WorkerThreadProject.js.map +1 -1
  117. package/dist/lsp/worker/WorkerThreadProjectRunner.js +6 -0
  118. package/dist/lsp/worker/WorkerThreadProjectRunner.js.map +1 -1
  119. package/dist/lsp/worker/run.js +20 -3
  120. package/dist/lsp/worker/run.js.map +1 -1
  121. package/dist/parser/AstNode.d.ts +59 -2
  122. package/dist/parser/AstNode.js +63 -5
  123. package/dist/parser/AstNode.js.map +1 -1
  124. package/dist/parser/BrsTranspileState.d.ts +44 -0
  125. package/dist/parser/BrsTranspileState.js +49 -0
  126. package/dist/parser/BrsTranspileState.js.map +1 -1
  127. package/dist/parser/Expression.d.ts +56 -8
  128. package/dist/parser/Expression.js +91 -8
  129. package/dist/parser/Expression.js.map +1 -1
  130. package/dist/parser/Parser.d.ts +0 -5
  131. package/dist/parser/Parser.js +5 -9
  132. package/dist/parser/Parser.js.map +1 -1
  133. package/dist/parser/SGParser.d.ts +7 -1
  134. package/dist/parser/SGParser.js +20 -10
  135. package/dist/parser/SGParser.js.map +1 -1
  136. package/dist/parser/SGTypes.js +8 -2
  137. package/dist/parser/SGTypes.js.map +1 -1
  138. package/dist/parser/Statement.d.ts +21 -10
  139. package/dist/parser/Statement.js +61 -1
  140. package/dist/parser/Statement.js.map +1 -1
  141. package/dist/preprocessor/Manifest.d.ts +16 -0
  142. package/dist/preprocessor/Manifest.js +21 -5
  143. package/dist/preprocessor/Manifest.js.map +1 -1
  144. package/dist/roku-types/index.d.ts +3 -0
  145. package/dist/types/BuiltInInterfaceAdder.js +1 -1
  146. package/dist/types/BuiltInInterfaceAdder.js.map +1 -1
  147. package/dist/types/InheritableType.d.ts +0 -1
  148. package/dist/types/InheritableType.js +12 -11
  149. package/dist/types/InheritableType.js.map +1 -1
  150. package/dist/types/InterfaceType.js +6 -0
  151. package/dist/types/InterfaceType.js.map +1 -1
  152. package/dist/types/IntersectionType.d.ts +1 -1
  153. package/dist/types/IntersectionType.js +7 -7
  154. package/dist/types/IntersectionType.js.map +1 -1
  155. package/dist/types/ReferenceType.js +1 -1
  156. package/dist/types/ReferenceType.js.map +1 -1
  157. package/dist/types/helpers.d.ts +2 -2
  158. package/dist/types/helpers.js +8 -5
  159. package/dist/types/helpers.js.map +1 -1
  160. package/dist/util.d.ts +38 -4
  161. package/dist/util.js +296 -29
  162. package/dist/util.js.map +1 -1
  163. package/package.json +12 -18
package/dist/util.d.ts CHANGED
@@ -15,7 +15,7 @@ import { ObjectType } from './types/ObjectType';
15
15
  import { StringType } from './types/StringType';
16
16
  import { VoidType } from './types/VoidType';
17
17
  import { ParseMode } from './parser/Parser';
18
- import type { CallExpression, CallfuncExpression, DottedGetExpression, VariableExpression } from './parser/Expression';
18
+ import type { CallExpression, CallfuncExpression, VariableExpression } from './parser/Expression';
19
19
  import { type Identifier, type Token } from './lexer/Token';
20
20
  import { SourceNode } from 'source-map';
21
21
  import type { RawSourceMap, SourceMapGenerator } from 'source-map';
@@ -132,7 +132,7 @@ export declare class Util {
132
132
  /**
133
133
  * Walks left in a DottedGetExpression and returns a VariableExpression if found, or undefined if not found
134
134
  */
135
- findBeginningVariableExpression(dottedGet: DottedGetExpression): VariableExpression | undefined;
135
+ findBeginningVariableExpression(expression: Expression): VariableExpression | undefined;
136
136
  /**
137
137
  * Do `a` and `b` overlap by at least one character. This returns false if they are at the edges. Here's some examples:
138
138
  * ```
@@ -160,6 +160,22 @@ export declare class Util {
160
160
  rangeContains(range: Range | undefined, position: Position | undefined): boolean;
161
161
  comparePositionToRange(position: Position | undefined, range: Range | undefined): 1 | -1 | 0;
162
162
  comparePosition(a: Position | undefined, b: Position): 1 | -1 | 0;
163
+ /**
164
+ * Convert a file path into a `file://` URL string (e.g. `file:///C:/projects/file.brs`).
165
+ * Mirrors the `file-url` package: resolves the path, normalizes slashes, prefixes a leading slash
166
+ * (required for Windows drive letters), and escapes per RFC 3986.
167
+ */
168
+ fileUrl(filePath: string): string;
169
+ /**
170
+ * `JSON.stringify` that is safe against circular references and throwing getters. Replaces the
171
+ * `safe-json-stringify` package.
172
+ */
173
+ safeJsonStringify(data: any, replacer?: (key: string, value: any) => any, space?: string | number): string;
174
+ /**
175
+ * Serialize an error (or any thrown value) into a plain object suitable for `JSON.stringify`,
176
+ * handling circular references. Replaces the `serialize-error` package.
177
+ */
178
+ serializeError(value: any): any;
163
179
  /**
164
180
  * Is the inner range completely enclosed in the outer range
165
181
  */
@@ -380,6 +396,13 @@ export declare class Util {
380
396
  * Mostly used to convert namespaced item full names to a strings
381
397
  */
382
398
  getAllDottedGetPartsAsString(node: Expression | Statement, parseMode?: ParseMode, lastSep?: string): string;
399
+ /**
400
+ * Reconstruct the written name of a "complex" type expression - one that isn't a plain
401
+ * dotted-get chain, so `getAllDottedGetPartsAsString` can't represent it. Handles
402
+ * unions/intersections, inline interfaces, typed arrays, typed function types, and groupings.
403
+ * Returns `undefined` for anything it can't render.
404
+ */
405
+ getTypeExpressionName(node: Expression, parseMode?: ParseMode): string;
383
406
  /**
384
407
  * Break an expression into each part.
385
408
  */
@@ -412,6 +435,17 @@ export declare class Util {
412
435
  * Wraps SourceNode's constructor to be compatible with the TranspileResult type
413
436
  */
414
437
  sourceNodeFromTranspileResult(line: number | null, column: number | null, source: string | null, chunks?: string | SourceNode | TranspileResult, name?: string): SourceNode;
438
+ /**
439
+ * Strip a trailing `sourceMappingURL` comment (and the newline preceding it) from the end of a
440
+ * transpile result, so that appending a freshly-generated one doesn't produce a duplicate. A file
441
+ * can already carry a comment from a previous build, which is either preserved verbatim (for
442
+ * files that don't need transpiling) or re-emitted as a comment by the AST transpile.
443
+ *
444
+ * Handles both BrightScript-style (`'//# sourceMappingURL=...`) and XML-style
445
+ * (`<!--//# sourceMappingURL=... -->`) comments. Leaves the node untouched when no trailing
446
+ * sourceMappingURL comment is present.
447
+ */
448
+ stripTrailingSourceMappingURLComment(node: SourceNode): SourceNode;
415
449
  /**
416
450
  * Find the index of the last item in the array that matches.
417
451
  */
@@ -444,7 +478,7 @@ export declare class Util {
444
478
  srcPath: string;
445
479
  }): Promise<string>;
446
480
  isBuiltInType(typeName: string): boolean;
447
- isGenericNodeType(type: BscType): boolean;
481
+ isGenericNodeType(type: BscType, mustBeCallfuncAble: boolean): boolean;
448
482
  hasAnyRequiredSymbolChanged(requiredSymbols: UnresolvedSymbol[], changedSymbols: Map<SymbolTypeFlag, Set<string>>): boolean;
449
483
  setContainsUnresolvedSymbol(symbolLowerNameSet: Set<string>, symbol: UnresolvedSymbol): boolean;
450
484
  getCustomTypesInSymbolTree(setToFill: Set<BscType>, type: BscType, filter?: (t: BscType) => boolean): void;
@@ -494,7 +528,7 @@ export declare class Util {
494
528
  * A tagged template literal function for standardizing the path. This has to be defined as standalone function since it's a tagged template literal function,
495
529
  * we can't use `object.tag` syntax.
496
530
  */
497
- export declare function standardizePath(stringParts: any, ...expressions: any[]): string;
531
+ export declare function standardizePath(stringParts: TemplateStringsArray | string, ...expressions: any[]): string;
498
532
  /**
499
533
  * An item that can be coerced into a `Range`
500
534
  */
package/dist/util.js CHANGED
@@ -8,6 +8,7 @@ const path = require("path");
8
8
  const roku_deploy_1 = require("roku-deploy");
9
9
  const vscode_languageserver_1 = require("vscode-languageserver");
10
10
  const vscode_uri_1 = require("vscode-uri");
11
+ const BsConfig_1 = require("./BsConfig");
11
12
  const DiagnosticMessages_1 = require("./DiagnosticMessages");
12
13
  const interfaces_1 = require("./interfaces");
13
14
  const BooleanType_1 = require("./types/BooleanType");
@@ -172,7 +173,7 @@ class Util {
172
173
  * @param parentProjectPaths a list of parent config files. This is used by this method to recursively build the config list
173
174
  */
174
175
  loadConfigFile(configFilePath, parentProjectPaths, cwd = process.cwd()) {
175
- var _a;
176
+ var _a, _b, _c, _d, _e, _f, _g;
176
177
  if (configFilePath) {
177
178
  //if the config file path starts with question mark, then it's optional. return undefined if it doesn't exist
178
179
  if (configFilePath.startsWith('?')) {
@@ -212,11 +213,18 @@ class Util {
212
213
  //`require` paths should be relative to cwd
213
214
  exports.util.resolvePathsRelativeTo(projectConfig, 'require', projectFileCwd);
214
215
  let result;
216
+ let baseProjectConfigDeprecationDiagnostics;
215
217
  //if the project has a base file, load it
216
218
  if (projectConfig && typeof projectConfig.extends === 'string') {
217
219
  let baseProjectConfig = this.loadConfigFile(projectConfig.extends, [...parentProjectPaths, configFilePath], projectFileCwd);
218
220
  //extend the base config with the current project settings
219
221
  result = Object.assign(Object.assign({}, baseProjectConfig), projectConfig);
222
+ //`compilerOptions` is deep-merged (like TypeScript does), so a child config only
223
+ //overriding one option doesn't wipe out the rest of the options set by its parent(s)
224
+ if ((baseProjectConfig === null || baseProjectConfig === void 0 ? void 0 : baseProjectConfig.compilerOptions) || projectConfig.compilerOptions) {
225
+ result.compilerOptions = Object.assign(Object.assign({}, baseProjectConfig === null || baseProjectConfig === void 0 ? void 0 : baseProjectConfig.compilerOptions), projectConfig.compilerOptions);
226
+ }
227
+ baseProjectConfigDeprecationDiagnostics = baseProjectConfig === null || baseProjectConfig === void 0 ? void 0 : baseProjectConfig._deprecationDiagnostics;
220
228
  }
221
229
  else {
222
230
  result = projectConfig;
@@ -231,11 +239,44 @@ class Util {
231
239
  if (result.outDir) {
232
240
  result.outDir = path.resolve(projectFileCwd, result.outDir);
233
241
  }
242
+ //map the deprecated staging options to `outDir` (relative to THIS config file).
243
+ //the deprecated options themselves are left as-is so consumers that still read them keep working
244
+ if (!('outDir' in projectConfig)) {
245
+ if (projectConfig.stagingFolderPath) {
246
+ result.outDir = path.resolve(projectFileCwd, projectConfig.stagingFolderPath);
247
+ }
248
+ else if (projectConfig.stagingDir) {
249
+ result.outDir = path.resolve(projectFileCwd, projectConfig.stagingDir);
250
+ }
251
+ }
234
252
  if (result.cwd) {
235
253
  result.cwd = path.resolve(projectFileCwd, result.cwd);
236
254
  }
237
- if (result.sourceRoot && result.resolveSourceRoot) {
238
- result.sourceRoot = path.resolve(projectFileCwd, result.sourceRoot);
255
+ //flag any deprecated top-level `compilerOptions` options used directly in THIS config file
256
+ //(this is deliberately scoped to options loaded from an actual bsconfig.json file; options
257
+ //passed programmatically to `Program`/`ProgramBuilder` are not flagged)
258
+ const deprecationDiagnostics = [...((_b = (baseProjectConfigDeprecationDiagnostics)) !== null && _b !== void 0 ? _b : [])];
259
+ for (const key of BsConfig_1.deprecatedCompilerOptionKeys) {
260
+ if (key in projectConfig) {
261
+ deprecationDiagnostics.push(Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.deprecatedBsConfigOption(key)), { location: {
262
+ uri: this.pathToUri(configFilePath),
263
+ range: this.createRange(0, 0, 0, 0)
264
+ } }));
265
+ }
266
+ }
267
+ result._deprecationDiagnostics = deprecationDiagnostics;
268
+ //`sourceRoot`/`resolveSourceRoot` may live at the top level (deprecated) or in `compilerOptions`.
269
+ //resolve whichever location actually holds the value, relative to THIS config file
270
+ const sourceRootValue = (_d = (_c = result.compilerOptions) === null || _c === void 0 ? void 0 : _c.sourceRoot) !== null && _d !== void 0 ? _d : result.sourceRoot;
271
+ const resolveSourceRootValue = (_f = (_e = result.compilerOptions) === null || _e === void 0 ? void 0 : _e.resolveSourceRoot) !== null && _f !== void 0 ? _f : result.resolveSourceRoot;
272
+ if (sourceRootValue && resolveSourceRootValue) {
273
+ const resolvedSourceRoot = path.resolve(projectFileCwd, sourceRootValue);
274
+ if (((_g = result.compilerOptions) === null || _g === void 0 ? void 0 : _g.sourceRoot) !== undefined) {
275
+ result.compilerOptions.sourceRoot = resolvedSourceRoot;
276
+ }
277
+ else {
278
+ result.sourceRoot = resolvedSourceRoot;
279
+ }
239
280
  }
240
281
  return result;
241
282
  }
@@ -265,24 +306,28 @@ class Util {
265
306
  * @param config a bsconfig object to use as the baseline for the resulting config
266
307
  */
267
308
  normalizeAndResolveConfig(config) {
268
- let result = this.normalizeConfig(Object.assign({}, config));
269
309
  if (config === null || config === void 0 ? void 0 : config.noProject) {
270
- return result;
310
+ return this.normalizeConfig(Object.assign({}, config));
271
311
  }
312
+ let project;
272
313
  //if no options were provided, try to find a bsconfig.json file
273
314
  if (!config || !config.project) {
274
- result.project = this.getConfigFilePath(config === null || config === void 0 ? void 0 : config.cwd);
315
+ project = this.getConfigFilePath(config === null || config === void 0 ? void 0 : config.cwd);
275
316
  }
276
317
  else {
277
318
  //use the config's project link
278
- result.project = config.project;
279
- }
280
- if (result.project) {
281
- let configFile = this.loadConfigFile(result.project, undefined, config === null || config === void 0 ? void 0 : config.cwd);
282
- result = Object.assign(result, configFile);
283
- }
284
- //override the defaults with the specified options
285
- result = Object.assign(result, config);
319
+ project = config.project;
320
+ }
321
+ let mergedConfig = Object.assign({}, config);
322
+ if (project) {
323
+ let configFile = this.loadConfigFile(project, undefined, config === null || config === void 0 ? void 0 : config.cwd);
324
+ //the project file values are the defaults; the provided options override them
325
+ mergedConfig = Object.assign(Object.assign({}, configFile), config);
326
+ }
327
+ //set defaults and map deprecated options AFTER merging the project file, so that
328
+ //deprecated options (i.e. `stagingFolderPath`, `copyToStaging`) from the project file are properly honored
329
+ let result = this.normalizeConfig(mergedConfig);
330
+ result.project = project;
286
331
  return result;
287
332
  }
288
333
  /**
@@ -290,14 +335,31 @@ class Util {
290
335
  * @param config a bsconfig object to use as the baseline for the resulting config
291
336
  */
292
337
  normalizeConfig(config) {
293
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
338
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
294
339
  config = config !== null && config !== void 0 ? config : {};
295
340
  const cwd = (_a = config.cwd) !== null && _a !== void 0 ? _a : process.cwd();
341
+ //Resolve `compilerOptions`: values set there win over their deprecated top-level counterparts.
342
+ //(deprecation diagnostics for options loaded directly from a bsconfig.json file are collected
343
+ //separately, in `loadConfigFile`, and simply carried through on `config._deprecationDiagnostics`)
344
+ const compilerOptions = Object.assign({}, ((_b = config.compilerOptions) !== null && _b !== void 0 ? _b : {}));
345
+ for (const key of BsConfig_1.deprecatedCompilerOptionKeys) {
346
+ if (!(key in compilerOptions) && key in config) {
347
+ compilerOptions[key] = config[key];
348
+ }
349
+ //push the resolved (winning) value back onto the flat config so the rest of this function
350
+ //(and any code that still reads the deprecated flat option) sees the correct, resolved value
351
+ if (key in compilerOptions) {
352
+ config[key] = compilerOptions[key];
353
+ }
354
+ }
296
355
  let logLevel = logging_1.LogLevel.log;
297
356
  if (typeof config.logLevel === 'string') {
298
- logLevel = (_b = logging_1.LogLevel[config.logLevel.toLowerCase()]) !== null && _b !== void 0 ? _b : logging_1.LogLevel.log;
357
+ logLevel = (_c = logging_1.LogLevel[config.logLevel.toLowerCase()]) !== null && _c !== void 0 ? _c : logging_1.LogLevel.log;
299
358
  }
300
- let bslibDestinationDir = (_c = config.bslibDestinationDir) !== null && _c !== void 0 ? _c : 'source';
359
+ else if (typeof config.logLevel === 'number') {
360
+ logLevel = config.logLevel;
361
+ }
362
+ let bslibDestinationDir = (_d = config.bslibDestinationDir) !== null && _d !== void 0 ? _d : 'source';
301
363
  if (bslibDestinationDir !== 'source') {
302
364
  // strip leading and trailing slashes
303
365
  bslibDestinationDir = bslibDestinationDir.replace(/^(\/*)(.*?)(\/*)$/, '$2');
@@ -314,7 +376,7 @@ class Util {
314
376
  }
315
377
  let outDir;
316
378
  if ('outDir' in config) {
317
- outDir = (_d = config.outDir) !== null && _d !== void 0 ? _d : './out';
379
+ outDir = (_e = config.outDir) !== null && _e !== void 0 ? _e : './out';
318
380
  }
319
381
  else if ('stagingFolderPath' in config) {
320
382
  outDir = config.stagingFolderPath;
@@ -325,21 +387,22 @@ class Util {
325
387
  else {
326
388
  outDir = './out'; //default case
327
389
  }
390
+ const strictValue = !!config.strict;
328
391
  const configWithDefaults = {
329
392
  cwd: cwd,
330
393
  //use default files array from rokuDeploy
331
- files: (_e = config.files) !== null && _e !== void 0 ? _e : [...roku_deploy_1.DefaultFiles],
394
+ files: (_f = config.files) !== null && _f !== void 0 ? _f : [...roku_deploy_1.DefaultFiles],
332
395
  outDir: outDir,
333
396
  sourceMap: config.sourceMap === true,
334
397
  relativeSourceMaps: config.relativeSourceMaps === true,
335
398
  watch: config.watch === true ? true : false,
336
399
  emitFullPaths: config.emitFullPaths === true ? true : false,
337
400
  noEmit: noEmit,
338
- ignoreErrorCodes: (_f = config.ignoreErrorCodes) !== null && _f !== void 0 ? _f : [],
339
- diagnosticSeverityOverrides: (_g = config.diagnosticSeverityOverrides) !== null && _g !== void 0 ? _g : {},
340
- diagnosticFilters: (_h = config.diagnosticFilters) !== null && _h !== void 0 ? _h : [],
401
+ ignoreErrorCodes: (_g = config.ignoreErrorCodes) !== null && _g !== void 0 ? _g : [],
402
+ diagnosticSeverityOverrides: (_h = config.diagnosticSeverityOverrides) !== null && _h !== void 0 ? _h : {},
403
+ diagnosticFilters: (_j = config.diagnosticFilters) !== null && _j !== void 0 ? _j : [],
341
404
  diagnosticFiltersV0Compatibility: config.diagnosticFiltersV0Compatibility === true ? true : false,
342
- plugins: (_j = config.plugins) !== null && _j !== void 0 ? _j : [],
405
+ plugins: (_k = config.plugins) !== null && _k !== void 0 ? _k : [],
343
406
  pruneEmptyCodeFiles: config.pruneEmptyCodeFiles === true ? true : false,
344
407
  autoImportComponentScript: config.autoImportComponentScript === true ? true : false,
345
408
  showDiagnosticsInConsole: config.showDiagnosticsInConsole === false ? false : true,
@@ -351,7 +414,11 @@ class Util {
351
414
  logLevel: logLevel,
352
415
  bslibDestinationDir: bslibDestinationDir,
353
416
  legacyCallfuncHandling: config.legacyCallfuncHandling === true ? true : false,
354
- validate: config.validate === false ? false : true
417
+ validate: config.validate === false ? false : true,
418
+ strict: strictValue,
419
+ strictCallFunc: (typeof config.strictCallFunc === 'boolean' ? config.strictCallFunc : strictValue),
420
+ strictNodeMembers: (typeof config.strictNodeMembers === 'boolean' ? config.strictNodeMembers : strictValue),
421
+ compilerOptions: compilerOptions
355
422
  };
356
423
  //mutate `config` in case anyone is holding a reference to the incomplete one
357
424
  const merged = Object.assign(config, configWithDefaults);
@@ -504,8 +571,8 @@ class Util {
504
571
  /**
505
572
  * Walks left in a DottedGetExpression and returns a VariableExpression if found, or undefined if not found
506
573
  */
507
- findBeginningVariableExpression(dottedGet) {
508
- let left = dottedGet;
574
+ findBeginningVariableExpression(expression) {
575
+ let left = expression;
509
576
  while (left) {
510
577
  if ((0, reflection_1.isVariableExpression)(left)) {
511
578
  return left;
@@ -601,6 +668,106 @@ class Util {
601
668
  }
602
669
  return 0;
603
670
  }
671
+ /**
672
+ * Convert a file path into a `file://` URL string (e.g. `file:///C:/projects/file.brs`).
673
+ * Mirrors the `file-url` package: resolves the path, normalizes slashes, prefixes a leading slash
674
+ * (required for Windows drive letters), and escapes per RFC 3986.
675
+ */
676
+ fileUrl(filePath) {
677
+ let pathName = path.resolve(filePath).replace(/\\/g, '/');
678
+ //Windows drive letter must be prefixed with a slash
679
+ if (!pathName.startsWith('/')) {
680
+ pathName = `/${pathName}`;
681
+ }
682
+ //escape required characters for path components
683
+ return encodeURI(`file://${pathName}`).replace(/[?#]/g, encodeURIComponent);
684
+ }
685
+ /**
686
+ * `JSON.stringify` that is safe against circular references and throwing getters. Replaces the
687
+ * `safe-json-stringify` package.
688
+ */
689
+ safeJsonStringify(data, replacer, space) {
690
+ const seen = [];
691
+ const throwsMessage = (err) => '[Throws: ' + (err ? err.message : '?') + ']';
692
+ const safeGetValue = (obj, property) => {
693
+ try {
694
+ return obj[property];
695
+ }
696
+ catch (err) {
697
+ return throwsMessage(err);
698
+ }
699
+ };
700
+ const visit = (obj) => {
701
+ if (obj === null || typeof obj !== 'object') {
702
+ return obj;
703
+ }
704
+ if (seen.includes(obj)) {
705
+ return '[Circular]';
706
+ }
707
+ seen.push(obj);
708
+ try {
709
+ if (typeof obj.toJSON === 'function') {
710
+ try {
711
+ return visit(obj.toJSON());
712
+ }
713
+ catch (err) {
714
+ return throwsMessage(err);
715
+ }
716
+ }
717
+ if (Array.isArray(obj)) {
718
+ return obj.map(visit);
719
+ }
720
+ return Object.keys(obj).reduce((result, prop) => {
721
+ result[prop] = visit(safeGetValue(obj, prop));
722
+ return result;
723
+ }, {});
724
+ }
725
+ finally {
726
+ seen.pop();
727
+ }
728
+ };
729
+ return JSON.stringify(visit(data), replacer, space);
730
+ }
731
+ /**
732
+ * Serialize an error (or any thrown value) into a plain object suitable for `JSON.stringify`,
733
+ * handling circular references. Replaces the `serialize-error` package.
734
+ */
735
+ serializeError(value) {
736
+ const commonProperties = ['name', 'message', 'stack', 'code'];
737
+ const destroyCircular = (from, seen) => {
738
+ const to = Array.isArray(from) ? [] : {};
739
+ seen.push(from);
740
+ for (const [key, val] of Object.entries(from)) {
741
+ if (typeof val === 'function') {
742
+ continue;
743
+ }
744
+ if (!val || typeof val !== 'object') {
745
+ to[key] = val;
746
+ continue;
747
+ }
748
+ if (!seen.includes(from[key])) {
749
+ to[key] = destroyCircular(from[key], seen.slice());
750
+ continue;
751
+ }
752
+ to[key] = '[Circular]';
753
+ }
754
+ for (const property of commonProperties) {
755
+ if (typeof from[property] === 'string') {
756
+ to[property] = from[property];
757
+ }
758
+ }
759
+ return to;
760
+ };
761
+ if (typeof value === 'object' && value !== null) {
762
+ return destroyCircular(value, []);
763
+ }
764
+ //people sometimes throw things besides Error objects…
765
+ if (typeof value === 'function') {
766
+ //`JSON.stringify()` discards functions. We do too, unless a function is thrown directly.
767
+ return `[Function: ${(value.name || 'anonymous')}]`;
768
+ }
769
+ return value;
770
+ }
604
771
  /**
605
772
  * Is the inner range completely enclosed in the outer range
606
773
  */
@@ -1006,11 +1173,13 @@ class Util {
1006
1173
  */
1007
1174
  cloneToken(token) {
1008
1175
  if (token) {
1176
+ //keep this field order identical to `Lexer.addToken` so cloned tokens
1177
+ //share the same V8 hidden class as lexer-produced tokens
1009
1178
  const result = {
1010
1179
  kind: token.kind,
1011
- location: this.cloneLocation(token.location),
1012
1180
  text: token.text,
1013
1181
  isReserved: token.isReserved,
1182
+ location: this.cloneLocation(token.location),
1014
1183
  leadingWhitespace: token.leadingWhitespace,
1015
1184
  leadingTrivia: token.leadingTrivia ? token.leadingTrivia.map(x => this.cloneToken(x)) : undefined
1016
1185
  };
@@ -1376,7 +1545,15 @@ class Util {
1376
1545
  if ((0, reflection_1.isUnionType)(rightType)) {
1377
1546
  rightType = this.getHighestPriorityType(rightType.types);
1378
1547
  }
1379
- if ((0, reflection_1.isVoidType)(leftType) || (0, reflection_1.isVoidType)(rightType) || (0, reflection_1.isUninitializedType)(leftType) || (0, reflection_1.isUninitializedType)(rightType)) {
1548
+ if ((0, reflection_1.isUninitializedType)(leftType) || (0, reflection_1.isUninitializedType)(rightType)) {
1549
+ return undefined;
1550
+ }
1551
+ if ((0, reflection_1.isVoidType)(leftType) || (0, reflection_1.isVoidType)(rightType)) {
1552
+ // = and <> can still be used to check a possibly-void value against invalid/dynamic
1553
+ if ((operator.kind === TokenKind_1.TokenKind.Equal || operator.kind === TokenKind_1.TokenKind.LessGreater) &&
1554
+ ((0, reflection_1.isInvalidTypeLike)(leftType) || (0, reflection_1.isInvalidTypeLike)(rightType) || (0, reflection_1.isDynamicType)(leftType) || (0, reflection_1.isDynamicType)(rightType))) {
1555
+ return BooleanType_1.BooleanType.instance;
1556
+ }
1380
1557
  return undefined;
1381
1558
  }
1382
1559
  if ((0, reflection_1.isEnumMemberType)(leftType)) {
@@ -1987,6 +2164,71 @@ class Util {
1987
2164
  return result;
1988
2165
  /* eslint-enable no-var */
1989
2166
  }
2167
+ /**
2168
+ * Reconstruct the written name of a "complex" type expression - one that isn't a plain
2169
+ * dotted-get chain, so `getAllDottedGetPartsAsString` can't represent it. Handles
2170
+ * unions/intersections, inline interfaces, typed arrays, typed function types, and groupings.
2171
+ * Returns `undefined` for anything it can't render.
2172
+ */
2173
+ getTypeExpressionName(node, parseMode = Parser_1.ParseMode.BrighterScript) {
2174
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
2175
+ if ((0, reflection_1.isTypeExpression)(node)) {
2176
+ return this.getTypeExpressionName(node.expression, parseMode);
2177
+ }
2178
+ if ((0, reflection_1.isBinaryExpression)(node)) {
2179
+ //union (`or`) / intersection (`and`) types
2180
+ const left = this.getTypeExpressionName(node.left, parseMode);
2181
+ const right = this.getTypeExpressionName(node.right, parseMode);
2182
+ if (left === undefined || right === undefined) {
2183
+ return undefined;
2184
+ }
2185
+ return `${left} ${(_b = (_a = node.tokens.operator) === null || _a === void 0 ? void 0 : _a.text) !== null && _b !== void 0 ? _b : 'or'} ${right}`;
2186
+ }
2187
+ if ((0, reflection_1.isGroupingExpression)(node)) {
2188
+ const inner = this.getTypeExpressionName(node.expression, parseMode);
2189
+ return inner === undefined ? undefined : `(${inner})`;
2190
+ }
2191
+ if ((0, reflection_1.isTypedArrayExpression)(node)) {
2192
+ const inner = this.getTypeExpressionName(node.innerType, parseMode);
2193
+ return inner === undefined ? undefined : `${inner}[]`;
2194
+ }
2195
+ if ((0, reflection_1.isInlineInterfaceExpression)(node)) {
2196
+ const members = [];
2197
+ for (const member of (_c = node.members) !== null && _c !== void 0 ? _c : []) {
2198
+ const memberType = member.typeExpression
2199
+ ? this.getTypeExpressionName(member.typeExpression, parseMode)
2200
+ : undefined;
2201
+ members.push([
2202
+ member.isOptional ? 'optional ' : '',
2203
+ (_e = (_d = member.tokens.name) === null || _d === void 0 ? void 0 : _d.text) !== null && _e !== void 0 ? _e : '',
2204
+ memberType === undefined ? '' : ` as ${memberType}`
2205
+ ].join(''));
2206
+ }
2207
+ return `{ ${members.join(', ')} }`;
2208
+ }
2209
+ if ((0, reflection_1.isTypedFunctionTypeExpression)(node)) {
2210
+ const params = [];
2211
+ for (const param of (_f = node.params) !== null && _f !== void 0 ? _f : []) {
2212
+ const paramType = param.typeExpression
2213
+ ? this.getTypeExpressionName(param.typeExpression, parseMode)
2214
+ : undefined;
2215
+ params.push([
2216
+ (_h = (_g = param.tokens.name) === null || _g === void 0 ? void 0 : _g.text) !== null && _h !== void 0 ? _h : '',
2217
+ paramType === undefined ? '' : ` as ${paramType}`
2218
+ ].join(''));
2219
+ }
2220
+ const returnType = node.returnType
2221
+ ? this.getTypeExpressionName(node.returnType, parseMode)
2222
+ : undefined;
2223
+ return [
2224
+ (_k = (_j = node.tokens.functionType) === null || _j === void 0 ? void 0 : _j.text) !== null && _k !== void 0 ? _k : 'function',
2225
+ `(${params.join(', ')})`,
2226
+ returnType === undefined ? '' : ` as ${returnType}`
2227
+ ].join('');
2228
+ }
2229
+ //fall back to the dotted-get chain (variable/dotted-get leaves of the type expression)
2230
+ return this.getAllDottedGetPartsAsString(node, parseMode);
2231
+ }
1990
2232
  /**
1991
2233
  * Break an expression into each part.
1992
2234
  */
@@ -2115,6 +2357,28 @@ class Util {
2115
2357
  // accepts a more permissive type than its typedef states
2116
2358
  return new source_map_1.SourceNode(line, column, source, chunks, name);
2117
2359
  }
2360
+ /**
2361
+ * Strip a trailing `sourceMappingURL` comment (and the newline preceding it) from the end of a
2362
+ * transpile result, so that appending a freshly-generated one doesn't produce a duplicate. A file
2363
+ * can already carry a comment from a previous build, which is either preserved verbatim (for
2364
+ * files that don't need transpiling) or re-emitted as a comment by the AST transpile.
2365
+ *
2366
+ * Handles both BrightScript-style (`'//# sourceMappingURL=...`) and XML-style
2367
+ * (`<!--//# sourceMappingURL=... -->`) comments. Leaves the node untouched when no trailing
2368
+ * sourceMappingURL comment is present.
2369
+ */
2370
+ stripTrailingSourceMappingURLComment(node) {
2371
+ //`\S+` cannot backtrack across whitespace, so this stays linear-time on adversarial input
2372
+ const pattern = /(?:\r?\n)?[ \t]*(?:'\/\/# sourceMappingURL=\S+|<!--[ \t]*\/\/# sourceMappingURL=\S+[ \t]*-->)\s*$/;
2373
+ if (pattern.test(node.toString())) {
2374
+ //`replaceRight` operates on the right-most leaf string, which is where a trailing comment
2375
+ //lands in both the verbatim and AST-transpiled cases. The `source-map` typings declare the
2376
+ //pattern as a string, but it is handed straight to `String.prototype.replace`, which
2377
+ //accepts a RegExp
2378
+ node.replaceRight(pattern, '');
2379
+ }
2380
+ return node;
2381
+ }
2118
2382
  /**
2119
2383
  * Find the index of the last item in the array that matches.
2120
2384
  */
@@ -2311,12 +2575,15 @@ class Util {
2311
2575
  }
2312
2576
  return false;
2313
2577
  }
2314
- isGenericNodeType(type) {
2578
+ isGenericNodeType(type, mustBeCallfuncAble) {
2315
2579
  if ((0, reflection_1.isComponentType)(type)) {
2316
2580
  const lowerName = type.toString().toLowerCase();
2317
2581
  if (lowerName === 'rosgnode' || lowerName === 'rosgnodenode') {
2318
2582
  return true;
2319
2583
  }
2584
+ if (!mustBeCallfuncAble && (lowerName === 'rosgnodecontentnode')) {
2585
+ return true;
2586
+ }
2320
2587
  }
2321
2588
  return false;
2322
2589
  }