Browse Source

prepared terminus-core for typedocs

Eugene Pankov 6 years ago
parent
commit
2ed35cb400
47 changed files with 766 additions and 219 deletions
  1. 2 0
      .gitignore
  2. 1 0
      package.json
  3. 29 0
      terminus-core/README.md
  4. 34 1
      terminus-core/src/api/configProvider.ts
  5. 6 2
      terminus-core/src/api/hotkeyProvider.ts
  6. 3 0
      terminus-core/src/api/tabContextMenuProvider.ts
  7. 30 2
      terminus-core/src/api/tabRecovery.ts
  8. 8 0
      terminus-core/src/api/theme.ts
  9. 21 1
      terminus-core/src/api/toolbarButtonProvider.ts
  10. 6 0
      terminus-core/src/components/appRoot.component.ts
  11. 66 7
      terminus-core/src/components/baseTab.component.ts
  12. 1 0
      terminus-core/src/components/checkbox.component.ts
  13. 1 0
      terminus-core/src/components/renameTabModal.component.ts
  14. 1 0
      terminus-core/src/components/safeModeModal.component.ts
  15. 80 8
      terminus-core/src/components/splitTab.component.ts
  16. 1 0
      terminus-core/src/components/splitTabSpanner.component.ts
  17. 1 0
      terminus-core/src/components/startPage.component.ts
  18. 1 0
      terminus-core/src/components/tabBody.component.ts
  19. 1 0
      terminus-core/src/components/tabHeader.component.ts
  20. 1 0
      terminus-core/src/components/titleBar.component.ts
  21. 1 0
      terminus-core/src/components/toggle.component.ts
  22. 1 1
      terminus-core/src/components/windowControls.component.pug
  23. 6 0
      terminus-core/src/components/windowControls.component.ts
  24. 1 0
      terminus-core/src/config.ts
  25. 1 0
      terminus-core/src/directives/autofocus.directive.ts
  26. 117 0
      terminus-core/src/hotkeys.ts
  27. 2 2
      terminus-core/src/index.ts
  28. 40 27
      terminus-core/src/services/app.service.ts
  29. 27 1
      terminus-core/src/services/config.service.ts
  30. 2 1
      terminus-core/src/services/docking.service.ts
  31. 4 12
      terminus-core/src/services/electron.service.ts
  32. 1 0
      terminus-core/src/services/homeBase.service.ts
  33. 54 15
      terminus-core/src/services/hostApp.service.ts
  34. 19 123
      terminus-core/src/services/hotkeys.service.ts
  35. 7 7
      terminus-core/src/services/hotkeys.util.ts
  36. 2 1
      terminus-core/src/services/log.service.ts
  37. 1 1
      terminus-core/src/services/shellIntegration.service.ts
  38. 1 0
      terminus-core/src/services/tabRecovery.service.ts
  39. 7 1
      terminus-core/src/services/tabs.service.ts
  40. 2 1
      terminus-core/src/services/themes.service.ts
  41. 1 0
      terminus-core/src/services/touchbar.service.ts
  42. 1 0
      terminus-core/src/services/updater.service.ts
  43. 4 1
      terminus-core/src/tabContextMenu.ts
  44. 3 0
      terminus-core/src/theme.ts
  45. 2 3
      terminus-plugin-manager/src/components/pluginsSettingsTab.component.ts
  46. 7 0
      typedoc.js
  47. 158 1
      yarn.lock

+ 2 - 0
.gitignore

@@ -18,3 +18,5 @@ npm-debug.log
 builtin-plugins
 package-lock.json
 yarn-error.log
+
+docs/api

+ 1 - 0
package.json

@@ -45,6 +45,7 @@
     "tslint": "^5.12.0",
     "tslint-config-standard": "^8.0.1",
     "tslint-eslint-rules": "^5.4.0",
+    "typedoc": "^0.14.2",
     "typescript": "^3.1.3",
     "url-loader": "^1.1.1",
     "val-loader": "0.5.0",

+ 29 - 0
terminus-core/README.md

@@ -0,0 +1,29 @@
+Terminus Core Plugin
+--------------------
+
+* tabbed interface services
+* toolbar UI
+* config file management
+* hotkeys
+* tab recovery
+* logging
+* theming
+
+Using the API:
+
+```ts
+import { AppService, TabContextMenuItemProvider } from 'terminus-core'
+```
+
+Exporting your subclasses:
+
+```ts
+@NgModule({
+  ...
+  providers: [
+    ...
+    { provide: TabContextMenuItemProvider, useClass: MyContextMenu, multi: true },
+    ...
+  ]
+})
+```

+ 34 - 1
terminus-core/src/api/configProvider.ts

@@ -1,4 +1,37 @@
+/**
+ * Extend to add your own config options
+ */
 export abstract class ConfigProvider {
+    /**
+     * Default values, e.g.
+     *
+     * ```ts
+     * defaults = {
+     *   myPlugin: {
+     *     foo: 1
+     *   }
+     * }
+     * ```
+     */
     defaults: any = {}
-    platformDefaults: any = {}
+
+    /**
+     * [[Platform]] specific defaults, e.g.
+     *
+     * ```ts
+     * platformDefaults = {
+     *   [Platform.Windows]: {
+     *     myPlugin: {
+     *       bar: true
+     *     }
+     *   },
+     *   [Platform.macOS]: {
+     *     myPlugin: {
+     *       bar: false
+     *     }
+     *   },
+     * }
+     * ```
+     */
+    platformDefaults: {[platform: string]: any} = {}
 }

+ 6 - 2
terminus-core/src/api/hotkeyProvider.ts

@@ -1,8 +1,12 @@
 export interface IHotkeyDescription {
-    id: string,
-    name: string,
+    id: string
+    name: string
 }
 
