From 871f2da787e5f214d910cb0bf1840bc28a98fad9 Mon Sep 17 00:00:00 2001
From: Jason Grout <jgrout6@bloomberg.net>
Date: Fri, 11 Jun 2021 18:34:46 -0700
Subject: [PATCH 1/2] Upgrade @types/backbone

---
 packages/base-manager/src/manager-base.ts | 24 ++++++++++++-----------
 packages/base/package.json                |  2 +-
 packages/base/src/nativeview.ts           | 14 ++++++-------
 packages/base/src/widget.ts               |  6 +++++-
 yarn.lock                                 |  8 ++++++++
 5 files changed, 34 insertions(+), 20 deletions(-)

diff --git a/packages/base-manager/src/manager-base.ts b/packages/base-manager/src/manager-base.ts
index 82ea294bba..e14220620f 100644
--- a/packages/base-manager/src/manager-base.ts
+++ b/packages/base-manager/src/manager-base.ts
@@ -21,7 +21,8 @@ import {
   PROTOCOL_VERSION,
   IWidgetManager,
   IModelOptions,
-  IWidgetOptions
+  IWidgetOptions,
+  IBackboneModelOptions
 } from '@jupyter-widgets/base';
 
 import { base64ToBuffer, bufferToBase64, hexToBuffer } from './utils';
@@ -52,6 +53,11 @@ export interface IBase64Buffers extends PartialJSONObject {
   encoding: 'base64';
 }
 
+/**
+ * Make all properties in K (of T) required
+ */
+export type RequiredSome<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
+
 /**
  * Manager abstract base class
  */
