Sfoglia il codice sorgente

strict null checks in application

Steven Silvester 7 anni fa
parent
commit
0da08d31cc
2 ha cambiato i file con 62 aggiunte e 32 eliminazioni
  1. 34 17
      packages/application/src/layoutrestorer.ts
  2. 28 15
      packages/application/src/shell.ts

+ 34 - 17
packages/application/src/layoutrestorer.ts

@@ -165,12 +165,13 @@ class LayoutRestorer implements ILayoutRestorer {
     this._registry = options.registry;
     this._state = options.state;
     this._first = options.first;
-    this._first.then(() => Promise.all(this._promises)).then(() => {
-      // Release the promises held in memory.
-      this._promises = null;
+    this._first.then(() => {
+      this._firstDone = true;
+      return Promise.all(this._promises);
+    }).then(() => {
+      this._promisesDone = true;
       // Release the tracker set.
       this._trackers.clear();
-      this._trackers = null;
     }).then(() => {
       this._restored.resolve(void 0);
     });
@@ -236,7 +237,7 @@ class LayoutRestorer implements ILayoutRestorer {
    * @param options - The restoration options.
    */
   restore(tracker: InstanceTracker<Widget>, options: ILayoutRestorer.IRestoreOptions<Widget>): Promise<any> {
-    if (!this._promises) {
+    if (this._firstDone) {
       const warning = 'restore() can only be called before `first` has resolved.';
       console.warn(warning);
       return Promise.reject(warning);
@@ -289,7 +290,7 @@ class LayoutRestorer implements ILayoutRestorer {
    */
   save(data: ApplicationShell.ILayout): Promise<void> {
     // If there are promises that are unresolved, bail.
-    if (this._promises) {
+    if (!this._promisesDone) {
       let warning = 'save() was called prematurely.';
       console.warn(warning);
       return Promise.reject(warning);
@@ -312,7 +313,10 @@ class LayoutRestorer implements ILayoutRestorer {
   /**
    * Dehydrate a main area description into a serializable object.
    */
-  private _dehydrateMainArea(area: ApplicationShell.IMainArea): Private.IMainArea {
+  private _dehydrateMainArea(area: ApplicationShell.IMainArea | null): Private.IMainArea | null {
+    if (!area) {
+      return null;
+    }
     return Private.serializeMain(area);
   }
 
@@ -323,14 +327,20 @@ class LayoutRestorer implements ILayoutRestorer {
    * This function consumes data that can become corrupted, so it uses type
    * coercion to guarantee the dehydrated object is safely processed.
    */
-  private _rehydrateMainArea(area: Private.IMainArea): ApplicationShell.IMainArea {
+  private _rehydrateMainArea(area?: Private.IMainArea | null): ApplicationShell.IMainArea | null {
+    if (!area) {
+      return null;
+    }
     return Private.deserializeMain(area, this._widgets);
   }
 
   /**
    * Dehydrate a side area description into a serializable object.
    */
-  private _dehydrateSideArea(area: ApplicationShell.ISideArea): Private.ISideArea {
+  private _dehydrateSideArea(area?: ApplicationShell.ISideArea | null): Private.ISideArea | null {
+    if (!area) {
+      return null;
+    }
     let dehydrated: Private.ISideArea = { collapsed: area.collapsed };
     if (area.currentWidget) {
       let current = Private.nameProperty.get(area.currentWidget);
@@ -353,7 +363,7 @@ class LayoutRestorer implements ILayoutRestorer {
    * This function consumes data that can become corrupted, so it uses type
    * coercion to guarantee the dehydrated object is safely processed.
    */
-  private _rehydrateSideArea(area: Private.ISideArea): ApplicationShell.ISideArea {
+  private _rehydrateSideArea(area?: Private.ISideArea | null): ApplicationShell.ISideArea {
     if (!area) {
       return { collapsed: true, currentWidget: null, widgets: null };
     }
@@ -366,7 +376,11 @@ class LayoutRestorer implements ILayoutRestorer {
       : area.widgets
           .map(name => internal.has(`${name}`) ? internal.get(`${name}`) : null)
           .filter(widget => !!widget);
-    return { collapsed, currentWidget, widgets };
+    return {
+      collapsed,
+      currentWidget: currentWidget!,
+      widgets: widgets as Widget[] | null
+    };
   }
 
   /**
@@ -377,11 +391,13 @@ class LayoutRestorer implements ILayoutRestorer {
     this._widgets.delete(name);
   }
 
-  private _first: Promise<any> = null;
+  private _first: Promise<any>;
+  private _firstDone = false;
+  private _promisesDone = false;
   private _promises: Promise<any>[] = [];
   private _restored = new PromiseDelegate<void>();
-  private _registry: CommandRegistry = null;
-  private _state: IStateDB = null;
+  private _registry: CommandRegistry ;
+  private _state: IStateDB;
   private _trackers = new Set<string>();
   private _widgets = new Map<string, Widget>();
 }
@@ -549,7 +565,7 @@ namespace Private {
   /**
    * Serialize individual areas within the main area.
    */
-  function serializeArea(area: ApplicationShell.AreaConfig): ITabArea | ISplitArea | null {
+  function serializeArea(area: ApplicationShell.AreaConfig | null): ITabArea | ISplitArea | null {
     if (!area || !area.type) {
       return null;
     }
@@ -569,6 +585,7 @@ namespace Private {
       orientation: area.orientation,
       sizes: area.sizes,
       children: area.children.map(serializeArea)
+                  .filter(area => !!area) as (ITabArea | ISplitArea)[]
     };
   }
 
@@ -621,7 +638,7 @@ namespace Private {
         type: 'tab-area',
         currentIndex: currentIndex || 0,
         widgets: widgets && widgets.map(widget => names.get(widget))
-            .filter(widget => !!widget) || []
+            .filter(widget => !!widget) as Widget[] || []
       };
 
       // Make sure the current index is within bounds.
@@ -639,7 +656,7 @@ namespace Private {
       sizes: sizes || [],
       children: children &&
         children.map(child => deserializeArea(child, names))
-           .filter(widget => !!widget) || []
+           .filter(widget => !!widget) as ApplicationShell.AreaConfig[] || []
     };
 
     return hydrated;

+ 28 - 15
packages/application/src/shell.ts

@@ -226,7 +226,9 @@ class ApplicationShell extends Widget {
 
     // In case the active widget in the dock panel is *not* the active widget
     // of the application, defer to the application.
-    dock.activateWidget(this.currentWidget);
+    if (this.currentWidget) {
+      dock.activateWidget(this.currentWidget);
+    }
 
     // Set the mode data attribute on the document body.
     document.body.setAttribute(MODE_ATTRIBUTE, mode);
@@ -278,7 +280,9 @@ class ApplicationShell extends Widget {
 
     if (ci < current.titles.length - 1) {
       current.currentIndex += 1;
-      current.currentTitle.owner.activate();
+      if (current.currentTitle) {
+        current.currentTitle.owner.activate();
+      }
       return;
     }
 
@@ -286,7 +290,9 @@ class ApplicationShell extends Widget {
       let nextBar = this._adjacentBar('next');
       if (nextBar) {
         nextBar.currentIndex = 0;
-        nextBar.currentTitle.owner.activate();
+        if (nextBar.currentTitle) {
+          nextBar.currentTitle.owner.activate();
+        }
       }
     }
   }
@@ -307,7 +313,9 @@ class ApplicationShell extends Widget {
 
     if (ci > 0) {
       current.currentIndex -= 1;
-      current.currentTitle.owner.activate();
+      if (current.currentTitle) {
+        current.currentTitle.owner.activate();
+      }
       return;
     }
 
@@ -316,7 +324,9 @@ class ApplicationShell extends Widget {
       if (prevBar) {
         let len = prevBar.titles.length;
         prevBar.currentIndex = len - 1;
-        prevBar.currentTitle.owner.activate();
+        if (prevBar.currentTitle) {
+          prevBar.currentTitle.owner.activate();
+        }
       }
     }
   }
@@ -333,7 +343,7 @@ class ApplicationShell extends Widget {
       return;
     }
     let rank = 'rank' in options ? options.rank : DEFAULT_RANK;
-    this._leftHandler.addWidget(widget, rank);
+    this._leftHandler.addWidget(widget, rank!);
     this._layoutModified.emit(void 0);
   }
 
@@ -355,7 +365,7 @@ class ApplicationShell extends Widget {
 
     let ref: Widget | null = null;
     if (options.ref) {
-      ref = find(dock.widgets(), value => value.id === options.ref);
+      ref = find(dock.widgets(), value => value.id === options.ref!) || null;
     }
 
     dock.addWidget(widget, { mode: 'tab-after', ref });
@@ -374,7 +384,7 @@ class ApplicationShell extends Widget {
       return;
     }
     let rank = 'rank' in options ? options.rank : DEFAULT_RANK;
-    this._rightHandler.addWidget(widget, rank);
+    this._rightHandler.addWidget(widget, rank!);
     this._onLayoutModified();
   }
 
@@ -511,7 +521,7 @@ class ApplicationShell extends Widget {
       case 'top':
         return this._topPanel.children();
       default:
-        break;
+        throw new Error('Invalid area');
     }
   }
 
@@ -767,10 +777,13 @@ namespace Private {
    * Removes widgets that have been disposed from an area config, mutates area.
    */
   export
-  function normalizeAreaConfig(parent: DockPanel, area: DockLayout.AreaConfig): void {
+  function normalizeAreaConfig(parent: DockPanel, area?: DockLayout.AreaConfig | null): void {
+    if (!area) {
+      return;
+    }
     if (area.type === 'tab-area') {
       area.widgets = area.widgets
-        .filter(widget => !widget.isDisposed && widget.parent === parent);
+        .filter(widget => !widget.isDisposed && widget.parent === parent) as Widget[];
       return;
     }
     area.children.forEach(child => { normalizeAreaConfig(parent, child); });
@@ -894,7 +907,7 @@ namespace Private {
     /**
      * Find the widget which owns the given title, or `null`.
      */
-    private _findWidgetByTitle(title: Title<Widget>): Widget {
+    private _findWidgetByTitle(title: Title<Widget>): Widget | null {
       let item = find(this._items, value => value.widget.title === title);
       return item ? item.widget : null;
     }
@@ -902,7 +915,7 @@ namespace Private {
     /**
      * Find the widget with the given id, or `null`.
      */
-    private _findWidgetByID(id: string): Widget {
+    private _findWidgetByID(id: string): Widget | null {
       let item = find(this._items, value => value.widget.id === id);
       return item ? item.widget : null;
     }
@@ -919,8 +932,8 @@ namespace Private {
      * Handle the `currentChanged` signal from the sidebar.
      */
     private _onCurrentChanged(sender: TabBar<Widget>, args: TabBar.ICurrentChangedArgs<Widget>): void {
-      const oldWidget = this._findWidgetByTitle(args.previousTitle);
-      const newWidget = this._findWidgetByTitle(args.currentTitle);
+      const oldWidget = args.previousTitle ? this._findWidgetByTitle(args.previousTitle) : null;
+      const newWidget = args.currentTitle ? this._findWidgetByTitle(args.currentTitle) : null;
       if (oldWidget) {
         oldWidget.hide();
       }