+/**
+ * Extend to provide your own hotkeys. A corresponding [[ConfigProvider]]
+ * must also provide the `hotkeys.foo` config options with the default values
+ */
 export abstract class HotkeyProvider {
     hotkeys: IHotkeyDescription[] = []
 

+ 3 - 0
terminus-core/src/api/tabContextMenuProvider.ts

@@ -1,6 +1,9 @@
 import { BaseTabComponent } from '../components/baseTab.component'
 import { TabHeaderComponent } from '../components/tabHeader.component'
 
+/**
+ * Extend to add items to the tab header's context menu
+ */
 export abstract class TabContextMenuItemProvider {
     weight = 0
 

+ 30 - 2
terminus-core/src/api/tabRecovery.ts

@@ -1,10 +1,38 @@
 import { TabComponentType } from '../services/tabs.service'
 
 export interface RecoveredTab {
-    type: TabComponentType,
-    options?: any,
+    /**
+     * Component type to be instantiated
+     */
+    type: TabComponentType
+
+    /**
+     * Component instance inputs
+     */
+    options?: any
 }
 
+/**
+ * Extend to enable recovery for your custom tab.
+ * This works in conjunction with [[getRecoveryToken()]]
+ *
+ * Terminus will try to find any [[TabRecoveryProvider]] that is able to process
+ * the recovery token previously returned by [[getRecoveryToken]].
+ *
+ * Recommended token format:
+ *
+ * ```json
+ * {
+ *   type: 'my-tab-type',
+ *   foo: 'bar',
+ * }
+ * ```
+ */
 export abstract class TabRecoveryProvider {
+    /**
+     * @param recoveryToken a recovery token found in the saved tabs list
+     * @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>
 }

+ 8 - 0
terminus-core/src/api/theme.ts

@@ -1,5 +1,13 @@
+/**
+ * Extend to add a custom CSS theme
+ */
 export abstract class Theme {
     name: string
+
+    /**
+     * Complete CSS stylesheet
+     */
     css: string
+
     terminalBackground: string
 }

+ 21 - 1
terminus-core/src/api/toolbarButtonProvider.ts

@@ -1,14 +1,34 @@
 import { SafeHtml } from '@angular/platform-browser'
 
+/**
+ * See [[ToolbarButtonProvider]]
+ */
 export interface IToolbarButton {
+    /**
+     * Raw SVG icon code
+     */
     icon: SafeHtml
-    touchBarNSImage?: string
+
     title: string
+
+    /**
+     * Optional Touch Bar icon ID
+     */
+    touchBarNSImage?: string
+
+    /**
+     * Optional Touch Bar button label
+     */
     touchBarTitle?: string
+
     weight?: number
+
     click: () => void
 }
 
+/**
+ * Extend to add buttons to the toolbar
+ */
 export abstract class ToolbarButtonProvider {
     abstract provide (): IToolbarButton[]
 }

+ 6 - 0
terminus-core/src/components/appRoot.component.ts

@@ -17,6 +17,7 @@ import { BaseTabComponent } from './baseTab.component'
 import { SafeModeModalComponent } from './safeModeModal.component'
 import { AppService, IToolbarButton, ToolbarButtonProvider } from '../api'
 
+/** @hidden */
 @Component({
     selector: 'app-root',
     template: require('./appRoot.component.pug'),
@@ -126,6 +127,11 @@ export class AppRootComponent {
             this.onGlobalHotkey()
         })
 
+        this.hostApp.windowCloseRequest$.subscribe(async () => {
+            await this.app.closeAllTabs()
+            this.hostApp.closeWindow()
+        })
+
         if (window['safeModeReason']) {
             ngbModal.open(SafeModeModalComponent)
         }

+ 66 - 7
terminus-core/src/components/baseTab.component.ts

@@ -1,26 +1,58 @@
 import { Observable, Subject } from 'rxjs'
 import { ViewRef } from '@angular/core'
 
+/**
+ * Represents an active "process" inside a tab,
+ * for example, a user process running inside a terminal tab
+ */
 export interface BaseTabProcess {
     name: string
 }
 
+/**
+ * Abstract base class for custom tab components
+ */
 export abstract class BaseTabComponent {
+    /**
+     * Current tab title
+     */
     title: string
+
+    /**
+     * User-defined title override
+     */
     customTitle: string
-    hasFocus = false
+
+    /**
+     * Last tab activity state
+     */
     hasActivity = false
+
+    /**
+     * ViewRef to the tab DOM element
+     */
     hostView: ViewRef
+
+    /**
+     * CSS color override for the tab's header
+     */
     color: string = null
-    protected titleChange = new Subject<string>()
-    protected focused = new Subject<void>()
-    protected blurred = new Subject<void>()
-    protected progress = new Subject<number>()
-    protected activity = new Subject<boolean>()
-    protected destroyed = new Subject<void>()
+
+    protected hasFocus = false
+
+    /**
+     * Ping this if your recovery state has been changed and you want
+     * your tab state to be saved sooner
+     */
     protected recoveryStateChangedHint = new Subject<void>()
 
     private progressClearTimeout: number
+    private titleChange = new Subject<string>()
+    private focused = new Subject<void>()
+    private blurred = new Subject<void>()
+    private progress = new Subject<number>()
+    private activity = new Subject<boolean>()
+    private destroyed = new Subject<void>()
 
     get focused$ (): Observable<void> { return this.focused }
     get blurred$ (): Observable<void> { return this.blurred }
@@ -46,6 +78,11 @@ export abstract class BaseTabComponent {
         }
     }
 
+    /**
+     * Sets visual progressbar on the tab
+     *
+     * @param  {type} progress: value between 0 and 1, or `null` to remove
+     */
     setProgress (progress: number) {
         this.progress.next(progress)
         if (progress) {
@@ -58,24 +95,43 @@ export abstract class BaseTabComponent {
         }
     }
 
+    /**
+     * Shows the acticity marker on the tab header
+     */
     displayActivity (): void {
         this.hasActivity = true
         this.activity.next(true)
     }
 
+    /**
+     * Removes the acticity marker from the tab header
+     */
     clearActivity (): void {
         this.hasActivity = false
         this.activity.next(false)
     }
 
+    /**
+     * Override this and implement a [[TabRecoveryProvider]] to enable recovery
+     * for your custom tab
+     *
+     * @return JSON serializable tab state representation
+     *         for your [[TabRecoveryProvider]] to parse
+     */
     async getRecoveryToken (): Promise<any> {
         return null
     }
 
+    /**
+     * Override this to enable task completion notifications for the tab
+     */
     async getCurrentProcess (): Promise<BaseTabProcess> {
         return null
     }
 
+    /**
+     * Return false to prevent the tab from being closed
+     */
     async canClose (): Promise<boolean> {
         return true
     }
@@ -88,6 +144,9 @@ export abstract class BaseTabComponent {
         this.blurred.next()
     }
 
+    /**
+     * Called before the tab is closed
+     */
     destroy (): void {
         this.focused.complete()
         this.blurred.complete()

+ 1 - 0
terminus-core/src/components/checkbox.component.ts

@@ -1,6 +1,7 @@
 import { NgZone, Component, Input, HostBinding, HostListener } from '@angular/core'
 import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
 
+/** @hidden */
 @Component({
     selector: 'checkbox',
     template: require('./checkbox.component.pug'),

+ 1 - 0
terminus-core/src/components/renameTabModal.component.ts

@@ -1,6 +1,7 @@
 import { Component, Input, ElementRef, ViewChild } from '@angular/core'
 import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
 
+/** @hidden */
 @Component({
     selector: 'rename-tab-modal',
     template: require('./renameTabModal.component.pug'),

+ 1 - 0
terminus-core/src/components/safeModeModal.component.ts

@@ -1,6 +1,7 @@
 import { Component, Input } from '@angular/core'
 import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
 
+/** @hidden */
 @Component({
     template: require('./safeModeModal.component.pug'),
 })

+ 80 - 8
terminus-core/src/components/splitTab.component.ts

@@ -9,15 +9,30 @@ import { TabRecoveryService } from '../services/tabRecovery.service'
 export declare type SplitOrientation = 'v' | 'h'
 export declare type SplitDirection = 'r' | 't' | 'b' | 'l'
 
+/**
+ * Describes a horizontal or vertical split row or column
+ */
 export class SplitContainer {
     orientation: SplitOrientation = 'h'
+
+    /**
+     * Children could be tabs or other containers
+     */
     children: (BaseTabComponent | SplitContainer)[] = []
+
+    /**
+     * Relative sizes of children, between 0 and 1. Total sum is 1
+     */
     ratios: number[] = []
+
     x: number
     y: number
     w: number
     h: number
 
+    /**
+     * @return Flat list of all tabs inside this container
+     */
     getAllTabs () {
         let r = []
         for (let child of this.children) {
@@ -30,6 +45,9 @@ export class SplitContainer {
         return r
     }
 
+    /**
+     * Remove unnecessarily nested child containers and renormalizes [[ratios]]
+     */
     normalize () {
         for (let i = 0; i < this.children.length; i++) {
             let child = this.children[i]
@@ -64,6 +82,9 @@ export class SplitContainer {
         this.ratios = this.ratios.map(x => x / s)
     }
 
+    /**
+     * Gets the left/top side offset for the given element index (between 0 and 1)
+     */
     getOffsetRatio (index: number): number {
         let s = 0
         for (let i = 0; i < index; i++) {
@@ -90,11 +111,22 @@ export class SplitContainer {
     }
 }
 
+/**
+ * Represents a spanner (draggable border between two split areas)
+ */
 export interface SplitSpannerInfo {
     container: SplitContainer
+
+    /**
+     * Number of the right/bottom split in the container
+     */
     index: number
 }
 
+/**
+ * Split tab is a tab that contains other tabs and allows further splitting them
+ * You'll mainly encounter it inside [[AppService]].tabs
+ */
 @Component({
     selector: 'split-tab',
     template: `
@@ -109,23 +141,43 @@ export interface SplitSpannerInfo {
     styles: [require('./splitTab.component.scss')],
 })
 export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDestroy {
+    /** @hidden */
     @ViewChild('vc', { read: ViewContainerRef }) viewContainer: ViewContainerRef
+
+    /**
+     * Top-level split container
+     */
     root: SplitContainer
+
+    /** @hidden */
     _recoveredState: any
+
+    /** @hidden */
     _spanners: SplitSpannerInfo[] = []
+
     private focusedTab: BaseTabComponent
     private hotkeysSubscription: Subscription
     private viewRefs: Map<BaseTabComponent, EmbeddedViewRef<any>> = new Map()
 
-    protected tabAdded = new Subject<BaseTabComponent>()
-    protected tabRemoved = new Subject<BaseTabComponent>()
-    protected splitAdjusted = new Subject<SplitSpannerInfo>()
-    protected focusChanged = new Subject<BaseTabComponent>()
+    private tabAdded = new Subject<BaseTabComponent>()
+    private tabRemoved = new Subject<BaseTabComponent>()
+    private splitAdjusted = new Subject<SplitSpannerInfo>()
+    private focusChanged = new Subject<BaseTabComponent>()
+
     get tabAdded$ (): Observable<BaseTabComponent> { return this.tabAdded }
     get tabRemoved$ (): Observable<BaseTabComponent> { return this.tabRemoved }
+
+    /**
+     * Fired when split ratio is changed for a given spanner
+     */
     get splitAdjusted$ (): Observable<SplitSpannerInfo> { return this.splitAdjusted }
+
+    /**
+     * Fired when a different sub-tab gains focus
+     */
     get focusChanged$ (): Observable<BaseTabComponent> { return this.focusChanged }
 
+    /** @hidden */
     constructor (
         private hotkeys: HotkeysService,
         private tabsService: TabsService,
@@ -174,6 +226,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
         })
     }
 
+    /** @hidden */
     async ngOnInit () {
         if (this._recoveredState) {
             await this.recoverContainer(this.root, this._recoveredState)
@@ -185,10 +238,12 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
         }
     }
 
+    /** @hidden */
     ngOnDestroy () {
         this.hotkeysSubscription.unsubscribe()
     }
 
+    /** @returns Flat list of all sub-tabs */
     getAllTabs () {
         return this.root.getAllTabs()
     }
@@ -211,6 +266,9 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
         this.layout()
     }
 
+    /**
+     * Focuses the first available tab inside the given [[SplitContainer]]
+     */
     focusAnyIn (parent: BaseTabComponent | SplitContainer) {
         if (!parent) {
             return
@@ -222,13 +280,16 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
         }
     }
 
-    addTab (tab: BaseTabComponent, relative: BaseTabComponent, dir: SplitDirection) {
+    /**
+     * 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)
 
         if (
-            (target.orientation === 'v' && ['l', 'r'].includes(dir)) ||
-            (target.orientation === 'h' && ['t', 'b'].includes(dir))
+            (target.orientation === 'v' && ['l', 'r'].includes(side)) ||
+            (target.orientation === 'h' && ['t', 'b'].includes(side))
         ) {
             let newContainer = new SplitContainer()
             newContainer.orientation = (target.orientation === 'v') ? 'h' : 'v'
@@ -242,7 +303,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
         if (insertIndex === -1) {
             insertIndex = 0
         } else {
-            insertIndex += (dir === 'l' || dir === 't') ? 0 : 1
+            insertIndex += (side === 'l' || side === 't') ? 0 : 1
         }
 
         for (let i = 0; i < target.children.length; i++) {
@@ -278,6 +339,9 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
         }
     }
 
+    /**
+     * Moves focus in the given direction
+     */
     navigate (dir: SplitDirection) {
         let rel: BaseTabComponent | SplitContainer = this.focusedTab
         let parent = this.getParentOf(rel)
@@ -309,6 +373,9 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
         this.addTab(newTab, tab, dir)
     }
 
+    /**
+     * @returns the immediate parent of `tab`
+     */
     getParentOf (tab: BaseTabComponent | SplitContainer, root?: SplitContainer): SplitContainer {
         root = root || this.root
         for (let child of root.children) {
@@ -325,18 +392,22 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
         return null
     }
 
+    /** @hidden */
     async canClose (): Promise<boolean> {
         return !(await Promise.all(this.getAllTabs().map(x => x.canClose()))).some(x => !x)
     }
 
+    /** @hidden */
     async getRecoveryToken (): Promise<any> {
         return this.root.serialize()
     }
 
+    /** @hidden */
     async getCurrentProcess (): Promise<BaseTabProcess> {
         return (await Promise.all(this.getAllTabs().map(x => x.getCurrentProcess()))).find(x => !!x)
     }
 
+    /** @hidden */
     onSpannerAdjusted (spanner: SplitSpannerInfo) {
         this.layout()
         this.splitAdjusted.next(spanner)
@@ -433,6 +504,7 @@ export class SplitTabComponent extends BaseTabComponent implements OnInit, OnDes
     }
 }
 
+/** @hidden */
 @Injectable()
 export class SplitTabRecoveryProvider extends TabRecoveryProvider {
     async recover (recoveryToken: any): Promise<RecoveredTab> {

+ 1 - 0
terminus-core/src/components/splitTabSpanner.component.ts

@@ -1,6 +1,7 @@
 import { Component, Input, HostBinding, ElementRef, Output, EventEmitter } from '@angular/core'
 import { SplitContainer } from './splitTab.component'
 
+/** @hidden */
 @Component({
     selector: 'split-tab-spanner',
     template: '',

+ 1 - 0
terminus-core/src/components/startPage.component.ts

@@ -3,6 +3,7 @@ import { ConfigService } from '../services/config.service'
 import { HomeBaseService } from '../services/homeBase.service'
 import { IToolbarButton, ToolbarButtonProvider } from '../api'
 
+/** @hidden */
 @Component({
     selector: 'start-page',
     template: require('./startPage.component.pug'),

+ 1 - 0
terminus-core/src/components/tabBody.component.ts

@@ -1,6 +1,7 @@
 import { Component, Input, ViewChild, HostBinding, ViewContainerRef, OnChanges } from '@angular/core'
 import { BaseTabComponent } from '../components/baseTab.component'
 
+/** @hidden */
 @Component({
     selector: 'tab-body',
     template: `

+ 1 - 0
terminus-core/src/components/tabHeader.component.ts

@@ -9,6 +9,7 @@ import { ElectronService } from '../services/electron.service'
 import { AppService } from '../services/app.service'
 import { HostAppService, Platform } from '../services/hostApp.service'
 
+/** @hidden */
 @Component({
     selector: 'tab-header',
     template: require('./tabHeader.component.pug'),

+ 1 - 0
terminus-core/src/components/titleBar.component.ts

@@ -1,5 +1,6 @@
 import { Component } from '@angular/core'
 
+/** @hidden */
 @Component({
     selector: 'title-bar',
     template: require('./titleBar.component.pug'),

+ 1 - 0
terminus-core/src/components/toggle.component.ts

@@ -2,6 +2,7 @@ import { Component } from '@angular/core'
 import { NG_VALUE_ACCESSOR } from '@angular/forms'
 import { CheckboxComponent } from './checkbox.component'
 
+/** @hidden */
 @Component({
     selector: 'toggle',
     template: `

+ 1 - 1
terminus-core/src/components/windowControls.component.pug

@@ -9,7 +9,7 @@ button.btn.btn-secondary.btn-maximize(
     svg(version='1.1', width='10', height='10')
         path(d='M 0,0 0,10 10,10 10,0 Z M 1,1 9,1 9,9 1,9 Z')
 button.btn.btn-secondary.btn-close(
-    (click)='app.closeWindow()'
+    (click)='closeWindow()'
 )
     svg(version='1.1', width='10', height='10')
         path(d='M 0,0 0,0.7 4.3,5 0,9.3 0,10 0.7,10 5,5.7 9.3,10 10,10 10,9.3 5.7,5 10,0.7 10,0 9.3,0 5,4.3 0.7,0 Z')

+ 6 - 0
terminus-core/src/components/windowControls.component.ts

@@ -2,6 +2,7 @@ import { Component } from '@angular/core'
 import { HostAppService } from '../services/hostApp.service'
 import { AppService } from '../services/app.service'
 
+/** @hidden */
 @Component({
     selector: 'window-controls',
     template: require('./windowControls.component.pug'),
@@ -9,4 +10,9 @@ import { AppService } from '../services/app.service'
 })
 export class WindowControlsComponent {
     constructor (public hostApp: HostAppService, public app: AppService) { }
+
+    async closeWindow () {
+        await this.app.closeAllTabs()
+        this.hostApp.closeWindow()
+    }
 }

+ 1 - 0
terminus-core/src/config.ts

@@ -1,6 +1,7 @@
 import { ConfigProvider } from './api/configProvider'
 import { Platform } from './services/hostApp.service'
 
+/** @hidden */
 export class CoreConfigProvider extends ConfigProvider {
     platformDefaults = {
         [Platform.macOS]: require('./configDefaults.macos.yaml'),

+ 1 - 0
terminus-core/src/directives/autofocus.directive.ts

@@ -1,5 +1,6 @@
 import { Directive, AfterViewInit, ElementRef } from '@angular/core'
 
+/** @hidden */
 @Directive({
     selector: '[autofocus]'
 })

+ 117 - 0
terminus-core/src/hotkeys.ts

@@ -0,0 +1,117 @@
+import { Injectable } from '@angular/core'
+import { IHotkeyDescription, HotkeyProvider } from './api/hotkeyProvider'
+
+/** @hidden */
+@Injectable()
+export class AppHotkeyProvider extends HotkeyProvider {
+    hotkeys: IHotkeyDescription[] = [
+        {
+            id: 'new-window',
+            name: 'New window',
+        },
+        {
+            id: 'toggle-window',
+            name: 'Toggle terminal window',
+        },
+        {
+            id: 'toggle-fullscreen',
+            name: 'Toggle fullscreen mode',
+        },
+        {
+            id: 'rename-tab',
+            name: 'Rename Tab',
+        },
+        {
+            id: 'close-tab',
+            name: 'Close tab',
+        },
+        {
+            id: 'toggle-last-tab',
+            name: 'Toggle last tab',
+        },
+        {
+            id: 'next-tab',
+            name: 'Next tab',
+        },
+        {
+            id: 'previous-tab',
+            name: 'Previous tab',
+        },
+        {
+            id: 'tab-1',
+            name: 'Tab 1',
+        },
+        {
+            id: 'tab-2',
+            name: 'Tab 2',
+        },
+        {
+            id: 'tab-3',
+            name: 'Tab 3',
+        },
+        {
+            id: 'tab-4',
+            name: 'Tab 4',
+        },
+        {
+            id: 'tab-5',
+            name: 'Tab 5',
+        },
+        {
+            id: 'tab-6',
+            name: 'Tab 6',
+        },
+        {
+            id: 'tab-7',
+            name: 'Tab 7',
+        },
+        {
+            id: 'tab-8',
+            name: 'Tab 8',
+        },
+        {
+            id: 'tab-9',
+            name: 'Tab 9',
+        },
+        {
+            id: 'tab-10',
+            name: 'Tab 10',
+        },
+        {
+            id: 'split-right',
+            name: 'Split to the right',
+        },
+        {
+            id: 'split-bottom',
+            name: 'Split to the bottom',
+        },
+        {
+            id: 'split-left',
+            name: 'Split to the left',
+        },
+        {
+            id: 'split-top',
+            name: 'Split to the top',
+        },
+        {
+            id: 'split-nav-up',
+            name: 'Focus the pane above',
+        },
+        {
+            id: 'split-nav-down',
+            name: 'Focus the pane below',
+        },
+        {
+            id: 'split-nav-left',
+            name: 'Focus the pane on the left',
+        },
+        {
+            id: 'split-nav-right',
+            name: 'Focus the pane on the right',
+        },
+    ]
+
+    async provide (): Promise<IHotkeyDescription[]> {
+        return this.hotkeys
+    }
+}

+ 2 - 2
terminus-core/src/index.ts

@@ -6,8 +6,6 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
 import { PerfectScrollbarModule, PERFECT_SCROLLBAR_CONFIG } from 'ngx-perfect-scrollbar'
 import { DndModule } from 'ng2-dnd'
 
-import { AppHotkeyProvider } from './services/hotkeys.service'
-
 import { AppRootComponent } from './components/appRoot.component'
 import { CheckboxComponent } from './components/checkbox.component'
 import { TabBodyComponent } from './components/tabBody.component'
@@ -31,6 +29,7 @@ import { TabRecoveryProvider } from './api/tabRecovery'
 
 import { StandardTheme, StandardCompactTheme, PaperTheme } from './theme'
 import { CoreConfigProvider } from './config'
+import { AppHotkeyProvider } from './hotkeys'
 import { TaskCompletionContextMenu, CommonOptionsContextMenu, CloseContextMenu } from './tabContextMenu'
 
 import 'perfect-scrollbar/css/perfect-scrollbar.css'
@@ -49,6 +48,7 @@ const PROVIDERS = [
     { provide: PERFECT_SCROLLBAR_CONFIG, useValue: { suppressScrollX: true } }
 ]
 
+/** @hidden */
 @NgModule({
     imports: [
         BrowserModule,

+ 40 - 27
terminus-core/src/services/app.service.ts

@@ -3,7 +3,6 @@ import { takeUntil } from 'rxjs/operators'
 import { Injectable } from '@angular/core'
 import { BaseTabComponent } from '../components/baseTab.component'
 import { SplitTabComponent } from '../components/splitTab.component'
-import { Logger, LogService } from './log.service'
 import { ConfigService } from './config.service'
 import { HostAppService } from './hostApp.service'
 import { TabRecoveryService } from './tabRecovery.service'
@@ -39,9 +38,11 @@ class CompletionObserver {
 @Injectable({ providedIn: 'root' })
 export class AppService {
     tabs: BaseTabComponent[] = []
-    activeTab: BaseTabComponent
-    lastTabIndex = 0
-    logger: Logger
+
+    get activeTab (): BaseTabComponent { return this._activeTab }
+
+    private lastTabIndex = 0
+    private _activeTab: BaseTabComponent
 
     private activeTabChange = new Subject<BaseTabComponent>()
     private tabsChanged = new Subject<void>()
@@ -55,19 +56,17 @@ export class AppService {
     get tabOpened$ (): Observable<BaseTabComponent> { return this.tabOpened }
     get tabsChanged$ (): Observable<void> { return this.tabsChanged }
     get tabClosed$ (): Observable<BaseTabComponent> { return this.tabClosed }
+
+    /** Fires once when the app is ready */
     get ready$ (): Observable<void> { return this.ready }
 
+    /** @hidden */
     constructor (
         private config: ConfigService,
         private hostApp: HostAppService,
         private tabRecovery: TabRecoveryService,
         private tabsService: TabsService,
-        log: LogService,
     ) {
-        this.logger = log.create('app')
-
-        this.hostApp.windowCloseRequest$.subscribe(() => this.closeWindow())
-
         this.tabRecovery.recoverTabs().then(tabs => {
             for (let tab of tabs) {
                 this.openNewTabRaw(tab.type, tab.options)
@@ -82,7 +81,7 @@ export class AppService {
         })
     }
 
-    addTabRaw (tab: BaseTabComponent) {
+    private addTabRaw (tab: BaseTabComponent) {
         this.tabs.push(tab)
         this.selectTab(tab)
         this.tabsChanged.next()
@@ -93,7 +92,7 @@ export class AppService {
         })
 
         tab.titleChange$.subscribe(title => {
-            if (tab === this.activeTab) {
+            if (tab === this._activeTab) {
                 this.hostApp.setTitle(title)
             }
         })
@@ -101,7 +100,7 @@ export class AppService {
         tab.destroyed$.subscribe(() => {
             let newIndex = Math.max(0, this.tabs.indexOf(tab) - 1)
             this.tabs = this.tabs.filter((x) => x !== tab)
-            if (tab === this.activeTab) {
+            if (tab === this._activeTab) {
                 this.selectTab(this.tabs[newIndex])
             }
             this.tabsChanged.next()
@@ -109,12 +108,20 @@ export class AppService {
         })
     }
 
+    /**
+     * Adds a new tab **without** wrapping it in a SplitTabComponent
+     * @param inputs  Properties to be assigned on the new tab component instance
+     */
     openNewTabRaw (type: TabComponentType, inputs?: any): BaseTabComponent {
         let tab = this.tabsService.create(type, inputs)
         this.addTabRaw(tab)
         return tab
     }
 
+    /**
+     * Adds a new tab while wrapping it in a SplitTabComponent
+     * @param inputs  Properties to be assigned on the new tab component instance
+     */
     openNewTab (type: TabComponentType, inputs?: any): BaseTabComponent {
         let splitTab = this.tabsService.create(SplitTabComponent) as SplitTabComponent
         let tab = this.tabsService.create(type, inputs)
@@ -124,29 +131,30 @@ export class AppService {
     }
 
     selectTab (tab: BaseTabComponent) {
-        if (this.activeTab === tab) {
-            this.activeTab.emitFocused()
+        if (this._activeTab === tab) {
+            this._activeTab.emitFocused()
             return
         }
-        if (this.tabs.includes(this.activeTab)) {
-            this.lastTabIndex = this.tabs.indexOf(this.activeTab)
+        if (this.tabs.includes(this._activeTab)) {
+            this.lastTabIndex = this.tabs.indexOf(this._activeTab)
         } else {
             this.lastTabIndex = null
         }
-        if (this.activeTab) {
-            this.activeTab.clearActivity()
-            this.activeTab.emitBlurred()
+        if (this._activeTab) {
+            this._activeTab.clearActivity()
+            this._activeTab.emitBlurred()
         }
-        this.activeTab = tab
+        this._activeTab = tab
         this.activeTabChange.next(tab)
-        if (this.activeTab) {
+        if (this._activeTab) {
             setImmediate(() => {
-                this.activeTab.emitFocused()
+                this._activeTab.emitFocused()
             })
-            this.hostApp.setTitle(this.activeTab.title)
+            this.hostApp.setTitle(this._activeTab.title)
         }
     }
 
+    /** Switches between the current tab and the previously active one */
     toggleLastTab () {
         if (!this.lastTabIndex || this.lastTabIndex >= this.tabs.length) {
             this.lastTabIndex = 0
@@ -156,7 +164,7 @@ export class AppService {
 
     nextTab () {
         if (this.tabs.length > 1) {
-            let tabIndex = this.tabs.indexOf(this.activeTab)
+            let tabIndex = this.tabs.indexOf(this._activeTab)
             if (tabIndex < this.tabs.length - 1) {
                 this.selectTab(this.tabs[tabIndex + 1])
             } else if (this.config.store.appearance.cycleTabs) {
@@ -167,7 +175,7 @@ export class AppService {
 
     previousTab () {
         if (this.tabs.length > 1) {
-            let tabIndex = this.tabs.indexOf(this.activeTab)
+            let tabIndex = this.tabs.indexOf(this._activeTab)
             if (tabIndex > 0) {
                 this.selectTab(this.tabs[tabIndex - 1])
             } else if (this.config.store.appearance.cycleTabs) {
@@ -176,6 +184,7 @@ export class AppService {
         }
     }
 
+    /** @hidden */
     emitTabsChanged () {
         this.tabsChanged.next()
     }
@@ -197,7 +206,7 @@ export class AppService {
         }
     }
 
-    async closeWindow () {
+    async closeAllTabs () {
         for (let tab of this.tabs) {
             if (!await tab.canClose()) {
                 return
@@ -206,15 +215,19 @@ export class AppService {
         for (let tab of this.tabs) {
             tab.destroy()
         }
-        this.hostApp.closeWindow()
     }
 
+    /** @hidden */
     emitReady () {
         this.ready.next(null)
         this.ready.complete()
         this.hostApp.emitReady()
     }
 
+    /**
+     * Returns an observable that fires once
+     * the tab's internal "process" (see [[BaseTabProcess]]) completes
+     */
     observeTabCompletion (tab: BaseTabComponent): Observable<void> {
         if (!this.completionObservers.has(tab)) {
             let observer = new CompletionObserver(tab)

+ 27 - 1
terminus-core/src/services/config.service.ts

@@ -18,6 +18,7 @@ function isNonStructuralObjectMember (v) {
     return v instanceof Object && !(v instanceof Array) && v.__nonStructural
 }
 
+/** @hidden */
 export class ConfigProxy {
     constructor (real: any, defaults: any) {
         for (let key in defaults) {
@@ -76,9 +77,21 @@ export class ConfigProxy {
 
 @Injectable({ providedIn: 'root' })
 export class ConfigService {
+    /**
+     * Contains the actual config values
+     */
     store: any
+
+    /**
+     * Whether an app restart is required due to recent changes
+     */
     restartRequested: boolean
+
+    /**
+     * Full config file path
+     */
     path: string
+
     private changed = new Subject<void>()
     private _store: any
     private defaults: any
@@ -86,6 +99,7 @@ export class ConfigService {
 
     get changed$ (): Observable<void> { return this.changed }
 
+    /** @hidden */
     constructor (
         electron: ElectronService,
         private hostApp: HostAppService,
@@ -129,10 +143,16 @@ export class ConfigService {
         this.hostApp.broadcastConfigChange()
     }
 
+    /**
+     * Reads config YAML as string
+     */
     readRaw (): string {
         return yaml.safeDump(this._store)
     }
 
+    /**
+     * Writes config YAML as string
+     */
     writeRaw (data: string): void {
         this._store = yaml.safeLoad(data)
         this.save()
@@ -140,7 +160,7 @@ export class ConfigService {
         this.emitChange()
     }
 
-    emitChange (): void {
+    private emitChange (): void {
         this.changed.next()
     }
 
@@ -148,6 +168,12 @@ export class ConfigService {
         this.restartRequested = true
     }
 
+    /**
+     * Filters a list of Angular services to only include those provided
+     * by plugins that are enabled
+     *
+     * @typeparam T Base provider type
+     */
     enabledServices<T> (services: T[]): T[] {
         if (!this.servicesCache) {
             this.servicesCache = {}

+ 2 - 1
terminus-core/src/services/docking.service.ts

@@ -10,6 +10,7 @@ export interface IScreen {
 
 @Injectable({ providedIn: 'root' })
 export class DockingService {
+    /** @hidden */
     constructor (
         private electron: ElectronService,
         private config: ConfigService,
@@ -78,7 +79,7 @@ export class DockingService {
         })
     }
 
-    repositionWindow () {
+    private repositionWindow () {
         let [x, y] = this.hostApp.getWindow().getPosition()
         for (let screen of this.electron.screen.getAllDisplays()) {
             let bounds = screen.bounds

+ 4 - 12
terminus-core/src/services/electron.service.ts

@@ -24,6 +24,7 @@ export class ElectronService {
     MenuItem: typeof MenuItem
     private electron: any
 
+    /** @hidden */
     constructor () {
         this.electron = require('electron')
         this.remote = this.electron.remote
@@ -42,18 +43,9 @@ export class ElectronService {
         this.MenuItem = this.remote.MenuItem
     }
 
-    remoteRequire (name: string): any {
-        return this.remote.require(name)
-    }
-
-    remoteRequirePluginModule (plugin: string, module: string, globals: any): any {
-        return this.remoteRequire(this.remoteResolvePluginModule(plugin, module, globals))
-    }
-
-    remoteResolvePluginModule (plugin: string, module: string, globals: any): any {
-        return globals.require.resolve(`${plugin}/node_modules/${module}`)
-    }
-
+    /**
+     * Removes OS focus from Terminus' window
+     */
     loseFocus () {
         if (process.platform === 'darwin') {
             this.remote.Menu.sendActionToFirstResponder('hide:')

+ 1 - 0
terminus-core/src/services/homeBase.service.ts

@@ -9,6 +9,7 @@ import uuidv4 = require('uuid/v4')
 export class HomeBaseService {
     appVersion: string
 
+    /** @hidden */
     constructor (
         private electron: ElectronService,
         private config: ConfigService,

+ 54 - 15
terminus-core/src/services/hostApp.service.ts

@@ -16,12 +16,19 @@ export interface Bounds {
     height: number
 }
 
+/**
+ * Provides interaction with the main process
+ */
 @Injectable({ providedIn: 'root' })
 export class HostAppService {
     platform: Platform
-    nodePlatform: string
+
+    /**
+     * Fired once the window is visible
+     */
     shown = new EventEmitter<any>()
     isFullScreen = false
+
     private preferencesMenu = new Subject<void>()
     private secondInstance = new Subject<void>()
     private cliOpenDirectory = new Subject<string>()
@@ -35,29 +42,62 @@ export class HostAppService {
     private logger: Logger
     private windowId: number
 
+    /**
+     * Fired when Preferences is selected in the macOS menu
+     */
     get preferencesMenu$ (): Observable<void> { return this.preferencesMenu }
+
+    /**
+     * Fired when a second instance of Terminus is launched
+     */
     get secondInstance$ (): Observable<void> { return this.secondInstance }
+
+    /**
+     * Fired for the `terminus open` CLI command
+     */
     get cliOpenDirectory$ (): Observable<string> { return this.cliOpenDirectory }
+
+    /**
+     * Fired for the `terminus run` CLI command
+     */
     get cliRunCommand$ (): Observable<string[]> { return this.cliRunCommand }
+
+    /**
+     * Fired for the `terminus paste` CLI command
+     */
     get cliPaste$ (): Observable<string> { return this.cliPaste }
+
+    /**
+     * Fired for the `terminus profile` CLI command
+     */
     get cliOpenProfile$ (): Observable<string> { return this.cliOpenProfile }
+
+    /**
+     * Fired when another window modified the config file
+     */
     get configChangeBroadcast$ (): Observable<void> { return this.configChangeBroadcast }
+
+    /**
+     * Fired when the window close button is pressed
+     */
     get windowCloseRequest$ (): Observable<void> { return this.windowCloseRequest }
+
     get windowMoved$ (): Observable<void> { return this.windowMoved }
+
     get displayMetricsChanged$ (): Observable<void> { return this.displayMetricsChanged }
 
+    /** @hidden */
     constructor (
         private zone: NgZone,
         private electron: ElectronService,
         log: LogService,
     ) {
         this.logger = log.create('hostApp')
-        this.nodePlatform = require('os').platform()
         this.platform = {
             win32: Platform.Windows,
             darwin: Platform.macOS,
             linux: Platform.Linux
-        }[this.nodePlatform]
+        }[process.platform]
 
         this.windowId = parseInt(location.search.substring(1))
         this.logger.info('Window ID:', this.windowId)
@@ -117,6 +157,9 @@ export class HostAppService {
         }))
     }
 
+    /**
+     * Returns the current remote [[BrowserWindow]]
+     */
     getWindow () {
         return this.electron.BrowserWindow.fromId(this.windowId)
     }
@@ -125,18 +168,6 @@ export class HostAppService {
         this.electron.ipcRenderer.send('app:new-window')
     }
 
-    getShell () {
-        return this.electron.shell
-    }
-
-    getAppPath () {
-        return this.electron.app.getAppPath()
-    }
-
-    getPath (type: string) {
-        return this.electron.app.getPath(type)
-    }
-
     toggleFullscreen () {
         let window = this.getWindow()
         window.setFullScreen(!this.isFullScreen)
@@ -174,6 +205,11 @@ export class HostAppService {
         this.electron.ipcRenderer.send('window-set-always-on-top', flag)
     }
 
+    /**
+     * Sets window vibrancy mode (Windows, macOS)
+     *
+     * @param type `null`, or `fluent` when supported (Windowd only)
+     */
     setVibrancy (enable: boolean, type: string) {
         document.body.classList.toggle('vibrant', enable)
         if (this.platform === Platform.macOS) {
@@ -196,6 +232,9 @@ export class HostAppService {
         this.electron.Menu.buildFromTemplate(menuDefinition).popup({})
     }
 
+    /**
+     * Notifies other windows of config file changes
+     */
     broadcastConfigChange () {
         this.electron.ipcRenderer.send('app:config-change')
     }

+ 19 - 123
terminus-core/src/services/hotkeys.service.ts

@@ -5,16 +5,16 @@ import { ConfigService } from '../services/config.service'
 import { ElectronService } from '../services/electron.service'
 
 export interface PartialHotkeyMatch {
-    id: string,
-    strokes: string[],
-    matchedLength: number,
+    id: string
+    strokes: string[]
+    matchedLength: number
 }
 
 const KEY_TIMEOUT = 2000
 
 interface EventBufferEntry {
-    event: NativeKeyEvent,
-    time: number,
+    event: NativeKeyEvent
+    time: number
 }
 
 @Injectable({ providedIn: 'root' })
@@ -26,6 +26,7 @@ export class HotkeysService {
     private disabledLevel = 0
     private hotkeyDescriptions: IHotkeyDescription[] = []
 
+    /** @hidden */
     constructor (
         private zone: NgZone,
         private electron: ElectronService,
@@ -51,11 +52,20 @@ export class HotkeysService {
         })
     }
 
+    /**
+     * Adds a new key event to the buffer
+     *
+     * @param name DOM event name
+     * @param nativeEvent event object
+     */
     pushKeystroke (name, nativeEvent) {
         nativeEvent.event = name
         this.currentKeystrokes.push({ event: nativeEvent, time: performance.now() })
     }
 
+    /**
+     * Check the buffer for new complete keystrokes
+     */
     processKeystrokes () {
         if (this.isEnabled()) {
             this.zone.run(() => {
@@ -84,7 +94,7 @@ export class HotkeysService {
         return stringifyKeySequence(this.currentKeystrokes.map(x => x.event))
     }
 
-    registerGlobalHotkey () {
+    private registerGlobalHotkey () {
         this.electron.globalShortcut.unregisterAll()
         let value = this.config.store.hotkeys['toggle-window'] || []
         if (typeof value === 'string') {
@@ -103,11 +113,11 @@ export class HotkeysService {
         })
     }
 
-    getHotkeysConfig () {
+    private getHotkeysConfig () {
         return this.getHotkeysConfigRecursive(this.config.store.hotkeys)
     }
 
-    getHotkeysConfigRecursive (branch) {
+    private getHotkeysConfigRecursive (branch) {
         let keys = {}
         for (let key in branch) {
             let value = branch[key]
@@ -129,7 +139,7 @@ export class HotkeysService {
         return keys
     }
 
-    getCurrentFullyMatchedHotkey (): string {
+    private getCurrentFullyMatchedHotkey (): string {
         let currentStrokes = this.getCurrentKeystrokes()
         let config = this.getHotkeysConfig()
         for (let id in config) {
@@ -199,117 +209,3 @@ export class HotkeysService {
         ).reduce((a, b) => a.concat(b))
     }
 }
-
-@Injectable()
-export class AppHotkeyProvider extends HotkeyProvider {
-    hotkeys: IHotkeyDescription[] = [
-        {
-            id: 'new-window',
-            name: 'New window',
-        },
-        {
-            id: 'toggle-window',
-            name: 'Toggle terminal window',
-        },
-        {
-            id: 'toggle-fullscreen',
-            name: 'Toggle fullscreen mode',
-        },
-        {
-            id: 'rename-tab',
-            name: 'Rename Tab',
-        },
-        {
-            id: 'close-tab',
-            name: 'Close tab',
-        },
-        {
-            id: 'toggle-last-tab',
-            name: 'Toggle last tab',
-        },
-        {
-            id: 'next-tab',
-            name: 'Next tab',
-        },
-        {
-            id: 'previous-tab',
-            name: 'Previous tab',
-        },
-        {
-            id: 'tab-1',
-            name: 'Tab 1',
-        },
-        {
-            id: 'tab-2',
-            name: 'Tab 2',
-        },
-        {
-            id: 'tab-3',
-            name: 'Tab 3',
-        },
-        {
-            id: 'tab-4',
-            name: 'Tab 4',
-        },
-        {
-            id: 'tab-5',
-            name: 'Tab 5',
-        },
-        {
-            id: 'tab-6',
-            name: 'Tab 6',
-        },
-        {
-            id: 'tab-7',
-            name: 'Tab 7',
-        },
-        {
-            id: 'tab-8',
-            name: 'Tab 8',
-        },
-        {
-            id: 'tab-9',
-            name: 'Tab 9',
-        },
-        {
-            id: 'tab-10',
-            name: 'Tab 10',
-        },
-        {
-            id: 'split-right',
-            name: 'Split to the right',
-        },
-        {
-            id: 'split-bottom',
-            name: 'Split to the bottom',
-        },
-        {
-            id: 'split-left',
-            name: 'Split to the left',
-        },
-        {
-            id: 'split-top',
-            name: 'Split to the top',
-        },
-        {
-            id: 'split-nav-up',
-            name: 'Focus the pane above',
-        },
-        {
-            id: 'split-nav-down',
-            name: 'Focus the pane below',
-        },
-        {
-            id: 'split-nav-left',
-            name: 'Focus the pane on the left',
-        },
-        {
-            id: 'split-nav-right',
-            name: 'Focus the pane on the right',
-        },
-    ]
-
-    async provide (): Promise<IHotkeyDescription[]> {
-        return this.hotkeys
-    }
-}

+ 7 - 7
terminus-core/src/services/hotkeys.util.ts

@@ -11,13 +11,13 @@ export const altKeyName = {
 }[process.platform]
 
 export interface NativeKeyEvent {
-    event?: string,
-    altKey: boolean,
-    ctrlKey: boolean,
-    metaKey: boolean,
-    shiftKey: boolean,
-    key: string,
-    keyCode: string,
+    event?: string
+    altKey: boolean
+    ctrlKey: boolean
+    metaKey: boolean
+    shiftKey: boolean
+    key: string
+    keyCode: string
 }
 
 export function stringifyKeySequence (events: NativeKeyEvent[]): string[] {

+ 2 - 1
terminus-core/src/services/log.service.ts

@@ -39,7 +39,7 @@ export class Logger {
         private name: string,
     ) {}
 
-    doLog (level: string, ...args: any[]) {
+    private doLog (level: string, ...args: any[]) {
         console[level](`%c[${this.name}]`, 'color: #aaa', ...args)
         if (this.winstonLogger) {
             this.winstonLogger[level](...args)
@@ -57,6 +57,7 @@ export class Logger {
 export class LogService {
     private log: any
 
+    /** @hidden */
     constructor (electron: ElectronService) {
         this.log = initializeWinston(electron)
     }

+ 1 - 1
terminus-core/src/services/shellIntegration.service.ts

@@ -37,7 +37,7 @@ export class ShellIntegrationService {
         this.updatePaths()
     }
 
-    async updatePaths (): Promise<void> {
+    private async updatePaths (): Promise<void> {
         // Update paths in case of an update
         if (this.hostApp.platform === Platform.Windows) {
             if (await this.isInstalled()) {

+ 1 - 0
terminus-core/src/services/tabRecovery.service.ts

@@ -4,6 +4,7 @@ import { BaseTabComponent } from '../components/baseTab.component'
 import { Logger, LogService } from '../services/log.service'
 import { ConfigService } from '../services/config.service'
 
+/** @hidden */
 @Injectable({ providedIn: 'root' })
 export class TabRecoveryService {
     logger: Logger

+ 7 - 1
terminus-core/src/services/tabs.service.ts

@@ -6,12 +6,16 @@ export declare type TabComponentType = new (...args: any[]) => BaseTabComponent
 
 @Injectable({ providedIn: 'root' })
 export class TabsService {
+    /** @hidden */
     constructor (
         private componentFactoryResolver: ComponentFactoryResolver,
         private injector: Injector,
         private tabRecovery: TabRecoveryService,
     ) { }
 
+    /**
+     * Instantiates a tab component and assigns given inputs
+     */
     create (type: TabComponentType, inputs?: any): BaseTabComponent {
         let componentFactory = this.componentFactoryResolver.resolveComponentFactory(type)
         let componentRef = componentFactory.create(this.injector)
@@ -21,6 +25,9 @@ export class TabsService {
         return tab
     }
 
+    /**
+     * Duplicates an existing tab instance (using the tab recovery system)
+     */
     async duplicate (tab: BaseTabComponent): Promise<BaseTabComponent> {
         let token = await tab.getRecoveryToken()
         if (!token) {
@@ -32,5 +39,4 @@ export class TabsService {
         }
         return null
     }
-
 }

+ 2 - 1
terminus-core/src/services/themes.service.ts

@@ -6,6 +6,7 @@ import { Theme } from '../api/theme'
 export class ThemesService {
     private styleElement: HTMLElement = null
 
+    /** @hidden */
     constructor (
         private config: ConfigService,
         @Inject(Theme) private themes: Theme[],
@@ -34,7 +35,7 @@ export class ThemesService {
         document.querySelector('style#custom-css').innerHTML = this.config.store.appearance.css
     }
 
-    applyCurrentTheme (): void {
+    private applyCurrentTheme (): void {
         this.applyTheme(this.findCurrentTheme())
     }
 }

+ 1 - 0
terminus-core/src/services/touchbar.service.ts

@@ -6,6 +6,7 @@ import { ElectronService } from './electron.service'
 import { HostAppService, Platform } from './hostApp.service'
 import { IToolbarButton, ToolbarButtonProvider } from '../api'
 
+/** @hidden */
 @Injectable({ providedIn: 'root' })
 export class TouchbarService {
     private tabsSegmentedControl: TouchBarSegmentedControl

+ 1 - 0
terminus-core/src/services/updater.service.ts

@@ -6,6 +6,7 @@ import { ElectronService } from './electron.service'
 
 const UPDATES_URL = 'https://api.github.com/repos/eugeny/terminus/releases/latest'
 
+/** @hidden */
 @Injectable({ providedIn: 'root' })
 export class UpdaterService {
     private logger: Logger

+ 4 - 1
terminus-core/src/tabContextMenu.ts

@@ -4,6 +4,7 @@ import { BaseTabComponent } from './components/baseTab.component'
 import { TabHeaderComponent } from './components/tabHeader.component'
 import { TabContextMenuItemProvider } from './api/tabContextMenuProvider'
 
+/** @hidden */
 @Injectable()
 export class CloseContextMenu extends TabContextMenuItemProvider {
     weight = -5
@@ -61,6 +62,7 @@ const COLORS = [
     { name: 'Yellow', value: '#ffd500' },
 ]
 
+/** @hidden */
 @Injectable()
 export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
     weight = -1
@@ -98,6 +100,7 @@ export class CommonOptionsContextMenu extends TabContextMenuItemProvider {
     }
 }
 
+/** @hidden */
 @Injectable()
 export class TaskCompletionContextMenu extends TabContextMenuItemProvider {
     constructor (
@@ -121,7 +124,7 @@ export class TaskCompletionContextMenu extends TabContextMenuItemProvider {
                     type: 'checkbox',
                     checked: (tab as any).__completionNotificationEnabled,
                     click: () => this.zone.run(() => {
-                        ;(tab as any).__completionNotificationEnabled = !(tab as any).__completionNotificationEnabled
+                        (tab as any).__completionNotificationEnabled = !(tab as any).__completionNotificationEnabled
 
                         if ((tab as any).__completionNotificationEnabled) {
                             this.app.observeTabCompletion(tab).subscribe(() => {

+ 3 - 0
terminus-core/src/theme.ts

@@ -1,6 +1,7 @@
 import { Injectable } from '@angular/core'
 import { Theme } from './api'
 
+/** @hidden */
 @Injectable()
 export class StandardTheme extends Theme {
     name = 'Standard'
@@ -8,6 +9,7 @@ export class StandardTheme extends Theme {
     terminalBackground = '#222a33'
 }
 
+/** @hidden */
 @Injectable()
 export class StandardCompactTheme extends Theme {
     name = 'Compact'
@@ -15,6 +17,7 @@ export class StandardCompactTheme extends Theme {
     terminalBackground = '#222a33'
 }
 
+/** @hidden */
 @Injectable()
 export class PaperTheme extends Theme {
     name = 'Paper'

+ 2 - 3
terminus-plugin-manager/src/components/pluginsSettingsTab.component.ts

@@ -3,7 +3,7 @@ import { debounceTime, distinctUntilChanged, first, tap, flatMap } from 'rxjs/op
 import * as semver from 'semver'
 
 import { Component, Input } from '@angular/core'
-import { ConfigService, HostAppService, ElectronService } from 'terminus-core'
+import { ConfigService, ElectronService } from 'terminus-core'
 import { IPluginInfo, PluginManagerService } from '../services/pluginManager.service'
 
 enum BusyState { Installing, Uninstalling }
@@ -25,7 +25,6 @@ export class PluginsSettingsTabComponent {
     constructor (
         private electron: ElectronService,
         private config: ConfigService,
-        private hostApp: HostAppService,
         public pluginManager: PluginManagerService
     ) {
     }
@@ -51,7 +50,7 @@ export class PluginsSettingsTabComponent {
     }
 
     openPluginsFolder (): void {
-        this.hostApp.getShell().openItem(this.pluginManager.userPluginsPath)
+        this.electron.shell.openItem(this.pluginManager.userPluginsPath)
     }
 
     searchAvailable (query: string) {

+ 7 - 0
typedoc.js

@@ -0,0 +1,7 @@
+module.exports = {
+  ignoreCompilerErrors: true,
+  excludeNotExported: true,
+  excludePrivate: true,
+  excludeExternals: true,
+  mode: 'file'
+}

+ 158 - 1
yarn.lock

@@ -39,6 +39,18 @@
   resolved "https://registry.yarnpkg.com/@types/electron-debug/-/electron-debug-1.1.0.tgz#b9203bad33dccc5a4ea180a89a9dbcf1961f4c3c"
   integrity sha1-uSA7rTPczFpOoYComp288ZYfTDw=
 
+"@types/events@*":
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
+  integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
+
+"@types/fs-extra@^5.0.3":
+  version "5.0.5"
+  resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-5.0.5.tgz#080d90a792f3fa2c5559eb44bd8ef840aae9104b"
+  integrity sha512-w7iqhDH9mN8eLClQOYTkhdYUOSpp25eXxfc6VbFOGtzxW34JcvctH2bKjj4jD4++z4R5iO5D+pg48W2e03I65A==
+  dependencies:
+    "@types/node" "*"
+
 "@types/[email protected]":
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/@types/fs-promise/-/fs-promise-1.0.1.tgz#a77e18c055d7757d44a34c1ed7e8bb505992f783"
@@ -47,11 +59,47 @@
     "@types/mz" "*"
     "@types/node" "*"
 
+"@types/glob@*":
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
+  integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==
+  dependencies:
+    "@types/events" "*"
+    "@types/minimatch" "*"
+    "@types/node" "*"
+
+"@types/handlebars@^4.0.38":
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/@types/handlebars/-/handlebars-4.1.0.tgz#3fcce9bf88f85fe73dc932240ab3fb682c624850"
+  integrity sha512-gq9YweFKNNB1uFK71eRqsd4niVkXrxHugqWFQkeLRJvGjnxsLr16bYtcsG4tOFwmYi0Bax+wCkbf1reUfdl4kA==
+  dependencies:
+    handlebars "*"
+
+"@types/highlight.js@^9.12.3":
+  version "9.12.3"
+  resolved "https://registry.yarnpkg.com/@types/highlight.js/-/highlight.js-9.12.3.tgz#b672cfaac25cbbc634a0fd92c515f66faa18dbca"
+  integrity sha512-pGF/zvYOACZ/gLGWdQH8zSwteQS1epp68yRcVLJMgUck/MjEn/FBYmPub9pXT8C1e4a8YZfHo1CKyV8q1vKUnQ==
+
 "@types/js-yaml@^3.11.2":
   version "3.11.2"
   resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.11.2.tgz#699ad86054cc20043c30d66a6fcde30bbf5d3d5e"
   integrity sha512-JRDtMPEqXrzfuYAdqbxLot1GvAr/QvicIZAnOAigZaj8xVMhuSJTg/xsv9E1TvyL+wujYhRLx9ZsQ0oFOSmwyA==
 
+"@types/lodash@^4.14.110":
+  version "4.14.122"
+  resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.122.tgz#3e31394c38cf1e5949fb54c1192cbc406f152c6c"
+  integrity sha512-9IdED8wU93ty8gP06ninox+42SBSJHp2IAamsSYMUY76mshRTeUsid/gtbl8ovnOwy8im41ib4cxTiIYMXGKew==
+
+"@types/marked@^0.4.0":
+  version "0.4.2"
+  resolved "https://registry.yarnpkg.com/@types/marked/-/marked-0.4.2.tgz#64a89e53ea37f61cc0f3ee1732c555c2dbf6452f"
+  integrity sha512-cDB930/7MbzaGF6U3IwSQp6XBru8xWajF5PV2YZZeV8DyiliTuld11afVztGI9+yJZ29il5E+NpGA6ooV/Cjkg==
+
+"@types/minimatch@*", "@types/[email protected]":
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
+  integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
+
 "@types/mz@*":
   version "0.0.32"
   resolved "https://registry.yarnpkg.com/@types/mz/-/mz-0.0.32.tgz#e8248b4e41424c052edc1725dd33650c313a3659"
@@ -69,6 +117,14 @@
   resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.26.tgz#2dec19f1f7981c95cb54bab8f618ecb5dc983d0e"
   integrity sha512-nMRqS+mL1TOnIJrL6LKJcNZPB8V3eTfRo9FQA2b5gDvrHurC8XbSA86KNe0dShlEL7ReWJv/OU9NL7Z0dnqWTg==
 
+"@types/shelljs@^0.8.0":
+  version "0.8.3"
+  resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.8.3.tgz#f713f312dbae49ab5025290007e71ea32998e9a9"
+  integrity sha512-miY41hqc5SkRlsZDod3heDa4OS9xv8G77EMBQuSpqq86HBn66l7F+f8y9YKm+1PIuwC8QEZVwN8YxOOG7Y67fA==
+  dependencies:
+    "@types/glob" "*"
+    "@types/node" "*"
+
 "@types/[email protected]":
   version "1.13.0"
   resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.13.0.tgz#3044381647e11ee973c5af2e925323930f691d80"
@@ -649,6 +705,13 @@ async@^2.0.0:
   dependencies:
     lodash "^4.17.10"
 
+async@^2.5.0:
+  version "2.6.2"
+  resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381"
+  integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==
+  dependencies:
+    lodash "^4.17.11"
+
 asynckit@^0.4.0:
   version "0.4.0"
   resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
@@ -3051,6 +3114,17 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6:
   resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
   integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
 
+handlebars@*, handlebars@^4.0.6:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.0.tgz#0d6a6f34ff1f63cecec8423aa4169827bf787c3a"
+  integrity sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w==
+  dependencies:
+    async "^2.5.0"
+    optimist "^0.6.1"
+    source-map "^0.6.1"
+  optionalDependencies:
+    uglify-js "^3.1.4"
+
 har-schema@^1.0.5:
   version "1.0.5"
   resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
@@ -3181,6 +3255,11 @@ [email protected]:
   resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
   integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0=
 
+highlight.js@^9.13.1:
+  version "9.15.6"
+  resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.15.6.tgz#72d4d8d779ec066af9a17cb14360c3def0aa57c4"
+  integrity sha512-zozTAWM1D6sozHo8kqhfYgsac+B+q0PmsjXeyDrYIHHcBN0zTVT66+s2GW1GZv7DbyaROdLXKdabwS/WqPyIdQ==
+
 hmac-drbg@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
@@ -4135,7 +4214,7 @@ lodash.without@~4.4.0:
   resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac"
   integrity sha1-PNRXSgC2e643OpS3SHcmQFB7eqw=
 
-lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.10:
+lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.10:
   version "4.17.11"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
   integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
@@ -4242,6 +4321,11 @@ map-visit@^1.0.0:
   dependencies:
     object-visit "^1.0.0"
 
+marked@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/marked/-/marked-0.4.0.tgz#9ad2c2a7a1791f10a852e0112f77b571dce10c66"
+  integrity sha512-tMsdNBgOsrUophCAFQl0XPe6Zqk/uy9gnue+jIIKhykO51hxyu6uNx7zBPy0+y/WKYVZZMspV9YeXLNdKk+iYw==
+
 math-expression-evaluator@^1.2.14:
   version "1.2.17"
   resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac"
@@ -4388,6 +4472,11 @@ minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0:
   resolved "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
   integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
 
+minimist@~0.0.1:
+  version "0.0.10"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
+  integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=
+
 minipass@^2.2.1, minipass@^2.3.3:
   version "2.3.4"
   resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.4.tgz#4768d7605ed6194d6d576169b9e12ef71e9d9957"
@@ -5066,6 +5155,14 @@ opener@~1.4.3:
   resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8"
   integrity sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=
 
+optimist@^0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
+  integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY=
+  dependencies:
+    minimist "~0.0.1"
+    wordwrap "~0.0.2"
+
 ora@^1.2.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/ora/-/ora-1.4.0.tgz#884458215b3a5d4097592285f93321bb7a79e2e5"
@@ -5709,6 +5806,11 @@ progress-stream@^1.1.0:
     speedometer "~0.1.2"
     through2 "~0.2.3"
 
+progress@^2.0.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
+  integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
+
 promise-inflight@^1.0.1, promise-inflight@~1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
@@ -6671,6 +6773,15 @@ [email protected]:
     interpret "^1.0.0"
     rechoir "^0.6.2"
 
+shelljs@^0.8.2:
+  version "0.8.3"
+  resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097"
+  integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==
+  dependencies:
+    glob "^7.0.0"
+    interpret "^1.0.0"
+    rechoir "^0.6.2"
+
 signal-exit@^3.0.0, signal-exit@^3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
@@ -7472,6 +7583,39 @@ typedarray@^0.0.6:
   resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
   integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
 
+typedoc-default-themes@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/typedoc-default-themes/-/typedoc-default-themes-0.5.0.tgz#6dc2433e78ed8bea8e887a3acde2f31785bd6227"
+  integrity sha1-bcJDPnjti+qOiHo6zeLzF4W9Yic=
+
+typedoc@^0.14.2:
+  version "0.14.2"
+  resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.14.2.tgz#769f457f4f9e4bdb8b5f3b177c86b6a31d8c3dc3"
+  integrity sha512-aEbgJXV8/KqaVhcedT7xG6d2r+mOvB5ep3eIz1KuB5sc4fDYXcepEEMdU7XSqLFO5hVPu0nllHi1QxX2h/QlpQ==
+  dependencies:
+    "@types/fs-extra" "^5.0.3"
+    "@types/handlebars" "^4.0.38"
+    "@types/highlight.js" "^9.12.3"
+    "@types/lodash" "^4.14.110"
+    "@types/marked" "^0.4.0"
+    "@types/minimatch" "3.0.3"
+    "@types/shelljs" "^0.8.0"
+    fs-extra "^7.0.0"
+    handlebars "^4.0.6"
+    highlight.js "^9.13.1"
+    lodash "^4.17.10"
+    marked "^0.4.0"
+    minimatch "^3.0.0"
+    progress "^2.0.0"
+    shelljs "^0.8.2"
+    typedoc-default-themes "^0.5.0"
+    typescript "3.2.x"
+
[email protected]:
+  version "3.2.4"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.4.tgz#c585cb952912263d915b462726ce244ba510ef3d"
+  integrity sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg==
+
 typescript@^3.1.3:
   version "3.1.3"
   resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.1.3.tgz#01b70247a6d3c2467f70c45795ef5ea18ce191d5"
@@ -7495,6 +7639,14 @@ uglify-js@^2.6.1:
   optionalDependencies:
     uglify-to-browserify "~1.0.0"
 
+uglify-js@^3.1.4:
+  version "3.4.9"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3"
+  integrity sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==
+  dependencies:
+    commander "~2.17.1"
+    source-map "~0.6.1"
+
 uglify-to-browserify@~1.0.0:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
@@ -7881,6 +8033,11 @@ [email protected]:
   resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
   integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=
 
+wordwrap@~0.0.2:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
+  integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc=
+
 worker-farm@^1.5.2:
   version "1.6.0"
   resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0"