diff --git a/azure-pipelines-linux-mac.yml b/azure-pipelines-linux-mac.yml index 5c6115125a..90c1044df2 100644 --- a/azure-pipelines-linux-mac.yml +++ b/azure-pipelines-linux-mac.yml @@ -41,5 +41,9 @@ steps: condition: succeededOrFailed() - script: | - yarn run tslint + yarn tslint displayName: 'Run TSLint' + +- script: | + yarn strict-null-check + displayName: 'Run Strict Null Check' diff --git a/azure-pipelines-windows.yml b/azure-pipelines-windows.yml index b66aa62af4..a6caba377b 100644 --- a/azure-pipelines-windows.yml +++ b/azure-pipelines-windows.yml @@ -26,5 +26,9 @@ steps: condition: succeededOrFailed() - script: | - yarn run tslint + yarn tslint displayName: 'Run TSLint' + +- script: | + yarn strict-null-check + displayName: 'Run Strict Null Check' diff --git a/src/sql/base/browser/ui/dropdownList/dropdownList.ts b/src/sql/base/browser/ui/dropdownList/dropdownList.ts index 88cd2ec349..466ff2ddf3 100644 --- a/src/sql/base/browser/ui/dropdownList/dropdownList.ts +++ b/src/sql/base/browser/ui/dropdownList/dropdownList.ts @@ -98,7 +98,7 @@ export class DropdownList extends Dropdown { * Render the selected label of the dropdown */ public renderLabel(): void { - if (this._options.labelRenderer) { + if (this._options.labelRenderer && this.label) { this._options.labelRenderer(this.label); } } diff --git a/src/sql/base/browser/ui/editableDropdown/dropdown.ts b/src/sql/base/browser/ui/editableDropdown/dropdown.ts index 03e752b2e2..711ccc4dc4 100644 --- a/src/sql/base/browser/ui/editableDropdown/dropdown.ts +++ b/src/sql/base/browser/ui/editableDropdown/dropdown.ts @@ -298,7 +298,7 @@ export class Dropdown extends Disposable { this.$treeContainer.style('outline', `1px solid ${style.contextBorder || this._options.contextBorder}`); } - private _inputValidator(value: string): IMessage { + private _inputValidator(value: string): IMessage | null { if (this._dataSource.options && !this._dataSource.options.find(i => i.value === value)) { if (this._options.strictSelection && this._options.errorMessage) { return { @@ -313,7 +313,7 @@ export class Dropdown extends Disposable { } } - return undefined; + return null; } public set enabled(val: boolean) { diff --git a/src/sql/base/browser/ui/editableDropdown/dropdownTree.ts b/src/sql/base/browser/ui/editableDropdown/dropdownTree.ts index 34aae529bb..7e637f073e 100644 --- a/src/sql/base/browser/ui/editableDropdown/dropdownTree.ts +++ b/src/sql/base/browser/ui/editableDropdown/dropdownTree.ts @@ -91,7 +91,7 @@ export class DropdownDataSource implements tree.IDataSource { export class DropdownFilter extends TreeDefaults.DefaultFilter { public filterString: string; - public isVisible(tree: tree.ITree, element: Resource): boolean { + public isVisible(tree: tree.ITree | undefined, element: Resource): boolean { return element.value.toLowerCase().includes(this.filterString.toLowerCase()); } } diff --git a/src/sql/base/browser/ui/panel/panel.component.ts b/src/sql/base/browser/ui/panel/panel.component.ts index b4a60ec733..25ee178e83 100644 --- a/src/sql/base/browser/ui/panel/panel.component.ts +++ b/src/sql/base/browser/ui/panel/panel.component.ts @@ -141,51 +141,54 @@ export class PanelComponent extends Disposable { * Select a tab based on index (unrecommended) * @param index index of tab in the html */ - selectTab(index: number); + selectTab(index: number): void; /** * Select a tab based on the identifier that was passed into the tab * @param identifier specified identifer of the tab */ - selectTab(identifier: string); + selectTab(identifier: string): void; /** * Select a tab directly if you have access to the object * @param tab tab to navigate to */ - selectTab(tab: TabComponent); - selectTab(input: TabComponent | number | string) { + selectTab(tab: TabComponent): void; + selectTab(input: TabComponent | number | string): void { if (this._tabs && this._tabs.length > 0) { - let tab: TabComponent; + let foundTab: TabComponent | undefined; if (input instanceof TabComponent) { - tab = input; + foundTab = input; } else if (types.isNumber(input)) { - tab = this._tabs.toArray()[input]; + foundTab = this._tabs.toArray()[input]; } else if (types.isString(input)) { - tab = this._tabs.find(i => i.identifier === input); + foundTab = this._tabs.find(i => i.identifier === input); } - // since we need to compare identifiers in this next step we are going to go through and make sure all tabs have one - this._tabs.forEach(i => { - if (!i.identifier) { - i.identifier = 'tabIndex_' + idPool++; - } - }); + if (foundTab) { + const tab = foundTab; + // since we need to compare identifiers in this next step we are going to go through and make sure all tabs have one + this._tabs.forEach(i => { + if (!i.identifier) { + i.identifier = 'tabIndex_' + idPool++; + } + }); - if (this._activeTab && tab === this._activeTab) { - this.onTabChange.emit(tab); - return; + if (this._activeTab && tab === this._activeTab) { + this.onTabChange.emit(tab); + return; + } + + this._zone.run(() => { + if (this._activeTab) { + this._activeTab.active = false; + } + + this._activeTab = tab; + this.setMostRecentlyUsed(tab); + this._activeTab.active = true; + + this.onTabChange.emit(tab); + }); } - - this._zone.run(() => { - if (this._activeTab) { - this._activeTab.active = false; - } - - this._activeTab = tab; - this.setMostRecentlyUsed(tab); - this._activeTab.active = true; - - this.onTabChange.emit(tab); - }); } } diff --git a/src/sql/base/browser/ui/panel/panel.ts b/src/sql/base/browser/ui/panel/panel.ts index b9ab4c51cd..2070cd4a78 100644 --- a/src/sql/base/browser/ui/panel/panel.ts +++ b/src/sql/base/browser/ui/panel/panel.ts @@ -47,7 +47,7 @@ export type PanelTabIdentifier = string; export class TabbedPanel extends Disposable implements IThemable { private _tabMap = new Map(); - private _shownTab: PanelTabIdentifier; + private _shownTabId?: PanelTabIdentifier; public readonly headersize = 35; private header: HTMLElement; private tabList: HTMLElement; @@ -103,7 +103,7 @@ export class TabbedPanel extends Disposable implements IThemable { internalTab.disposables = []; this._tabMap.set(tab.identifier, internalTab); this._createTab(internalTab); - if (!this._shownTab) { + if (!this._shownTabId) { this.showTab(tab.identifier); } if (this._tabMap.size > 1 && !this._headerVisible) { @@ -147,24 +147,23 @@ export class TabbedPanel extends Disposable implements IThemable { } public showTab(id: PanelTabIdentifier): void { - if (this._shownTab && this._shownTab === id) { + if (this._shownTabId === id || !this._tabMap.has(id)) { return; } - if (this._shownTab) { - DOM.removeClass(this._tabMap.get(this._shownTab).label, 'active'); - DOM.removeClass(this._tabMap.get(this._shownTab).header, 'active'); - this._tabMap.get(this._shownTab).header.setAttribute('aria-selected', 'false'); + if (this._shownTabId) { + const shownTab = this._tabMap.get(this._shownTabId); + if (shownTab) { + DOM.removeClass(shownTab.label, 'active'); + DOM.removeClass(shownTab.header, 'active'); + shownTab.header.setAttribute('aria-selected', 'false'); + shownTab.body.remove(); + } } - let prevTab = this._tabMap.get(this._shownTab); - if (prevTab) { - prevTab.body.remove(); - } - - this._shownTab = id; + this._shownTabId = id; this.tabHistory.push(id); - let tab = this._tabMap.get(this._shownTab); + const tab = this._tabMap.get(this._shownTabId)!; // @anthonydresser we know this can't be undefined since we check further up if the map contains the id if (!tab.body) { tab.body = DOM.$('.tab-container'); tab.body.style.width = '100%'; @@ -183,7 +182,10 @@ export class TabbedPanel extends Disposable implements IThemable { } public removeTab(tab: PanelTabIdentifier) { - let actualTab = this._tabMap.get(tab); + const actualTab = this._tabMap.get(tab); + if (!actualTab) { + return; + } if (actualTab.view && actualTab.view.remove) { actualTab.view.remove(); } @@ -195,12 +197,14 @@ export class TabbedPanel extends Disposable implements IThemable { } dispose(actualTab.disposables); this._tabMap.delete(tab); - if (this._shownTab === tab) { - this._shownTab = undefined; - while (this._shownTab === undefined && this.tabHistory.length > 0) { + if (this._shownTabId === tab) { + this._shownTabId = undefined; + while (this._shownTabId === undefined && this.tabHistory.length > 0) { let lastTab = this.tabHistory.shift(); - if (this._tabMap.get(lastTab)) { - this.showTab(lastTab); + if (lastTab) { + if (this._tabMap.get(lastTab)) { + this.showTab(lastTab); + } } } } @@ -230,11 +234,13 @@ export class TabbedPanel extends Disposable implements IThemable { } private _layoutCurrentTab(dimension: DOM.Dimension): void { - if (this._shownTab) { - let tab = this._tabMap.get(this._shownTab); - tab.body.style.width = dimension.width + 'px'; - tab.body.style.height = dimension.height + 'px'; - tab.view.layout(dimension); + if (this._shownTabId) { + const tab = this._tabMap.get(this._shownTabId); + if (tab) { + tab.body.style.width = dimension.width + 'px'; + tab.body.style.height = dimension.height + 'px'; + tab.view.layout(dimension); + } } } diff --git a/src/sql/base/browser/ui/panel/tab.component.ts b/src/sql/base/browser/ui/panel/tab.component.ts index 99aafad3cf..208df1afeb 100644 --- a/src/sql/base/browser/ui/panel/tab.component.ts +++ b/src/sql/base/browser/ui/panel/tab.component.ts @@ -21,7 +21,7 @@ export abstract class TabChild extends Disposable { }) export class TabComponent implements OnDestroy { private _child: TabChild; - @ContentChild(TemplateRef) templateRef; + @ContentChild(TemplateRef) templateRef: TemplateRef; @Input() public title: string; @Input() public canClose: boolean; @Input() public actions: Array; @@ -32,8 +32,7 @@ export class TabComponent implements OnDestroy { private rendered = false; private destroyed: boolean = false; - - @ContentChild(TabChild) private set child(tab: TabChild) { + @ContentChild(TabChild) public set child(tab: TabChild) { this._child = tab; if (this.active && this._child) { this._child.layout(); diff --git a/src/sql/base/browser/ui/radioButton/radioButton.ts b/src/sql/base/browser/ui/radioButton/radioButton.ts index 3b5ee65781..d3363b59f3 100644 --- a/src/sql/base/browser/ui/radioButton/radioButton.ts +++ b/src/sql/base/browser/ui/radioButton/radioButton.ts @@ -3,13 +3,9 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; -import * as DOM from 'vs/base/browser/dom'; -import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; -import { Color } from 'vs/base/common/color'; -import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox'; import { Event, Emitter } from 'vs/base/common/event'; import { Widget } from 'vs/base/browser/ui/widget'; +import { withNullAsUndefined } from 'vs/base/common/types'; export interface IRadioButtonOptions { label: string; @@ -43,20 +39,24 @@ export class RadioButton extends Widget { container.appendChild(this._label); } - public set name(value: string) { - this.inputElement.setAttribute('name', value); + public set name(value: string | undefined) { + if (value) { + this.inputElement.setAttribute('name', value); + } } - public get name(): string { - return this.inputElement.getAttribute('name'); + public get name(): string | undefined { + return withNullAsUndefined(this.inputElement.getAttribute('name')); } - public set value(value: string) { - this.inputElement.setAttribute('value', value); + public set value(value: string | undefined) { + if (value) { + this.inputElement.setAttribute('value', value); + } } - public get value(): string { - return this.inputElement.getAttribute('value'); + public get value(): string | undefined { + return withNullAsUndefined(this.inputElement.getAttribute('value')); } public set checked(val: boolean) { @@ -83,4 +83,4 @@ export class RadioButton extends Widget { this._label.innerText = val; } -} \ No newline at end of file +} diff --git a/src/sql/base/browser/ui/scrollable/scrollable.directive.ts b/src/sql/base/browser/ui/scrollable/scrollable.directive.ts index 13d5775672..2fb2e76c01 100644 --- a/src/sql/base/browser/ui/scrollable/scrollable.directive.ts +++ b/src/sql/base/browser/ui/scrollable/scrollable.directive.ts @@ -30,7 +30,7 @@ export class ScrollableDirective extends AngularDisposable { ngOnInit() { this.scrolled = this._el.nativeElement as HTMLElement; - this.parent = this.scrolled.parentElement; + this.parent = this.scrolled.parentElement!; const next = this.scrolled.nextSibling; this.parent.removeChild(this.scrolled); diff --git a/src/sql/base/browser/ui/scrollableSplitview/heightMap.ts b/src/sql/base/browser/ui/scrollableSplitview/heightMap.ts index faec25ae6b..0b6dedcd03 100644 --- a/src/sql/base/browser/ui/scrollableSplitview/heightMap.ts +++ b/src/sql/base/browser/ui/scrollableSplitview/heightMap.ts @@ -31,8 +31,8 @@ export class HeightMap { return !last ? 0 : last.top + last.height; } - public onInsertItems(iterator: INextIterator, afterItemId: string = null): number { - let viewItem: IViewItem; + public onInsertItems(iterator: INextIterator, afterItemId: string | undefined = undefined): number | undefined { + let viewItem: IViewItem | undefined = undefined; let i: number, j: number; let totalSize: number; let sizeDiff = 0; @@ -89,10 +89,10 @@ export class HeightMap { // Contiguous items public onRemoveItems(iterator: INextIterator): void { - let itemId: string; + let itemId: string | undefined = undefined; let viewItem: IViewItem; - let startIndex: number = null; - let i: number; + let startIndex: number | undefined = undefined; + let i = 0; let sizeDiff = 0; while (itemId = iterator.next()) { @@ -108,12 +108,12 @@ export class HeightMap { delete this.indexes[itemId]; this.onRemoveItem(viewItem); - if (startIndex === null) { + if (startIndex === undefined) { startIndex = i; } } - if (sizeDiff === 0) { + if (sizeDiff === 0 || startIndex === undefined) { return; } diff --git a/src/sql/base/browser/ui/scrollableSplitview/scrollableSplitview.ts b/src/sql/base/browser/ui/scrollableSplitview/scrollableSplitview.ts index b07f116f88..223171f695 100644 --- a/src/sql/base/browser/ui/scrollableSplitview/scrollableSplitview.ts +++ b/src/sql/base/browser/ui/scrollableSplitview/scrollableSplitview.ts @@ -275,7 +275,7 @@ export class ScrollableSplitView extends HeightMap implements IDisposable { // Add sash if (this.options.enableResizing && this.viewItems.length > 1) { const orientation = this.orientation === Orientation.VERTICAL ? Orientation.HORIZONTAL : Orientation.VERTICAL; - const layoutProvider = this.orientation === Orientation.VERTICAL ? { getHorizontalSashTop: sash => this.getSashPosition(sash) } : { getVerticalSashLeft: sash => this.getSashPosition(sash) }; + const layoutProvider = this.orientation === Orientation.VERTICAL ? { getHorizontalSashTop: (sash: Sash) => this.getSashPosition(sash) } : { getVerticalSashLeft: (sash: Sash) => this.getSashPosition(sash) }; const sash = new Sash(this.sashContainer, layoutProvider, { orientation, orthogonalStartSash: this.orthogonalStartSash, @@ -321,8 +321,8 @@ export class ScrollableSplitView extends HeightMap implements IDisposable { // this isn't actually scrolling up or down let scrollTop = this.lastRenderTop; let viewHeight = this.lastRenderHeight; - this.lastRenderTop = undefined; - this.lastRenderHeight = undefined; + this.lastRenderTop = 0; + this.lastRenderHeight = 0; this.render(scrollTop, viewHeight); } @@ -378,7 +378,7 @@ export class ScrollableSplitView extends HeightMap implements IDisposable { // Add sash if (this.options.enableResizing && this.viewItems.length > 1) { const orientation = this.orientation === Orientation.VERTICAL ? Orientation.HORIZONTAL : Orientation.VERTICAL; - const layoutProvider = this.orientation === Orientation.VERTICAL ? { getHorizontalSashTop: sash => this.getSashPosition(sash) } : { getVerticalSashLeft: sash => this.getSashPosition(sash) }; + const layoutProvider = this.orientation === Orientation.VERTICAL ? { getHorizontalSashTop: (sash: Sash) => this.getSashPosition(sash) } : { getVerticalSashLeft: (sash: Sash) => this.getSashPosition(sash) }; const sash = new Sash(this.sashContainer, layoutProvider, { orientation, orthogonalStartSash: this.orthogonalStartSash, @@ -502,8 +502,8 @@ export class ScrollableSplitView extends HeightMap implements IDisposable { const previousSize = Math.max(this.size, this.contentSize); this.size = size; this.contentSize = 0; - this.lastRenderHeight = undefined; - this.lastRenderTop = undefined; + this.lastRenderHeight = 0; + this.lastRenderTop = 0; if (!this.proportions) { this.resize(this.viewItems.length - 1, size - previousSize); @@ -734,14 +734,14 @@ export class ScrollableSplitView extends HeightMap implements IDisposable { return false; } - let elementAfter: HTMLElement = null; + let elementAfter: HTMLElement | undefined = undefined; let itemAfter = this.itemAfter(item); if (itemAfter && itemAfter.container) { elementAfter = itemAfter.container; } - if (elementAfter === null) { + if (elementAfter === undefined) { this.viewContainer.appendChild(item.container); } else { try { diff --git a/src/sql/base/browser/ui/selectBox/selectBox.ts b/src/sql/base/browser/ui/selectBox/selectBox.ts index 288e138f5b..c35c57c06f 100644 --- a/src/sql/base/browser/ui/selectBox/selectBox.ts +++ b/src/sql/base/browser/ui/selectBox/selectBox.ts @@ -11,7 +11,7 @@ import { Color } from 'vs/base/common/color'; import { IContextViewProvider, AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; import * as dom from 'vs/base/browser/dom'; import { RenderOptions, renderFormattedText, renderText } from 'vs/base/browser/htmlContentRenderer'; -import { IMessage, MessageType, defaultOpts } from 'vs/base/browser/ui/inputbox/inputBox'; +import { IMessage, MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; import aria = require('vs/base/browser/ui/aria/aria'); import nls = require('vs/nls'); @@ -22,40 +22,51 @@ export interface ISelectBoxStyles extends vsISelectBoxStyles { disabledSelectForeground?: Color; inputValidationInfoBorder?: Color; inputValidationInfoBackground?: Color; + inputinputValidationInfoForeground?: Color; inputValidationWarningBorder?: Color; inputValidationWarningBackground?: Color; + inputValidationWarningForeground?: Color; inputValidationErrorBorder?: Color; inputValidationErrorBackground?: Color; + inputValidationErrorForeground?: Color; } export class SelectBox extends vsSelectBox { - private _optionsDictionary; + private _optionsDictionary: Map; private _dialogOptions: string[]; private _selectedOption: string; - private _selectBoxOptions: ISelectBoxOptions; - private enabledSelectBackground: Color; - private enabledSelectForeground: Color; - private enabledSelectBorder: Color; - private disabledSelectBackground: Color; - private disabledSelectForeground: Color; - private disabledSelectBorder: Color; + private _selectBoxOptions?: ISelectBoxOptions; + private enabledSelectBackground?: Color; + private enabledSelectForeground?: Color; + private enabledSelectBorder?: Color; + private disabledSelectBackground?: Color; + private disabledSelectForeground?: Color; + private disabledSelectBorder?: Color; private contextViewProvider: IContextViewProvider; - private message: IMessage; - private inputValidationInfoBorder: Color; - private inputValidationInfoBackground: Color; - private inputValidationWarningBorder: Color; - private inputValidationWarningBackground: Color; - private inputValidationErrorBorder: Color; - private inputValidationErrorBackground: Color; + private message?: IMessage; + + private inputValidationInfoBorder?: Color; + private inputValidationInfoBackground?: Color; + private inputValidationInfoForeground?: Color; + private inputValidationWarningBorder?: Color; + private inputValidationWarningBackground?: Color; + private inputValidationWarningForeground?: Color; + private inputValidationErrorBorder?: Color; + private inputValidationErrorBackground?: Color; + private inputValidationErrorForeground?: Color; + private element: HTMLElement; constructor(options: string[], selectedOption: string, contextViewProvider: IContextViewProvider, container?: HTMLElement, selectBoxOptions?: ISelectBoxOptions) { super(options.map(option => { return { text: option }; }), 0, contextViewProvider, undefined, selectBoxOptions); - this._optionsDictionary = new Array(); - for (var i = 0; i < options.length; i++) { - this._optionsDictionary[options[i]] = i; + this._optionsDictionary = new Map(); + for (let i = 0; i < options.length; i++) { + this._optionsDictionary.set(options[i], i); + } + const option = this._optionsDictionary.get(selectedOption); + if (option) { + super.select(option); } - super.select(this._optionsDictionary[selectedOption]); this._selectedOption = selectedOption; this._dialogOptions = options; this._register(this.onDidSelect(newInput => { @@ -66,8 +77,8 @@ export class SelectBox extends vsSelectBox { this.enabledSelectForeground = this.selectForeground; this.enabledSelectBorder = this.selectBorder; this.disabledSelectBackground = Color.transparent; - this.disabledSelectForeground = null; - this.disabledSelectBorder = null; + this.disabledSelectForeground = undefined; + this.disabledSelectBorder = undefined; this.contextViewProvider = contextViewProvider; if (container) { this.element = dom.append(container, $('.monaco-selectbox.idle')); @@ -77,7 +88,7 @@ export class SelectBox extends vsSelectBox { this.selectElement.setAttribute('role', 'combobox'); this._selectBoxOptions = selectBoxOptions; - var focusTracker = dom.trackFocus(this.selectElement); + let focusTracker = dom.trackFocus(this.selectElement); this._register(focusTracker); this._register(focusTracker.onDidBlur(() => this._hideMessage())); this._register(focusTracker.onDidFocus(() => this._showMessage())); @@ -92,16 +103,20 @@ export class SelectBox extends vsSelectBox { this.disabledSelectForeground = styles.disabledSelectForeground; this.inputValidationInfoBorder = styles.inputValidationInfoBorder; this.inputValidationInfoBackground = styles.inputValidationInfoBackground; + this.inputValidationInfoForeground = styles.inputinputValidationInfoForeground; this.inputValidationWarningBorder = styles.inputValidationWarningBorder; this.inputValidationWarningBackground = styles.inputValidationWarningBackground; + this.inputValidationWarningForeground = styles.inputValidationWarningForeground; this.inputValidationErrorBorder = styles.inputValidationErrorBorder; this.inputValidationErrorBackground = styles.inputValidationErrorBackground; + this.inputValidationErrorForeground = styles.inputValidationErrorForeground; this.applyStyles(); } public selectWithOptionName(optionName: string): void { - if (this._optionsDictionary[optionName]) { - this.select(this._optionsDictionary[optionName]); + const option = this._optionsDictionary.get(optionName); + if (option) { + this.select(option); } else { this.select(0); } @@ -121,9 +136,9 @@ export class SelectBox extends vsSelectBox { } else { stringOptions = options as string[]; } - this._optionsDictionary = []; - for (var i = 0; i < stringOptions.length; i++) { - this._optionsDictionary[stringOptions[i]] = i; + this._optionsDictionary = new Map(); + for (let i = 0; i < stringOptions.length; i++) { + this._optionsDictionary.set(stringOptions[i], i); } this._dialogOptions = stringOptions; super.setOptions(stringOptions.map(option => { return { text: option }; }), selected); @@ -187,6 +202,7 @@ export class SelectBox extends vsSelectBox { public _showMessage(): void { if (this.message && this.contextViewProvider && this.element) { + const message = this.message; let div: HTMLElement; let layout = () => div.style.width = dom.getTotalWidth(this.selectElement) + 'px'; @@ -202,12 +218,12 @@ export class SelectBox extends vsSelectBox { className: 'monaco-inputbox-message' }; - let spanElement: HTMLElement = (this.message.formatContent - ? renderFormattedText(this.message.content, renderOptions) - : renderText(this.message.content, renderOptions)) as any; - dom.addClass(spanElement, this.classForType(this.message.type)); + let spanElement: HTMLElement = (message.formatContent + ? renderFormattedText(message.content, renderOptions) + : renderText(message.content, renderOptions)) as any; + dom.addClass(spanElement, this.classForType(message.type)); - const styles = this.stylesForType(this.message.type); + const styles = this.stylesForType(message.type); spanElement.style.backgroundColor = styles.background ? styles.background.toString() : null; spanElement.style.border = styles.border ? `1px solid ${styles.border}` : null; @@ -229,7 +245,7 @@ export class SelectBox extends vsSelectBox { this._hideMessage(); this.applyStyles(); - this.message = null; + this.message = undefined; } private _hideMessage(): void { @@ -238,7 +254,7 @@ export class SelectBox extends vsSelectBox { } } - private classForType(type: MessageType): string { + private classForType(type: MessageType | undefined): string { switch (type) { case MessageType.INFO: return 'info'; case MessageType.WARNING: return 'warning'; @@ -246,11 +262,11 @@ export class SelectBox extends vsSelectBox { } } - private stylesForType(type: MessageType): { border: Color; background: Color } { + private stylesForType(type: MessageType | undefined): { border: Color | undefined; background: Color | undefined; foreground: Color | undefined } { switch (type) { - case MessageType.INFO: return { border: this.inputValidationInfoBorder, background: this.inputValidationInfoBackground }; - case MessageType.WARNING: return { border: this.inputValidationWarningBorder, background: this.inputValidationWarningBackground }; - default: return { border: this.inputValidationErrorBorder, background: this.inputValidationErrorBackground }; + case MessageType.INFO: return { border: this.inputValidationInfoBorder, background: this.inputValidationInfoBackground, foreground: this.inputValidationInfoForeground }; + case MessageType.WARNING: return { border: this.inputValidationWarningBorder, background: this.inputValidationWarningBackground, foreground: this.inputValidationWarningForeground }; + default: return { border: this.inputValidationErrorBorder, background: this.inputValidationErrorBackground, foreground: this.inputValidationErrorForeground }; } } diff --git a/src/sql/base/browser/ui/table/asyncDataView.ts b/src/sql/base/browser/ui/table/asyncDataView.ts index 574c53efdd..d05775475c 100644 --- a/src/sql/base/browser/ui/table/asyncDataView.ts +++ b/src/sql/base/browser/ui/table/asyncDataView.ts @@ -16,7 +16,7 @@ export interface IObservableCollection { } class DataWindow { - private _data: T[]; + private _data: T[] | undefined; private _length: number = 0; private _offsetFromDataSource: number = -1; @@ -30,9 +30,6 @@ class DataWindow { dispose() { this._data = undefined; - this.loadFunction = undefined; - this.placeholderItemGenerator = undefined; - this.loadCompleteCallback = undefined; this.cancellationToken.cancel(); } @@ -157,7 +154,7 @@ export class VirtualizedCollection implements IObserv } private getRangeFromCurrent(start: number, end: number): T[] { - let currentData = []; + const currentData: Array = []; for (let i = 0; i < end - start; i++) { currentData.push(this.getDataFromCurrent(start + i)); } diff --git a/src/sql/base/browser/ui/table/interfaces.ts b/src/sql/base/browser/ui/table/interfaces.ts index 3cb0f916e7..eb56fea0a6 100644 --- a/src/sql/base/browser/ui/table/interfaces.ts +++ b/src/sql/base/browser/ui/table/interfaces.ts @@ -21,7 +21,7 @@ export interface ITableStyles extends IListStyles { } export interface ITableSorter { - sort(args: Slick.OnSortEventArgs); + (args: Slick.OnSortEventArgs): void; } export interface ITableConfiguration { diff --git a/src/sql/base/browser/ui/table/table.ts b/src/sql/base/browser/ui/table/table.ts index f74a357b75..7b4ba63a25 100644 --- a/src/sql/base/browser/ui/table/table.ts +++ b/src/sql/base/browser/ui/table/table.ts @@ -6,7 +6,6 @@ import 'vs/css!./media/table'; import { TableDataView } from './tableDataView'; import { IDisposableDataProvider, ITableSorter, ITableMouseEvent, ITableConfiguration, ITableStyles } from 'sql/base/browser/ui/table/interfaces'; -import { $ } from 'sql/base/browser/builder'; import { IThemable } from 'vs/platform/theme/common/styler'; import * as DOM from 'vs/base/browser/dom'; @@ -94,7 +93,7 @@ export class Table extends Widget implements IThemabl if (configuration && configuration.sorter) { this._sorter = configuration.sorter; this._grid.onSort.subscribe((e, args) => { - this._sorter.sort(args); + this._sorter(args); this._grid.invalidate(); this._grid.render(); }); @@ -121,7 +120,7 @@ export class Table extends Widget implements IThemabl } public dispose() { - $(this._container).dispose(); + this._container.remove(); super.dispose(); } @@ -146,9 +145,9 @@ export class Table extends Widget implements IThemabl return this._grid; } - setData(data: Array); - setData(data: TableDataView); - setData(data: Array | TableDataView) { + setData(data: Array): void; + setData(data: TableDataView): void; + setData(data: Array | TableDataView): void { if (data instanceof TableDataView) { this._data = data; } else { diff --git a/src/sql/base/browser/ui/table/tableDataView.ts b/src/sql/base/browser/ui/table/tableDataView.ts index cf5bd2d631..f3b0683533 100644 --- a/src/sql/base/browser/ui/table/tableDataView.ts +++ b/src/sql/base/browser/ui/table/tableDataView.ts @@ -16,22 +16,27 @@ export interface IFindPosition { row: number; } -function defaultSort(args: Slick.OnSortEventArgs, data: Array): Array { - let field = args.sortCol.field; - let sign = args.sortAsc ? 1 : -1; - let comparer: (a, b) => number; +function defaultSort(args: Slick.OnSortEventArgs, data: Array): Array { + if (!args.sortCol || !args.sortCol.field) { + return data; + } + const field = args.sortCol.field; + const sign = args.sortAsc ? 1 : -1; + let comparer: (a: T, b: T) => number; if (types.isString(data[0][field])) { if (Number(data[0][field]) !== NaN) { - comparer = (a: number, b: number) => { + comparer = (a: T, b: T) => { let anum = Number(a[field]); let bnum = Number(b[field]); return anum === bnum ? 0 : anum > bnum ? 1 : -1; }; } else { - comparer = stringCompare; + comparer = (a: T, b: T) => { + return stringCompare(a[field], b[field]); + }; } } else { - comparer = (a: number, b: number) => { + comparer = (a: T, b: T) => { return a[field] === b[field] ? 0 : (a[field] > b[field] ? 1 : -1); }; } @@ -44,7 +49,7 @@ export class TableDataView implements IDisposableData //Used when filtering is enabled, _allData holds the complete set of data. private _allData: Array; private _findArray: Array; - private _findObs: Observable; + private _findObs: Observable | undefined; private _findIndex: number; private _filterEnabled: boolean; @@ -57,11 +62,14 @@ export class TableDataView implements IDisposableData private _onFilterStateChange = new Emitter(); get onFilterStateChange(): Event { return this._onFilterStateChange.event; } + private _filterFn: (data: Array) => Array; + private _sortFn: (args: Slick.OnSortEventArgs, data: Array) => Array; + constructor( data?: Array, private _findFn?: (val: T, exp: string) => Array, - private _sortFn?: (args: Slick.OnSortEventArgs, data: Array) => Array, - private _filterFn?: (data: Array) => Array + _sortFn?: (args: Slick.OnSortEventArgs, data: Array) => Array, + _filterFn?: (data: Array) => Array ) { if (data) { this._data = data; @@ -69,13 +77,9 @@ export class TableDataView implements IDisposableData this._data = new Array(); } - if (!_sortFn) { - this._sortFn = defaultSort; - } + this._sortFn = _sortFn ? _sortFn : defaultSort; - if (!_filterFn) { - this._filterFn = (dataToFilter) => dataToFilter; - } + this._filterFn = _filterFn ? _filterFn : (dataToFilter) => dataToFilter; this._filterEnabled = false; } @@ -119,9 +123,9 @@ export class TableDataView implements IDisposableData return this.filterEnabled ? this._allData.length : this._data.length; } - push(items: Array); - push(item: T); - push(input: T | Array) { + push(items: Array): void; + push(item: T): void; + push(input: T | Array): void { let inputArray = new Array(); if (Array.isArray(input)) { inputArray.push(...input); @@ -161,7 +165,7 @@ export class TableDataView implements IDisposableData this._findObs = Observable.create((observer: Observer) => { for (let i = 0; i < this._data.length; i++) { let item = this._data[i]; - let result = this._findFn(item, exp); + let result = this._findFn!(item, exp); if (result) { result.forEach(pos => { let index = { col: pos, row: i }; @@ -175,7 +179,7 @@ export class TableDataView implements IDisposableData } } }); - return this._findObs.take(1).toPromise().then(() => { + return this._findObs!.take(1).toPromise().then(() => { return this._findArray[this._findIndex]; }); } else { @@ -234,9 +238,9 @@ export class TableDataView implements IDisposableData } dispose() { - this._data = undefined; - this._allData = undefined; - this._findArray = undefined; + this._data = []; + this._allData = []; + this._findArray = []; this._findObs = undefined; } } diff --git a/src/sql/base/browser/ui/taskbar/actionbar.ts b/src/sql/base/browser/ui/taskbar/actionbar.ts index 546869b59b..63500682ea 100644 --- a/src/sql/base/browser/ui/taskbar/actionbar.ts +++ b/src/sql/base/browser/ui/taskbar/actionbar.ts @@ -3,13 +3,10 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - import 'vs/css!vs/base/browser/ui/actionbar/actionbar'; import { Builder, $ } from 'sql/base/browser/builder'; import { IAction, IActionRunner, ActionRunner } from 'vs/base/common/actions'; -import { EventEmitter } from 'sql/base/common/eventEmitter'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { diff --git a/src/sql/parts/profiler/editor/controller/profilerTableEditor.ts b/src/sql/parts/profiler/editor/controller/profilerTableEditor.ts index 2a29e7469c..5408e3160b 100644 --- a/src/sql/parts/profiler/editor/controller/profilerTableEditor.ts +++ b/src/sql/parts/profiler/editor/controller/profilerTableEditor.ts @@ -80,12 +80,10 @@ export class ProfilerTableEditor extends BaseEditor implements IProfilerControll parent.appendChild(this._overlay); this._profilerTable = new Table(parent, { - sorter: { - sort: (args) => { - let input = this.input as ProfilerInput; - if (input && input.data) { - input.data.sort(args); - } + sorter: (args) => { + let input = this.input as ProfilerInput; + if (input && input.data) { + input.data.sort(args); } } }, { diff --git a/src/sql/parts/queryPlan/topOperations.ts b/src/sql/parts/queryPlan/topOperations.ts index b6f289f6d5..9d050442c6 100644 --- a/src/sql/parts/queryPlan/topOperations.ts +++ b/src/sql/parts/queryPlan/topOperations.ts @@ -70,10 +70,8 @@ export class TopOperationsView implements IPanelView { this.table = new Table(this.container, { columns: topOperationColumns, dataProvider: this.dataView, - sorter: { - sort: (args) => { - this.dataView.sort(args); - } + sorter: (args) => { + this.dataView.sort(args); } }); this.disposables.push(this.table); diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json new file mode 100644 index 0000000000..58498f5f89 --- /dev/null +++ b/src/tsconfig.strictNullChecks.json @@ -0,0 +1,26 @@ +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + "noEmit": true, + "strictNullChecks": true, + "moduleResolution": "classic" + }, + "include": [ + "./typings", + "./vs/**.*.ts", + "./sql/base/browser/ui/breadcrumb/*.ts", + "./sql/base/browser/ui/button/*.ts", + "./sql/base/browser/ui/checkbox/*.ts", + "./sql/base/browser/ui/dropdownList/*.ts", + "./sql/base/browser/ui/inputBox/*.ts", + "./sql/base/browser/ui/listBox/*.ts", + "./sql/base/browser/ui/panel/*.ts", + "./sql/base/browser/ui/radioButton/*.ts", + "./sql/base/browser/ui/scrollable/*.ts", + "./sql/base/browser/ui/selectBox/*.ts", + "./sql/base/browser/ui/table/*.ts", + ], + "exclude": [ + "node_modules/**" + ] +} diff --git a/src/tsconfig.strictNullChecks.sql.json b/src/tsconfig.strictNullChecks.sql.json deleted file mode 100644 index 76154b77b8..0000000000 --- a/src/tsconfig.strictNullChecks.sql.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "extends": "./tsconfig.strictNullChecks.json", - "include": [ - "./typings", - "./vs/base/browser/**/*.ts", - "./vs/base/common/**/*.ts", - "./vs/base/node/**/*.ts", - "./vs/editor/browser/**/*.ts", - "./vs/editor/common/**/*.ts", - "./vs/editor/contrib/codeAction/**/*.ts", - "./vs/editor/contrib/format/**/*.ts", - "./vs/editor/contrib/gotoError/**/*.ts", - "./vs/editor/contrib/inPlaceReplace/**/*.ts", - "./vs/editor/contrib/smartSelect/**/*.ts", - "./vs/editor/contrib/snippet/**/*.ts", - "./vs/editor/contrib/suggest/**/*.ts", - "./vs/editor/test/**/*.ts", - "./sql/base/common/**/*ts", - ], - "files": [ - // "./sql/base/browser/ui/breadcrumb/breadcrumb.component.ts", // pulls in angular which gives extrenous errors - // "./sql/base/browser/ui/breadcrumb/interfaces.ts", // pulls in angular which gives extrenous errors - "./sql/base/browser/ui/button/button.ts", - "./sql/base/browser/ui/checkbox/checkbox.ts", - // "./sql/base/browser/ui/checkbox/checkbox.component.ts", // pulls in angular which gives extrenous errors - // "./sql/base/browser/ui/dropdownList/dropdownList.ts", // skipping since vscode hasn't checked their dropdown yet - // "./sql/base/browser/ui/editableDropdown/actions.ts", // skipping since vscode hasn't checked their dropdown yet and it isn't in the right place anyways - // "./sql/base/browser/ui/editableDropdown/dropdown.ts", // skipping since vscode hasn't checked their dropdown yet and it isn't in the right place anyways - // "./sql/base/browser/ui/editableDropdown/dropdownTree.ts", // skipping since vscode hasn't checked their dropdown yet and it isn't in the right place anyways - // "./sql/base/browser/ui/editableDropdown/editableDropdown.component.ts", // skipping since vscode hasn't checked their dropdown yet and it isn't in the right place anyways - // "./sql/base/browser/ui/inputBox/inputBox.component.ts", // pulls in angular which gives extrenous errors - // "./sql/base/browser/ui/inputBox/inputBox.ts", // skipping since vscode hasn't checked their inputbox yet - // "./sql/base/browser/ui/listBox/listBox.ts", - ] -} diff --git a/src/typings/modules/@angular/core/index.d.ts b/src/typings/modules/@angular/core/index.d.ts index 6eebdc2850..7bb6e33d1e 100644 --- a/src/typings/modules/@angular/core/index.d.ts +++ b/src/typings/modules/@angular/core/index.d.ts @@ -5469,7 +5469,7 @@ export interface IterableChanges { * original `Iterable` location, where as `currentIndex` refers to the transient location * of the item, after applying the operations up to this point. */ - forEachOperation(fn: (record: IterableChangeRecord, previousIndex: number, currentIndex: number) => void): void; + forEachOperation(fn: (record: IterableChangeRecord, previousIndex: number | null, currentIndex: number | null) => void): void; /** * Iterate over changes in the order of original `Iterable` showing where the original items * have moved. diff --git a/src/vs/base/browser/ui/selectBox/selectBox.ts b/src/vs/base/browser/ui/selectBox/selectBox.ts index d8ec30e46b..21c83e4cb1 100644 --- a/src/vs/base/browser/ui/selectBox/selectBox.ts +++ b/src/vs/base/browser/ui/selectBox/selectBox.ts @@ -74,9 +74,9 @@ export interface ISelectData { export class SelectBox extends Widget implements ISelectBoxDelegate { // {{SQL CARBON EDIT}} protected selectElement: HTMLSelectElement; - protected selectBackground: Color; - protected selectForeground: Color; - protected selectBorder: Color; + protected selectBackground?: Color; + protected selectForeground?: Color; + protected selectBorder?: Color; private styles: ISelectBoxStyles; private selectBoxDelegate: ISelectBoxDelegate; @@ -137,14 +137,15 @@ export class SelectBox extends Widget implements ISelectBoxDelegate { public applyStyles(): void { this.selectBoxDelegate.applyStyles(); } + // {{SQL CARBON EDIT}} protected createOption(value: string, disabled?: boolean): HTMLOptionElement { let option = document.createElement('option'); option.value = value; option.text = value; - option.disabled = disabled; + option.disabled = disabled || false; return option; } -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts index 1ed2b7fc74..3c24d0e6d1 100644 --- a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts +++ b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts @@ -20,6 +20,9 @@ import { ISelectBoxDelegate, ISelectOptionItem, ISelectBoxOptions, ISelectBoxSty import { isMacintosh } from 'vs/base/common/platform'; import { renderMarkdown } from 'vs/base/browser/htmlContentRenderer'; +// {{SQL CARBON EDIT}} import color +import { Color } from 'vs/base/common/color'; + const $ = dom.$; const SELECT_OPTION_ENTRY_TEMPLATE_ID = 'selectOption.entry.template'; @@ -372,23 +375,22 @@ export class SelectBoxList implements ISelectBoxDelegate, IListVirtualDelegatethis.styles).disabledSelectBackground ? (this.styles).disabledSelectBackground.toString() : null; - foreground = (this.styles).disabledSelectForeground ? (this.styles).disabledSelectForeground.toString() : null; - border = null; + background = (this.styles).disabledSelectBackground; + foreground = (this.styles).disabledSelectForeground; } else { - background = this.styles.selectBackground ? this.styles.selectBackground.toString() : null; - foreground = this.styles.selectForeground ? this.styles.selectForeground.toString() : null; - border = this.styles.selectBorder ? this.styles.selectBorder.toString() : null; + background = this.styles.selectBackground; + foreground = this.styles.selectForeground; + border = this.styles.selectBorder; } - this.selectElement.style.backgroundColor = background; - this.selectElement.style.color = foreground; - this.selectElement.style.borderColor = border; + this.selectElement.style.backgroundColor = background ? background.toString() : null; + this.selectElement.style.color = foreground ? foreground.toString() : null; + this.selectElement.style.borderColor = border ? border.toString() : null; } // Style drop down select list (non-native mode only)