brighterscript 1.0.0-alpha.14 → 1.0.0-alpha.17

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 (151) hide show
  1. package/CHANGELOG.md +83 -1
  2. package/README.md +28 -9
  3. package/dist/Cache.d.ts +2 -7
  4. package/dist/Cache.js +4 -13
  5. package/dist/Cache.js.map +1 -1
  6. package/dist/DependencyGraph.js +5 -4
  7. package/dist/DependencyGraph.js.map +1 -1
  8. package/dist/DiagnosticMessages.d.ts +21 -1
  9. package/dist/DiagnosticMessages.js +21 -1
  10. package/dist/DiagnosticMessages.js.map +1 -1
  11. package/dist/Logger.js +5 -5
  12. package/dist/Logger.js.map +1 -1
  13. package/dist/Program.d.ts +3 -3
  14. package/dist/Program.js +9 -7
  15. package/dist/Program.js.map +1 -1
  16. package/dist/ProgramBuilder.js +1 -1
  17. package/dist/ProgramBuilder.js.map +1 -1
  18. package/dist/Scope.d.ts +16 -11
  19. package/dist/Scope.js +42 -12
  20. package/dist/Scope.js.map +1 -1
  21. package/dist/XmlScope.d.ts +3 -3
  22. package/dist/XmlScope.js +1 -1
  23. package/dist/XmlScope.js.map +1 -1
  24. package/dist/astUtils/AstEditor.d.ts +6 -0
  25. package/dist/astUtils/AstEditor.js +10 -0
  26. package/dist/astUtils/AstEditor.js.map +1 -1
  27. package/dist/astUtils/AstEditor.spec.js +37 -0
  28. package/dist/astUtils/AstEditor.spec.js.map +1 -1
  29. package/dist/astUtils/creators.d.ts +10 -6
  30. package/dist/astUtils/creators.js +93 -12
  31. package/dist/astUtils/creators.js.map +1 -1
  32. package/dist/astUtils/creators.spec.js +10 -0
  33. package/dist/astUtils/creators.spec.js.map +1 -1
  34. package/dist/astUtils/reflection.d.ts +7 -2
  35. package/dist/astUtils/reflection.js +19 -3
  36. package/dist/astUtils/reflection.js.map +1 -1
  37. package/dist/astUtils/reflection.spec.js +5 -4
  38. package/dist/astUtils/reflection.spec.js.map +1 -1
  39. package/dist/astUtils/visitors.d.ts +3 -1
  40. package/dist/astUtils/visitors.js.map +1 -1
  41. package/dist/astUtils/visitors.spec.js +2 -0
  42. package/dist/astUtils/visitors.spec.js.map +1 -1
  43. package/dist/bscPlugin/BscPlugin.d.ts +4 -1
  44. package/dist/bscPlugin/BscPlugin.js +16 -0
  45. package/dist/bscPlugin/BscPlugin.js.map +1 -1
  46. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.d.ts +1 -0
  47. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js +38 -2
  48. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.js.map +1 -1
  49. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js +28 -0
  50. package/dist/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.js.map +1 -1
  51. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.d.ts +8 -0
  52. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js +40 -0
  53. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.js.map +1 -0
  54. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.d.ts +1 -0
  55. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js +32 -0
  56. package/dist/bscPlugin/transpile/BrsFilePreTranspileProcessor.spec.js.map +1 -0
  57. package/dist/bscPlugin/validation/BrsFileValidator.d.ts +9 -0
  58. package/dist/bscPlugin/validation/BrsFileValidator.js +66 -0
  59. package/dist/bscPlugin/validation/BrsFileValidator.js.map +1 -0
  60. package/dist/bscPlugin/validation/ScopeValidator.d.ts +11 -0
  61. package/dist/bscPlugin/validation/ScopeValidator.js +94 -0
  62. package/dist/bscPlugin/validation/ScopeValidator.js.map +1 -0
  63. package/dist/diagnosticUtils.js +3 -3
  64. package/dist/diagnosticUtils.js.map +1 -1
  65. package/dist/examples/plugins/removePrint.js +12 -14
  66. package/dist/examples/plugins/removePrint.js.map +1 -1
  67. package/dist/files/BrsFile.Class.spec.js +22 -23
  68. package/dist/files/BrsFile.Class.spec.js.map +1 -1
  69. package/dist/files/BrsFile.d.ts +10 -3
  70. package/dist/files/BrsFile.js +133 -49
  71. package/dist/files/BrsFile.js.map +1 -1
  72. package/dist/files/BrsFile.spec.js +299 -123
  73. package/dist/files/BrsFile.spec.js.map +1 -1
  74. package/dist/files/XmlFile.d.ts +5 -5
  75. package/dist/files/XmlFile.js +3 -3
  76. package/dist/files/XmlFile.js.map +1 -1
  77. package/dist/files/XmlFile.spec.js +9 -9
  78. package/dist/files/XmlFile.spec.js.map +1 -1
  79. package/dist/interfaces.d.ts +29 -37
  80. package/dist/lexer/Lexer.spec.js +8 -0
  81. package/dist/lexer/Lexer.spec.js.map +1 -1
  82. package/dist/lexer/TokenKind.d.ts +2 -0
  83. package/dist/lexer/TokenKind.js +5 -0
  84. package/dist/lexer/TokenKind.js.map +1 -1
  85. package/dist/parser/Expression.d.ts +85 -21
  86. package/dist/parser/Expression.js +177 -53
  87. package/dist/parser/Expression.js.map +1 -1
  88. package/dist/parser/Parser.Class.spec.js +1 -1
  89. package/dist/parser/Parser.Class.spec.js.map +1 -1
  90. package/dist/parser/Parser.d.ts +12 -3
  91. package/dist/parser/Parser.js +156 -56
  92. package/dist/parser/Parser.js.map +1 -1
  93. package/dist/parser/Parser.spec.js +57 -2
  94. package/dist/parser/Parser.spec.js.map +1 -1
  95. package/dist/parser/Statement.d.ts +94 -30
  96. package/dist/parser/Statement.js +281 -106
  97. package/dist/parser/Statement.js.map +1 -1
  98. package/dist/parser/tests/statement/Enum.spec.d.ts +1 -0
  99. package/dist/parser/tests/statement/Enum.spec.js +774 -0
  100. package/dist/parser/tests/statement/Enum.spec.js.map +1 -0
  101. package/dist/parser/tests/statement/For.spec.d.ts +1 -0
  102. package/dist/parser/tests/statement/For.spec.js +46 -0
  103. package/dist/parser/tests/statement/For.spec.js.map +1 -0
  104. package/dist/parser/tests/statement/ForEach.spec.d.ts +1 -0
  105. package/dist/parser/tests/statement/ForEach.spec.js +37 -0
  106. package/dist/parser/tests/statement/ForEach.spec.js.map +1 -0
  107. package/dist/types/BooleanType.d.ts +4 -2
  108. package/dist/types/BooleanType.js +5 -1
  109. package/dist/types/BooleanType.js.map +1 -1
  110. package/dist/types/DoubleType.d.ts +2 -0
  111. package/dist/types/DoubleType.js +5 -1
  112. package/dist/types/DoubleType.js.map +1 -1
  113. package/dist/types/DynamicType.d.ts +2 -0
  114. package/dist/types/DynamicType.js +5 -1
  115. package/dist/types/DynamicType.js.map +1 -1
  116. package/dist/types/FloatType.d.ts +3 -1
  117. package/dist/types/FloatType.js +5 -1
  118. package/dist/types/FloatType.js.map +1 -1
  119. package/dist/types/FunctionType.d.ts +2 -1
  120. package/dist/types/FunctionType.js +11 -8
  121. package/dist/types/FunctionType.js.map +1 -1
  122. package/dist/types/FunctionType.spec.js +6 -0
  123. package/dist/types/FunctionType.spec.js.map +1 -1
  124. package/dist/types/IntegerType.d.ts +3 -1
  125. package/dist/types/IntegerType.js +5 -1
  126. package/dist/types/IntegerType.js.map +1 -1
  127. package/dist/types/InvalidType.d.ts +4 -2
  128. package/dist/types/InvalidType.js +5 -1
  129. package/dist/types/InvalidType.js.map +1 -1
  130. package/dist/types/LongIntegerType.d.ts +3 -1
  131. package/dist/types/LongIntegerType.js +5 -1
  132. package/dist/types/LongIntegerType.js.map +1 -1
  133. package/dist/types/ObjectType.d.ts +2 -1
  134. package/dist/types/ObjectType.js +4 -2
  135. package/dist/types/ObjectType.js.map +1 -1
  136. package/dist/types/StringType.d.ts +4 -2
  137. package/dist/types/StringType.js +5 -1
  138. package/dist/types/StringType.js.map +1 -1
  139. package/dist/types/UninitializedType.js.map +1 -1
  140. package/dist/types/UniversalFunctionType.d.ts +9 -0
  141. package/dist/types/UniversalFunctionType.js +25 -0
  142. package/dist/types/UniversalFunctionType.js.map +1 -0
  143. package/dist/types/VoidType.d.ts +4 -2
  144. package/dist/types/VoidType.js +5 -1
  145. package/dist/types/VoidType.js.map +1 -1
  146. package/dist/util.d.ts +12 -2
  147. package/dist/util.js +74 -44
  148. package/dist/util.js.map +1 -1
  149. package/dist/validators/ClassValidator.js +3 -3
  150. package/dist/validators/ClassValidator.js.map +1 -1
  151. package/package.json +2 -3
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const chai_1 = require("chai");
4
4
  const sinonImport = require("sinon");