@@ -270,25 +276,21 @@ export abstract class ManagerBase implements IWidgetManager {
     options: IModelOptions,
     serialized_state: any = {}
   ): Promise<WidgetModel> {
-    let model_id;
-    if (options.model_id) {
-      model_id = options.model_id;
-    } else if (options.comm) {
-      model_id = options.model_id = options.comm.comm_id;
-    } else {
+    const model_id = options.model_id ?? options.comm?.comm_id;
+    if (!model_id) {
       throw new Error(
         'Neither comm nor model_id provided in options object. At least one must exist.'
       );
     }
-
-    const modelPromise = this._make_model(options, serialized_state);
+    options.model_id = model_id;
+    const modelPromise = this._make_model(options as RequiredSome<IModelOptions, 'model_id'>, serialized_state);
     // this call needs to happen before the first `await`, see note in `set_state`:
     this.register_model(model_id, modelPromise);
     return await modelPromise;
   }
 
   async _make_model(
-    options: IModelOptions,
+    options: RequiredSome<IModelOptions, 'model_id'>,
     serialized_state: any = {}
   ): Promise<WidgetModel> {
     const model_id = options.model_id;
@@ -315,7 +317,7 @@ export abstract class ManagerBase implements IWidgetManager {
       serialized_state,
       this
     );
-    const modelOptions = {
+    const modelOptions: IBackboneModelOptions = {
       widget_manager: this,
       model_id: model_id,
       comm: options.comm
diff --git a/packages/base/package.json b/packages/base/package.json
index 26b5e48fae..e8cc01d5d4 100644
--- a/packages/base/package.json
+++ b/packages/base/package.json
@@ -36,7 +36,7 @@
     "@lumino/coreutils": "^1.2.0",
     "@lumino/messaging": "^1.2.1",
     "@lumino/widgets": "^1.3.0",
-    "@types/backbone": "1.4.1",
+    "@types/backbone": "1.4.10",
     "@types/lodash": "^4.14.134",
     "backbone": "1.4.0",
     "jquery": "^3.1.1",
diff --git a/packages/base/src/nativeview.ts b/packages/base/src/nativeview.ts
index 5c049bf57a..5ff15e16d9 100644
--- a/packages/base/src/nativeview.ts
+++ b/packages/base/src/nativeview.ts
@@ -80,7 +80,7 @@ export class NativeView<T extends Backbone.Model> extends Backbone.View<T> {
   _setAttributes(attrs: Backbone.ObjectHash): void {
     for (const attr in attrs) {
       attr in this.el
-        ? (this.el[attr] = attrs[attr])
+        ? ((this.el as any)[attr] = attrs[attr])
         : this.el.setAttribute(attr, attrs[attr]);
     }
   }
@@ -99,17 +99,17 @@ export class NativeView<T extends Backbone.Model> extends Backbone.View<T> {
    * https://github.com/jquery/jquery/blob/7d21f02b9ec9f655583e898350badf89165ed4d5/src/event.js#L442
    * for some similar exceptional cases).
    */
-  delegate(eventName: string, listener: Function): Backbone.View<T>;
+  delegate(eventName: string, listener: Function): this;
   delegate(
     eventName: string,
     selector: string,
     listener: Function
-  ): Backbone.View<T>;
+  ): this;
   delegate(
     eventName: string,
     selector: string | Function,
     listener?: any
-  ): Backbone.View<T> {
+  ): this {
     if (typeof selector !== 'string') {
       listener = selector;
       selector = null!;
@@ -150,8 +150,8 @@ export class NativeView<T extends Backbone.Model> extends Backbone.View<T> {
     eventName: string,
     selector?: string,
     listener?: Function
-  ): NativeView<T>;
-  undelegate(selector: string, listener?: Function): NativeView<T>;
+  ): this;
+  undelegate(selector: string, listener?: Function): this;
   undelegate(
     eventName: string,
     selector?: string | Function,
@@ -185,7 +185,7 @@ export class NativeView<T extends Backbone.Model> extends Backbone.View<T> {
   }
 
   // Remove all events created with `delegate` from `el`
-  undelegateEvents(): NativeView<T> {
+  undelegateEvents(): this {
     if (this.el && this._domEvents) {
       const len = this._domEvents.length;
       for (let i = 0; i < len; i++) {
diff --git a/packages/base/src/widget.ts b/packages/base/src/widget.ts
index 3fc5bc5353..83a90d4c77 100644
--- a/packages/base/src/widget.ts
+++ b/packages/base/src/widget.ts
@@ -66,6 +66,10 @@ export interface ISerializers {
   };
 }
 
+export interface IBackboneModelOptions extends Backbone.ModelSetOptions {
+  model_id: string; comm?: any; widget_manager: any
+}
+
 export class WidgetModel extends Backbone.Model {
   /**
    * The default attributes.
@@ -107,7 +111,7 @@ export class WidgetModel extends Backbone.Model {
    */
   initialize(
     attributes: Backbone.ObjectHash,
-    options: { model_id: string; comm?: any; widget_manager: any }
+    options: IBackboneModelOptions
   ): void {
     super.initialize(attributes, options);
 
diff --git a/yarn.lock b/yarn.lock
index e9fdd49097..1ab7094b94 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1802,6 +1802,14 @@
     "@types/jquery" "*"
     "@types/underscore" "*"
 
+"@types/backbone@1.4.10":
+  version "1.4.10"
+  resolved "https://registry.npmjs.org/@types/backbone/-/backbone-1.4.10.tgz#042e72ffc966fe920ed02ff92afa66984a036844"
+  integrity sha512-X6UM8N9i4WFtO1F53Z3DE7mjI7UxEfxyFtMTYHOPFhYFvExDuu0UJENstnA023+/FnVOdxltMIKc4picZxW4dA==
+  dependencies:
+    "@types/jquery" "*"
+    "@types/underscore" "*"
+
 "@types/base64-js@^1.2.5":
   version "1.3.0"
   resolved "https://registry.npmjs.org/@types/base64-js/-/base64-js-1.3.0.tgz#c939fdba49846861caf5a246b165dbf5698a317c"

From 78fa12bdab002fa00437eb1b80ef11d5d079f9ff Mon Sep 17 00:00:00 2001
From: Jeremy Tuloup <jeremy.tuloup@gmail.com>
Date: Thu, 17 Jun 2021 12:17:57 +0200
Subject: [PATCH 2/2] Fix backbone types in tests

---
 packages/base/test/src/widget_test.ts | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/packages/base/test/src/widget_test.ts b/packages/base/test/src/widget_test.ts
index 2434ae3d16..6df9a63ec6 100644
--- a/packages/base/test/src/widget_test.ts
+++ b/packages/base/test/src/widget_test.ts
@@ -2,6 +2,7 @@ import { DummyManager, MockComm } from './dummy-manager';
 
 import { expect } from 'chai';
 
+import { IBackboneModelOptions } from '../../lib/';
 import * as widgets from '../../lib/';
 const WidgetModel = widgets.WidgetModel;
 
@@ -82,7 +83,7 @@ describe('WidgetModel', function() {
           model_id: 'widget',
           widget_manager: this.manager,
           comm: this.comm
-        }
+        } as IBackboneModelOptions
       );
       // Create some dummy deserializers.  One returns synchronously, and the
       // other asynchronously using a promise.
@@ -128,7 +129,7 @@ describe('WidgetModel', function() {
         {
           model_id: 'widget',
           widget_manager: this.manager
-        }
+        } as IBackboneModelOptions
       );
       expect(widget.attributes).to.deep.equal({
         ...widget.defaults(),
@@ -143,7 +144,7 @@ describe('WidgetModel', function() {
         {
           model_id: 'widgetDead',
           widget_manager: this.manager
-        }
+        } as IBackboneModelOptions
       );
       expect(widgetDead.model_id).to.equal('widgetDead');
       expect(widgetDead.widget_manager).to.equal(this.manager);
@@ -157,7 +158,7 @@ describe('WidgetModel', function() {
           model_id: 'widgetLive',
           widget_manager: this.manager,
           comm: comm
-        }
+        } as IBackboneModelOptions
       );
       expect(widgetLive.model_id).to.equal('widgetLive');
       expect(widgetLive.widget_manager).to.equal(this.manager);
@@ -171,7 +172,7 @@ describe('WidgetModel', function() {
         {
           model_id: 'widget',
           widget_manager: this.manager
-        }
+        } as IBackboneModelOptions
       );
       const x = await widget.state_change;
       expect(x).to.be.undefined;
@@ -193,7 +194,7 @@ describe('WidgetModel', function() {
           model_id: 'widget',
           widget_manager: this.manager,
           comm: comm
-        }
+        } as IBackboneModelOptions
       );
       const data1 = { a: 1, b: 'state' };
       const data2 = { a: 2, b: 'state' };