strict null checks

This commit is contained in:
Eugene Pankov
2019-09-18 20:56:59 +02:00
parent 9b904856fa
commit 181c523020
62 changed files with 202 additions and 170 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "terminus-core",
"version": "1.0.83-nightly.4",
"version": "1.0.92-nightly.0",
"description": "Terminus core",
"keywords": [
"terminus-builtin-plugin"

View File

@@ -34,5 +34,5 @@ export abstract class TabRecoveryProvider {
* @returns [[RecoveredTab]] descriptor containing tab type and component inputs
* or `null` if this token is from a different tab type or is not supported
*/
abstract async recover (recoveryToken: any): Promise<RecoveredTab | null>
abstract async recover (recoveryToken: any): Promise<RecoveredTab|null>
}

View File

@@ -5,7 +5,7 @@ export interface ToolbarButton {
/**
* Raw SVG icon code
*/
icon: string
icon?: string
title: string

View File

@@ -144,7 +144,7 @@ export class AppRootComponent {
config.changed$.subscribe(() => this.updateVibrancy())
this.updateVibrancy()
let lastProgress = null
let lastProgress: number|null = null
this.app.tabOpened$.subscribe(tab => {
this.unsortedTabs.push(tab)
tab.progress$.subscribe(progress => {
@@ -258,7 +258,7 @@ export class AppRootComponent {
buttons = buttons.concat(provider.provide())
})
return buttons
.filter(button => button.weight > 0 === aboveZero)
.filter(button => (button.weight || 0) > 0 === aboveZero)
.sort((a: ToolbarButton, b: ToolbarButton) => (a.weight || 0) - (b.weight || 0))
}

View File

@@ -36,7 +36,7 @@ export abstract class BaseTabComponent {
/**
* CSS color override for the tab's header
*/
color: string = null
color: string|null = null
protected hasFocus = false
@@ -50,14 +50,14 @@ export abstract class BaseTabComponent {
private titleChange = new Subject<string>()
private focused = new Subject<void>()
private blurred = new Subject<void>()
private progress = new Subject<number>()
private progress = new Subject<number|null>()
private activity = new Subject<boolean>()
private destroyed = new Subject<void>()
get focused$ (): Observable<void> { return this.focused }
get blurred$ (): Observable<void> { return this.blurred }
get titleChange$ (): Observable<string> { return this.titleChange }
get progress$ (): Observable<number> { return this.progress }
get progress$ (): Observable<number|null> { return this.progress }
get activity$ (): Observable<boolean> { return this.activity }
get destroyed$ (): Observable<void> { return this.destroyed }
get recoveryStateChangedHint$ (): Observable<void> { return this.recoveryStateChangedHint }
@@ -83,7 +83,7 @@ export abstract class BaseTabComponent {
*
* @param {type} progress: value between 0 and 1, or `null` to remove
*/
setProgress (progress: number) {
setProgress (progress: number|null) {
this.progress.next(progress)
if (progress) {
if (this.progressClearTimeout) {
@@ -125,7 +125,7 @@ export abstract class BaseTabComponent {
/**
* Override this to enable task completion notifications for the tab
*/
async getCurrentProcess (): Promise<BaseTabProcess> {
async getCurrentProcess (): Promise<BaseTabProcess|null> {
return null
}

View File

@@ -33,8 +33,8 @@ export class SplitContainer {
/**
* @return Flat list of all tabs inside this container
*/
getAllTabs () {
let r = []
getAllTabs (): BaseTabComponent[] {
let r: BaseTabComponent[] = []
for (const child of this.children) {
if (child instanceof SplitContainer) {
r = r.concat(child.getAllTabs())
@@ -94,7 +94,7 @@ export class SplitContainer {
}
async serialize () {
const children = []
const children: any[] = []
for (const child of this.children) {
if (child instanceof SplitContainer) {
children.push(await child.serialize())
@@ -292,9 +292,9 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
/**
* Inserts a new `tab` to the `side` of the `relative` tab
*/
addTab (tab: BaseTabComponent, relative: BaseTabComponent, side: SplitDirection) {
let target = this.getParentOf(relative) || this.root
let insertIndex = target.children.indexOf(relative)
addTab (tab: BaseTabComponent, relative: BaseTabComponent|null, side: SplitDirection) {
let target = (relative ? this.getParentOf(relative) : null) || this.root
let insertIndex = relative ? target.children.indexOf(relative) : -1
if (
target.orientation === 'v' && ['l', 'r'].includes(side) ||
@@ -302,7 +302,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
) {
const newContainer = new SplitContainer()
newContainer.orientation = target.orientation === 'v' ? 'h' : 'v'
newContainer.children = [relative]
newContainer.children = relative ? [relative] : []
newContainer.ratios = [1]
target.children[insertIndex] = newContainer
target = newContainer
@@ -333,6 +333,9 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
removeTab (tab: BaseTabComponent) {
const parent = this.getParentOf(tab)
if (!parent) {
return
}
const index = parent.children.indexOf(tab)
parent.ratios.splice(index, 1)
parent.children.splice(index, 1)
@@ -356,11 +359,18 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
navigate (dir: SplitDirection) {
let rel: BaseTabComponent | SplitContainer = this.focusedTab
let parent = this.getParentOf(rel)
if (!parent) {
return
}
const orientation = ['l', 'r'].includes(dir) ? 'h' : 'v'
while (parent !== this.root && parent.orientation !== orientation) {
rel = parent
parent = this.getParentOf(rel)
if (!parent) {
return
}
}
if (parent.orientation !== orientation) {
@@ -381,13 +391,15 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
async splitTab (tab: BaseTabComponent, dir: SplitDirection) {
const newTab = await this.tabsService.duplicate(tab)
this.addTab(newTab, tab, dir)
if (newTab) {
this.addTab(newTab, tab, dir)
}
}
/**
* @returns the immediate parent of `tab`
*/
getParentOf (tab: BaseTabComponent | SplitContainer, root?: SplitContainer): SplitContainer {
getParentOf (tab: BaseTabComponent | SplitContainer, root?: SplitContainer): SplitContainer|null {
root = root || this.root
for (const child of root.children) {
if (child instanceof SplitContainer) {
@@ -414,8 +426,8 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
}
/** @hidden */
async getCurrentProcess (): Promise<BaseTabProcess> {
return (await Promise.all(this.getAllTabs().map(x => x.getCurrentProcess()))).find(x => !!x)
async getCurrentProcess (): Promise<BaseTabProcess|null> {
return (await Promise.all(this.getAllTabs().map(x => x.getCurrentProcess()))).find(x => !!x) || null
}
/** @hidden */
@@ -443,8 +455,10 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
private detachTabView (tab: BaseTabComponent) {
const ref = this.viewRefs.get(tab)
this.viewRefs.delete(tab)
this.viewContainer.remove(this.viewContainer.indexOf(ref))
if (ref) {
this.viewRefs.delete(tab)
this.viewContainer.remove(this.viewContainer.indexOf(ref))
}
}
private layout () {
@@ -471,7 +485,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
if (child instanceof SplitContainer) {
this.layoutInternal(child, childX, childY, childW, childH)
} else {
const element = this.viewRefs.get(child).rootNodes[0]
const element = this.viewRefs.get(child)!.rootNodes[0]
element.style.position = 'absolute'
element.style.left = `${childX}%`
element.style.top = `${childY}%`
@@ -518,7 +532,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
/** @hidden */
@Injectable()
export class SplitTabRecoveryProvider extends TabRecoveryProvider {
async recover (recoveryToken: any): Promise<RecoveredTab> {
async recover (recoveryToken: any): Promise<RecoveredTab|null> {
if (recoveryToken && recoveryToken.type === 'app:split-tab') {
return {
type: SplitTabComponent,

View File

@@ -67,13 +67,13 @@ export class SplitTabSpannerComponent {
this.container.x,
this.container.y + this.container.h * this.container.getOffsetRatio(this.index),
this.container.w,
null
0
)
} else {
this.setDimensions(
this.container.x + this.container.w * this.container.getOffsetRatio(this.index),
this.container.y,
null,
0,
this.container.h
)
}
@@ -82,7 +82,7 @@ export class SplitTabSpannerComponent {
private setDimensions (x: number, y: number, w: number, h: number) {
this.cssLeft = `${x}%`
this.cssTop = `${y}%`
this.cssWidth = w ? `${w}%` : null
this.cssHeight = h ? `${h}%` : null
this.cssWidth = w ? `${w}%` : 'initial'
this.cssHeight = h ? `${h}%` : 'initial'
}
}

View File

@@ -25,7 +25,7 @@ export class TabHeaderComponent {
@Input() @HostBinding('class.active') active: boolean
@Input() @HostBinding('class.has-activity') hasActivity: boolean
@Input() tab: BaseTabComponent
@Input() progress: number
@Input() progress: number|null
@ViewChild('handle') handle: ElementRef
private constructor (
@@ -83,7 +83,7 @@ export class TabHeaderComponent {
this.app.closeTab(this.tab, true)
}
if ($event.which === 3) {
event.preventDefault()
$event.preventDefault()
const contextMenu = this.electron.remote.Menu.buildFromTemplate(await this.buildContextMenu())

View File

@@ -12,6 +12,8 @@ export class WindowControlsComponent {
constructor (public hostApp: HostAppService, public app: AppService) { }
async closeWindow () {
await this.app.closeAllTabs() && this.hostApp.closeWindow()
if (await this.app.closeAllTabs()) {
this.hostApp.closeWindow()
}
}
}

View File

@@ -25,14 +25,14 @@ class CompletionObserver {
async tick () {
if (!await this.tab.getCurrentProcess()) {
this.done.next(null)
this.done.next()
this.stop()
}
}
stop () {
clearInterval(this.interval)
this.destroyed.next(null)
this.destroyed.next()
this.destroyed.complete()
this.done.complete()
}
@@ -144,7 +144,7 @@ export class AppService {
if (this.tabs.includes(this._activeTab)) {
this.lastTabIndex = this.tabs.indexOf(this._activeTab)
} else {
this.lastTabIndex = null
this.lastTabIndex = 0
}
if (this._activeTab) {
this._activeTab.clearActivity()
@@ -229,7 +229,7 @@ export class AppService {
/** @hidden */
emitReady () {
this.ready.next(null)
this.ready.next()
this.ready.complete()
this.hostApp.emitReady()
}
@@ -246,7 +246,7 @@ export class AppService {
})
this.completionObservers.set(tab, observer)
}
return this.completionObservers.get(tab).done$
return this.completionObservers.get(tab)!.done$
}
stopObservingTabCompletion (tab: BaseTabComponent) {

View File

@@ -95,7 +95,7 @@ export class ConfigService {
private changed = new Subject<void>()
private _store: any
private defaults: any
private servicesCache: { [id: string]: Function[] } = null
private servicesCache: { [id: string]: Function[] }|null = null
get changed$ (): Observable<void> { return this.changed }
@@ -170,7 +170,7 @@ export class ConfigService {
*
* @typeparam T Base provider type
*/
enabledServices<T> (services: T[]): T[] {
enabledServices<T extends object> (services: T[]): T[] {
if (!this.servicesCache) {
this.servicesCache = {}
const ngModule = window['rootModule'].ngInjectorDef

View File

@@ -215,7 +215,7 @@ export class HostAppService {
setVibrancy (enable: boolean, type: string) {
document.body.classList.toggle('vibrant', enable)
if (this.platform === Platform.macOS) {
this.getWindow().setVibrancy(enable ? 'dark' : null)
this.getWindow().setVibrancy(enable ? 'dark' : null as any) // electron issue 20269
}
if (this.platform === Platform.Windows) {
this.electron.ipcRenderer.send('window-set-vibrancy', enable, type)

View File

@@ -93,7 +93,7 @@ export class HotkeysService {
return stringifyKeySequence(this.currentKeystrokes.map(x => x.event))
}
getCurrentFullyMatchedHotkey (): string {
getCurrentFullyMatchedHotkey (): string|null {
const currentStrokes = this.getCurrentKeystrokes()
const config = this.getHotkeysConfig()
for (const id in config) {
@@ -116,7 +116,7 @@ export class HotkeysService {
getCurrentPartiallyMatchedHotkeys (): PartialHotkeyMatch[] {
const currentStrokes = this.getCurrentKeystrokes()
const config = this.getHotkeysConfig()
const result = []
const result: PartialHotkeyMatch[] = []
for (const id in config) {
for (const sequence of config[id]) {
for (let matchLength = Math.min(currentStrokes.length, sequence.length); matchLength > 0; matchLength--) {

View File

@@ -15,7 +15,7 @@ export function stringifyKeySequence (events: KeyboardEvent[]): string[] {
events = events.slice()
while (events.length > 0) {
const event = events.shift()
const event = events.shift()!
if ((event as any).event === 'keydown') {
const itemKeys: string[] = []
if (event.ctrlKey) {

View File

@@ -37,7 +37,7 @@ export class ShellIntegrationService {
'extras',
'automator-workflows',
)
this.automatorWorkflowsDestination = path.join(process.env.HOME, 'Library', 'Services')
this.automatorWorkflowsDestination = path.join(process.env.HOME as string, 'Library', 'Services')
}
this.updatePaths()
}

View File

@@ -27,7 +27,7 @@ export class TabRecoveryService {
)
}
async recoverTab (token: any): Promise<RecoveredTab> {
async recoverTab (token: any): Promise<RecoveredTab|null> {
for (const provider of this.config.enabledServices(this.tabRecoveryProviders)) {
try {
const tab = await provider.recover(token)

View File

@@ -29,7 +29,7 @@ export class TabsService {
/**
* Duplicates an existing tab instance (using the tab recovery system)
*/
async duplicate (tab: BaseTabComponent): Promise<BaseTabComponent> {
async duplicate (tab: BaseTabComponent): Promise<BaseTabComponent|null> {
const token = await tab.getRecoveryToken()
if (!token) {
return null

View File

@@ -4,7 +4,7 @@ import { Theme } from '../api/theme'
@Injectable({ providedIn: 'root' })
export class ThemesService {
private styleElement: HTMLElement = null
private styleElement: HTMLElement|null = null
/** @hidden */
constructor (
@@ -17,22 +17,22 @@ export class ThemesService {
})
}
findTheme (name: string): Theme {
return this.config.enabledServices(this.themes).find(x => x.name === name)
findTheme (name: string): Theme|null {
return this.config.enabledServices(this.themes).find(x => x.name === name) || null
}
findCurrentTheme (): Theme {
return this.findTheme(this.config.store.appearance.theme) || this.findTheme('Standard')
return this.findTheme(this.config.store.appearance.theme) || this.findTheme('Standard')!
}
applyTheme (theme: Theme): void {
if (!this.styleElement) {
this.styleElement = document.createElement('style')
this.styleElement.setAttribute('id', 'theme')
document.querySelector('head').appendChild(this.styleElement)
document.querySelector('head')!.appendChild(this.styleElement)
}
this.styleElement.textContent = theme.css
document.querySelector('style#custom-css').innerHTML = this.config.store.appearance.css
document.querySelector('style#custom-css')!.innerHTML = this.config.store.appearance.css
}
private applyCurrentTheme (): void {

View File

@@ -42,7 +42,7 @@ export class TouchbarService {
const showIcon = this.app.activeTab !== tab && hasActivity
const segment = this.tabSegments[app.tabs.indexOf(tab)]
if (segment) {
segment.icon = showIcon ? activityIcon : null
segment.icon = showIcon ? activityIcon : undefined
}
})
})
@@ -83,7 +83,9 @@ export class TouchbarService {
segments: buttons.map(button => this.getButton(button)),
mode: 'buttons',
change: (selectedIndex) => this.zone.run(() => {
buttons[selectedIndex].click()
if (buttons[selectedIndex].click) {
buttons[selectedIndex].click!()
}
}),
})
@@ -100,8 +102,8 @@ export class TouchbarService {
private getButton (button: ToolbarButton): Electron.SegmentedControlSegment {
return {
label: button.touchBarNSImage ? null : this.shortenTitle(button.touchBarTitle || button.title),
icon: button.touchBarNSImage ? this.getCachedNSImage(button.touchBarNSImage) : null,
label: button.touchBarNSImage ? undefined : this.shortenTitle(button.touchBarTitle || button.title),
icon: button.touchBarNSImage ? this.getCachedNSImage(button.touchBarNSImage) : undefined,
// click: () => this.zone.run(() => button.click()),
}
}

View File

@@ -78,7 +78,7 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
return [
{
label: 'Rename',
click: () => this.zone.run(() => tabHeader.showRenameTabModal()),
click: () => this.zone.run(() => tabHeader && tabHeader.showRenameTabModal()),
},
{
label: 'Duplicate',
@@ -86,7 +86,7 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
},
{
label: 'Color',
sublabel: COLORS.find(x => x.value === tab.color).name,
sublabel: COLORS.find(x => x.value === tab.color)!.name,
submenu: COLORS.map(color => ({
label: color.name,
type: 'radio',