diff --git a/src/LanguageServer.spec.ts b/src/LanguageServer.spec.ts
index ed594703b..59b84c1ae 100644
--- a/src/LanguageServer.spec.ts
+++ b/src/LanguageServer.spec.ts
@@ -228,7 +228,7 @@ describe('LanguageServer', () => {
it('sends diagnostics that were triggered by the program instead of vscode', async () => {
server['connection'] = server['createConnection']();
await server['createProject'](workspacePath);
- let stub: SinonStub;
+ let stub: SinonStub | undefined;
const promise = new Promise((resolve) => {
stub = sinon.stub(connection, 'sendDiagnostics').callsFake(resolve as any);
});
@@ -240,7 +240,7 @@ describe('LanguageServer', () => {
`);
program.validate();
await promise;
- expect(stub.called).to.be.true;
+ expect(stub!.called).to.be.true;
});
});
@@ -836,7 +836,7 @@ describe('LanguageServer', () => {
expect(symbols.length).to.equal(1);
const classSymbol = symbols[0];
expect(classSymbol.name).to.equal('MyFirstClass');
- const classChildrenSymbols = classSymbol.children;
+ const classChildrenSymbols = classSymbol.children!;
expect(classChildrenSymbols.length).to.equal(2);
expect(classChildrenSymbols[0].name).to.equal('pi');
expect(classChildrenSymbols[1].name).to.equal('buildAwesome');
@@ -866,7 +866,7 @@ describe('LanguageServer', () => {
expect(symbols.length).to.equal(1);
const namespaceSymbol = symbols[0];
expect(namespaceSymbol.name).to.equal('MyFirstNamespace');
- const classChildrenSymbols = namespaceSymbol.children;
+ const classChildrenSymbols = namespaceSymbol.children!;
expect(classChildrenSymbols.length).to.equal(2);
expect(classChildrenSymbols[0].name).to.equal('MyFirstNamespace.pi');
expect(classChildrenSymbols[1].name).to.equal('MyFirstNamespace.buildAwesome');
diff --git a/src/PluginInterface.spec.ts b/src/PluginInterface.spec.ts
index 47fd4fea1..1e839829a 100644
--- a/src/PluginInterface.spec.ts
+++ b/src/PluginInterface.spec.ts
@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/prefer-ts-expect-error */
+/* eslint-disable @typescript-eslint/ban-ts-comment */
import { expect } from './chai-config.spec';
import * as sinon from 'sinon';
import { Logger } from './Logger';
@@ -16,8 +18,10 @@ describe('PluginInterface', () => {
name: 'allows adding a plugin',
beforePublish: beforePublish
};
+ //@ts-ignore the current definition of `emit` doesn't like this third argument
pluginInterface.emit('beforePublish', undefined, []);
pluginInterface.add(plugin);
+ //@ts-ignore the current definition of `emit` doesn't like this third argument
pluginInterface.emit('beforePublish', undefined, []);
expect(beforePublish.callCount).to.equal(1);
});
@@ -39,6 +43,7 @@ describe('PluginInterface', () => {
};
pluginInterface.add(plugin);
pluginInterface.add(plugin);
+ //@ts-ignore the current definition of `emit` doesn't like this third argument
pluginInterface.emit('beforePublish', undefined, []);
expect(beforePublish.callCount).to.equal(1);
pluginInterface.remove(plugin);
@@ -52,9 +57,11 @@ describe('PluginInterface', () => {
beforePublish: beforePublish
};
pluginInterface.add(plugin);
+ //@ts-ignore the current definition of `emit` doesn't like this third argument
pluginInterface.emit('beforePublish', undefined, []);
expect(beforePublish.callCount).to.equal(1);
pluginInterface.remove(plugin);
+ //@ts-ignore the current definition of `emit` doesn't like this third argument
pluginInterface.emit('beforePublish', undefined, []);
expect(beforePublish.callCount).to.equal(1);
});
diff --git a/src/Program.spec.ts b/src/Program.spec.ts
index 04b405980..3d0cf0aaf 100644
--- a/src/Program.spec.ts
+++ b/src/Program.spec.ts
@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { assert, expect } from './chai-config.spec';
import * as pick from 'object.pick';
import * as sinonImport from 'sinon';
@@ -21,6 +23,7 @@ import { isBrsFile } from './astUtils/reflection';
import type { LiteralExpression } from './parser/Expression';
import type { AstEditor } from './astUtils/AstEditor';
import { tempDir, rootDir, stagingDir } from './testHelpers.spec';
+import type { BsDiagnostic } from './interfaces';
let sinon = sinonImport.createSandbox();
@@ -263,11 +266,11 @@ describe('Program', () => {
});
it('allows adding diagnostics', () => {
- const expected = [{
+ const expected: BsDiagnostic[] = [{
message: 'message',
file: undefined,
range: undefined
- }];
+ }] as any;
program.addDiagnostics(expected);
const actual = (program as any).diagnostics;
expect(actual).to.deep.equal(expected);
@@ -720,7 +723,7 @@ describe('Program', () => {
describe('reloadFile', () => {
it('picks up new files in a scope when an xml file is loaded', () => {
- program.options.ignoreErrorCodes.push(1013);
+ program.options.ignoreErrorCodes!.push(1013);
program.setFile('components/component1.xml', trim`
@@ -766,7 +769,7 @@ describe('Program', () => {
});
it('reloads referenced fles when xml file changes', () => {
- program.options.ignoreErrorCodes.push(1013);
+ program.options.ignoreErrorCodes!.push(1013);
program.setFile('components/component1.brs', '');
let xmlFile = program.setFile('components/component1.xml', trim`
@@ -1735,19 +1738,19 @@ describe('Program', () => {
});
it('does not create map by default', async () => {
- fsExtra.ensureDirSync(program.options.stagingDir);
+ fsExtra.ensureDirSync(program.options.stagingDir!);
program.setFile('source/main.brs', `
sub main()
end sub
`);
program.validate();
- await program.transpile([], program.options.stagingDir);
+ await program.transpile([], program.options.stagingDir!);
expect(fsExtra.pathExistsSync(s`${stagingDir}/source/main.brs`)).is.true;
expect(fsExtra.pathExistsSync(s`${stagingDir}/source/main.brs.map`)).is.false;
});
it('creates sourcemap for brs and xml files', async () => {
- fsExtra.ensureDirSync(program.options.stagingDir);
+ fsExtra.ensureDirSync(program.options.stagingDir!);
program.setFile('source/main.brs', `
sub main()
end sub
@@ -1770,27 +1773,27 @@ describe('Program', () => {
dest: s`components/comp1.xml`
}];
program.options.sourceMap = true;
- await program.transpile(filePaths, program.options.stagingDir);
+ await program.transpile(filePaths, program.options.stagingDir!);
expect(fsExtra.pathExistsSync(s`${stagingDir}/source/main.brs.map`)).is.true;
expect(fsExtra.pathExistsSync(s`${stagingDir}/components/comp1.xml.map`)).is.true;
});
it('copies the bslib.brs file', async () => {
- fsExtra.ensureDirSync(program.options.stagingDir);
+ fsExtra.ensureDirSync(program.options.stagingDir!);
program.validate();
- await program.transpile([], program.options.stagingDir);
+ await program.transpile([], program.options.stagingDir!);
expect(fsExtra.pathExistsSync(s`${stagingDir}/source/bslib.brs`)).is.true;
});
it('copies the bslib.brs file to optionally specified directory', async () => {
- fsExtra.ensureDirSync(program.options.stagingDir);
+ fsExtra.ensureDirSync(program.options.stagingDir!);
program.options.bslibDestinationDir = 'source/opt';
program.validate();
- await program.transpile([], program.options.stagingDir);
+ await program.transpile([], program.options.stagingDir!);
expect(fsExtra.pathExistsSync(s`${stagingDir}/source/opt/bslib.brs`)).is.true;
});
@@ -1873,7 +1876,7 @@ describe('Program', () => {
}, {
src: s`${rootDir}/source/main.bs`,
dest: 'source/main.bs'
- }], program.options.stagingDir);
+ }], program.options.stagingDir!);
//entries should now be in alphabetic order
expect(
@@ -1960,7 +1963,7 @@ describe('Program', () => {
print "hello world"
end sub
`);
- let literalExpression: LiteralExpression;
+ let literalExpression: LiteralExpression | undefined;
//replace all strings with "goodbye world"
program.plugins.add({
name: 'TestPlugin',
@@ -1989,7 +1992,7 @@ describe('Program', () => {
);
//our literalExpression should have been restored to its original value
- expect(literalExpression.token.text).to.eql('"hello world"');
+ expect(literalExpression!.token.text).to.eql('"hello world"');
});
it('handles AstEditor for beforeProgramTranspile', async () => {
@@ -1998,7 +2001,7 @@ describe('Program', () => {
print "hello world"
end sub
`);
- let literalExpression: LiteralExpression;
+ let literalExpression: LiteralExpression | undefined;
//replace all strings with "goodbye world"
program.plugins.add({
name: 'TestPlugin',
@@ -2025,7 +2028,7 @@ describe('Program', () => {
);
//our literalExpression should have been restored to its original value
- expect(literalExpression.token.text).to.eql('"hello world"');
+ expect(literalExpression!.token.text).to.eql('"hello world"');
});
it('copies bslib.brs when no ropm version was found', async () => {
@@ -2046,7 +2049,7 @@ describe('Program', () => {
print SOURCE_LINE_NUM
end sub
`);
- await program.transpile([], program.options.stagingDir);
+ await program.transpile([], program.options.stagingDir!);
expect(trimMap(
fsExtra.readFileSync(s`${stagingDir}/source/logger.brs`).toString()
)).to.eql(trim`
@@ -2062,7 +2065,7 @@ describe('Program', () => {
print "logInfo"
end sub
`);
- await program.transpile([], program.options.stagingDir);
+ await program.transpile([], program.options.stagingDir!);
expect(trimMap(
fsExtra.readFileSync(s`${stagingDir}/source/logger.brs`).toString()
)).to.eql(trim`
@@ -2078,7 +2081,7 @@ describe('Program', () => {
`);
- await program.transpile([], program.options.stagingDir);
+ await program.transpile([], program.options.stagingDir!);
expect(trimMap(
fsExtra.readFileSync(s`${stagingDir}/components/Component1.xml`).toString()
)).to.eql(trim`
@@ -2096,7 +2099,7 @@ describe('Program', () => {
`);
- await program.transpile([], program.options.stagingDir);
+ await program.transpile([], program.options.stagingDir!);
expect(trimMap(
fsExtra.readFileSync(s`${stagingDir}/components/Component1.xml`).toString()
)).to.eql(trim`
diff --git a/src/ProgramBuilder.spec.ts b/src/ProgramBuilder.spec.ts
index 9f2403411..63ac78bd8 100644
--- a/src/ProgramBuilder.spec.ts
+++ b/src/ProgramBuilder.spec.ts
@@ -274,7 +274,7 @@ describe('ProgramBuilder', () => {
let diagnostics = createBsDiagnostic('p1', ['m1']);
let f1 = diagnostics[0].file as BrsFile;
- f1.fileContents = null;
+ (f1.fileContents as any) = null;
sinon.stub(builder, 'getDiagnostics').returns(diagnostics);
sinon.stub(builder.program, 'getFile').returns(f1);
@@ -292,7 +292,7 @@ describe('ProgramBuilder', () => {
let diagnostics = createBsDiagnostic('p1', ['m1']);
sinon.stub(builder, 'getDiagnostics').returns(diagnostics);
- sinon.stub(builder.program, 'getFile').returns(null);
+ sinon.stub(builder.program, 'getFile').returns(null as any);
let printStub = sinon.stub(diagnosticUtils, 'printDiagnostic');
@@ -351,8 +351,8 @@ describe('ProgramBuilder', () => {
});
function createBsDiagnostic(filePath: string, messages: string[]): BsDiagnostic[] {
- let file = new BrsFile(filePath, filePath, null);
- let diagnostics = [];
+ let file = new BrsFile(filePath, filePath, null as any);
+ let diagnostics: BsDiagnostic[] = [];
for (let message of messages) {
let d = createDiagnostic(file, 1, message);
d.file = file;
diff --git a/src/Scope.spec.ts b/src/Scope.spec.ts
index fb7a915de..c28100774 100644
--- a/src/Scope.spec.ts
+++ b/src/Scope.spec.ts
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { expect } from './chai-config.spec';
import * as sinonImport from 'sinon';
import { Position, Range } from 'vscode-languageserver';
@@ -9,7 +10,7 @@ import PluginInterface from './PluginInterface';
import { expectDiagnostics, expectZeroDiagnostics, trim } from './testHelpers.spec';
import { Logger } from './Logger';
import type { BrsFile } from './files/BrsFile';
-import type { FunctionStatement, NamespaceStatement } from './parser/Statement';
+import type { NamespaceStatement } from './parser/Statement';
import type { OnScopeValidateEvent } from './interfaces';
describe('Scope', () => {
@@ -30,7 +31,7 @@ describe('Scope', () => {
it('getEnumMemberFileLink does not crash on undefined name', () => {
program.setFile('source/main.bs', ``);
const scope = program.getScopesForFile('source/main.bs')[0];
- scope.getEnumMemberFileLink(null);
+ scope.getEnumMemberFileLink(null as any);
//test passes if this doesn't explode
});
@@ -1481,7 +1482,7 @@ describe('Scope', () => {
`);
program.setFile(s`components/child.brs`, ``);
program.validate();
- let childScope = program.getComponentScope('child');
+ let childScope = program.getComponentScope('child')!;
expect(childScope.getAllCallables().map(x => x.callable.name)).not.to.include('parentSub');
program.setFile('components/parent.xml', trim`
@@ -1542,7 +1543,7 @@ describe('Scope', () => {
end function
end namespace
`);
- delete ((file.ast.statements[0] as NamespaceStatement).body.statements[0] as FunctionStatement).name;
+ delete ((file.ast.statements[0] as NamespaceStatement).body.statements[0] as any).name;
program.validate();
program['scopes']['source'].buildNamespaceLookup();
});
diff --git a/src/Scope.ts b/src/Scope.ts
index 3804ccec7..7302a1f3d 100644
--- a/src/Scope.ts
+++ b/src/Scope.ts
@@ -917,8 +917,8 @@ export class Scope {
}
private validateClasses() {
- let validator = new BsClassValidator();
- validator.validate(this);
+ let validator = new BsClassValidator(this);
+ validator.validate();
this.diagnostics.push(...validator.diagnostics);
}
diff --git a/src/Stopwatch.ts b/src/Stopwatch.ts
index 9c743102d..2866e9a2e 100644
--- a/src/Stopwatch.ts
+++ b/src/Stopwatch.ts
@@ -6,7 +6,7 @@ export class Stopwatch {
/**
* The number of milliseconds when the stopwatch was started.
*/
- private startTime: number;
+ private startTime: number | undefined;
start() {
this.startTime = performance.now();
}
@@ -17,7 +17,7 @@ export class Stopwatch {
this.startTime = undefined;
}
reset() {
- this.totalMilliseconds = undefined;
+ this.totalMilliseconds = 0;
this.startTime = undefined;
}
getDurationText() {
diff --git a/src/SymbolTable.spec.ts b/src/SymbolTable.spec.ts
index 8267c6822..48bcbfd3d 100644
--- a/src/SymbolTable.spec.ts
+++ b/src/SymbolTable.spec.ts
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { SymbolTable } from './SymbolTable';
import { expect } from './chai-config.spec';
import { StringType } from './types/StringType';
@@ -13,36 +14,36 @@ describe('SymbolTable', () => {
it('is case insensitive', () => {
const st = new SymbolTable('Child');
- st.addSymbol('foo', null, new StringType());
- expect(st.getSymbol('FOO').length).eq(1);
- expect(st.getSymbol('FOO')[0].type.toString()).eq('string');
+ st.addSymbol('foo', null as any, new StringType());
+ expect(st.getSymbol('FOO')!.length).eq(1);
+ expect(st.getSymbol('FOO')![0].type.toString()).eq('string');
});
it('stores all previous symbols', () => {
const st = new SymbolTable('Child');
- st.addSymbol('foo', null, new StringType());
- st.addSymbol('foo', null, new IntegerType());
- expect(st.getSymbol('FOO').length).eq(2);
+ st.addSymbol('foo', null as any, new StringType());
+ st.addSymbol('foo', null as any, new IntegerType());
+ expect(st.getSymbol('FOO')!.length).eq(2);
});
it('reads from parent symbol table if not found in current', () => {
const st = new SymbolTable('Child', () => parent);
- parent.addSymbol('foo', null, new StringType());
- expect(st.getSymbol('foo')[0].type.toString()).eq('string');
+ parent.addSymbol('foo', null as any, new StringType());
+ expect(st.getSymbol('foo')![0].type.toString()).eq('string');
});
it('reads from current table if it exists', () => {
const st = new SymbolTable('Child', () => parent);
- parent.addSymbol('foo', null, new StringType());
- st.addSymbol('foo', null, new IntegerType());
- expect(st.getSymbol('foo')[0].type.toString()).eq('integer');
+ parent.addSymbol('foo', null as any, new StringType());
+ st.addSymbol('foo', null as any, new IntegerType());
+ expect(st.getSymbol('foo')![0].type.toString()).eq('integer');
});
it('correct checks if a symbol is in the table using hasSymbol', () => {
const child = new SymbolTable('Child', () => parent);
- parent.addSymbol('foo', null, new StringType());
- child.addSymbol('bar', null, new IntegerType());
+ parent.addSymbol('foo', null as any, new StringType());
+ child.addSymbol('bar', null as any, new IntegerType());
expect(parent.hasSymbol('foo')).to.be.true;
expect(parent.hasSymbol('bar')).to.be.false;
expect(child.hasSymbol('foo')).to.be.true;
@@ -54,25 +55,25 @@ describe('SymbolTable', () => {
it('adds each symbol to the table', () => {
const st = new SymbolTable('Child');
- st.addSymbol('foo', null, new StringType());
+ st.addSymbol('foo', null as any, new StringType());
const otherTable = new SymbolTable('OtherTable');
- otherTable.addSymbol('bar', null, new IntegerType());
- otherTable.addSymbol('foo', null, new IntegerType());
+ otherTable.addSymbol('bar', null as any, new IntegerType());
+ otherTable.addSymbol('foo', null as any, new IntegerType());
st.mergeSymbolTable(otherTable);
});
});
it('searches siblings before parents', () => {
- parent.addSymbol('alpha', null, new StringType());
+ parent.addSymbol('alpha', null as any, new StringType());
const child = new SymbolTable('Child', () => parent);
const sibling = new SymbolTable('Sibling');
child.addSibling(sibling);
- sibling.addSymbol('alpha', null, new BooleanType());
+ sibling.addSymbol('alpha', null as any, new BooleanType());
expect(
- child.getSymbol('alpha').map(x => x.type.toTypeString())
+ child.getSymbol('alpha')!.map(x => x.type.toTypeString())
).to.eql([
'boolean'
]);
diff --git a/src/XmlScope.spec.ts b/src/XmlScope.spec.ts
index a8141c609..3e0e97959 100644
--- a/src/XmlScope.spec.ts
+++ b/src/XmlScope.spec.ts
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { expect } from './chai-config.spec';
import { Position, Range } from 'vscode-languageserver';
import { DiagnosticMessages } from './DiagnosticMessages';
@@ -40,7 +41,7 @@ describe('XmlScope', () => {
`);
- let childScope = program.getComponentScope('Child');
+ let childScope = program.getComponentScope('Child')!;
program.validate();
@@ -86,7 +87,7 @@ describe('XmlScope', () => {
`);
program.validate();
- expect(program.getComponentScope('Child').getOwnFiles()[0]).to.equal(xmlFile);
+ expect(program.getComponentScope('Child')!.getOwnFiles()[0]).to.equal(xmlFile);
});
});
@@ -113,7 +114,7 @@ describe('XmlScope', () => {
end sub
`);
program.validate();
- let childScope = program.getComponentScope('child');
+ let childScope = program.getComponentScope('child')!;
expectDiagnostics(childScope, [{
...DiagnosticMessages.xmlFunctionNotFound('func2'),
range: Range.create(4, 24, 4, 29)
@@ -157,7 +158,7 @@ describe('XmlScope', () => {
end sub
`);
program.validate();
- expectDiagnostics(program.getComponentScope('child'), [{
+ expectDiagnostics(program.getComponentScope('child')!, [{
...DiagnosticMessages.xmlInvalidFieldType('no'),
range: Range.create(4, 33, 4, 35)
}, {
diff --git a/src/astUtils/AstEditor.spec.ts b/src/astUtils/AstEditor.spec.ts
index c1e1bda28..31da12a18 100644
--- a/src/astUtils/AstEditor.spec.ts
+++ b/src/astUtils/AstEditor.spec.ts
@@ -124,7 +124,7 @@ describe('AstEditor', () => {
it('restores array after being removed', () => {
editor.removeFromArray(obj.hobbies, 0);
- editor.setProperty(obj, 'hobbies', undefined);
+ editor.setProperty(obj, 'hobbies', undefined as any);
expect(obj.hobbies).to.be.undefined;
editor.undoAll();
expect(obj.hobbies).to.eql(['gaming', 'reading', 'cycling']);
@@ -139,7 +139,7 @@ describe('AstEditor', () => {
editor.removeFromArray(obj.hobbies, 0);
editor.removeFromArray(obj.hobbies, 0);
editor.removeFromArray(obj.hobbies, 0);
- editor.setProperty(obj, 'hobbies', undefined);
+ editor.setProperty(obj, 'hobbies', undefined as any);
expect(obj).to.eql({
name: 'bob',
@@ -294,9 +294,9 @@ describe('AstEditor', () => {
it('edit handles missing functions', () => {
//missing undo
- editor.edit((data) => { }, undefined);
+ editor.edit((data) => { }, undefined as any);
//missing edit
- editor.edit(undefined, (data) => { });
+ editor.edit(undefined as any, (data) => { });
//test passes if no exceptions were thrown
});
diff --git a/src/astUtils/stackedVisitor.spec.ts b/src/astUtils/stackedVisitor.spec.ts
index 1b0c1d0b1..3b978aa16 100644
--- a/src/astUtils/stackedVisitor.spec.ts
+++ b/src/astUtils/stackedVisitor.spec.ts
@@ -43,7 +43,7 @@ describe('createStackedVisitor', () => {
assert(stack !== undefined, 'stack is undefined');
actual.push(`${stack.length ? stack.map(e => e.id).join('/') + '/' : ''}${item.id}`);
});
- visitStruct(test1Struct, undefined, stackedVisitor);
+ visitStruct(test1Struct, undefined as any, stackedVisitor);
expect(actual).to.deep.equal([
'1',
'1/2',
@@ -73,7 +73,7 @@ describe('createStackedVisitor', () => {
assert(stack !== undefined, 'stack is undefined');
actual.push(`<${stack.map(e => e.id).join('/')}:${popped.id}`);
});
- visitStruct(test1Struct, undefined, stackedVisitor);
+ visitStruct(test1Struct, undefined as any, stackedVisitor);
expect(actual).to.deep.equal([
'>1:1',
'>1/3:3',
diff --git a/src/bscPlugin/codeActions/CodeActionsProcessor.spec.ts b/src/bscPlugin/codeActions/CodeActionsProcessor.spec.ts
index f5e83ada5..56b3bcb26 100644
--- a/src/bscPlugin/codeActions/CodeActionsProcessor.spec.ts
+++ b/src/bscPlugin/codeActions/CodeActionsProcessor.spec.ts
@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { expect } from '../../chai-config.spec';
import { URI } from 'vscode-uri';
import type { Range } from 'vscode-languageserver';
@@ -93,7 +95,7 @@ describe('CodeActionsProcessor', () => {
util.createRange(1, 5, 1, 5)
);
expect(
- codeActions[0].edit.changes[URI.file(s`${rootDir}/components/comp1.xml`).toString()][0].range
+ codeActions[0].edit!.changes![URI.file(s`${rootDir}/components/comp1.xml`).toString()][0].range
).to.eql(
util.createRange(1, 51, 1, 51)
);
diff --git a/src/bscPlugin/hover/HoverProcessor.ts b/src/bscPlugin/hover/HoverProcessor.ts
index 951d6d9d1..5f4c1f8f1 100644
--- a/src/bscPlugin/hover/HoverProcessor.ts
+++ b/src/bscPlugin/hover/HoverProcessor.ts
@@ -17,7 +17,7 @@ export class HoverProcessor {
}
public process() {
- let hover: Hover;
+ let hover: Hover | null | undefined;
if (isBrsFile(this.event.file)) {
hover = this.getBrsFileHover(this.event.file);
} else if (isXmlFile(this.event.file)) {
@@ -40,7 +40,7 @@ export class HoverProcessor {
return parts.join('\n');
}
- private getBrsFileHover(file: BrsFile): Hover {
+ private getBrsFileHover(file: BrsFile): Hover | null | undefined {
const scope = this.event.scopes[0];
const fence = (code: string) => util.mdFence(code, 'brightscript');
//get the token at the position
@@ -127,6 +127,9 @@ export class HoverProcessor {
*/
private getTokenDocumentation(tokens: Token[], token?: Token) {
const comments = [] as Token[];
+ if (!token) {
+ return undefined;
+ }
const idx = tokens?.indexOf(token);
if (!idx || idx === -1) {
return undefined;
@@ -150,7 +153,7 @@ export class HoverProcessor {
}
}
- private getXmlFileHover(file: XmlFile) {
+ private getXmlFileHover(file: XmlFile): Hover | undefined {
//TODO add xml hovers
return undefined;
}
diff --git a/src/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.ts b/src/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.ts
index fc3232826..def2ffde1 100644
--- a/src/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.ts
+++ b/src/bscPlugin/semanticTokens/BrsFileSemanticTokensProcessor.spec.ts
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { expect } from '../../chai-config.spec';
import { SemanticTokenModifiers, SemanticTokenTypes } from 'vscode-languageserver-protocol';
import type { BrsFile } from '../../files/BrsFile';
@@ -25,7 +26,7 @@ describe('BrsFileSemanticTokensProcessor', () => {
expectZeroDiagnostics(program);
}
const result = util.sortByRange(
- program.getSemanticTokens(file.srcPath)
+ program.getSemanticTokens(file.srcPath)!
);
//sort modifiers
diff --git a/src/bscPlugin/validation/BrsFileValidator.spec.ts b/src/bscPlugin/validation/BrsFileValidator.spec.ts
index d345e78ad..ad89123a3 100644
--- a/src/bscPlugin/validation/BrsFileValidator.spec.ts
+++ b/src/bscPlugin/validation/BrsFileValidator.spec.ts
@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { expect } from '../../chai-config.spec';
import type { BrsFile } from '../../files/BrsFile';
import type { AALiteralExpression, DottedGetExpression } from '../../parser/Expression';
@@ -44,11 +46,11 @@ describe('BrsFileValidator', () => {
end class
end namespace
`);
- const namespace = ast.findChild(isNamespaceStatement);
- const deltaClass = namespace.findChild(isClassStatement);
+ const namespace = ast.findChild(isNamespaceStatement)!;
+ const deltaClass = namespace.findChild(isClassStatement)!;
expect(deltaClass.parent).to.equal(namespace.body);
- const charlie = (deltaClass.parentClassName.expression as DottedGetExpression);
+ const charlie = (deltaClass.parentClassName!.expression as DottedGetExpression);
expect(charlie.parent).to.equal(deltaClass.parentClassName);
const bravo = charlie.obj as DottedGetExpression;
diff --git a/src/diagnosticUtils.ts b/src/diagnosticUtils.ts
index bf88de752..0a8835039 100644
--- a/src/diagnosticUtils.ts
+++ b/src/diagnosticUtils.ts
@@ -13,7 +13,7 @@ export function getPrintDiagnosticOptions(options: BsConfig) {
let emitFullPaths = options?.emitFullPaths === true;
- let diagnosticLevel = options?.diagnosticLevel || 'warn';
+ let diagnosticLevel = options?.diagnosticLevel ?? 'warn';
let diagnosticSeverityMap = {} as Record;
diagnosticSeverityMap.info = DiagnosticSeverity.Information;
@@ -56,7 +56,7 @@ export function getPrintDiagnosticOptions(options: BsConfig) {
export function printDiagnostic(
options: ReturnType,
severity: DiagnosticSeverity,
- filePath: string,
+ filePath: string | undefined,
lines: string[],
diagnostic: BsDiagnostic,
relatedInformation?: Array<{ range: Range; filePath: string; message: string }>
@@ -150,7 +150,7 @@ export function getDiagnosticLine(diagnostic: BsDiagnostic, diagnosticLine: stri
/**
* Given a diagnostic, compute the range for the squiggly
*/
-export function getDiagnosticSquigglyText(line: string, startCharacter: number, endCharacter: number) {
+export function getDiagnosticSquigglyText(line: string | undefined, startCharacter: number | undefined, endCharacter: number | undefined) {
let squiggle: string;
//fill the entire line
if (
diff --git a/src/files/BrsFile.Class.spec.ts b/src/files/BrsFile.Class.spec.ts
index dad7a61c6..f42076535 100644
--- a/src/files/BrsFile.Class.spec.ts
+++ b/src/files/BrsFile.Class.spec.ts
@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
import * as sinonImport from 'sinon';
import { Program } from '../Program';
@@ -112,7 +114,7 @@ describe('BrsFile BrighterScript classes', () => {
expectZeroDiagnostics(program);
let duckClass = file.parser.references.classStatements.find(x => x.name.text.toLowerCase() === 'duck');
expect(duckClass).to.exist;
- expect(duckClass.memberMap['move']).to.exist;
+ expect(duckClass!.memberMap['move']).to.exist;
});
it('supports various namespace configurations', () => {
diff --git a/src/files/BrsFile.spec.ts b/src/files/BrsFile.spec.ts
index 9a71d26ad..6733d0dc0 100644
--- a/src/files/BrsFile.spec.ts
+++ b/src/files/BrsFile.spec.ts
@@ -1,7 +1,9 @@
+/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { assert, expect } from '../chai-config.spec';
import * as sinonImport from 'sinon';
import { CompletionItemKind, Position, Range } from 'vscode-languageserver';
-import type { Callable, CommentFlag, VariableDeclaration } from '../interfaces';
+import type { BsDiagnostic, Callable, CommentFlag, VariableDeclaration } from '../interfaces';
import { Program } from '../Program';
import { BooleanType } from '../types/BooleanType';
import { DynamicType } from '../types/DynamicType';
@@ -156,10 +158,10 @@ describe('BrsFile', () => {
});
it('allows adding diagnostics', () => {
- const expected = [{
+ const expected: BsDiagnostic[] = [{
message: 'message',
- file: undefined,
- range: undefined
+ file: undefined as any,
+ range: undefined as any
}];
file.addDiagnostics(expected);
expectDiagnostics(file, expected);
@@ -1334,10 +1336,10 @@ describe('BrsFile', () => {
`);
expect(file.callables.length).to.equal(2);
expect(file.callables[0].name).to.equal('DoA');
- expect(file.callables[0].nameRange.start.line).to.equal(1);
+ expect(file.callables[0].nameRange!.start.line).to.equal(1);
expect(file.callables[1].name).to.equal('DoA');
- expect(file.callables[1].nameRange.start.line).to.equal(5);
+ expect(file.callables[1].nameRange!.start.line).to.equal(5);
});
it('finds function call line and column numbers', () => {
@@ -2331,7 +2333,7 @@ describe('BrsFile', () => {
testTranspile(
'sub main()\n name = "john \nend sub',
'sub main()\n name = "john "\nend sub',
- null,
+ null as any,
'source/main.bs',
false
);
@@ -2559,7 +2561,7 @@ describe('BrsFile', () => {
person = {}
stuff = []
end sub
- `, null, 'trim');
+ `, null as any, 'trim');
});
it('does not add leading or trailing newlines', () => {
@@ -2612,8 +2614,8 @@ describe('BrsFile', () => {
kind: token.kind,
start: Position.create(
//convert source-map 1-based line to token 0-based line
- originalPosition.line - 1,
- originalPosition.column
+ originalPosition.line! - 1,
+ originalPosition.column!
)
};
});
@@ -3398,7 +3400,7 @@ describe('BrsFile', () => {
`);
const parser = file['_parser'];
//clear the private _parser instance
- file['_parser'] = undefined;
+ file['_parser'] = undefined as any;
//force the file to get a new instance of parser
const newParser = file.parser;
@@ -3514,7 +3516,7 @@ describe('BrsFile', () => {
end sub
`);
program.validate();
- sinon.stub(util, 'getAllDottedGetParts').returns(null);
+ sinon.stub(util, 'getAllDottedGetParts').returns(null as any);
// print alpha.be|ta
expect(program.getDefinition(file.srcPath, Position.create(2, 34))).to.eql([]);
});
diff --git a/src/files/XmlFile.spec.ts b/src/files/XmlFile.spec.ts
index 610a9e50a..c914abb8f 100644
--- a/src/files/XmlFile.spec.ts
+++ b/src/files/XmlFile.spec.ts
@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { assert, expect } from '../chai-config.spec';
import * as path from 'path';
import * as sinonImport from 'sinon';
@@ -59,13 +61,13 @@ describe('XmlFile', () => {
program.plugins.add({
name: 'allows modifying the parsed XML model',
afterFileParse: () => {
- let child = file.parser.ast.component.children.children[0];
+ let child = file.parser.ast.component!.children.children[0];
expect(child.attributes).to.have.lengthOf(4);
- child.setAttribute('text', undefined);
- expect(child.getAttribute('id').value.text).to.equal('one');
+ child.setAttribute('text', undefined as any);
+ expect(child.getAttribute('id')!.value.text).to.equal('one');
expect(child.attributes).to.have.lengthOf(3);
- child.setAttribute('text3', undefined);
- expect(child.getAttribute('id').value.text).to.equal('one');
+ child.setAttribute('text3', undefined as any);
+ expect(child.getAttribute('id')!.value.text).to.equal('one');
expect(child.attributes).to.have.lengthOf(2);
}
});
@@ -489,10 +491,10 @@ describe('XmlFile', () => {
});
it('allows adding diagnostics', () => {
- const expected = [{
+ const expected: BsDiagnostic[] = [{
message: 'message',
- file: undefined,
- range: undefined
+ file: undefined as any,
+ range: undefined as any
}];
file.addDiagnostics(expected);
expectDiagnostics(file, expected);
@@ -829,7 +831,7 @@ describe('XmlFile', () => {
- `, null, 'components/comp.xml');
+ `, null as any, 'components/comp.xml');
});
it('returns the XML unmodified if needsTranspiled is false', () => {
@@ -1003,7 +1005,7 @@ describe('XmlFile', () => {
`);
program.validate();
expectZeroDiagnostics(program);
- const scope = program.getComponentScope('ChildComponent');
+ const scope = program.getComponentScope('ChildComponent')!;
expect([...scope.namespaceLookup.keys()].sort()).to.eql([
'lib',
'parent'
@@ -1214,7 +1216,7 @@ describe('XmlFile', () => {
`);
- expect(program.getComponent('comp1').file.pkgPath).to.equal(comp2.pkgPath);
+ expect(program.getComponent('comp1')!.file.pkgPath).to.equal(comp2.pkgPath);
//add comp1. it should become the main component with this name
const comp1 = program.setFile('components/comp1.xml', trim`
@@ -1222,11 +1224,11 @@ describe('XmlFile', () => {
`);
- expect(program.getComponent('comp1').file.pkgPath).to.equal(comp1.pkgPath);
+ expect(program.getComponent('comp1')!.file.pkgPath).to.equal(comp1.pkgPath);
//remove comp1, comp2 should be the primary again
program.removeFile(s`${rootDir}/components/comp1.xml`);
- expect(program.getComponent('comp1').file.pkgPath).to.equal(comp2.pkgPath);
+ expect(program.getComponent('comp1')!.file.pkgPath).to.equal(comp2.pkgPath);
//add comp3
program.setFile('components/comp3.xml', trim`
@@ -1235,7 +1237,7 @@ describe('XmlFile', () => {
`);
//...the 2nd file should still be main
- expect(program.getComponent('comp1').file.pkgPath).to.equal(comp2.pkgPath);
+ expect(program.getComponent('comp1')!.file.pkgPath).to.equal(comp2.pkgPath);
});
});
});
diff --git a/src/files/tests/imports.spec.ts b/src/files/tests/imports.spec.ts
index 2c2af9657..96a72f91a 100644
--- a/src/files/tests/imports.spec.ts
+++ b/src/files/tests/imports.spec.ts
@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { expect } from '../../chai-config.spec';
import * as sinonImport from 'sinon';
import * as fsExtra from 'fs-extra';
@@ -53,8 +55,8 @@ describe('import statements', () => {
`);
let files = Object.keys(program.files).map(x => program.getFile(x)).filter(x => !!x).map(x => {
return {
- src: x.srcPath,
- dest: x.pkgPath
+ src: x!.srcPath,
+ dest: x!.pkgPath
};
});
await program.transpile(files, stagingDir);
@@ -247,7 +249,7 @@ describe('import statements', () => {
- `, null, 'components/AuthenticationService.xml');
+ `, null as any, 'components/AuthenticationService.xml');
});
it('handles malformed imports', () => {
diff --git a/src/parser/AstNode.spec.ts b/src/parser/AstNode.spec.ts
index d774e5e99..b256277d4 100644
--- a/src/parser/AstNode.spec.ts
+++ b/src/parser/AstNode.spec.ts
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { util } from '../util';
import * as fsExtra from 'fs-extra';
import { Program } from '../Program';
@@ -36,10 +37,10 @@ describe('AstNode', () => {
`);
program.validate();
expectZeroDiagnostics(program);
- const delta = file.ast.findChildAtPosition(util.createPosition(3, 52));
+ const delta = file.ast.findChildAtPosition(util.createPosition(3, 52))!;
expect(delta.name.text).to.eql('delta');
- const foxtrot = file.ast.findChildAtPosition(util.createPosition(3, 71));
+ const foxtrot = file.ast.findChildAtPosition(util.createPosition(3, 71))!;
expect(foxtrot.name.text).to.eql('foxtrot');
});
});
@@ -131,7 +132,7 @@ describe('AstNode', () => {
const secondStatement = (file.ast.statements[0] as FunctionStatement).func.body.statements[1];
const foxtrot = file.ast.findChild((node) => {
return isDottedGetExpression(node) && node.name?.text === 'foxtrot';
- });
+ })!;
expect(
foxtrot.findAncestor(isPrintStatement)
).to.equal(secondStatement);
@@ -146,7 +147,7 @@ describe('AstNode', () => {
`);
const foxtrot = file.ast.findChild((node) => {
return isDottedGetExpression(node) && node.name?.text === 'foxtrot';
- });
+ })!;
expect(
foxtrot.findAncestor(isClassStatement)
).to.be.undefined;
@@ -162,7 +163,7 @@ describe('AstNode', () => {
const firstStatement = (file.ast.statements[0] as FunctionStatement).func.body.statements[0];
const foxtrot = file.ast.findChild((node) => {
return isDottedGetExpression(node) && node.name?.text === 'foxtrot';
- });
+ })!;
expect(
foxtrot.findAncestor(node => firstStatement)
).to.equal(firstStatement);
diff --git a/src/parser/Parser.Class.spec.ts b/src/parser/Parser.Class.spec.ts
index f6919b891..828f2eef5 100644
--- a/src/parser/Parser.Class.spec.ts
+++ b/src/parser/Parser.Class.spec.ts
@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { expect } from '../chai-config.spec';
import { DiagnosticMessages } from '../DiagnosticMessages';
import { TokenKind, AllowedLocalIdentifiers, AllowedProperties } from '../lexer/TokenKind';
@@ -196,10 +198,10 @@ describe('parser class', () => {
expect(diagnostics).to.be.empty;
expect(statements[0]).instanceof(ClassStatement);
let field = (statements[0] as ClassStatement).body[0] as FieldStatement;
- expect(field.accessModifier.kind).to.equal(TokenKind.Public);
- expect(field.name.text).to.equal('firstName');
- expect(field.as.text).to.equal('as');
- expect(field.type.text).to.equal('string');
+ expect(field.accessModifier!.kind).to.equal(TokenKind.Public);
+ expect(field.name!.text).to.equal('firstName');
+ expect(field.as!.text).to.equal('as');
+ expect(field.type!.text).to.equal('string');
});
it('can be solely an identifier', () => {
@@ -211,7 +213,7 @@ describe('parser class', () => {
let { statements, diagnostics } = Parser.parse(tokens, { mode: ParseMode.BrighterScript });
expect(diagnostics).to.be.lengthOf(0);
let cls = statements[0] as ClassStatement;
- expect(cls.fields[0].name.text).to.equal('firstName');
+ expect(cls.fields[0].name!.text).to.equal('firstName');
});
it('malformed field does not impact leading and trailing fields', () => {
@@ -224,8 +226,8 @@ describe('parser class', () => {
`);
let { statements } = Parser.parse(tokens, { mode: ParseMode.BrighterScript });
let cls = statements[0] as ClassStatement;
- expect(cls.fields[0].name.text).to.equal('firstName');
- expect(cls.fields[cls.fields.length - 1].name.text).to.equal('lastName');
+ expect(cls.fields[0].name!.text).to.equal('firstName');
+ expect(cls.fields[cls.fields.length - 1].name!.text).to.equal('lastName');
});
it(`detects missing type after 'as' keyword`, () => {
@@ -237,7 +239,7 @@ describe('parser class', () => {
let { diagnostics, statements } = Parser.parse(tokens, { mode: ParseMode.BrighterScript });
expect(diagnostics.length).to.be.greaterThan(0);
let cls = statements[0] as ClassStatement;
- expect(cls.fields[0].name.text).to.equal('middleName');
+ expect(cls.fields[0].name!.text).to.equal('middleName');
expect(diagnostics[0].code).to.equal(DiagnosticMessages.expectedIdentifierAfterKeyword('as').code);
});
@@ -269,7 +271,7 @@ describe('parser class', () => {
expect(theClass).to.be.instanceof(ClassStatement);
let method = theClass.methods[0];
expect(method.name.text).to.equal('getName');
- expect(method.accessModifier.text).to.equal('public');
+ expect(method.accessModifier!.text).to.equal('public');
expect(method.func).to.exist;
});
@@ -285,7 +287,7 @@ describe('parser class', () => {
expect(diagnostics).to.be.lengthOf(0);
let theClass = statements[0] as ClassStatement;
let method = theClass.methods[0];
- expect(method.accessModifier.text).to.equal('public');
+ expect(method.accessModifier!.text).to.equal('public');
expect(method.func).to.exist;
});
@@ -366,8 +368,8 @@ describe('parser class', () => {
let { statements, diagnostics } = Parser.parse(tokens, { mode: ParseMode.BrighterScript });
expect(diagnostics[0]?.message).to.not.exist;
let stmt = (statements[1] as ClassStatement);
- expect(stmt.extendsKeyword.text).to.equal('extends');
- expect(stmt.parentClassName.getName(ParseMode.BrighterScript)).to.equal('Person');
+ expect(stmt.extendsKeyword!.text).to.equal('extends');
+ expect(stmt.parentClassName!.getName(ParseMode.BrighterScript)).to.equal('Person');
});
it('catches missing identifier after "extends" keyword', () => {
diff --git a/src/parser/Parser.spec.ts b/src/parser/Parser.spec.ts
index a9f03fb0a..a42198243 100644
--- a/src/parser/Parser.spec.ts
+++ b/src/parser/Parser.spec.ts
@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { expect, assert } from '../chai-config.spec';
import { Lexer } from '../lexer/Lexer';
import { ReservedWords, TokenKind } from '../lexer/TokenKind';
@@ -750,13 +752,13 @@ describe('parser', () => {
expectCommentWithText(ifStmt.thenBranch.statements[1], `'comment 2`);
expectCommentWithText(ifStmt.thenBranch.statements[3], `'comment 3`);
- let elseIfBranch = ifStmt.elseBranch;
+ let elseIfBranch = ifStmt.elseBranch!;
if (isIfStatement(elseIfBranch)) {
expectCommentWithText(elseIfBranch.thenBranch.statements[0], `'comment 4`);
expectCommentWithText(elseIfBranch.thenBranch.statements[1], `'comment 5`);
expectCommentWithText(elseIfBranch.thenBranch.statements[3], `'comment 6`);
- let elseBranch = elseIfBranch.elseBranch;
+ let elseBranch = elseIfBranch.elseBranch!;
if (isBlock(elseBranch)) {
expectCommentWithText(elseBranch.statements[0], `'comment 7`);
expectCommentWithText(elseBranch.statements[1], `'comment 8`);
@@ -1310,7 +1312,8 @@ describe('parser', () => {
function parse(text: string, mode?: ParseMode) {
let { tokens } = Lexer.scan(text);
return Parser.parse(tokens, {
- mode: mode
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ mode: mode!
});
}
diff --git a/src/parser/Statement.spec.ts b/src/parser/Statement.spec.ts
index ba5a2262a..ec88713b1 100644
--- a/src/parser/Statement.spec.ts
+++ b/src/parser/Statement.spec.ts
@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { expect } from '../chai-config.spec';
import type { NamespaceStatement } from './Statement';
import { Body, CommentStatement, EmptyStatement } from './Statement';
@@ -58,12 +60,12 @@ describe('Statement', () => {
end namespace
`);
program.validate();
- let node = program.getFile('source/main.brs').ast.findChild(isNamespaceStatement);
- while (node.findChild(isNamespaceStatement)) {
- node = node.findChild(isNamespaceStatement);
+ let node = program.getFile('source/main.brs')!.ast.findChild(isNamespaceStatement);
+ while (node!.findChild(isNamespaceStatement)) {
+ node = node!.findChild(isNamespaceStatement);
}
- expect(node.getName(ParseMode.BrighterScript)).to.equal('NameA.NameB');
- expect(node.getName(ParseMode.BrightScript)).to.equal('NameA_NameB');
+ expect(node!.getName(ParseMode.BrighterScript)).to.equal('NameA.NameB');
+ expect(node!.getName(ParseMode.BrightScript)).to.equal('NameA_NameB');
});
});
diff --git a/src/parser/tests/Parser.spec.ts b/src/parser/tests/Parser.spec.ts
index f6ec177ef..31e034118 100644
--- a/src/parser/tests/Parser.spec.ts
+++ b/src/parser/tests/Parser.spec.ts
@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
import type { Token } from '../../lexer/Token';
import { TokenKind, ReservedWords } from '../../lexer/TokenKind';
import { interpolatedRange } from '../../astUtils/creators';
@@ -11,8 +13,8 @@ import type { Range } from 'vscode-languageserver';
export function token(kind: TokenKind, text?: string): Token {
return {
kind: kind,
- text: text,
- isReserved: ReservedWords.has((text || '').toLowerCase()),
+ text: text!,
+ isReserved: ReservedWords.has((text ?? '').toLowerCase()),
range: interpolatedRange,
leadingWhitespace: ''
};
diff --git a/src/parser/tests/expression/Call.spec.ts b/src/parser/tests/expression/Call.spec.ts
index 3d238dc23..a92e82090 100644
--- a/src/parser/tests/expression/Call.spec.ts
+++ b/src/parser/tests/expression/Call.spec.ts
@@ -14,7 +14,7 @@ describe('parser call expressions', () => {
it('parses named function calls', () => {
const { statements, diagnostics } = Parser.parse([
identifier('RebootSystem'),
- { kind: TokenKind.LeftParen, text: '(', range: null },
+ { kind: TokenKind.LeftParen, text: '(', range: null as any },
token(TokenKind.RightParen, ')'),
EOF
]);
@@ -65,7 +65,7 @@ describe('parser call expressions', () => {
it('allows closing parentheses on separate line', () => {
const { statements, diagnostics } = Parser.parse([
identifier('RebootSystem'),
- { kind: TokenKind.LeftParen, text: '(', range: null },
+ { kind: TokenKind.LeftParen, text: '(', range: null as any },
token(TokenKind.Newline, '\\n'),
token(TokenKind.Newline, '\\n'),
token(TokenKind.RightParen, ')'),
@@ -128,9 +128,9 @@ describe('parser call expressions', () => {
it('accepts arguments', () => {
const { statements, diagnostics } = Parser.parse([
identifier('add'),
- { kind: TokenKind.LeftParen, text: '(', range: null },
+ { kind: TokenKind.LeftParen, text: '(', range: null as any },
token(TokenKind.IntegerLiteral, '1'),
- { kind: TokenKind.Comma, text: ',', range: null },
+ { kind: TokenKind.Comma, text: ',', range: null as any },
token(TokenKind.IntegerLiteral, '2'),
token(TokenKind.RightParen, ')'),
EOF
diff --git a/src/parser/tests/statement/Dim.spec.ts b/src/parser/tests/statement/Dim.spec.ts
index 5c9b474f2..4d4492041 100644
--- a/src/parser/tests/statement/Dim.spec.ts
+++ b/src/parser/tests/statement/Dim.spec.ts
@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { expect } from '../../../chai-config.spec';
import type { DimStatement } from '../../Statement';
import { DiagnosticMessages } from '../../../DiagnosticMessages';
@@ -68,10 +70,10 @@ function validatePass(text: string, dimStatementIndex: number, identifierText: s
expect(dimStatement).to.exist;
expect(dimStatement.dimToken).to.exist;
expect(dimStatement.identifier).to.exist;
- expect(dimStatement.identifier.text).to.equal(identifierText);
+ expect(dimStatement.identifier!.text).to.equal(identifierText);
expect(dimStatement.openingSquare).to.exist;
expect(dimStatement.dimensions).to.exist;
- expect(dimStatement.dimensions.length).to.equal(dimensionsCount);
+ expect(dimStatement.dimensions!.length).to.equal(dimensionsCount);
expect(dimStatement.closingSquare).to.exist;
expect(dimStatement.range).to.exist;
}
diff --git a/src/parser/tests/statement/Enum.spec.ts b/src/parser/tests/statement/Enum.spec.ts
index 5a11f1760..58b039aef 100644
--- a/src/parser/tests/statement/Enum.spec.ts
+++ b/src/parser/tests/statement/Enum.spec.ts
@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { expect } from '../../../chai-config.spec';
import { LiteralExpression } from '../../Expression';
import { DiagnosticMessages } from '../../../DiagnosticMessages';
@@ -447,7 +449,7 @@ describe('EnumStatement', () => {
function expectMemberValueMap(code: string, expected: Record) {
const file = program.setFile('source/lib.brs', code);
const cancel = new CancellationTokenSource();
- let firstEnum: EnumStatement;
+ let firstEnum: EnumStatement | undefined;
file.ast.walk(statement => {
if (isEnumStatement(statement)) {
firstEnum = statement;
@@ -458,7 +460,7 @@ describe('EnumStatement', () => {
cancel: cancel.token
});
expect(firstEnum).to.exist;
- const values = firstEnum.getMemberValueMap();
+ const values = firstEnum!.getMemberValueMap();
expect(
[...values].reduce((prev, [key, value]) => {
prev[key] = value;
diff --git a/src/parser/tests/statement/Function.spec.ts b/src/parser/tests/statement/Function.spec.ts
index d2fd5c121..e6dab558b 100644
--- a/src/parser/tests/statement/Function.spec.ts
+++ b/src/parser/tests/statement/Function.spec.ts
@@ -15,7 +15,7 @@ describe('parser', () => {
end su
`);
const func = parser.ast.findChild(isFunctionStatement);
- expect(func.func.body).to.exist;
+ expect(func?.func.body).to.exist;
});
it('recovers when using `end sub` instead of `end function`', () => {
diff --git a/src/parser/tests/statement/Misc.spec.ts b/src/parser/tests/statement/Misc.spec.ts
index 066b080a7..cef3684fc 100644
--- a/src/parser/tests/statement/Misc.spec.ts
+++ b/src/parser/tests/statement/Misc.spec.ts
@@ -5,6 +5,7 @@ import { DisallowedLocalIdentifiersText, TokenKind } from '../../../lexer/TokenK
import { Range } from 'vscode-languageserver';
import type { AAMemberExpression } from '../../Expression';
import { expectZeroDiagnostics } from '../../../testHelpers.spec';
+import type { Statement } from '../../AstNode';
describe('parser', () => {
describe('`end` keyword', () => {
@@ -59,7 +60,7 @@ describe('parser', () => {
});
it('most reserved words are not allowed as local var identifiers', () => {
- let statementList = [];
+ let statementList: Statement[][] = [];
[...DisallowedLocalIdentifiersText].filter(x => x === 'if').forEach((disallowedIdentifier) => {
//use the lexer to generate tokens because there are many different TokenKind types represented in this list
let { tokens } = Lexer.scan(`
diff --git a/src/parser/tests/statement/ReturnStatement.spec.ts b/src/parser/tests/statement/ReturnStatement.spec.ts
index fe1563f9e..0c65b1ea6 100644
--- a/src/parser/tests/statement/ReturnStatement.spec.ts
+++ b/src/parser/tests/statement/ReturnStatement.spec.ts
@@ -51,7 +51,7 @@ describe('parser return statements', () => {
token(TokenKind.Newline, '\\n'),
token(TokenKind.Return, 'return'),
identifier('RebootSystem'),
- { kind: TokenKind.LeftParen, text: '(', range: null },
+ { kind: TokenKind.LeftParen, text: '(', range: null as any },
token(TokenKind.RightParen, ')'),
token(TokenKind.Newline, '\\n'),
token(TokenKind.EndFunction, 'end function'),
diff --git a/src/parser/tests/statement/Throw.spec.ts b/src/parser/tests/statement/Throw.spec.ts
index 4f970ae35..84a383999 100644
--- a/src/parser/tests/statement/Throw.spec.ts
+++ b/src/parser/tests/statement/Throw.spec.ts
@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
+/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
import { expect } from '../../../chai-config.spec';
import type { TryCatchStatement, ThrowStatement } from '../../Statement';
import { DiagnosticMessages } from '../../../DiagnosticMessages';
@@ -12,7 +14,7 @@ describe('parser ThrowStatement', () => {
catch
end try
`);
- const throwStatement = (parser.ast.statements[0] as TryCatchStatement).tryBranch.statements[0] as ThrowStatement;
+ const throwStatement = (parser.ast.statements[0] as TryCatchStatement).tryBranch!.statements[0] as ThrowStatement;
//the statement should still exist and have null expression
expect(throwStatement).to.exist;
expect(throwStatement.expression).to.be.instanceof(LiteralExpression);
@@ -26,7 +28,7 @@ describe('parser ThrowStatement', () => {
end try
`);
expect(parser.diagnostics[0]?.message).to.eql(DiagnosticMessages.missingExceptionExpressionAfterThrowKeyword().message);
- const throwStatement = (parser.ast.statements[0] as TryCatchStatement).tryBranch.statements[0] as ThrowStatement;
+ const throwStatement = (parser.ast.statements[0] as TryCatchStatement).tryBranch!.statements[0] as ThrowStatement;
//the statement should still exist and have null expression
expect(throwStatement).to.exist;
expect(throwStatement.expression).to.not.exist;
diff --git a/src/parser/tests/statement/TryCatch.spec.ts b/src/parser/tests/statement/TryCatch.spec.ts
index b7b237f70..985ac58c2 100644
--- a/src/parser/tests/statement/TryCatch.spec.ts
+++ b/src/parser/tests/statement/TryCatch.spec.ts
@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { expect } from '../../../chai-config.spec';
import { Parser } from '../../Parser';
import { TryCatchStatement } from '../../Statement';
@@ -20,9 +22,9 @@ describe('parser try/catch', () => {
expect(stmt.tryBranch).to.exist.and.ownProperty('statements').to.be.lengthOf(1);
expect(stmt.catchStatement).to.exist;
const cstmt = stmt.catchStatement;
- expect(cstmt.tokens.catch?.text).to.eql('catch');
- expect(cstmt.exceptionVariable.text).to.eql('e');
- expect(cstmt.catchBranch).to.exist.and.ownProperty('statements').to.be.lengthOf(1);
+ expect(cstmt!.tokens.catch?.text).to.eql('catch');
+ expect(cstmt!.exceptionVariable!.text).to.eql('e');
+ expect(cstmt!.catchBranch).to.exist.and.ownProperty('statements').to.be.lengthOf(1);
expect(stmt.tokens.endTry?.text).to.eql('end try');
});
diff --git a/src/preprocessor/Preprocessor.ts b/src/preprocessor/Preprocessor.ts
index 1762827c2..b55fd2a75 100644
--- a/src/preprocessor/Preprocessor.ts
+++ b/src/preprocessor/Preprocessor.ts
@@ -17,7 +17,7 @@ export class Preprocessor implements CC.Visitor {
/** The set of errors encountered when pre-processing conditional compilation directives. */
public diagnostics = [] as Diagnostic[];
- public processedTokens: Token[];
+ public processedTokens: Token[] | undefined;
/**
* Filters the tokens contained within a set of chunks based on a set of constants.
@@ -169,11 +169,10 @@ export class Preprocessor implements CC.Visitor {
}
/**
- * Resolves a token to a JavaScript boolean value, or throws an error.
- * @param token the token to resolve to either `true`, `false`, or an error
- * @throws if attempting to reference an undefined `#const` or if `token` is neither `true`, `false`, nor an identifier.
+ * Resolves a token to a JavaScript boolean value, or logs a diagnostic error.
+ * @param token the token to resolve to either `true`, `false`, or `undefined`
*/
- public evaluateCondition(token: Token): boolean {
+ public evaluateCondition(token: Token): boolean | undefined {
switch (token.kind) {
case TokenKind.True:
return true;
diff --git a/src/preprocessor/PreprocessorParser.ts b/src/preprocessor/PreprocessorParser.ts
index 980065e7b..53ba0671b 100644
--- a/src/preprocessor/PreprocessorParser.ts
+++ b/src/preprocessor/PreprocessorParser.ts
@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
import type { Token } from '../lexer/Token';
import { TokenKind, AllowedLocalIdentifiers, ReservedWords, DisallowedLocalIdentifiers, AllowedProperties } from '../lexer/TokenKind';
import * as CC from './Chunk';
@@ -7,16 +9,16 @@ import { DiagnosticMessages } from '../DiagnosticMessages';
/** * Parses `Tokens` into chunks of tokens, excluding conditional compilation directives. */
export class PreprocessorParser {
- public diagnostics: Diagnostic[];
+ public diagnostics: Diagnostic[] = [];
- public tokens: Token[];
+ public tokens: Token[] | undefined;
private current = 0;
/**
* an array of chunks (conditional compilation directives and the associated BrightScript)
*/
- public chunks: CC.Chunk[];
+ public chunks: CC.Chunk[] = [];
/**
* Parses an array of tokens into an array of "chunks" - conditional compilation directives and their
@@ -251,10 +253,10 @@ export class PreprocessorParser {
}
private peek() {
- return this.tokens[this.current];
+ return this.tokens![this.current];
}
private previous() {
- return this.tokens[this.current - 1];
+ return this.tokens![this.current - 1];
}
}
diff --git a/src/testHelpers.spec.ts b/src/testHelpers.spec.ts
index a865fd74b..8932bb0d6 100644
--- a/src/testHelpers.spec.ts
+++ b/src/testHelpers.spec.ts
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
import type { BscFile, BsDiagnostic } from './interfaces';
import * as assert from 'assert';
import chalk from 'chalk';
@@ -85,7 +86,7 @@ function cloneDiagnostic(actualDiagnosticInput: BsDiagnostic, expectedDiagnostic
for (let j = 0; j < actualDiagnostic.relatedInformation.length; j++) {
actualDiagnostic.relatedInformation[j] = cloneObject(
actualDiagnostic.relatedInformation[j],
- expectedDiagnostic?.relatedInformation[j],
+ expectedDiagnostic?.relatedInformation?.[j],
['location', 'message']
) as any;
}
@@ -191,7 +192,7 @@ export function expectZeroDiagnostics(arg: DiagnosticCollection) {
* @param diagnosticsCollection a collection of diagnostics
* @param length if specified, checks the diagnostic count is exactly that amount. If omitted, the collection is just verified as non-empty
*/
-export function expectHasDiagnostics(diagnosticsCollection: DiagnosticCollection, length: number = null) {
+export function expectHasDiagnostics(diagnosticsCollection: DiagnosticCollection, length: number | null = null) {
const diagnostics = getDiagnostics(diagnosticsCollection);
if (length) {
expect(diagnostics).lengthOf(length);
@@ -245,7 +246,7 @@ export function getTestGetTypedef(scopeGetter: () => [program: Program, rootDir:
return {
code: (file as BrsFile).getTypedef(),
map: undefined
- };
+ } as any as CodeWithSourceMap;
}, scopeGetter);
}
@@ -307,7 +308,7 @@ export function expectCompletionsIncludes(completions: CompletionItem[], expecte
//match all existing properties of the expectedItem
let actualItem = pick(
expectedItem,
- completions.find(x => x.label === expectedItem.label)
+ completions.find(x => x.label === expectedItem.label)!
);
expect(actualItem).to.eql(expectedItem);
}
@@ -325,14 +326,14 @@ export function expectCompletionsExcludes(completions: CompletionItem[], expecte
//match all existing properties of the expectedItem
let actualItem = pick(
expectedItem,
- completions.find(x => x.label === expectedItem.label)
+ completions.find(x => x.label === expectedItem.label)!
);
expect(actualItem).to.not.eql(expectedItem);
}
}
}
-export function expectThrows(callback: () => any, expectedMessage = undefined, failedTestMessage = 'Expected to throw but did not') {
+export function expectThrows(callback: () => any, expectedMessage: string | undefined = undefined, failedTestMessage = 'Expected to throw but did not') {
let wasExceptionThrown = false;
try {
callback();
diff --git a/src/types/FunctionType.ts b/src/types/FunctionType.ts
index 5dc5358ce..b9cca29b5 100644
--- a/src/types/FunctionType.ts
+++ b/src/types/FunctionType.ts
@@ -11,7 +11,7 @@ export class FunctionType implements BscType {
/**
* The name of the function for this type. Can be null
*/
- public name: string;
+ public name: string | undefined;
/**
* Determines if this is a sub or not
@@ -65,7 +65,7 @@ export class FunctionType implements BscType {
}
public toString() {
- let paramTexts = [];
+ let paramTexts: string[] = [];
for (let param of this.params) {
paramTexts.push(`${param.name}${param.isOptional ? '?' : ''} as ${param.type.toString()}`);
}
diff --git a/src/types/InterfaceType.ts b/src/types/InterfaceType.ts
index dfbafb007..5e2080586 100644
--- a/src/types/InterfaceType.ts
+++ b/src/types/InterfaceType.ts
@@ -11,18 +11,19 @@ export class InterfaceType implements BscType {
/**
* The name of the interface. Can be null.
*/
- public name: string;
+ public name: string | undefined;
public isAssignableTo(targetType: BscType) {
//we must have all of the members of the target type, and they must be equivalent types
if (isInterfaceType(targetType)) {
for (const [targetMemberName, targetMemberType] of targetType.members) {
+ const ourMemberType = this.members.get(targetMemberName);
//we don't have the target member
- if (!this.members.has(targetMemberName)) {
+ if (!ourMemberType) {
return false;
}
//our member's type is not assignable to the target member type
- if (!this.members.get(targetMemberName).isAssignableTo(targetMemberType)) {
+ if (!ourMemberType.isAssignableTo(targetMemberType)) {
return false;
}
}
diff --git a/src/validators/ClassValidator.ts b/src/validators/ClassValidator.ts
index aa5d11b18..65725af4e 100644
--- a/src/validators/ClassValidator.ts
+++ b/src/validators/ClassValidator.ts
@@ -12,6 +12,7 @@ import { createVisitor, WalkMode } from '../astUtils/visitors';
import type { BrsFile } from '../files/BrsFile';
import { TokenKind } from '../lexer/TokenKind';
import { DynamicType } from '../types/DynamicType';
+import type { BscType } from '../types/BscType';
export class BsClassValidator {
private scope: Scope;
@@ -21,10 +22,13 @@ export class BsClassValidator {
*/
private classes: Map;
- public validate(scope: Scope) {
+ public constructor(scope: Scope) {
this.scope = scope;
this.diagnostics = [];
+ this.classes = new Map();
+ }
+ public validate() {
this.findClasses();
this.findNamespaceNonNamespaceCollisions();
this.linkClassesWithParents();
@@ -89,7 +93,8 @@ export class BsClassValidator {
private findNamespaceNonNamespaceCollisions() {
for (const [className, classStatement] of this.classes) {
//catch namespace class collision with global class
- let nonNamespaceClass = this.classes.get(util.getTextAfterFinalDot(className).toLowerCase());
+ let nonNamespaceClassName = util.getTextAfterFinalDot(className)?.toLowerCase();
+ let nonNamespaceClass = nonNamespaceClassName ? this.classes.get(nonNamespaceClassName) : undefined;
const namespace = classStatement.findAncestor(isNamespaceStatement);
if (namespace && nonNamespaceClass) {
this.diagnostics.push({
@@ -122,7 +127,7 @@ export class BsClassValidator {
) {
//prevent use of `m.` anywhere before the `super()` call
const cancellationToken = new CancellationTokenSource();
- let superCall: CallExpression;
+ let superCall: CallExpression | undefined;
newMethod.func.body.walk(createVisitor({
VariableExpression: (expression, parent) => {
const expressionNameLower = expression?.name?.text.toLowerCase();
@@ -161,20 +166,26 @@ export class BsClassValidator {
const names = new Map();
do {
const className = cls.getName(ParseMode.BrighterScript);
+ if (!className) {
+ break;
+ }
const lowerClassName = className.toLowerCase();
//if we've already seen this class name before, then we have a circular dependency
- if (names.has(lowerClassName)) {
+ if (lowerClassName && names.has(lowerClassName)) {
this.diagnostics.push({
- ...DiagnosticMessages.circularReferenceDetected([
- ...names.values(),
- className
- ], this.scope.name),
+ ...DiagnosticMessages.circularReferenceDetected(
+ Array.from(names.values()).concat(className), this.scope.name),
file: cls.file,
range: cls.name.range
});
break;
}
names.set(lowerClassName, className);
+
+ if (!cls.parentClass) {
+ break;
+ }
+
cls = cls.parentClass;
} while (cls);
}
@@ -188,14 +199,20 @@ export class BsClassValidator {
for (let statement of classStatement.body) {
if (isMethodStatement(statement) || isFieldStatement(statement)) {
let member = statement;
- let lowerMemberName = member.name.text.toLowerCase();
+ let memberName = member.name;
+
+ if (!memberName) {
+ continue;
+ }
+
+ let lowerMemberName = memberName.text.toLowerCase();
//catch duplicate member names on same class
if (methods[lowerMemberName] || fields[lowerMemberName]) {
this.diagnostics.push({
- ...DiagnosticMessages.duplicateIdentifier(member.name.text),
+ ...DiagnosticMessages.duplicateIdentifier(memberName.text),
file: classStatement.file,
- range: member.name.range
+ range: memberName.range
});
}
@@ -219,20 +236,20 @@ export class BsClassValidator {
//child field has same name as parent
if (isFieldStatement(member)) {
- let ancestorMemberType = new DynamicType();
+ let ancestorMemberType: BscType = new DynamicType();
if (isFieldStatement(ancestorAndMember.member)) {
- ancestorMemberType = ancestorAndMember.member.getType();
+ ancestorMemberType = ancestorAndMember.member.getType() ?? new DynamicType();
} else if (isMethodStatement(ancestorAndMember.member)) {
ancestorMemberType = ancestorAndMember.member.func.getFunctionType();
}
const childFieldType = member.getType();
- if (!childFieldType.isAssignableTo(ancestorMemberType)) {
+ if (childFieldType && !childFieldType.isAssignableTo(ancestorMemberType)) {
//flag incompatible child field type to ancestor field type
this.diagnostics.push({
...DiagnosticMessages.childFieldTypeNotAssignableToBaseProperty(
- classStatement.getName(ParseMode.BrighterScript),
+ classStatement.getName(ParseMode.BrighterScript) ?? '',
ancestorAndMember.classStatement.getName(ParseMode.BrighterScript),
- member.name.text,
+ memberName.text,
childFieldType.toString(),
ancestorMemberType.toString()
),
@@ -270,7 +287,7 @@ export class BsClassValidator {
...DiagnosticMessages.mismatchedOverriddenMemberVisibility(
classStatement.name.text,
ancestorAndMember.member.name?.text,
- member.accessModifier?.text || 'public',
+ member.accessModifier?.text ?? 'public',
ancestorAndMember.member.accessModifier?.text || 'public',
ancestorAndMember.classStatement.getName(ParseMode.BrighterScript)
),
@@ -311,7 +328,7 @@ export class BsClassValidator {
if (!this.getClassByName(lowerFieldTypeName, currentNamespaceName) && !this.scope.hasInterface(lowerFieldTypeName) && !this.scope.hasEnum(lowerFieldTypeName)) {
this.diagnostics.push({
...DiagnosticMessages.cannotFindType(fieldTypeName),
- range: statement.type.range,
+ range: statement.type?.range ?? statement.range,
file: classStatement.file
});
}
@@ -344,7 +361,7 @@ export class BsClassValidator {
//unlink all classes from their parents so it doesn't mess up the next scope
for (const [, classStatement] of this.classes) {
delete classStatement.parentClass;
- delete classStatement.file;
+ delete (classStatement as any).file;
}
}
@@ -376,7 +393,7 @@ export class BsClassValidator {
relatedInformation: [{
location: util.createLocation(
URI.file(alreadyDefinedClass.file.srcPath).toString(),
- this.classes.get(lowerName).range
+ alreadyDefinedClass.range
),
message: ''
}]
@@ -417,7 +434,7 @@ export class BsClassValidator {
let relativeParent = this.classes.get(relativeName.toLowerCase());
let absoluteParent = this.classes.get(absoluteName.toLowerCase());
- let parentClass: AugmentedClassStatement;
+ let parentClass: AugmentedClassStatement | undefined;
//if we found a relative parent class
if (relativeParent) {
parentClass = relativeParent;
@@ -437,5 +454,5 @@ export class BsClassValidator {
type AugmentedClassStatement = ClassStatement & {
file: BscFile;
- parentClass: AugmentedClassStatement;
+ parentClass: AugmentedClassStatement | undefined;
};