5
- const path = require("path");
6
5
  const vscode_languageserver_1 = require("vscode-languageserver");
7
6
  const Program_1 = require("../Program");
8
7
  const BooleanType_1 = require("../types/BooleanType");
@@ -20,19 +19,24 @@ const PluginInterface_1 = require("../PluginInterface");
20
19
  const testHelpers_spec_1 = require("../testHelpers.spec");
21
20
  const Parser_1 = require("../parser/Parser");
22
21
  const Logger_1 = require("../Logger");
23
- const VoidType_1 = require("../types/VoidType");
22
+ const Statement_1 = require("../parser/Statement");
23
+ const creators_1 = require("../astUtils/creators");
24
+ const fsExtra = require("fs-extra");
25
+ const ArrayType_1 = require("../types/ArrayType");
24
26
  const FloatType_1 = require("../types/FloatType");
25
27
  const ObjectType_1 = require("../types/ObjectType");
26
- const ArrayType_1 = require("../types/ArrayType");
28
+ const VoidType_1 = require("../types/VoidType");
27
29
  let sinon = sinonImport.createSandbox();
28
30
  describe('BrsFile', () => {
29
- let rootDir = (0, util_1.standardizePath) `${process.cwd()}/.tmp/rootDir`;
31
+ let tempDir = (0, util_1.standardizePath) `${process.cwd()}/.tmp`;
32
+ let rootDir = (0, util_1.standardizePath) `${tempDir}/rootDir`;
30
33
  let program;
31
34
  let srcPath = (0, util_1.standardizePath) `${rootDir}/source/main.brs`;
32
35
  let destPath = 'source/main.brs';
33
36
  let file;
34
37
  let testTranspile = (0, testHelpers_spec_1.getTestTranspile)(() => [program, rootDir]);
35
38
  beforeEach(() => {
39
+ fsExtra.emptyDirSync(tempDir);
36
40
  program = new Program_1.Program({ rootDir: rootDir, sourceMap: true });
37
41
  file = new BrsFile_1.BrsFile(srcPath, destPath, program);
38
42
  });
@@ -64,6 +68,14 @@ describe('BrsFile', () => {
64
68
  //BrighterScript
65
69
  (0, chai_1.expect)(new BrsFile_1.BrsFile(`${rootDir}/source/main.bs`, 'source/main.bs', program).needsTranspiled).to.be.true;
66
70
  });
71
+ it('computes new import statements after clearing parser references', () => {
72
+ const file = program.setFile('source/main.bs', ``);
73
+ (0, chai_1.expect)(file.ownScriptImports).to.be.empty;
74
+ file.parser.ast.statements.push(new Statement_1.ImportStatement((0, creators_1.createToken)(TokenKind_1.TokenKind.Import), (0, creators_1.createToken)(TokenKind_1.TokenKind.StringLiteral, 'pkg:/source/lib.brs')));
75
+ (0, chai_1.expect)(file.ownScriptImports).to.be.empty;
76
+ file.parser.invalidateReferences();
77
+ (0, chai_1.expect)(file.ownScriptImports.map(x => x.text)).to.eql(['pkg:/source/lib.brs']);
78
+ });
67
79
  it('allows adding diagnostics', () => {
68
80
  const expected = [{
69
81
  message: 'message',
@@ -158,6 +170,76 @@ describe('BrsFile', () => {
158
170
  (0, chai_1.expect)(names).to.includes('Main');
159
171
  (0, chai_1.expect)(names).to.includes('SayHello');
160
172
  });
173
+ it('includes every type of item at base level', () => {
174
+ program.setFile('source/main.bs', `
175
+ sub main()
176
+ print
177
+ end sub
178
+ sub speak()
179
+ end sub
180
+ namespace stuff
181
+ end namespace
182
+ class Person
183
+ end class
184
+ enum Direction
185
+ end enum
186
+ `);
187
+ (0, testHelpers_spec_1.expectCompletionsIncludes)(program.getCompletions('source/main.bs', util_1.default.createPosition(2, 26)), [{
188
+ label: 'main',
189
+ kind: vscode_languageserver_1.CompletionItemKind.Function
190
+ }, {
191
+ label: 'speak',
192
+ kind: vscode_languageserver_1.CompletionItemKind.Function
193
+ }, {
194
+ label: 'stuff',
195
+ kind: vscode_languageserver_1.CompletionItemKind.Module
196
+ }, {
197
+ label: 'Person',
198
+ kind: vscode_languageserver_1.CompletionItemKind.Class
199
+ }, {
200
+ label: 'Direction',
201
+ kind: vscode_languageserver_1.CompletionItemKind.Enum
202
+ }]);
203
+ });
204
+ describe('namespaces', () => {
205
+ it('gets full namespace completions at any point through the leading identifier', () => {
206
+ program.setFile('source/main.bs', `
207
+ sub main()
208
+ foo.bar
209
+ end sub
210
+
211
+ namespace foo.bar
212
+ end namespace
213
+
214
+ class Person
215
+ end class
216
+ `);
217
+ const result = program.getCompletions(`${rootDir}/source/main.bs`, vscode_languageserver_1.Position.create(2, 24)).map(x => x.label);
218
+ (0, chai_1.expect)(result).includes('main');
219
+ (0, chai_1.expect)(result).includes('foo');
220
+ (0, chai_1.expect)(result).includes('Person');
221
+ });
222
+ it('gets namespace completions', () => {
223
+ program.setFile('source/main.bs', `
224
+ namespace foo.bar
225
+ function sayHello()
226
+ end function
227
+ end namespace
228
+
229
+ sub Main()
230
+ print "hello"
231
+ foo.ba
232
+ foo.bar.
233
+ end sub
234
+ `);
235
+ let result = program.getCompletions(`${rootDir}/source/main.bs`, vscode_languageserver_1.Position.create(8, 30));
236
+ let names = result.map(x => x.label);
237
+ (0, chai_1.expect)(names).to.includes('bar');
238
+ result = program.getCompletions(`${rootDir}/source/main.bs`, vscode_languageserver_1.Position.create(9, 32));
239
+ names = result.map(x => x.label);
240
+ (0, chai_1.expect)(names).to.includes('sayHello');
241
+ });
242
+ });
161
243
  it('always includes `m`', () => {
162
244
  //eslint-disable-next-line @typescript-eslint/no-floating-promises
163
245
  program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
@@ -354,7 +436,7 @@ describe('BrsFile', () => {
354
436
  'bs:disable-next-line: LINT9999
355
437
  name = "bob
356
438
  end sub
357
- `);
439
+ `);
358
440
  (0, chai_1.expect)(file.commentFlags[0]).to.exist;
359
441
  (0, testHelpers_spec_1.expectHasDiagnostics)(program);
360
442
  });
@@ -364,7 +446,7 @@ describe('BrsFile', () => {
364
446
  sub main()
365
447
  something = true 'bs:disable-line: LINT1005
366
448
  end sub
367
- `);
449
+ `);
368
450
  file.addDiagnostics([{
369
451
  code: 'LINT1005',
370
452
  file: file,
@@ -375,18 +457,18 @@ describe('BrsFile', () => {
375
457
  (0, testHelpers_spec_1.expectZeroDiagnostics)(scope);
376
458
  });
377
459
  it('adds diagnostics for unknown numeric diagnostic codes', () => {
378
- program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
460
+ program.setFile({ src: `${rootDir} / source / main.brs`, dest: 'source/main.brs' }, `
379
461
  sub main()
380
462
  print "hi" 'bs:disable-line: 123456 999999 aaaab
381
463
  end sub
382
- `);
464
+ `);
383
465
  program.validate();
384
466
  (0, testHelpers_spec_1.expectDiagnostics)(program, [Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unknownDiagnosticCode(123456)), { range: vscode_languageserver_1.Range.create(2, 53, 2, 59) }), Object.assign(Object.assign({}, DiagnosticMessages_1.DiagnosticMessages.unknownDiagnosticCode(999999)), { range: vscode_languageserver_1.Range.create(2, 60, 2, 66) })]);
385
467
  });
386
468
  });
387
469
  describe('bs:disable-line', () => {
388
470
  it('works for all', () => {
389
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
471
+ let file = program.setFile({ src: `${rootDir} / source / main.brs`, dest: 'source/main.brs' }, `
390
472
  sub Main()
391
473
  z::;;%%%%%% 'bs:disable-line
392
474
  end sub
@@ -402,7 +484,7 @@ describe('BrsFile', () => {
402
484
  (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
403
485
  });
404
486
  it('works for specific codes', () => {
405
- program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
487
+ program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
406
488
  sub main()
407
489
  'should not have any errors
408
490
  DoSomething(1) 'bs:disable-line:1002
@@ -421,12 +503,12 @@ describe('BrsFile', () => {
421
503
  //the current version of BRS causes parse errors after the `parse` keyword, showing error in comments
422
504
  //the program should ignore all diagnostics found in brs:* comment lines EXCEPT
423
505
  //for the diagnostics about using unknown error codes
424
- program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
506
+ program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
425
507
  sub main()
426
508
  stop 'bs:disable-line
427
509
  print "need a valid line to fix stop error"
428
510
  end sub
429
- `);
511
+ `);
430
512
  program.validate();
431
513
  (0, testHelpers_spec_1.expectZeroDiagnostics)(program);
432
514
  });
@@ -436,9 +518,9 @@ describe('BrsFile', () => {
436
518
  it('supports iife in assignment', () => {
437
519
  program.setFile('source/main.brs', `
438
520
  sub main()
439
- result = sub()
521
+ result = sub()
440
522
  end sub()
441
- result = (sub()
523
+ result = (sub()
442
524
  end sub)()
443
525
  end sub
444
526
  `);
@@ -457,26 +539,26 @@ describe('BrsFile', () => {
457
539
  testParseMode('source/main.spec.bs', Parser_1.ParseMode.BrighterScript);
458
540
  });
459
541
  it('supports labels and goto statements', () => {
460
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
542
+ let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
461
543
  sub Main()
462
544
  'multiple goto statements on one line
463
- goto myLabel : goto myLabel
545
+ goto myLabel: goto myLabel
464
546
  myLabel:
465
547
  end sub
466
548
  `);
467
549
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
468
550
  });
469
551
  it('supports empty print statements', () => {
470
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
552
+ let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
471
553
  sub main()
472
- print
554
+ print
473
555
  end sub
474
556
  `);
475
557
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
476
558
  });
477
559
  describe('conditional compile', () => {
478
560
  it('works for upper case keywords', () => {
479
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
561
+ let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
480
562
  sub main()
481
563
  #CONST someFlag = true
482
564
  #IF someFlag
@@ -491,7 +573,7 @@ describe('BrsFile', () => {
491
573
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
492
574
  });
493
575
  it('supports single-word #elseif and #endif', () => {
494
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
576
+ let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
495
577
  sub main()
496
578
  #const someFlag = true
497
579
  #if someFlag
@@ -504,7 +586,7 @@ describe('BrsFile', () => {
504
586
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
505
587
  });
506
588
  it('supports multi-word #else if and #end if', () => {
507
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
589
+ let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
508
590
  sub main()
509
591
  #const someFlag = true
510
592
  #if someFlag
@@ -517,17 +599,17 @@ describe('BrsFile', () => {
517
599
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
518
600
  });
519
601
  it('does not choke on invalid code inside a false conditional compile', () => {
520
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
602
+ let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
521
603
  sub main()
522
604
  #if false
523
- non-commented code here should not cause parse errors
605
+ non - commented code here should not cause parse errors
524
606
  #end if
525
607
  end sub
526
608
  `);
527
609
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
528
610
  });
529
611
  it('detects syntax error in #if', () => {
530
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
612
+ let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
531
613
  sub main()
532
614
  #if true1
533
615
  print "true"
@@ -539,7 +621,7 @@ describe('BrsFile', () => {
539
621
  ]);
540
622
  });
541
623
  it('detects syntax error in #const', () => {
542
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
624
+ let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
543
625
  sub main()
544
626
  #if %
545
627
  print "true"
@@ -552,7 +634,7 @@ describe('BrsFile', () => {
552
634
  ]);
553
635
  });
554
636
  it('detects #const name using reserved word', () => {
555
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
637
+ let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
556
638
  sub main()
557
639
  #const function = true
558
640
  end sub
@@ -563,7 +645,7 @@ describe('BrsFile', () => {
563
645
  ]);
564
646
  });
565
647
  it('detects syntax error in #const', () => {
566
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
648
+ let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
567
649
  sub main()
568
650
  #const someConst = 123
569
651
  end sub
@@ -574,22 +656,22 @@ describe('BrsFile', () => {
574
656
  });
575
657
  });
576
658
  it('supports stop statement', () => {
577
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
659
+ let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
578
660
  sub main()
579
- stop
661
+ stop
580
662
  end sub
581
663
  `);
582
664
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
583
665
  });
584
666
  it('supports single-line if statements', () => {
585
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
667
+ let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
586
668
  sub main()
587
669
  if 1 < 2: return true: end if
588
670
  if 1 < 2: return true
589
671
  end if
590
672
  if false : print "true" : end if
591
673
  if true: print "8 worked": else if true: print "not run": else: print "not run": end if
592
- if true then : test = sub() : print "yes" : end sub : end if
674
+ if true then: test = sub() : print "yes" : end sub: end if
593
675
  end sub
594
676
  `);
595
677
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
@@ -674,7 +756,7 @@ describe('BrsFile', () => {
674
756
  print &he2
675
757
  print 1.2E+2
676
758
  print 2!
677
- print 12D-12
759
+ print 12D - 12
678
760
  print 2.3#
679
761
  print &hFEDCBA9876543210&
680
762
  print 9876543210&
@@ -741,11 +823,11 @@ describe('BrsFile', () => {
741
823
  it('supports variable names ending with type designators', () => {
742
824
  file.parse(`
743
825
  sub main()
744
- name$ = "bob"
745
- age% = 1
746
- height! = 5.5
747
- salary# = 9.87654321
748
- someHex& = 13
826
+ name$ = "bob"
827
+ age% = 1
828
+ height! = 5.5
829
+ salary# = 9.87654321
830
+ someHex& = 13
749
831
  end sub
750
832
  `);
751
833
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
@@ -755,7 +837,7 @@ describe('BrsFile', () => {
755
837
  sub main()
756
838
  if true then
757
839
  print "true"
758
- else if true then
840
+ else if true then
759
841
  print "also true"
760
842
  end if
761
843
  end sub
@@ -766,9 +848,9 @@ describe('BrsFile', () => {
766
848
  file.parse(`
767
849
  function GetObject()
768
850
  obj = {
769
- stop: function() as void
851
+ stop: function () as void
770
852
 
771
- end function
853
+ end function
772
854
  }
773
855
  return obj
774
856
  end function
@@ -779,10 +861,10 @@ describe('BrsFile', () => {
779
861
  file.parse(`
780
862
  function GetObject()
781
863
  obj = {
782
- run: function() as void
864
+ run: function () as void
783
865
 
784
866
  end function
785
- }
867
+ }
786
868
  return obj
787
869
  end function
788
870
  `);
@@ -810,7 +892,7 @@ describe('BrsFile', () => {
810
892
  function Main()
811
893
  promise = {
812
894
  then: sub()
813
- end sub
895
+ end sub
814
896
  }
815
897
  promise.then()
816
898
  end function
@@ -820,7 +902,7 @@ describe('BrsFile', () => {
820
902
  it('supports function as parameter type', () => {
821
903
  file.parse(`
822
904
  sub Main()
823
- doWork = function(callback as function)
905
+ doWork = function (callback as function)
824
906
  end function
825
907
  end sub
826
908
  `);
@@ -936,7 +1018,7 @@ describe('BrsFile', () => {
936
1018
  sub main()
937
1019
  end sub
938
1020
  import "file.brs"
939
- `);
1021
+ `);
940
1022
  program.validate();
941
1023
  (0, testHelpers_spec_1.expectDiagnostics)(program, [
942
1024
  DiagnosticMessages_1.DiagnosticMessages.importStatementMustBeDeclaredAtTopOfFile()
@@ -973,7 +1055,7 @@ describe('BrsFile', () => {
973
1055
  it('supports colons as separators in associative array properties', () => {
974
1056
  file.parse(`
975
1057
  sub Main()
976
- obj = {x:0 : y: 1}
1058
+ obj = { x: 0 : y: 1 }
977
1059
  end sub
978
1060
  `);
979
1061
  (0, testHelpers_spec_1.expectZeroDiagnostics)(file);
@@ -991,8 +1073,8 @@ describe('BrsFile', () => {
991
1073
  });
992
1074
  it('succeeds when finding variables with the word "function" in them', () => {
993
1075
  file.parse(`
994
- function Test()
995
- typeCheckFunction = RBS_CMN_GetFunction(invalid, methodName)
1076
+ function Test()
1077
+ typeCheckFunction = RBS_CMN_GetFunction(invalid, methodName)
996
1078
  end function
997
1079
  `);
998
1080
  });
@@ -1003,14 +1085,14 @@ describe('BrsFile', () => {
1003
1085
  print "A"
1004
1086
  end function
1005
1087
 
1006
- function DoB()
1007
- print "B"
1008
- end function
1088
+ function DoB()
1089
+ print "B"
1090
+ end function
1009
1091
  `);
1010
1092
  (0, chai_1.expect)(file.callables[0].name).to.equal('DoA');
1011
1093
  (0, chai_1.expect)(file.callables[0].nameRange).to.eql(vscode_languageserver_1.Range.create(1, 25, 1, 28));
1012
1094
  (0, chai_1.expect)(file.callables[1].name).to.equal('DoB');
1013
- (0, chai_1.expect)(file.callables[1].nameRange).to.eql(vscode_languageserver_1.Range.create(5, 26, 5, 29));
1095
+ (0, chai_1.expect)(file.callables[1].nameRange).to.eql(vscode_languageserver_1.Range.create(5, 25, 5, 28));
1014
1096
  });
1015
1097
  it('throws an error if the file has already been parsed', () => {
1016
1098
  let file = new BrsFile_1.BrsFile('abspath', 'relpath', program);
@@ -1341,13 +1423,13 @@ describe('BrsFile', () => {
1341
1423
  it('finds variable type from other variable', () => {
1342
1424
  file.parse(`
1343
1425
  sub Main()
1344
- name = "bob"
1345
- nameCopy = name
1426
+ name = "bob"
1427
+ nameCopy = name
1346
1428
  end sub
1347
1429
  `);
1348
1430
  (0, testHelpers_spec_1.expectSymbolTableEquals)(file.parser.references.functionExpressions[0].symbolTable, [
1349
- ['name', new StringType_1.StringType(), util_1.default.createRange(2, 19, 2, 23)],
1350
- ['nameCopy', new StringType_1.StringType(), util_1.default.createRange(3, 19, 3, 27)]
1431
+ ['name', new StringType_1.StringType(), util_1.default.createRange(2, 20, 2, 24)],
1432
+ ['nameCopy', new StringType_1.StringType(), util_1.default.createRange(3, 20, 3, 28)]
1351
1433
  ]);
1352
1434
  });
1353
1435
  it('sets proper range for functions', () => {
@@ -1358,7 +1440,6 @@ describe('BrsFile', () => {
1358
1440
  end function
1359
1441
  end sub
1360
1442
  `);
1361
- (0, chai_1.expect)(file.parser.references.functionExpressions).to.be.length(2);
1362
1443
  (0, chai_1.expect)(file.parser.references.functionExpressions.map(x => x.range)).to.eql([
1363
1444
  util_1.default.createRange(1, 16, 5, 23),
1364
1445
  util_1.default.createRange(2, 30, 4, 32)
@@ -1367,10 +1448,10 @@ describe('BrsFile', () => {
1367
1448
  });
1368
1449
  describe('getHover', () => {
1369
1450
  it('works for param types', () => {
1370
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1451
+ let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
1371
1452
  sub DoSomething(name as string)
1372
1453
  name = 1
1373
- sayMyName = function(name as string)
1454
+ sayMyName = function (name as string)
1374
1455
  end function
1375
1456
  end sub
1376
1457
  `);
@@ -1385,19 +1466,19 @@ describe('BrsFile', () => {
1385
1466
  });
1386
1467
  //ignore this for now...it's not a huge deal
1387
1468
  it('does not match on keywords or data types', () => {
1388
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1469
+ let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
1389
1470
  sub Main(name as string)
1390
1471
  end sub
1391
- sub as()
1472
+ sub as ()
1392
1473
  end sub
1393
1474
  `);
1394
- //hover over the `as`
1475
+ //hover over the `as `
1395
1476
  (0, chai_1.expect)(file.getHover(vscode_languageserver_1.Position.create(1, 31))).not.to.exist;
1396
1477
  //hover over the `string`
1397
1478
  (0, chai_1.expect)(file.getHover(vscode_languageserver_1.Position.create(1, 36))).not.to.exist;
1398
1479
  });
1399
1480
  it('finds declared function', () => {
1400
- let file = program.setFile({ src: `${rootDir}/source/main.brs`, dest: 'source/main.brs' }, `
1481
+ let file = program.setFile({ src: `${rootDir} /source/main.brs`, dest: 'source/main.brs' }, `
1401
1482
  function Main(count = 1)
1402
1483
  firstName = "bob"
1403
1484
  age = 21
@@ -1666,6 +1747,106 @@ describe('BrsFile', () => {
1666
1747
  //this test will throw an exception if something went wrong
1667
1748
  });
1668
1749
  describe('transpile', () => {
1750
+ it('transpiles if statement keywords as provided', () => {
1751
+ const code = `
1752
+ If True Then
1753
+ Print True
1754
+ Else If True Then
1755
+ print True
1756
+ Else If False Then
1757
+ Print False
1758
+ Else
1759
+ Print False
1760
+ End If
1761
+ `;
1762
+ testTranspile(code);
1763
+ testTranspile(code.toLowerCase());
1764
+ testTranspile(code.toUpperCase());
1765
+ });
1766
+ it('does not transpile `then` tokens', () => {
1767
+ const code = `
1768
+ if true
1769
+ print true
1770
+ else if true
1771
+ print false
1772
+ end if
1773
+ `;
1774
+ testTranspile(code);
1775
+ });
1776
+ it('honors spacing between multi-word tokens', () => {
1777
+ testTranspile(`
1778
+ if true
1779
+ print true
1780
+ elseif true
1781
+ print false
1782
+ endif
1783
+ `);
1784
+ });
1785
+ it('handles when only some of the statements have `then`', () => {
1786
+ testTranspile(`
1787
+ if true
1788
+ else if true then
1789
+ else if true
1790
+ else if true then
1791
+ if true then
1792
+ return true
1793
+ end if
1794
+ end if
1795
+ `);
1796
+ });
1797
+ it('retains casing of parameter types', () => {
1798
+ function test(type) {
1799
+ testTranspile(`
1800
+ sub one(a as ${type}, b as ${type.toUpperCase()}, c as ${type.toLowerCase()})
1801
+ end sub
1802
+ `);
1803
+ }
1804
+ test('Boolean');
1805
+ test('Double');
1806
+ test('Dynamic');
1807
+ test('Float');
1808
+ test('Integer');
1809
+ test('LongInteger');
1810
+ test('Object');
1811
+ test('String');
1812
+ });
1813
+ it('retains casing of return types', () => {
1814
+ function test(type) {
1815
+ testTranspile(`
1816
+ sub one() as ${type}
1817
+ end sub
1818
+
1819
+ sub two() as ${type.toLowerCase()}
1820
+ end sub
1821
+
1822
+ sub three() as ${type.toUpperCase()}
1823
+ end sub
1824
+ `);
1825
+ }
1826
+ test('Boolean');
1827
+ test('Double');
1828
+ test('Dynamic');
1829
+ test('Float');
1830
+ test('Integer');
1831
+ test('LongInteger');
1832
+ test('Object');
1833
+ test('String');
1834
+ test('Void');
1835
+ });
1836
+ it('retains casing of literal types', () => {
1837
+ function test(type) {
1838
+ testTranspile(`
1839
+ sub main()
1840
+ thing = ${type}
1841
+ thing = ${type.toLowerCase()}
1842
+ thing = ${type.toUpperCase()}
1843
+ end sub
1844
+ `);
1845
+ }
1846
+ test('Invalid');
1847
+ test('True');
1848
+ test('False');
1849
+ });
1669
1850
  describe('throwStatement', () => {
1670
1851
  it('transpiles properly', () => {
1671
1852
  testTranspile(`
@@ -1914,29 +2095,6 @@ describe('BrsFile', () => {
1914
2095
  end sub
1915
2096
  `, null, 'trim');
1916
2097
  });
1917
- it('adds `then` when missing', () => {
1918
- testTranspile(`
1919
- sub a()
1920
- if true
1921
- print "true"
1922
- else if true
1923
- print "true"
1924
- else
1925
- print "true"
1926
- end if
1927
- end sub
1928
- `, `
1929
- sub a()
1930
- if true then
1931
- print "true"
1932
- else if true then
1933
- print "true"
1934
- else
1935
- print "true"
1936
- end if
1937
- end sub
1938
- `, 'trim');
1939
- });
1940
2098
  it('does not add leading or trailing newlines', () => {
1941
2099
  testTranspile(`function abc()\nend function`, undefined, 'none');
1942
2100
  });
@@ -2386,11 +2544,16 @@ describe('BrsFile', () => {
2386
2544
  end class
2387
2545
  class Duck extends Bird
2388
2546
  end class
2389
- end namespace`, (0, testHelpers_spec_1.trim) `
2547
+ end namespace
2548
+ `, (0, testHelpers_spec_1.trim) `
2390
2549
  namespace AnimalKingdom
2391
2550
  class Bird
2551
+ sub new()
2552
+ end sub
2392
2553
  end class
2393
2554
  class Duck extends AnimalKingdom.Bird
2555
+ sub new()
2556
+ end sub
2394
2557
  end class
2395
2558
  end namespace
2396
2559
  `);
@@ -2430,6 +2593,8 @@ describe('BrsFile', () => {
2430
2593
  function getDuck()
2431
2594
  end function
2432
2595
  class Duck
2596
+ sub new()
2597
+ end sub
2433
2598
  @anMember
2434
2599
  @anMember("field")
2435
2600
  private thing as dynamic
@@ -2489,6 +2654,8 @@ describe('BrsFile', () => {
2489
2654
  end namespace
2490
2655
  `, (0, testHelpers_spec_1.trim) `
2491
2656
  class Person
2657
+ sub new()
2658
+ end sub
2492
2659
  public name as string
2493
2660
  public age as integer
2494
2661
  public sub getAge() as integer
@@ -2496,6 +2663,8 @@ describe('BrsFile', () => {
2496
2663
  end class
2497
2664
  namespace NameA.NameB
2498
2665
  class Person
2666
+ sub new()
2667
+ end sub
2499
2668
  public name as string
2500
2669
  public age as integer
2501
2670
  public sub getAge() as integer
@@ -2504,6 +2673,17 @@ describe('BrsFile', () => {
2504
2673
  end namespace
2505
2674
  `);
2506
2675
  });
2676
+ it('creates constructor properly', () => {
2677
+ testTypedef(`
2678
+ class Parent
2679
+ end class
2680
+ `, (0, testHelpers_spec_1.trim) `
2681
+ class Parent
2682
+ sub new()
2683
+ end sub
2684
+ end class
2685
+ `);
2686
+ });
2507
2687
  it('sets properties to dynamic when initialized to invalid', () => {
2508
2688
  testTypedef(`
2509
2689
  class Human
@@ -2512,6 +2692,8 @@ describe('BrsFile', () => {
2512
2692
  end class
2513
2693
  `, (0, testHelpers_spec_1.trim) `
2514
2694
  class Human
2695
+ sub new()
2696
+ end sub
2515
2697
  public firstName as dynamic
2516
2698
  public lastName as string
2517
2699
  end class
@@ -2558,6 +2740,8 @@ describe('BrsFile', () => {
2558
2740
  end class
2559
2741
  `, (0, testHelpers_spec_1.trim) `
2560
2742
  class Human
2743
+ sub new()
2744
+ end sub
2561
2745
  public firstName as string
2562
2746
  protected middleName as string
2563
2747
  private lastName as string
@@ -2584,10 +2768,14 @@ describe('BrsFile', () => {
2584
2768
  end class
2585
2769
  `, (0, testHelpers_spec_1.trim) `
2586
2770
  class Animal
2771
+ sub new()
2772
+ end sub
2587
2773
  public sub speak()
2588
2774
  end sub
2589
2775
  end class
2590
2776
  class Dog extends Animal
2777
+ sub new()
2778
+ end sub
2591
2779
  public override sub speak()
2592
2780
  end sub
2593
2781
  end class
@@ -2659,47 +2847,35 @@ describe('BrsFile', () => {
2659
2847
  });
2660
2848
  });
2661
2849
  describe('Plugins', () => {
2662
- function testPluginTranspile() {
2663
- testTranspile(`
2664
- sub main()
2665
- sayHello(sub()
2666
- print "sub hello"
2667
- end sub)
2668
- print "something"
2669
- end sub
2670
-
2671
- sub sayHello(fn)
2672
- fn()
2673
- print "hello"
2674
- end sub
2675
- `, `
2676
- sub main()
2677
- sayHello(sub()
2678
- \n end sub)
2679
- \n end sub
2680
-
2681
- sub sayHello(fn)
2682
- fn()
2683
- \n end sub
2850
+ let pluginFileName;
2851
+ let idx = 1;
2852
+ beforeEach(() => {
2853
+ pluginFileName = `plugin-${idx++}.js`;
2854
+ fsExtra.outputFileSync((0, util_1.standardizePath) `${tempDir}/plugins/${pluginFileName}`, `
2855
+ function plugin() {
2856
+ return {
2857
+ name: 'lower-file-name',
2858
+ afterFileParse: (evt) => {
2859
+ evt.file._customProp = true;
2860
+ }
2861
+ };
2862
+ }
2863
+ exports.default = plugin;
2684
2864
  `);
2685
- }
2686
- it('can use a plugin object which transforms the AST', () => {
2687
- program.plugins = new PluginInterface_1.default(util_1.default.loadPlugins('', [
2688
- require.resolve('../examples/plugins/removePrint')
2689
- ]), new Logger_1.Logger());
2690
- testPluginTranspile();
2691
2865
  });
2692
- it('can load an absolute plugin which transforms the AST', () => {
2693
- program.plugins = new PluginInterface_1.default(util_1.default.loadPlugins('', [
2694
- path.resolve(process.cwd(), './dist/examples/plugins/removePrint.js')
2866
+ it('can load an absolute plugin which receives callbacks', () => {
2867
+ program.plugins = new PluginInterface_1.default(util_1.default.loadPlugins(tempDir, [
2868
+ (0, util_1.standardizePath) `${tempDir}/plugins/${pluginFileName}`
2695
2869
  ]), new Logger_1.Logger());
2696
- testPluginTranspile();
2870
+ const file = program.setFile('source/MAIN.brs', '');
2871
+ (0, chai_1.expect)(file._customProp).to.exist;
2697
2872
  });
2698
- it('can load a relative plugin which transforms the AST', () => {
2699
- program.plugins = new PluginInterface_1.default(util_1.default.loadPlugins(process.cwd(), [
2700
- './dist/examples/plugins/removePrint.js'
2873
+ it('can load a relative plugin which receives callbacks', () => {
2874
+ program.plugins = new PluginInterface_1.default(util_1.default.loadPlugins(tempDir, [
2875
+ `./plugins/${pluginFileName}`
2701
2876
  ]), new Logger_1.Logger());
2702
- testPluginTranspile();
2877
+ const file = program.setFile('source/MAIN.brs', '');
2878
+ (0, chai_1.expect)(file._customProp).to.exist;
2703
2879
  });
2704
2880
  });
2705
2881
  describe('getSymbolTypeFromToken', () => {