Skip to content

Commit 67b5c37

Browse files
authored
refactor(superdoc): type optional event callback registration (#3085)
* refactor(superdoc): close strict-null cluster in SuperDoc.js (SD-2867) * fix(superdoc): make documents invariant real, soften JSDoc claims (SD-2867) * docs(superdoc): note store-field lifecycle, link SD-2916 follow-up * refactor(superdoc): type optional event callback registration (SD-2867) * docs(superdoc): drop dead asEventListener generic, scope no-op invariant
1 parent a26f003 commit 67b5c37

1 file changed

Lines changed: 34 additions & 15 deletions

File tree

packages/superdoc/src/core/SuperDoc.js

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,25 @@ const DEFAULT_AWARENESS_PALETTE = Object.freeze([
7474
*/
7575
/** @typedef {import('./types/index.js').NavigableAddress} NavigableAddress */
7676

77+
/**
78+
* Config callbacks are optional on the public typedef because consumers do
79+
* not need to pass them. The fields wrapped by this helper (every callback
80+
* registered in `#initListeners` plus the toolbar `exception` listener)
81+
* default to `() => null` in the class-field initializer, so EventEmitter
82+
* receives a function in normal use. This helper is a runtime identity
83+
* cast: behavior is unchanged if that invariant is ever broken (e.g. a
84+
* consumer explicitly passes `undefined`), and EventEmitter sees the same
85+
* value it would have without the wrapper. Sites with a `null` default
86+
* (`onFontsResolved`, `onTrackedChangeBubbleAccept`, `onTrackedChangeBubbleReject`)
87+
* use a separate `if`-guard pattern instead of this helper.
88+
*
89+
* @param {((...args: any[]) => void) | undefined} listener
90+
* @returns {(...args: any[]) => void}
91+
*/
92+
function asEventListener(listener) {
93+
return /** @type {(...args: any[]) => void} */ (listener);
94+
}
95+
7796
/**
7897
* SuperDoc class
7998
* Expects a config object
@@ -558,21 +577,21 @@ export class SuperDoc extends EventEmitter {
558577
}
559578

560579
#initListeners() {
561-
this.on('editorBeforeCreate', this.config.onEditorBeforeCreate);
562-
this.on('editorCreate', this.config.onEditorCreate);
563-
this.on('editorDestroy', this.config.onEditorDestroy);
564-
this.on('ready', this.config.onReady);
565-
this.on('comments-update', this.config.onCommentsUpdate);
566-
this.on('awareness-update', this.config.onAwarenessUpdate);
567-
this.on('locked', this.config.onLocked);
568-
this.on('pdf:document-ready', this.config.onPdfDocumentReady);
569-
this.on('sidebar-toggle', this.config.onSidebarToggle);
570-
this.on('collaboration-ready', this.config.onCollaborationReady);
571-
this.on('editor-update', this.config.onEditorUpdate);
580+
this.on('editorBeforeCreate', asEventListener(this.config.onEditorBeforeCreate));
581+
this.on('editorCreate', asEventListener(this.config.onEditorCreate));
582+
this.on('editorDestroy', asEventListener(this.config.onEditorDestroy));
583+
this.on('ready', asEventListener(this.config.onReady));
584+
this.on('comments-update', asEventListener(this.config.onCommentsUpdate));
585+
this.on('awareness-update', asEventListener(this.config.onAwarenessUpdate));
586+
this.on('locked', asEventListener(this.config.onLocked));
587+
this.on('pdf:document-ready', asEventListener(this.config.onPdfDocumentReady));
588+
this.on('sidebar-toggle', asEventListener(this.config.onSidebarToggle));
589+
this.on('collaboration-ready', asEventListener(this.config.onCollaborationReady));
590+
this.on('editor-update', asEventListener(this.config.onEditorUpdate));
572591
this.on('content-error', this.onContentError);
573-
this.on('exception', this.config.onException);
574-
this.on('list-definitions-change', this.config.onListDefinitionsChange);
575-
this.on('pagination-update', this.config.onPaginationUpdate);
592+
this.on('exception', asEventListener(this.config.onException));
593+
this.on('list-definitions-change', asEventListener(this.config.onListDefinitionsChange));
594+
this.on('pagination-update', asEventListener(this.config.onPaginationUpdate));
576595

577596
if (this.config.onFontsResolved) {
578597
this.on('fonts-resolved', this.config.onFontsResolved);
@@ -1248,7 +1267,7 @@ export class SuperDoc extends EventEmitter {
12481267

12491268
this.toolbar = new SuperToolbar(config);
12501269

1251-
this.toolbar.on('exception', this.config.onException);
1270+
this.toolbar.on('exception', asEventListener(this.config.onException));
12521271
// `this.toolbar` infers as `SuperToolbar | null` from the field's
12531272
// first assignment in `#addToolbar` (the `null` placeholder a few
12541273
// lines up). The closure registers after the SuperToolbar instance

0 commit comments

Comments
 (0)