Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve null safety #996

Merged
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ module.exports = {
'@typescript-eslint/no-implicit-any-catch': 'off',
'@typescript-eslint/no-invalid-this': 'off',
'@typescript-eslint/no-magic-numbers': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-parameter-properties': 'off',
//had to add this rule to prevent eslint from crashing
'@typescript-eslint/no-restricted-imports': ['off', {}],
Expand All @@ -61,6 +62,7 @@ module.exports = {
'@typescript-eslint/no-type-alias': 'off',
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 'off',
'@typescript-eslint/no-unnecessary-condition': 'off',
'@typescript-eslint/no-unnecessary-type-assertion': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off',
Expand Down Expand Up @@ -240,8 +242,6 @@ module.exports = {
files: ['benchmarks/**/*.ts'],
rules: {
'@typescript-eslint/dot-notation': 'off',
'@typescript-eslint/no-unnecessary-type-assertion': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'camelcase': 'off'
}
}]
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"docs": "ts-node scripts/compile-doc-examples.ts",
"benchmark": "cd ./benchmarks && ts-node ./index.ts",
"scrape-roku-docs": "ts-node scripts/scrape-roku-docs.ts",
"rescrape-roku-docs": "rm scripts/.cache.json && ts-node scripts/scrape-roku-docs.ts"
"rescrape-roku-docs": "rm scripts/.cache.json && ts-node scripts/scrape-roku-docs.ts",
"null-check": "tsc -p tsconfig-null-safe.json"
},
"mocha": {
"spec": "src/**/*.spec.ts",
Expand Down
6 changes: 3 additions & 3 deletions src/BusyStatusTracker.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ describe('BusyStatusTracker', () => {
try {
tracker.run((finalize) => {
expect(latestStatus).to.eql(BusyStatus.busy);
finalize();
finalize?.();
expect(latestStatus).to.eql(BusyStatus.idle);
finalize();
finalize?.();
expect(latestStatus).to.eql(BusyStatus.idle);
});
} catch { }
Expand Down Expand Up @@ -125,7 +125,7 @@ describe('BusyStatusTracker', () => {
});

it('supports unsubscribing from events', () => {
const changes = []; //contains every busy/idle status change
const changes: BusyStatus[] = []; //contains every busy/idle status change
const disconnect = tracker.on('change', (status) => changes.push(status));

expect(changes.length).to.eql(0);
Expand Down
10 changes: 5 additions & 5 deletions src/CodeActionUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ export class CodeActionUtil {
const uri = URI.file(change.filePath).toString();

//create the edit changes array for this uri
if (!edit.changes[uri]) {
edit.changes[uri] = [];
if (!edit.changes![uri]) {
edit.changes![uri] = [];
}
if (change.type === 'insert') {
edit.changes[uri].push(
edit.changes![uri].push(
TextEdit.insert(change.position, change.newText)
);
} else if (change.type === 'replace') {
edit.changes[uri].push(
edit.changes![uri].push(
TextEdit.replace(change.range, change.newText)
);
}
Expand All @@ -31,7 +31,7 @@ export class CodeActionUtil {
return action;
}

public serializableDiagnostics(diagnostics: Diagnostic[]) {
public serializableDiagnostics(diagnostics: Diagnostic[] | undefined) {
return diagnostics?.map(({ range, severity, code, source, message, relatedInformation }) => ({
range: range,
severity: severity,
Expand Down
11 changes: 7 additions & 4 deletions src/CommentFlagProcessor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ import { expect } from './chai-config.spec';
import { Range } from 'vscode-languageserver';
import { CommentFlagProcessor } from './CommentFlagProcessor';
import { Lexer } from './lexer/Lexer';
import type { BscFile } from '.';

describe('CommentFlagProcessor', () => {
let processor: CommentFlagProcessor;

const mockBscFile: BscFile = null as any;

describe('tokenizeByWhitespace', () => {
beforeEach(() => {
processor = new CommentFlagProcessor(null);
processor = new CommentFlagProcessor(mockBscFile);
});

it('works with single chars', () => {
Expand Down Expand Up @@ -66,18 +69,18 @@ describe('CommentFlagProcessor', () => {

describe('tokenize', () => {
beforeEach(() => {
processor = new CommentFlagProcessor(null, [`'`]);
processor = new CommentFlagProcessor(mockBscFile, [`'`]);
});

it('skips non disable comments', () => {
expect(
processor['tokenize'](`'not disable comment`, null)
processor['tokenize'](`'not disable comment`, null as any as Range)
).not.to.exist;
});

it('tokenizes bs:disable-line comment', () => {
expect(
processor['tokenize'](`'bs:disable-line`, null)
processor['tokenize'](`'bs:disable-line`, null as any as Range)
).to.eql({
commentTokenText: `'`,
disableType: 'line',
Expand Down
30 changes: 23 additions & 7 deletions src/CommentFlagProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,12 @@ export class CommentFlagProcessor {
let affectedRange: Range;
if (tokenized.disableType === 'line') {
affectedRange = util.createRange(range.start.line, 0, range.start.line, range.start.character);
} else if (tokenized.disableType === 'next-line') {
} else {
// tokenized.disableType must be 'next-line'
josephjunker marked this conversation as resolved.
Show resolved Hide resolved
affectedRange = util.createRange(range.start.line + 1, 0, range.start.line + 1, Number.MAX_SAFE_INTEGER);
}

let commentFlag: CommentFlag;
let commentFlag: CommentFlag | null = null;

//statement to disable EVERYTHING
if (tokenized.codes.length === 0) {
Expand Down Expand Up @@ -115,10 +116,10 @@ export class CommentFlagProcessor {
/**
* Small tokenizer for bs:disable comments
*/
private tokenize(text: string, range: Range) {
private tokenize(text: string, range: Range): DisableToken | null {
let lowerText = text.toLowerCase();
let offset = 0;
let commentTokenText: string;
let commentTokenText: string | null = null;

for (const starter of this.commentStarters) {
if (text.startsWith(starter)) {
Expand Down Expand Up @@ -177,9 +178,10 @@ export class CommentFlagProcessor {
* Given a string, extract each item split by whitespace
* @param text the text to tokenize
*/
private tokenizeByWhitespace(text: string) {
let tokens = [] as Array<{ startIndex: number; text: string }>;
let currentToken = null;
private tokenizeByWhitespace(text: string): Token[] {
let tokens = [] as Array<Token>;
let currentToken: Token | null = null;

for (let i = 0; i < text.length; i++) {
let char = text[i];
//if we hit whitespace
Expand All @@ -206,3 +208,17 @@ export class CommentFlagProcessor {
return tokens;
}
}

interface Token {
startIndex: number;
text: string;
}

interface DisableToken {
commentTokenText: string | null;
disableType: 'line' | 'next-line';
codes: {
code: string;
range: Range;
}[];
}
josephjunker marked this conversation as resolved.
Show resolved Hide resolved
20 changes: 11 additions & 9 deletions src/DependencyGraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,17 +137,19 @@ export class Node {
) {
if (dependencies.length > 0) {
this.subscriptions = [];
}
for (let dependency of this.dependencies) {
let sub = this.graph.onchange(dependency, (event) => {
//notify the graph that we changed since one of our dependencies changed
this.graph.emit(this.key, event);
});

this.subscriptions.push(sub);
for (let dependency of this.dependencies) {
let sub = this.graph.onchange(dependency, (event) => {
//notify the graph that we changed since one of our dependencies changed
this.graph.emit(this.key, event);
});

this.subscriptions.push(sub);
}
josephjunker marked this conversation as resolved.
Show resolved Hide resolved
}
}
private subscriptions: Array<() => void>;

private subscriptions: Array<() => void> | undefined;

/**
* Return the full list of unique dependencies for this node by traversing all descendents
Expand All @@ -161,7 +163,7 @@ export class Node {
let dependency = dependencyStack.pop();

//if this is a new dependency and we aren't supposed to skip it
if (!dependencyMap[dependency] && !exclude.includes(dependency)) {
if (dependency && !dependencyMap[dependency] && !exclude.includes(dependency)) {
dependencyMap[dependency] = true;

//get the node for this dependency
Expand Down
6 changes: 3 additions & 3 deletions src/DiagnosticCollection.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ describe('DiagnosticCollection', () => {

it('does not crash for diagnostics with missing locations', () => {
const [d1] = addDiagnostics('file1.brs', ['I have no location']);
delete d1.range;
delete (d1 as any).range;
testPatch({
'file1.brs': ['I have no location']
});
Expand Down Expand Up @@ -104,7 +104,7 @@ describe('DiagnosticCollection', () => {
}

function addDiagnostics(srcPath: string, messages: string[]) {
const newDiagnostics = [];
const newDiagnostics: BsDiagnostic[] = [];
for (const message of messages) {
newDiagnostics.push({
file: {
Expand All @@ -117,6 +117,6 @@ describe('DiagnosticCollection', () => {
});
}
diagnostics.push(...newDiagnostics);
return newDiagnostics as typeof diagnostics;
return newDiagnostics;
}
});
16 changes: 10 additions & 6 deletions src/DiagnosticFilterer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ import { standardizePath as s } from './util';

export class DiagnosticFilterer {
private byFile: Record<string, BsDiagnostic[]>;
private filters: Array<{ src?: string; codes?: (number | string)[] }>;
private rootDir: string;
private filters: Array<{ src?: string; codes?: (number | string)[] }> | undefined;
private rootDir: string | undefined;

constructor() {
this.byFile = {};
}

/**
* Filter a list of diagnostics based on the provided filters
Expand All @@ -24,7 +28,7 @@ export class DiagnosticFilterer {
let result = this.getDiagnostics();

//clean up
delete this.byFile;
this.byFile = {};
josephjunker marked this conversation as resolved.
Show resolved Hide resolved
delete this.rootDir;
delete this.filters;

Expand Down Expand Up @@ -108,7 +112,7 @@ export class DiagnosticFilterer {
let fileDiagnostics = this.byFile[filePath];
for (let i = 0; i < fileDiagnostics.length; i++) {
let diagnostic = fileDiagnostics[i];
if (filter.codes.includes(diagnostic.code)) {
if (filter.codes.includes(diagnostic.code!)) {
//remove this diagnostic
fileDiagnostics.splice(i, 1);
//repeat this loop iteration (with the new item at this index)
Expand All @@ -123,7 +127,7 @@ export class DiagnosticFilterer {
let globalIgnoreCodes: (number | string)[] = [...config1.ignoreErrorCodes ?? []];
let diagnosticFilters = [...config1.diagnosticFilters ?? []];

let result = [];
let result: Array<{ src?: string; codes: (number | string)[] }> = [];

for (let filter of diagnosticFilters as any[]) {
if (typeof filter === 'number') {
Expand Down Expand Up @@ -151,6 +155,6 @@ export class DiagnosticFilterer {
codes: globalIgnoreCodes
});
}
return result as Array<{ src?: string; codes: (number | string)[] }>;
return result;
}
}
5 changes: 5 additions & 0 deletions src/DiagnosticSeverityAdjuster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ export class DiagnosticSeverityAdjuster {

public createSeverityMap(diagnosticSeverityOverrides: BsConfig['diagnosticSeverityOverrides']): Map<string, DiagnosticSeverity> {
const map = new Map<string, DiagnosticSeverity>();

if (!diagnosticSeverityOverrides) {
return map;
}

josephjunker marked this conversation as resolved.
Show resolved Hide resolved
Object.keys(diagnosticSeverityOverrides).forEach(key => {
const value = diagnosticSeverityOverrides[key];
switch (value) {
Expand Down
3 changes: 2 additions & 1 deletion src/FunctionScope.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { expect } from './chai-config.spec';

import { FunctionScope } from './FunctionScope';
import type { FunctionExpression } from './parser/Expression';
import { Program } from './Program';

describe('FunctionScope', () => {
Expand All @@ -9,7 +10,7 @@ describe('FunctionScope', () => {
let program: Program;
beforeEach(() => {
program = new Program({ rootDir: rootDir });
scope = new FunctionScope(null);
scope = new FunctionScope(null as any as FunctionExpression);
});

afterEach(() => {
Expand Down
2 changes: 1 addition & 1 deletion src/FunctionScope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class FunctionScope {
/**
* The parent scope of this scope
*/
public parentScope: FunctionScope;
public parentScope: FunctionScope | undefined;
public variableDeclarations = [] as VariableDeclaration[];
public labelStatements = [] as LabelDeclaration[];

Expand Down
Loading