Skip to content
This repository was archived by the owner on Dec 15, 2022. It is now read-only.

Commit f35633c

Browse files
authored
Merge pull request #179 from atom/dw-strict-null-checks
Enable strictNullChecks in tsconfig.json
2 parents d8be6eb + f42e380 commit f35633c

19 files changed

+130
-77
lines changed

lib/adapters/apply-edit-adapter.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export default class ApplyEditAdapter {
4040
}),
4141
);
4242

43-
const checkpoints = [];
43+
const checkpoints: Array<{ buffer: TextBuffer, checkpoint: number}> = [];
4444
try {
4545
for (let i = 0; i < editors.length; i++) {
4646
const editor = editors[i] as TextEditor;
@@ -52,7 +52,7 @@ export default class ApplyEditAdapter {
5252
const buffer = editor.getBuffer();
5353
const checkpoint = buffer.createCheckpoint();
5454
checkpoints.push({buffer, checkpoint});
55-
let prevEdit = null;
55+
let prevEdit: atomIde.TextEdit | null = null;
5656
for (const edit of edits) {
5757
ApplyEditAdapter.validateEdit(buffer, edit, prevEdit);
5858
buffer.setTextInRange(edit.oldRange, edit.newText);
@@ -74,9 +74,13 @@ export default class ApplyEditAdapter {
7474
}
7575

7676
// Private: Do some basic sanity checking on the edit ranges.
77-
private static validateEdit(buffer: TextBuffer, edit: atomIde.TextEdit, prevEdit: atomIde.TextEdit | null): void {
77+
private static validateEdit(
78+
buffer: TextBuffer,
79+
edit: atomIde.TextEdit,
80+
prevEdit: atomIde.TextEdit | null,
81+
): void {
7882
const path = buffer.getPath() || '';
79-
if (prevEdit != null && edit.oldRange.end.compare(prevEdit.oldRange.start) > 0) {
83+
if (prevEdit && edit.oldRange.end.compare(prevEdit.oldRange.start) > 0) {
8084
throw Error(`Found overlapping edit ranges in ${path}`);
8185
}
8286
const startRow = edit.oldRange.start.row;

lib/adapters/autocomplete-adapter.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -267,11 +267,11 @@ export default class AutocompleteAdapter {
267267
// * `editor` An Atom {TextEditor} used to obtain the necessary text replacement.
268268
// * `suggestion` An {atom$AutocompleteSuggestion} to set the replacementPrefix and text properties of.
269269
public static applyTextEditToSuggestion(
270-
textEdit: TextEdit | null,
270+
textEdit: TextEdit | undefined,
271271
editor: TextEditor,
272272
suggestion: AutocompleteSuggestion,
273273
): void {
274-
if (textEdit != null) {
274+
if (textEdit) {
275275
suggestion.replacementPrefix = editor.getTextInBufferRange(Convert.lsRangeToAtomRange(textEdit.range));
276276
suggestion.text = textEdit.newText;
277277
}
@@ -296,7 +296,7 @@ export default class AutocompleteAdapter {
296296
//
297297
// Returns a {String} containing the AutoComplete+ suggestion type equivalent
298298
// to the given completion kind.
299-
public static completionKindToSuggestionType(kind: number | null): string {
299+
public static completionKindToSuggestionType(kind: number | undefined): string {
300300
switch (kind) {
301301
case CompletionItemKind.Constant:
302302
return 'constant';

lib/adapters/code-action-adapter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export default class CodeActionAdapter {
2727
public static async getCodeActions(
2828
connection: LanguageClientConnection,
2929
serverCapabilities: ServerCapabilities,
30-
linterAdapter: LinterPushV2Adapter | null,
30+
linterAdapter: LinterPushV2Adapter | undefined ,
3131
editor: TextEditor,
3232
range: Range,
3333
diagnostics: atomIde.Diagnostic[],

lib/adapters/datatip-adapter.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,5 +88,8 @@ export default class DatatipAdapter {
8888
value: markedString.value,
8989
};
9090
}
91+
92+
// Catch-all case
93+
return { type: 'markdown', value: markedString.toString() };
9194
}
9295
}

lib/adapters/document-sync-adapter.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export default class DocumentSyncAdapter {
6464
// indicating whether this adapter should care about the contents of the editor.
6565
constructor(
6666
connection: LanguageClientConnection,
67-
documentSyncKind: TextDocumentSyncOptions | number | null,
67+
documentSyncKind: TextDocumentSyncOptions | number | undefined,
6868
editorSelector: (editor: TextEditor) => boolean,
6969
) {
7070
this._connection = connection;
@@ -129,7 +129,7 @@ export default class DocumentSyncAdapter {
129129
);
130130
}
131131

132-
public getEditorSyncAdapter(editor: TextEditor): TextEditorSyncAdapter | null {
132+
public getEditorSyncAdapter(editor: TextEditor): TextEditorSyncAdapter | undefined {
133133
return this._editors.get(editor);
134134
}
135135
}

lib/adapters/linter-push-v2-adapter.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,13 @@ export default class LinterPushV2Adapter {
113113
if (path != null) {
114114
const diagnosticCodes = this._diagnosticCodes.get(path);
115115
if (diagnosticCodes != null) {
116-
return diagnosticCodes.get(getCodeKey(range, text));
116+
return diagnosticCodes.get(getCodeKey(range, text)) || null;
117117
}
118118
}
119119
return null;
120120
}
121121
}
122122

123123
function getCodeKey(range: atom.Range, text: string): string {
124-
return [].concat(...range.serialize(), text).join(',');
124+
return ([] as any[]).concat(...range.serialize(), text).join(',');
125125
}

lib/adapters/outline-view-adapter.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,24 +115,27 @@ export default class OutlineViewAdapter {
115115
return null;
116116
}
117117

118-
let parent = null;
118+
let parent: atomIde.OutlineTree | undefined;
119119
for (const candidate of candidates) {
120120
if (
121121
candidate !== child &&
122122
candidate.startPosition.isLessThanOrEqual(child.startPosition) &&
123-
(candidate.endPosition == null || candidate.endPosition.isGreaterThanOrEqual(child.endPosition))
123+
(candidate.endPosition === undefined ||
124+
(child.endPosition && candidate.endPosition.isGreaterThanOrEqual(child.endPosition)))
124125
) {
125126
if (
126-
parent == null ||
127+
parent === undefined ||
127128
(parent.startPosition.isLessThanOrEqual(candidate.startPosition) ||
128-
(parent.endPosition != null && parent.endPosition.isGreaterThanOrEqual(candidate.endPosition)))
129+
(parent.endPosition != null &&
130+
candidate.endPosition &&
131+
parent.endPosition.isGreaterThanOrEqual(candidate.endPosition)))
129132
) {
130133
parent = candidate;
131134
}
132135
}
133136
}
134137

135-
return parent;
138+
return parent || null;
136139
}
137140

138141
// Public: Convert an individual {SymbolInformation} from the language server

lib/adapters/signature-help-adapter.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ export default class SignatureHelpAdapter {
3131
const {signatureHelpProvider} = this._capabilities;
3232
assert(signatureHelpProvider != null);
3333

34-
let triggerCharacters = null;
35-
if (Array.isArray(signatureHelpProvider.triggerCharacters)) {
34+
let triggerCharacters: Set<string> | undefined;
35+
if (signatureHelpProvider && Array.isArray(signatureHelpProvider.triggerCharacters)) {
3636
triggerCharacters = new Set(signatureHelpProvider.triggerCharacters);
3737
}
3838

lib/auto-languageclient.ts

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import * as rpc from 'vscode-jsonrpc';
44
import * as path from 'path';
55
import * as atomIde from 'atom-ide';
66
import * as linter from 'atom-linter';
7-
import * as stream from 'stream';
87
import { Socket } from 'net';
9-
import { EventEmitter } from 'events';
108
import { ConsoleLogger, NullLogger, Logger } from './logger';
11-
import { ServerManager, ActiveServer } from './server-manager.js';
9+
import { LanguageServerProcess, ServerManager, ActiveServer } from './server-manager.js';
1210
import Convert from './convert.js';
1311

12+
export { LanguageServerProcess };
13+
1414
import {
1515
AutocompleteDidInsert,
1616
AutocompleteProvider,
@@ -39,21 +39,6 @@ import SignatureHelpAdapter from './adapters/signature-help-adapter';
3939

4040
export type ConnectionType = 'stdio' | 'socket' | 'ipc';
4141

42-
// Public: Defines the minimum surface area for an object that resembles a
43-
// ChildProcess. This is used so that language packages with alternative
44-
// language server process hosting strategies can return something compatible
45-
// with AutoLanguageClient.startServerProcess.
46-
export interface LanguageServerProcess extends EventEmitter {
47-
stdin: stream.Writable;
48-
stdout: stream.Readable;
49-
stderr: stream.Readable;
50-
pid: number;
51-
52-
kill(signal?: string): void;
53-
on(event: 'error', listener: (err: Error) => void): this;
54-
on(event: 'exit', listener: (code: number, signal: string) => void): this;
55-
}
56-
5742
// Public: AutoLanguageClient provides a simple way to have all the supported
5843
// Atom-IDE services wired up entirely for you by just subclassing it and
5944
// implementing startServerProcess/getGrammarScopes/getLanguageName and
@@ -62,7 +47,7 @@ export default class AutoLanguageClient {
6247
private _disposable = new CompositeDisposable();
6348
private _serverManager: ServerManager;
6449
private _linterDelegate: linter.V2IndieDelegate;
65-
private _signatureHelpRegistry: atomIde.SignatureHelpRegistry;
50+
private _signatureHelpRegistry: atomIde.SignatureHelpRegistry | null;
6651
private _lastAutocompleteRequest: AutocompleteRequest;
6752
private _isDeactivating: boolean;
6853

lib/convert.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ export default class Convert {
159159
case 'deleted':
160160
return [{uri: Convert.pathToUri(fileEvent.path), type: ls.FileChangeType.Deleted}];
161161
case 'renamed': {
162-
const results = [];
162+
const results: Array<{ uri: string, type: ls.FileChangeType }> = [];
163163
if (fileEvent.oldPath) {
164164
results.push({uri: Convert.pathToUri(fileEvent.oldPath || ''), type: ls.FileChangeType.Deleted});
165165
}

lib/download-file.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export default (async function downloadFile(
3131
throw Error('No response body');
3232
}
3333

34-
const finalLength = length || parseInt(response.headers.get('Content-Length' || '0'), 10);
34+
const finalLength = length || parseInt(response.headers.get('Content-Length') || '0', 10);
3535
const reader = body.getReader();
3636
const writer = fs.createWriteStream(targetFile);
3737

@@ -72,7 +72,7 @@ async function streamWithProgress(
7272
writer.write(Buffer.from(chunk));
7373
if (progressCallback != null) {
7474
bytesDone += chunk.byteLength;
75-
const percent: number = length === 0 ? null : Math.floor(bytesDone / length * 100);
75+
const percent: number | undefined = length === 0 ? undefined : Math.floor(bytesDone / length * 100);
7676
progressCallback(bytesDone, percent);
7777
}
7878
}

lib/server-manager.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,37 @@
11
import { Logger } from './logger';
2+
import { EventEmitter } from 'events';
23
import LinterPushV2Adapter from './adapters/linter-push-v2-adapter';
34
import DocumentSyncAdapter from './adapters/document-sync-adapter';
45
import SignatureHelpAdapter from './adapters/signature-help-adapter';
56

67
import * as path from 'path';
8+
import * as stream from 'stream';
79
import * as cp from 'child_process';
810
import * as ls from './languageclient';
911
import * as atomIde from 'atom-ide';
1012
import Convert from './convert';
1113
import { CompositeDisposable, ProjectFileEvent, TextEditor } from 'atom';
1214

15+
// Public: Defines the minimum surface area for an object that resembles a
16+
// ChildProcess. This is used so that language packages with alternative
17+
// language server process hosting strategies can return something compatible
18+
// with AutoLanguageClient.startServerProcess.
19+
export interface LanguageServerProcess extends EventEmitter {
20+
stdin: stream.Writable;
21+
stdout: stream.Readable;
22+
stderr: stream.Readable;
23+
pid: number;
24+
25+
kill(signal?: string): void;
26+
on(event: 'error', listener: (err: Error) => void): this;
27+
on(event: 'exit', listener: (code: number, signal: string) => void): this;
28+
}
29+
1330
// The necessary elements for a server that has started or is starting.
1431
export interface ActiveServer {
1532
disposable: CompositeDisposable;
1633
projectPath: string;
17-
process: cp.ChildProcess;
34+
process: LanguageServerProcess;
1835
connection: ls.LanguageClientConnection;
1936
capabilities: ls.ServerCapabilities;
2037
linterPushV2?: LinterPushV2Adapter;
@@ -269,7 +286,7 @@ export class ServerManager {
269286
if (filePath == null) {
270287
return null;
271288
}
272-
return this._normalizedProjectPaths.find((d) => filePath.startsWith(d));
289+
return this._normalizedProjectPaths.find((d) => filePath.startsWith(d)) || null;
273290
}
274291

275292
public updateNormalizedProjectPaths(): void {
@@ -293,7 +310,7 @@ export class ServerManager {
293310
}
294311

295312
for (const activeServer of this._activeServers) {
296-
const changes = [];
313+
const changes: ls.FileEvent[] = [];
297314
for (const fileEvent of fileEvents) {
298315
if (fileEvent.path.startsWith(activeServer.projectPath) && this._changeWatchedFileFilter(fileEvent.path)) {
299316
changes.push(Convert.atomFileEventToLSFileEvents(fileEvent)[0]);

test/adapters/autocomplete-adapter.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ describe('AutoCompleteAdapter', () => {
2020
capabilities: {completionProvider: { }},
2121
connection: new ls.LanguageClientConnection(createSpyConnection()),
2222
disposable: new CompositeDisposable(),
23-
process: undefined,
23+
process: undefined as any,
2424
projectPath: '/',
2525
};
2626
}
@@ -279,7 +279,7 @@ describe('AutoCompleteAdapter', () => {
279279

280280
it('does not do anything if there is no textEdit', () => {
281281
const completionItem: AutocompleteSuggestion = {};
282-
AutoCompleteAdapter.applyTextEditToSuggestion(null, new TextEditor(), completionItem);
282+
AutoCompleteAdapter.applyTextEditToSuggestion(undefined, new TextEditor(), completionItem);
283283
expect(completionItem).deep.equals({});
284284
});
285285

@@ -315,7 +315,7 @@ describe('AutoCompleteAdapter', () => {
315315
});
316316

317317
it('defaults to "value"', () => {
318-
const result = AutoCompleteAdapter.completionKindToSuggestionType(null);
318+
const result = AutoCompleteAdapter.completionKindToSuggestionType(undefined);
319319
expect(result).equals('value');
320320
});
321321
});

test/adapters/code-highlight-adapter.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,10 @@ describe('CodeHighlightAdapter', () => {
5050
expect(highlightStub.called).to.be.true;
5151

5252
invariant(result != null);
53-
expect(result.length).to.equal(1);
54-
expect(result[0].isEqual(new Range([0, 1], [0, 2]))).to.be.true;
53+
if (result) {
54+
expect(result.length).to.equal(1);
55+
expect(result[0].isEqual(new Range([0, 1], [0, 2]))).to.be.true;
56+
}
5557
});
5658

5759
it('throws if document highlights are not supported', async () => {

test/adapters/datatip-adapter.test.ts

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -48,21 +48,23 @@ describe('DatatipAdapter', () => {
4848
expect(datatip).to.be.ok;
4949
invariant(datatip != null);
5050

51-
expect(datatip.range.start.row).equal(0);
52-
expect(datatip.range.start.column).equal(1);
53-
expect(datatip.range.end.row).equal(0);
54-
expect(datatip.range.end.column).equal(2);
51+
if (datatip) {
52+
expect(datatip.range.start.row).equal(0);
53+
expect(datatip.range.start.column).equal(1);
54+
expect(datatip.range.end.row).equal(0);
55+
expect(datatip.range.end.column).equal(2);
5556

56-
expect(datatip.markedStrings).to.have.lengthOf(2);
57-
expect(datatip.markedStrings[0]).eql({type: 'markdown', value: 'test'});
57+
expect(datatip.markedStrings).to.have.lengthOf(2);
58+
expect(datatip.markedStrings[0]).eql({type: 'markdown', value: 'test'});
5859

59-
const snippet = datatip.markedStrings[1];
60-
expect(snippet.type).equal('snippet');
61-
invariant(snippet.type === 'snippet');
62-
expect((snippet as any).grammar.scopeName).equal('text.plain.null-grammar');
63-
expect(snippet.value).equal('test snippet');
60+
const snippet = datatip.markedStrings[1];
61+
expect(snippet.type).equal('snippet');
62+
invariant(snippet.type === 'snippet');
63+
expect((snippet as any).grammar.scopeName).equal('text.plain.null-grammar');
64+
expect(snippet.value).equal('test snippet');
6465

65-
expect(grammarSpy.calledWith('source.testlang')).to.be.true;
66+
expect(grammarSpy.calledWith('source.testlang')).to.be.true;
67+
}
6668
});
6769
});
6870
});

test/adapters/document-sync-adapter.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ describe('DocumentSyncAdapter', () => {
4949

5050
describe('constructor', () => {
5151
function create(textDocumentSync) {
52-
return new DocumentSyncAdapter(null, textDocumentSync, () => false);
52+
return new DocumentSyncAdapter(null as any, textDocumentSync, () => false);
5353
}
5454

5555
it('sets _documentSyncKind correctly Incremental for v2 capabilities', () => {

0 commit comments

Comments
 (0)