diff --git a/blocksuite/affine/block-data-view/src/data-source.ts b/blocksuite/affine/block-data-view/src/data-source.ts index 11bc04b914..1ce001eb2b 100644 --- a/blocksuite/affine/block-data-view/src/data-source.ts +++ b/blocksuite/affine/block-data-view/src/data-source.ts @@ -10,7 +10,8 @@ import { import type { EditorHost } from '@blocksuite/block-std'; import { DataSourceBase, type PropertyMetaConfig } from '@blocksuite/data-view'; import { propertyPresets } from '@blocksuite/data-view/property-presets'; -import { assertExists, Slot } from '@blocksuite/global/utils'; +import { BlockSuiteError } from '@blocksuite/global/exceptions'; +import { Slot } from '@blocksuite/global/utils'; import type { Block, Store } from '@blocksuite/store'; import type { BlockMeta } from './block-meta/base.js'; @@ -95,7 +96,12 @@ export class BlockQueryDataSource extends DataSourceBase { private getProperty(propertyId: string) { const property = this.meta.properties.find(v => v.key === propertyId); - assertExists(property, `property ${propertyId} not found`); + if (!property) { + throw new BlockSuiteError( + BlockSuiteError.ErrorCode.ValueNotExists, + `property ${propertyId} not found` + ); + } return property; } diff --git a/blocksuite/affine/block-database/src/properties/rich-text/cell-renderer.ts b/blocksuite/affine/block-database/src/properties/rich-text/cell-renderer.ts index c4f4aea256..569c5e6fb2 100644 --- a/blocksuite/affine/block-database/src/properties/rich-text/cell-renderer.ts +++ b/blocksuite/affine/block-database/src/properties/rich-text/cell-renderer.ts @@ -18,7 +18,6 @@ import { createIcon, } from '@blocksuite/data-view'; import { IS_MAC } from '@blocksuite/global/env'; -import { assertExists } from '@blocksuite/global/utils'; import type { DeltaInsert } from '@blocksuite/inline'; import type { BlockSnapshot } from '@blocksuite/store'; import { Text } from '@blocksuite/store'; @@ -338,7 +337,7 @@ export class RichTextCellEditing extends BaseRichTextCell { private readonly _onSoftEnter = () => { if (this.value && this.inlineEditor) { const inlineRange = this.inlineEditor.getInlineRange(); - assertExists(inlineRange); + if (!inlineRange) return; const text = new Text(this.inlineEditor.yText); text.replace(inlineRange.index, inlineRange.length, '\n'); @@ -351,7 +350,7 @@ export class RichTextCellEditing extends BaseRichTextCell { private readonly _onCopy = (e: ClipboardEvent) => { const inlineEditor = this.inlineEditor; - assertExists(inlineEditor); + if (!inlineEditor) return; const inlineRange = inlineEditor.getInlineRange(); if (!inlineRange) return; @@ -368,7 +367,7 @@ export class RichTextCellEditing extends BaseRichTextCell { private readonly _onCut = (e: ClipboardEvent) => { const inlineEditor = this.inlineEditor; - assertExists(inlineEditor); + if (!inlineEditor) return; const inlineRange = inlineEditor.getInlineRange(); if (!inlineRange) return; diff --git a/blocksuite/affine/block-database/src/properties/title/text.ts b/blocksuite/affine/block-database/src/properties/title/text.ts index d3bd49af45..dafdfac2ab 100644 --- a/blocksuite/affine/block-database/src/properties/title/text.ts +++ b/blocksuite/affine/block-database/src/properties/title/text.ts @@ -13,7 +13,6 @@ import { } from '@blocksuite/affine-shared/utils'; import { BaseCellRenderer } from '@blocksuite/data-view'; import { IS_MAC } from '@blocksuite/global/env'; -import { assertExists } from '@blocksuite/global/utils'; import { LinkedPageIcon } from '@blocksuite/icons/lit'; import type { DeltaInsert } from '@blocksuite/inline'; import type { BlockSnapshot, Text } from '@blocksuite/store'; @@ -205,7 +204,7 @@ export class HeaderAreaTextCell extends BaseTextCell { export class HeaderAreaTextCellEditing extends BaseTextCell { private readonly _onCopy = (e: ClipboardEvent) => { const inlineEditor = this.inlineEditor; - assertExists(inlineEditor); + if (!inlineEditor) return; const inlineRange = inlineEditor.getInlineRange(); if (!inlineRange) return; @@ -222,7 +221,7 @@ export class HeaderAreaTextCellEditing extends BaseTextCell { private readonly _onCut = (e: ClipboardEvent) => { const inlineEditor = this.inlineEditor; - assertExists(inlineEditor); + if (!inlineEditor) return; const inlineRange = inlineEditor.getInlineRange(); if (!inlineRange) return; diff --git a/blocksuite/affine/block-embed/src/common/render-linked-doc.ts b/blocksuite/affine/block-embed/src/common/render-linked-doc.ts index 9795d5c818..e2e6878b84 100644 --- a/blocksuite/affine/block-embed/src/common/render-linked-doc.ts +++ b/blocksuite/affine/block-embed/src/common/render-linked-doc.ts @@ -11,7 +11,6 @@ import { EMBED_CARD_HEIGHT } from '@blocksuite/affine-shared/consts'; import { NotificationProvider } from '@blocksuite/affine-shared/services'; import { matchModels, SpecProvider } from '@blocksuite/affine-shared/utils'; import { BlockStdScope } from '@blocksuite/block-std'; -import { assertExists } from '@blocksuite/global/utils'; import { type BlockModel, type BlockSnapshot, @@ -36,10 +35,12 @@ export function renderLinkedDocInCard( card: EmbedLinkedDocBlockComponent | EmbedSyncedDocCard ) { const linkedDoc = card.linkedDoc; - assertExists( - linkedDoc, - `Trying to load page ${card.model.pageId} in linked page block, but the page is not found.` - ); + if (!linkedDoc) { + console.error( + `Trying to load page ${card.model.pageId} in linked page block, but the page is not found.` + ); + return; + } // eslint-disable-next-line sonarjs/no-collapsible-if if ('bannerContainer' in card) { @@ -59,10 +60,12 @@ export function renderLinkedDocInCard( async function renderPageAsBanner(card: EmbedSyncedDocCard) { const linkedDoc = card.linkedDoc; - assertExists( - linkedDoc, - `Trying to load page ${card.model.pageId} in linked page block, but the page is not found.` - ); + if (!linkedDoc) { + console.error( + `Trying to load page ${card.model.pageId} in linked page block, but the page is not found.` + ); + return; + } const notes = getNotesFromDoc(linkedDoc); if (!notes) { @@ -126,10 +129,12 @@ async function renderNoteContent( card.isNoteContentEmpty = true; const doc = card.linkedDoc; - assertExists( - doc, - `Trying to load page ${card.model.pageId} in linked page block, but the page is not found.` - ); + if (!doc) { + console.error( + `Trying to load page ${card.model.pageId} in linked page block, but the page is not found.` + ); + return; + } const notes = getNotesFromDoc(doc); if (!notes) { diff --git a/blocksuite/affine/block-embed/src/embed-github-block/utils.ts b/blocksuite/affine/block-embed/src/embed-github-block/utils.ts index b21f9ea8e7..e8a1673bea 100644 --- a/blocksuite/affine/block-embed/src/embed-github-block/utils.ts +++ b/blocksuite/affine/block-embed/src/embed-github-block/utils.ts @@ -4,7 +4,6 @@ import type { } from '@blocksuite/affine-model'; import type { LinkPreviewerService } from '@blocksuite/affine-shared/services'; import { isAbortError } from '@blocksuite/affine-shared/utils'; -import { assertExists } from '@blocksuite/global/utils'; import { nothing } from 'lit'; import type { EmbedGithubBlockComponent } from './embed-github-block.js'; @@ -89,8 +88,14 @@ export async function refreshEmbedGithubUrlData( try { embedGithubElement.loading = true; + // TODO(@mirone): remove service const queryUrlData = embedGithubElement.service?.queryUrlData; - assertExists(queryUrlData); + if (!queryUrlData) { + console.error( + `Trying to refresh github url data, but the queryUrlData is not found.` + ); + return; + } const githubUrlData = await queryUrlData(embedGithubElement.model); ({ @@ -126,8 +131,15 @@ export async function refreshEmbedGithubStatus( embedGithubElement: EmbedGithubBlockComponent, signal?: AbortSignal ) { + // TODO(@mirone): remove service const queryApiData = embedGithubElement.service?.queryApiData; - assertExists(queryApiData); + if (!queryApiData) { + console.error( + `Trying to refresh github status, but the queryApiData is not found.` + ); + return; + } + const githubApiData = await queryApiData(embedGithubElement.model, signal); if (!githubApiData.status || signal?.aborted) return; diff --git a/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-synced-doc-block.ts b/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-synced-doc-block.ts index ad41893107..e88a18acad 100644 --- a/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-synced-doc-block.ts +++ b/blocksuite/affine/block-embed/src/embed-synced-doc-block/embed-synced-doc-block.ts @@ -35,7 +35,6 @@ import { GfxExtension, } from '@blocksuite/block-std/gfx'; import { Bound, getCommonBound } from '@blocksuite/global/gfx'; -import { assertExists } from '@blocksuite/global/utils'; import { type GetBlocksOptions, type Query, Text } from '@blocksuite/store'; import { computed, signal } from '@preact/signals-core'; import { html, nothing, type PropertyValues } from 'lit'; @@ -284,7 +283,12 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent { const { doc } = this.model; const parent = doc.getParent(this.model); - assertExists(parent); + if (!parent) { + console.error( + `Trying to convert synced doc to inline, but the parent is not found.` + ); + return; + } const index = parent.children.indexOf(this.model); const yText = new Y.Text(); diff --git a/blocksuite/affine/block-embed/src/embed-youtube-block/utils.ts b/blocksuite/affine/block-embed/src/embed-youtube-block/utils.ts index d2349a5259..dd4dfa14ea 100644 --- a/blocksuite/affine/block-embed/src/embed-youtube-block/utils.ts +++ b/blocksuite/affine/block-embed/src/embed-youtube-block/utils.ts @@ -4,7 +4,6 @@ import type { } from '@blocksuite/affine-model'; import type { LinkPreviewerService } from '@blocksuite/affine-shared/services'; import { isAbortError } from '@blocksuite/affine-shared/utils'; -import { assertExists } from '@blocksuite/global/utils'; import type { EmbedYoutubeBlockComponent } from './embed-youtube-block.js'; @@ -73,8 +72,14 @@ export async function refreshEmbedYoutubeUrlData( try { embedYoutubeElement.loading = true; + // TODO(@mirone): remove service const queryUrlData = embedYoutubeElement.service?.queryUrlData; - assertExists(queryUrlData); + if (!queryUrlData) { + console.error( + `Trying to refresh youtube url data, but the queryUrlData is not found.` + ); + return; + } const youtubeUrlData = await queryUrlData( embedYoutubeElement.model, diff --git a/blocksuite/affine/block-image/src/image-resize-manager.ts b/blocksuite/affine/block-image/src/image-resize-manager.ts index 0e49c7d855..1e32eb3f43 100644 --- a/blocksuite/affine/block-image/src/image-resize-manager.ts +++ b/blocksuite/affine/block-image/src/image-resize-manager.ts @@ -5,7 +5,6 @@ import { } from '@blocksuite/affine-shared/utils'; import type { BlockComponent, PointerEventState } from '@blocksuite/block-std'; import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx'; -import { assertExists } from '@blocksuite/global/utils'; export class ImageResizeManager { private _activeComponent: BlockComponent | null = null; @@ -19,8 +18,9 @@ export class ImageResizeManager { private _zoom = 1; onEnd() { - assertExists(this._activeComponent); - assertExists(this._imageContainer); + if (!this._activeComponent || !this._imageContainer) { + return; + } const dragModel = getModelByElement(this._activeComponent); dragModel?.doc.captureSync(); @@ -32,12 +32,16 @@ export class ImageResizeManager { } onMove(e: PointerEventState) { - assertExists(this._activeComponent); const activeComponent = this._activeComponent; const activeImgContainer = this._imageContainer; - assertExists(activeImgContainer); + if (!activeComponent || !activeImgContainer) { + return; + } + const activeImg = activeComponent.querySelector('img'); - assertExists(activeImg); + if (!activeImg) { + return; + } let width = 0; if (this._dragMoveTarget === 'right') { @@ -84,7 +88,9 @@ export class ImageResizeManager { } this._imageContainer = eventTarget.closest('.resizable-img'); - assertExists(this._imageContainer); + if (!this._imageContainer) { + return; + } const rect = this._imageContainer.getBoundingClientRect() as DOMRect; this._imageCenterX = rect.left + rect.width / 2; if (eventTarget.className.includes('right')) { diff --git a/blocksuite/affine/block-root/src/clipboard/adapter.ts b/blocksuite/affine/block-root/src/clipboard/adapter.ts index 9931549541..f7ec271205 100644 --- a/blocksuite/affine/block-root/src/clipboard/adapter.ts +++ b/blocksuite/affine/block-root/src/clipboard/adapter.ts @@ -1,5 +1,4 @@ import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; -import { assertExists } from '@blocksuite/global/utils'; import type { BlockSnapshot, DocSnapshot, @@ -50,7 +49,12 @@ export class ClipboardAdapter extends BaseAdapter { ): Promise> { const snapshot = payload.snapshot; const assets = payload.assets; - assertExists(assets); + if (!assets) { + throw new BlockSuiteError( + ErrorCode.ValueNotExists, + 'ClipboardAdapter.fromSliceSnapshot: assets is not found' + ); + } const map = assets.getAssets(); const blobs: Record = await encodeClipboardBlobs(map); return { diff --git a/blocksuite/affine/block-root/src/clipboard/utils.ts b/blocksuite/affine/block-root/src/clipboard/utils.ts index 14efcc4aba..5fb4fad4e4 100644 --- a/blocksuite/affine/block-root/src/clipboard/utils.ts +++ b/blocksuite/affine/block-root/src/clipboard/utils.ts @@ -1,5 +1,4 @@ import { toast } from '@blocksuite/affine-components/toast'; -import { assertExists } from '@blocksuite/global/utils'; import type { FileSnapshot } from './adapter.js'; @@ -113,12 +112,17 @@ export function decodeClipboardBlobs( blobs: Record, map: Map | undefined ) { + if (!map) { + console.error( + `Trying to decode clipboard blobs, but the map is not found.` + ); + return; + } Object.entries(blobs).forEach(([sourceId, file]) => { const blob = new Blob([decode(file.content)]); const f = new File([blob], file.name, { type: file.type, }); - assertExists(map); map.set(sourceId, f); }); } diff --git a/blocksuite/affine/block-root/src/edgeless/clipboard/clipboard.ts b/blocksuite/affine/block-root/src/edgeless/clipboard/clipboard.ts index ca97ca9fd0..59cfc7bbf6 100644 --- a/blocksuite/affine/block-root/src/edgeless/clipboard/clipboard.ts +++ b/blocksuite/affine/block-root/src/edgeless/clipboard/clipboard.ts @@ -57,12 +57,7 @@ import { type SerializedXYWH, Vec, } from '@blocksuite/global/gfx'; -import { - assertExists, - assertType, - DisposableGroup, - nToLast, -} from '@blocksuite/global/utils'; +import { assertType, DisposableGroup, nToLast } from '@blocksuite/global/utils'; import { type BlockSnapshot, BlockSnapshotSchema, @@ -519,17 +514,19 @@ export class EdgelessClipboardController extends PageClipboard { clipboardData: SerializedElement, context: CreationContext, newXYWH: SerializedXYWH - ) { + ): GfxPrimitiveElementModel | null { if (clipboardData.type === GROUP) { const yMap = new Y.Map(); const children = clipboardData.children ?? {}; for (const [key, value] of Object.entries(children)) { const newKey = context.oldToNewIdMap.get(key); - assertExists( - newKey, - 'Copy failed: cannot find the copied child in group' - ); + if (!newKey) { + console.error( + `Copy failed: cannot find the copied child in group, key: ${key}` + ); + return null; + } yMap.set(newKey, value); } clipboardData.children = yMap; @@ -543,17 +540,21 @@ export class EdgelessClipboardController extends PageClipboard { const newValue = { ...oldValue, }; - assertExists( - newKey, - 'Copy failed: cannot find the copied node in mind map' - ); + if (!newKey) { + console.error( + `Copy failed: cannot find the copied node in mind map, key: ${oldKey}` + ); + return null; + } if (oldValue.parent) { const newParent = context.oldToNewIdMap.get(oldValue.parent); - assertExists( - newParent, - 'Copy failed: cannot find the copied node in mind map' - ); + if (!newParent) { + console.error( + `Copy failed: cannot find the copied node in mind map, parent: ${oldValue.parent}` + ); + return null; + } newValue.parent = newParent; } @@ -603,7 +604,10 @@ export class EdgelessClipboardController extends PageClipboard { type: clipboardData.type as string, }); const element = this.crud.getElementById(id) as GfxPrimitiveElementModel; - assertExists(element); + if (!element) { + console.error(`Copy failed: cannot find the copied element, id: ${id}`); + return null; + } return element; } @@ -898,7 +902,7 @@ export class EdgelessClipboardController extends PageClipboard { const editorMode = isInsidePageEditor(host); const rootComponent = getRootByEditorHost(host); - assertExists(rootComponent); + if (!rootComponent) return; const container = rootComponent.querySelector( '.affine-block-children-container' @@ -1355,7 +1359,10 @@ export class EdgelessClipboardController extends PageClipboard { bounds.push(shape.elementBound); }); const bound = getCommonBound(bounds); - assertExists(bound, 'bound not exist'); + if (!bound) { + console.error('bound not exist'); + return; + } const canvas = await this._edgelessToCanvas( this.host, diff --git a/blocksuite/affine/block-root/src/edgeless/components/auto-complete/edgeless-auto-complete.ts b/blocksuite/affine/block-root/src/edgeless/components/auto-complete/edgeless-auto-complete.ts index 4c382a3ed4..1ecd9a5924 100644 --- a/blocksuite/affine/block-root/src/edgeless/components/auto-complete/edgeless-auto-complete.ts +++ b/blocksuite/affine/block-root/src/edgeless/components/auto-complete/edgeless-auto-complete.ts @@ -27,11 +27,7 @@ import { type BlockStdScope, stdContext } from '@blocksuite/block-std'; import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx'; import type { Bound, IVec } from '@blocksuite/global/gfx'; import { Vec } from '@blocksuite/global/gfx'; -import { - assertExists, - DisposableGroup, - WithDisposable, -} from '@blocksuite/global/utils'; +import { DisposableGroup, WithDisposable } from '@blocksuite/global/utils'; import { ArrowUpBigIcon, PlusIcon, @@ -194,7 +190,9 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) { ); } if (this._isMoving) { - assertExists(connector); + if (!connector) { + return; + } const otherSideId = connector.source.id; connector.target = this.connectionOverlay.renderConnector( @@ -382,7 +380,9 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) { ); } else { const model = doc.getBlockById(id); - assertExists(model); + if (!model) { + return; + } const [x, y] = service.viewport.toViewCoord( bound.center[0], bound.y + DEFAULT_NOTE_HEIGHT / 2 diff --git a/blocksuite/affine/block-root/src/edgeless/components/resize/resize-manager.ts b/blocksuite/affine/block-root/src/edgeless/components/resize/resize-manager.ts index debf1c7350..dbeacdf2ef 100644 --- a/blocksuite/affine/block-root/src/edgeless/components/resize/resize-manager.ts +++ b/blocksuite/affine/block-root/src/edgeless/components/resize/resize-manager.ts @@ -7,7 +7,6 @@ import { type PointLocation, rotatePoints, } from '@blocksuite/global/gfx'; -import { assertExists } from '@blocksuite/global/utils'; import type { SelectableProps } from '../../utils/query.js'; import { HandleDirection, type ResizeMode } from './resize-handles.js'; @@ -113,7 +112,9 @@ export class HandleResizeManager { const rect = this._target .closest('.affine-edgeless-selected-rect') ?.getBoundingClientRect(); - assertExists(rect); + if (!rect) { + return; + } const { left, top, right, bottom } = rect; const x = (left + right) / 2; const y = (top + bottom) / 2; @@ -207,12 +208,10 @@ export class HandleResizeManager { _rotate, _resizeMode, _zoom, - _target, _originalRect, _currentRect, } = this; proportion ||= this._proportion; - assertExists(_target); const isAll = _resizeMode === 'all'; const isCorner = _resizeMode === 'corner'; diff --git a/blocksuite/affine/block-root/src/edgeless/components/text/edgeless-connector-label-editor.ts b/blocksuite/affine/block-root/src/edgeless/components/text/edgeless-connector-label-editor.ts index 64155a5242..0fed07f2fd 100644 --- a/blocksuite/affine/block-root/src/edgeless/components/text/edgeless-connector-label-editor.ts +++ b/blocksuite/affine/block-root/src/edgeless/components/text/edgeless-connector-label-editor.ts @@ -11,7 +11,7 @@ import { ShadowlessElement, } from '@blocksuite/block-std'; import { Bound, Vec } from '@blocksuite/global/gfx'; -import { assertExists, WithDisposable } from '@blocksuite/global/utils'; +import { WithDisposable } from '@blocksuite/global/utils'; import { css, html, nothing } from 'lit'; import { property, query } from 'lit/decorators.js'; import { styleMap } from 'lit/directives/style-map.js'; @@ -94,12 +94,11 @@ export class EdgelessConnectorLabelEditor extends WithDisposable( }; get inlineEditor() { - assertExists(this.richText.inlineEditor); return this.richText.inlineEditor; } get inlineEditorContainer() { - return this.inlineEditor.rootElement; + return this.inlineEditor?.rootElement; } override connectedCallback() { @@ -116,7 +115,6 @@ export class EdgelessConnectorLabelEditor extends WithDisposable( override firstUpdated() { const { edgeless, connector } = this; const { dispatcher } = edgeless; - assertExists(dispatcher); this._resizeObserver = new ResizeObserver(() => { this._updateLabelRect(); @@ -126,6 +124,7 @@ export class EdgelessConnectorLabelEditor extends WithDisposable( this.updateComplete .then(() => { + if (!this.inlineEditor) return; this.inlineEditor.selectAll(); this.inlineEditor.slots.renderComplete.on(() => { diff --git a/blocksuite/affine/block-root/src/edgeless/components/text/edgeless-frame-title-editor.ts b/blocksuite/affine/block-root/src/edgeless/components/text/edgeless-frame-title-editor.ts index 38f001950c..06bf28695d 100644 --- a/blocksuite/affine/block-root/src/edgeless/components/text/edgeless-frame-title-editor.ts +++ b/blocksuite/affine/block-root/src/edgeless/components/text/edgeless-frame-title-editor.ts @@ -10,7 +10,7 @@ import { ShadowlessElement, } from '@blocksuite/block-std'; import { Bound } from '@blocksuite/global/gfx'; -import { assertExists, WithDisposable } from '@blocksuite/global/utils'; +import { WithDisposable } from '@blocksuite/global/utils'; import { cssVarV2 } from '@toeverything/theme/v2'; import { css, html, nothing } from 'lit'; import { property, query } from 'lit/decorators.js'; @@ -63,7 +63,6 @@ export class EdgelessFrameTitleEditor extends WithDisposable( override firstUpdated(): void { const dispatcher = this.edgeless.dispatcher; - assertExists(dispatcher); this.updateComplete .then(() => { if (!this.inlineEditor) return; diff --git a/blocksuite/affine/block-root/src/edgeless/components/text/edgeless-group-title-editor.ts b/blocksuite/affine/block-root/src/edgeless/components/text/edgeless-group-title-editor.ts index 00ccd84483..5a63615fae 100644 --- a/blocksuite/affine/block-root/src/edgeless/components/text/edgeless-group-title-editor.ts +++ b/blocksuite/affine/block-root/src/edgeless/components/text/edgeless-group-title-editor.ts @@ -10,7 +10,7 @@ import { ShadowlessElement, } from '@blocksuite/block-std'; import { Bound } from '@blocksuite/global/gfx'; -import { assertExists, WithDisposable } from '@blocksuite/global/utils'; +import { WithDisposable } from '@blocksuite/global/utils'; import { html, nothing } from 'lit'; import { property, query } from 'lit/decorators.js'; import { styleMap } from 'lit/directives/style-map.js'; @@ -21,12 +21,11 @@ export class EdgelessGroupTitleEditor extends WithDisposable( ShadowlessElement ) { get inlineEditor() { - assertExists(this.richText.inlineEditor); return this.richText.inlineEditor; } get inlineEditorContainer() { - return this.inlineEditor.rootElement; + return this.inlineEditor?.rootElement; } private _unmount() { @@ -47,10 +46,10 @@ export class EdgelessGroupTitleEditor extends WithDisposable( override firstUpdated(): void { const dispatcher = this.edgeless.dispatcher; - assertExists(dispatcher); this.updateComplete .then(() => { + if (!this.inlineEditor) return; this.inlineEditor.selectAll(); this.group.showTitle = false; diff --git a/blocksuite/affine/block-root/src/edgeless/components/text/edgeless-shape-text-editor.ts b/blocksuite/affine/block-root/src/edgeless/components/text/edgeless-shape-text-editor.ts index 0b41ce91d2..cdaf58d60a 100644 --- a/blocksuite/affine/block-root/src/edgeless/components/text/edgeless-shape-text-editor.ts +++ b/blocksuite/affine/block-root/src/edgeless/components/text/edgeless-shape-text-editor.ts @@ -12,7 +12,7 @@ import { ShadowlessElement, } from '@blocksuite/block-std'; import { Bound, toRadian, Vec } from '@blocksuite/global/gfx'; -import { assertExists, WithDisposable } from '@blocksuite/global/utils'; +import { WithDisposable } from '@blocksuite/global/utils'; import { html, nothing } from 'lit'; import { property, query } from 'lit/decorators.js'; import { styleMap } from 'lit/directives/style-map.js'; @@ -32,12 +32,11 @@ export class EdgelessShapeTextEditor extends WithDisposable(ShadowlessElement) { private _resizeObserver: ResizeObserver | null = null; get inlineEditor() { - assertExists(this.richText.inlineEditor); return this.richText.inlineEditor; } get inlineEditorContainer() { - return this.inlineEditor.rootElement; + return this.inlineEditor?.rootElement; } get isMindMapNode() { @@ -175,7 +174,6 @@ export class EdgelessShapeTextEditor extends WithDisposable(ShadowlessElement) { override firstUpdated(): void { const dispatcher = this.edgeless.dispatcher; - assertExists(dispatcher); this.element.textDisplay = false; @@ -202,6 +200,7 @@ export class EdgelessShapeTextEditor extends WithDisposable(ShadowlessElement) { this.updateComplete .then(() => { + if (!this.inlineEditor) return; if (this.element.group instanceof MindmapElementModel) { this.inlineEditor.selectAll(); } else { diff --git a/blocksuite/affine/block-root/src/edgeless/components/text/edgeless-text-editor.ts b/blocksuite/affine/block-root/src/edgeless/components/text/edgeless-text-editor.ts index 983ca0e536..29459721de 100644 --- a/blocksuite/affine/block-root/src/edgeless/components/text/edgeless-text-editor.ts +++ b/blocksuite/affine/block-root/src/edgeless/components/text/edgeless-text-editor.ts @@ -11,7 +11,7 @@ import { ShadowlessElement, } from '@blocksuite/block-std'; import { Bound, toRadian, Vec } from '@blocksuite/global/gfx'; -import { assertExists, WithDisposable } from '@blocksuite/global/utils'; +import { WithDisposable } from '@blocksuite/global/utils'; import { css, html, nothing } from 'lit'; import { property, query } from 'lit/decorators.js'; import { styleMap } from 'lit/directives/style-map.js'; @@ -144,12 +144,11 @@ export class EdgelessTextEditor extends WithDisposable(ShadowlessElement) { }; get inlineEditor() { - assertExists(this.richText.inlineEditor); return this.richText.inlineEditor; } get inlineEditorContainer() { - return this.inlineEditor.rootElement; + return this.inlineEditor?.rootElement; } override connectedCallback(): void { @@ -170,10 +169,10 @@ export class EdgelessTextEditor extends WithDisposable(ShadowlessElement) { const edgeless = this.edgeless; const element = this.element; const { dispatcher } = this.edgeless; - assertExists(dispatcher); this.updateComplete .then(() => { + if (!this.inlineEditor) return; this.inlineEditor.slots.renderComplete.on(() => { this._updateRect(); this.requestUpdate(); diff --git a/blocksuite/affine/block-root/src/edgeless/components/toolbar/common/create-popper.ts b/blocksuite/affine/block-root/src/edgeless/components/toolbar/common/create-popper.ts index 26351a54eb..d0d8e47c62 100644 --- a/blocksuite/affine/block-root/src/edgeless/components/toolbar/common/create-popper.ts +++ b/blocksuite/affine/block-root/src/edgeless/components/toolbar/common/create-popper.ts @@ -1,4 +1,4 @@ -import { assertExists } from '@blocksuite/global/utils'; +import { BlockSuiteError } from '@blocksuite/global/exceptions'; // more than 100% due to the shadow const leaveToPercent = `calc(100% + 10px)`; @@ -28,26 +28,31 @@ export function createPopper( onDispose?: () => void; setProps?: (ele: HTMLElementTagNameMap[T]) => void; } -) { +): MenuPopper { const duration = options?.duration ?? 230; if (!popMap.has(reference)) popMap.set(reference, new Map()); const elMap = popMap.get(reference); - assertExists(elMap); // if there is already a popper, cancel leave transition and apply enter transition - if (elMap.has(tagName)) { + if (elMap && elMap.has(tagName)) { const popper = elMap.get(tagName); - assertExists(popper); - popper.cancel?.(); - requestAnimationFrame(() => animateEnter(popper.element)); - return popper as MenuPopper; + if (popper) { + popper.cancel?.(); + requestAnimationFrame(() => animateEnter(popper.element)); + return popper as MenuPopper; + } } const clipWrapper = document.createElement('div'); const menu = document.createElement(tagName); options?.setProps?.(menu); - assertExists(reference.shadowRoot); clipWrapper.append(menu); + if (!reference.shadowRoot) { + throw new BlockSuiteError( + BlockSuiteError.ErrorCode.ValueNotExists, + 'reference must be a shadow root' + ); + } reference.shadowRoot.append(clipWrapper); // apply enter transition diff --git a/blocksuite/affine/block-root/src/edgeless/components/toolbar/common/draggable/draggable-element.controller.ts b/blocksuite/affine/block-root/src/edgeless/components/toolbar/common/draggable/draggable-element.controller.ts index a0aa59500f..debc15a4ae 100644 --- a/blocksuite/affine/block-root/src/edgeless/components/toolbar/common/draggable/draggable-element.controller.ts +++ b/blocksuite/affine/block-root/src/edgeless/components/toolbar/common/draggable/draggable-element.controller.ts @@ -3,7 +3,6 @@ import { ThemeProvider, } from '@blocksuite/affine-shared/services'; import { Bound } from '@blocksuite/global/gfx'; -import { assertExists } from '@blocksuite/global/utils'; import { type ReactiveController, type ReactiveControllerHost, @@ -200,8 +199,7 @@ export class EdgelessDraggableElementController } const { overlay } = this; - assertExists(overlay); - + if (!overlay) return; const { x, y } = e; const { startPos, scopeRect } = info; const offsetX = x - startPos.x; diff --git a/blocksuite/affine/block-root/src/edgeless/components/toolbar/shape/shape-draggable.ts b/blocksuite/affine/block-root/src/edgeless/components/toolbar/shape/shape-draggable.ts index 6dd1f86a82..52208fed74 100644 --- a/blocksuite/affine/block-root/src/edgeless/components/toolbar/shape/shape-draggable.ts +++ b/blocksuite/affine/block-root/src/edgeless/components/toolbar/shape/shape-draggable.ts @@ -12,7 +12,7 @@ import { TelemetryProvider, ThemeProvider, } from '@blocksuite/affine-shared/services'; -import { assertExists, SignalWatcher } from '@blocksuite/global/utils'; +import { SignalWatcher } from '@blocksuite/global/utils'; import { css, html, LitElement, nothing } from 'lit'; import { property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; @@ -248,7 +248,10 @@ export class EdgelessToolbarShapeDraggable extends EdgelessToolbarToolMixin( const el = this.shapeContainer.querySelector( `.shape.${this.draggingShape}` ) as HTMLElement; - assertExists(el, 'Edgeless toolbar Shape element not found'); + if (!el) { + console.error('Edgeless toolbar Shape element not found'); + return; + } const { x, y } = service.gfx.tool.lastMousePos$.peek(); const { left, top } = this.edgeless.viewport; const clientPos = { x: x + left, y: y + top }; diff --git a/blocksuite/affine/block-root/src/edgeless/components/utils.ts b/blocksuite/affine/block-root/src/edgeless/components/utils.ts index b2276c12da..a3995dddb0 100644 --- a/blocksuite/affine/block-root/src/edgeless/components/utils.ts +++ b/blocksuite/affine/block-root/src/edgeless/components/utils.ts @@ -1,7 +1,6 @@ import type { CursorType, StandardCursor } from '@blocksuite/block-std/gfx'; import type { IVec } from '@blocksuite/global/gfx'; import { normalizeDegAngle, Vec } from '@blocksuite/global/gfx'; -import { assertExists } from '@blocksuite/global/utils'; import { css, html } from 'lit'; export function generateCursorUrl( @@ -89,7 +88,11 @@ export function calcAngle(target: HTMLElement, point: IVec, offset = 0) { const rect = target .closest('.affine-edgeless-selected-rect') ?.getBoundingClientRect(); - assertExists(rect); + + if (!rect) { + console.error('rect not found when calc angle'); + return 0; + } const { left, top, right, bottom } = rect; const center = Vec.med([left, top], [right, bottom]); return normalizeDegAngle( @@ -104,9 +107,7 @@ export function calcAngleWithRotation( rotate: number ) { const handle = target.parentElement; - assertExists(handle); - const ariaLabel = handle.getAttribute('aria-label'); - assertExists(ariaLabel); + const ariaLabel = handle?.getAttribute('aria-label'); const { left, top, right, bottom, width, height } = rect; const size = Math.min(width, height); const sx = size / width; @@ -160,9 +161,7 @@ export function calcAngleWithRotation( export function calcAngleEdgeWithRotation(target: HTMLElement, rotate: number) { let angleWithEdge = 0; const handle = target.parentElement; - assertExists(handle); - const ariaLabel = handle.getAttribute('aria-label'); - assertExists(ariaLabel); + const ariaLabel = handle?.getAttribute('aria-label'); switch (ariaLabel) { case 'top': { angleWithEdge = 270; @@ -187,9 +186,7 @@ export function calcAngleEdgeWithRotation(target: HTMLElement, rotate: number) { export function getResizeLabel(target: HTMLElement) { const handle = target.parentElement; - assertExists(handle); - const ariaLabel = handle.getAttribute('aria-label'); - assertExists(ariaLabel); + const ariaLabel = handle?.getAttribute('aria-label'); return ariaLabel; } diff --git a/blocksuite/affine/block-root/src/edgeless/edgeless-root-block.ts b/blocksuite/affine/block-root/src/edgeless/edgeless-root-block.ts index eaec5b706b..d23b5a3791 100644 --- a/blocksuite/affine/block-root/src/edgeless/edgeless-root-block.ts +++ b/blocksuite/affine/block-root/src/edgeless/edgeless-root-block.ts @@ -39,8 +39,8 @@ import { type GfxViewportElement, } from '@blocksuite/block-std/gfx'; import { IS_WINDOWS } from '@blocksuite/global/env'; +import { BlockSuiteError } from '@blocksuite/global/exceptions'; import { Bound, Point, Vec } from '@blocksuite/global/gfx'; -import { assertExists } from '@blocksuite/global/utils'; import { effect } from '@preact/signals-core'; import { css, html } from 'lit'; import { query } from 'lit/decorators.js'; @@ -191,7 +191,12 @@ export class EdgelessRootBlockComponent extends BlockComponent< this._viewportElement = this.host.closest( '.affine-edgeless-viewport' ) as HTMLElement | null; - assertExists(this._viewportElement); + if (!this._viewportElement) { + throw new BlockSuiteError( + BlockSuiteError.ErrorCode.ValueNotExists, + 'EdgelessRootBlockComponent.viewportElement: viewport element is not found' + ); + } return this._viewportElement; } diff --git a/blocksuite/affine/block-root/src/edgeless/edgeless-root-preview-block.ts b/blocksuite/affine/block-root/src/edgeless/edgeless-root-preview-block.ts index fa13585581..759e843e3c 100644 --- a/blocksuite/affine/block-root/src/edgeless/edgeless-root-preview-block.ts +++ b/blocksuite/affine/block-root/src/edgeless/edgeless-root-preview-block.ts @@ -17,7 +17,7 @@ import { SurfaceSelection, } from '@blocksuite/block-std'; import type { GfxViewportElement } from '@blocksuite/block-std/gfx'; -import { assertExists } from '@blocksuite/global/utils'; +import { BlockSuiteError } from '@blocksuite/global/exceptions'; import { css, html } from 'lit'; import { query, state } from 'lit/decorators.js'; import { styleMap } from 'lit/directives/style-map.js'; @@ -104,7 +104,12 @@ export class EdgelessRootPreviewBlockComponent this._viewportElement = this.host.closest( this.editorViewportSelector ) as HTMLElement | null; - assertExists(this._viewportElement); + if (!this._viewportElement) { + throw new BlockSuiteError( + BlockSuiteError.ErrorCode.ValueNotExists, + 'EdgelessRootPreviewBlockComponent.viewportElement: viewport element is not found' + ); + } return this._viewportElement; } diff --git a/blocksuite/affine/block-root/src/edgeless/gfx-tool/brush-tool.ts b/blocksuite/affine/block-root/src/edgeless/gfx-tool/brush-tool.ts index 9fa9c34c16..d70068c3b5 100644 --- a/blocksuite/affine/block-root/src/edgeless/gfx-tool/brush-tool.ts +++ b/blocksuite/affine/block-root/src/edgeless/gfx-tool/brush-tool.ts @@ -4,7 +4,6 @@ import { TelemetryProvider } from '@blocksuite/affine-shared/services'; import type { PointerEventState } from '@blocksuite/block-std'; import { BaseTool } from '@blocksuite/block-std/gfx'; import type { IVec } from '@blocksuite/global/gfx'; -import { assertExists } from '@blocksuite/global/utils'; export class BrushTool extends BaseTool { static BRUSH_POP_GAP = 20; @@ -40,8 +39,10 @@ export class BrushTool extends BaseTool { : 'vertical'; } - private _tryGetPressurePoints(e: PointerEventState) { - assertExists(this._draggingPathPressures); + private _tryGetPressurePoints(e: PointerEventState): number[][] { + if (!this._draggingPathPressures) { + return []; + } const pressures = [...this._draggingPathPressures, e.pressure]; this._draggingPathPressures = pressures; @@ -56,8 +57,10 @@ export class BrushTool extends BaseTool { this._pressureSupportedPointerIds.add(pointerId); } - assertExists(this._draggingPathPoints); const points = this._draggingPathPoints; + if (!points) { + return []; + } if (this._pressureSupportedPointerIds.has(pointerId)) { return points.map(([x, y], i) => [x, y, pressures[i]]); } else { @@ -83,12 +86,14 @@ export class BrushTool extends BaseTool { } override dragMove(e: PointerEventState) { - if (!this._draggingElementId || !this._draggingElement || !this.gfx.surface) + if ( + !this._draggingElementId || + !this._draggingElement || + !this.gfx.surface || + !this._draggingPathPoints + ) return; - assertExists(this._draggingElementId); - assertExists(this._draggingPathPoints); - let pointX = e.point.x; let pointY = e.point.y; const holdingShiftKey = e.keys.shift || this.gfx.keyboard.shiftKey$.peek(); diff --git a/blocksuite/affine/block-root/src/edgeless/services/template-middlewares.ts b/blocksuite/affine/block-root/src/edgeless/services/template-middlewares.ts index 5c2325d231..8bd383e1a6 100644 --- a/blocksuite/affine/block-root/src/edgeless/services/template-middlewares.ts +++ b/blocksuite/affine/block-root/src/edgeless/services/template-middlewares.ts @@ -1,7 +1,7 @@ import { generateElementId, sortIndex } from '@blocksuite/affine-block-surface'; import type { ConnectorElementModel } from '@blocksuite/affine-model'; import { Bound } from '@blocksuite/global/gfx'; -import { assertExists, assertType } from '@blocksuite/global/utils'; +import { assertType } from '@blocksuite/global/utils'; import type { BlockSnapshot, SnapshotNode } from '@blocksuite/store'; import type { SlotBlockPayload, TemplateJob } from './template.js'; @@ -154,8 +154,6 @@ export const createInsertPlaceMiddleware = (targetPlace: Bound) => { const ignoreType = new Set(['group', 'connector']); const changePosition = (blockJson: BlockSnapshot) => { - assertExists(templateBound); - if (blockJson.props.xywh) { const bound = Bound.deserialize(blockJson.props['xywh'] as string); diff --git a/blocksuite/affine/block-root/src/edgeless/services/template.ts b/blocksuite/affine/block-root/src/edgeless/services/template.ts index 34c377ad4b..afdee7b623 100644 --- a/blocksuite/affine/block-root/src/edgeless/services/template.ts +++ b/blocksuite/affine/block-root/src/edgeless/services/template.ts @@ -4,7 +4,7 @@ import type { } from '@blocksuite/affine-block-surface'; import type { ConnectorElementModel } from '@blocksuite/affine-model'; import { Bound, getCommonBound } from '@blocksuite/global/gfx'; -import { assertExists, assertType, Slot } from '@blocksuite/global/utils'; +import { assertType, Slot } from '@blocksuite/global/utils'; import { type BlockModel, type BlockSnapshot, @@ -194,7 +194,9 @@ export class TemplateJob { return; } - assertExists(modelData); + if (!modelData) { + return; + } doc.addBlock( modelData.flavour, diff --git a/blocksuite/affine/block-root/src/transformers/markdown.ts b/blocksuite/affine/block-root/src/transformers/markdown.ts index b2d1d4df1e..68c2a43489 100644 --- a/blocksuite/affine/block-root/src/transformers/markdown.ts +++ b/blocksuite/affine/block-root/src/transformers/markdown.ts @@ -8,7 +8,7 @@ import { import { SpecProvider } from '@blocksuite/affine-shared/utils'; import { Container } from '@blocksuite/global/di'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; -import { assertExists, sha } from '@blocksuite/global/utils'; +import { sha } from '@blocksuite/global/utils'; import type { Schema, Store, Workspace } from '@blocksuite/store'; import { extMimeMap, Transformer } from '@blocksuite/store'; @@ -112,7 +112,12 @@ async function importMarkdownToBlock({ pageId: doc.id, }); - assertExists(snapshot, 'import markdown failed, expected to get a snapshot'); + if (!snapshot) { + throw new BlockSuiteError( + BlockSuiteError.ErrorCode.ValueNotExists, + 'import markdown failed, expected to get a snapshot' + ); + } const blocks = snapshot.content.flatMap(x => x.children); diff --git a/blocksuite/affine/block-root/src/widgets/format-bar/components/highlight/highlight-button.ts b/blocksuite/affine/block-root/src/widgets/format-bar/components/highlight/highlight-button.ts index d1ddabe6ce..e0f73d14ba 100644 --- a/blocksuite/affine/block-root/src/widgets/format-bar/components/highlight/highlight-button.ts +++ b/blocksuite/affine/block-root/src/widgets/format-bar/components/highlight/highlight-button.ts @@ -16,7 +16,6 @@ import { } from '@blocksuite/affine-shared/commands'; import type { AffineTextAttributes } from '@blocksuite/affine-shared/types'; import type { EditorHost } from '@blocksuite/block-std'; -import { assertExists } from '@blocksuite/global/utils'; import { computePosition, flip, offset, shift } from '@floating-ui/dom'; import { html } from 'lit'; import { ref, type RefOrCallback } from 'lit/directives/ref.js'; @@ -125,8 +124,9 @@ export const HighlightButton = (formatBar: AffineFormatBarWidget) => { formatBar.shadowRoot?.querySelector('.highlight-button'); const panel = formatBar.shadowRoot?.querySelector('.highlight-panel'); - assertExists(button); - assertExists(panel); + if (!button || !panel) { + return; + } panel.style.display = 'flex'; computePosition(button, panel, { placement: 'bottom', diff --git a/blocksuite/affine/block-root/src/widgets/format-bar/components/paragraph-button.ts b/blocksuite/affine/block-root/src/widgets/format-bar/components/paragraph-button.ts index 8f372411ab..609e8e333c 100644 --- a/blocksuite/affine/block-root/src/widgets/format-bar/components/paragraph-button.ts +++ b/blocksuite/affine/block-root/src/widgets/format-bar/components/paragraph-button.ts @@ -3,7 +3,6 @@ import { ArrowDownIcon } from '@blocksuite/affine-components/icons'; import { textConversionConfigs } from '@blocksuite/affine-components/rich-text'; import type { ParagraphBlockModel } from '@blocksuite/affine-model'; import type { EditorHost } from '@blocksuite/block-std'; -import { assertExists } from '@blocksuite/global/utils'; import { computePosition, flip, offset, shift } from '@floating-ui/dom'; import { html } from 'lit'; import { ref, type RefOrCallback } from 'lit/directives/ref.js'; @@ -85,13 +84,11 @@ export const ParagraphButton = (formatBar: AffineFormatBarWidget) => { return; } const formatQuickBarElement = formatBar.formatBarElement; - const button = - formatBar.shadowRoot?.querySelector('.paragraph-button'); const panel = formatBar.shadowRoot?.querySelector('.paragraph-panel'); - assertExists(button); - assertExists(panel); - assertExists(formatQuickBarElement, 'format quick bar should exist'); + if (!panel || !formatQuickBarElement) { + return; + } panel.style.display = 'flex'; computePosition(formatQuickBarElement, panel, { placement: 'top-start', diff --git a/blocksuite/affine/block-root/src/widgets/format-bar/config.ts b/blocksuite/affine/block-root/src/widgets/format-bar/config.ts index 8294f8f0d1..6c2606eb0e 100644 --- a/blocksuite/affine/block-root/src/widgets/format-bar/config.ts +++ b/blocksuite/affine/block-root/src/widgets/format-bar/config.ts @@ -62,7 +62,6 @@ import type { InitCommandCtx, } from '@blocksuite/block-std'; import { tableViewMeta } from '@blocksuite/data-view/view-presets'; -import { assertExists } from '@blocksuite/global/utils'; import { MoreVerticalIcon } from '@blocksuite/icons/lit'; import { Slice, toDraftModel } from '@blocksuite/store'; import { html, type TemplateResult } from 'lit'; @@ -377,13 +376,17 @@ export const BUILT_IN_GROUPS: MenuItemGroup[] = [ .try<{ currentSelectionPath: string }>(cmd => [ cmd.pipe(getTextSelectionCommand).pipe((ctx, next) => { const textSelection = ctx.currentTextSelection; - assertExists(textSelection); + if (!textSelection) { + return; + } const end = textSelection.to ?? textSelection.from; next({ currentSelectionPath: end.blockId }); }), cmd.pipe(getBlockSelectionsCommand).pipe((ctx, next) => { const currentBlockSelections = ctx.currentBlockSelections; - assertExists(currentBlockSelections); + if (!currentBlockSelections) { + return; + } const blockSelection = currentBlockSelections.at(-1); if (!blockSelection) { return; diff --git a/blocksuite/affine/block-root/src/widgets/format-bar/format-bar.ts b/blocksuite/affine/block-root/src/widgets/format-bar/format-bar.ts index d217e35f3c..d40aaf8be2 100644 --- a/blocksuite/affine/block-root/src/widgets/format-bar/format-bar.ts +++ b/blocksuite/affine/block-root/src/widgets/format-bar/format-bar.ts @@ -29,11 +29,7 @@ import { TextSelection, WidgetComponent, } from '@blocksuite/block-std'; -import { - assertExists, - DisposableGroup, - nextTick, -} from '@blocksuite/global/utils'; +import { DisposableGroup, nextTick } from '@blocksuite/global/utils'; import type { BaseSelection } from '@blocksuite/store'; import { autoUpdate, @@ -239,7 +235,9 @@ export class AffineFormatBarWidget extends WidgetComponent { private _listenFloatingElement() { const formatQuickBarElement = this.formatBarElement; - assertExists(formatQuickBarElement, 'format quick bar should exist'); + if (!formatQuickBarElement) { + return; + } const listenFloatingElement = ( getElement: () => ReferenceElement | void @@ -249,7 +247,10 @@ export class AffineFormatBarWidget extends WidgetComponent { return; } - assertExists(this._floatDisposables); + if (!this._floatDisposables) { + return; + } + HoverController.globalAbortController?.abort(); this._floatDisposables.add( autoUpdate( @@ -512,7 +513,9 @@ export class AffineFormatBarWidget extends WidgetComponent { this._abortController = new AbortController(); const rootComponent = this.block; - assertExists(rootComponent); + if (!rootComponent) { + return; + } const widgets = rootComponent.widgets; // check if the host use the format bar widget diff --git a/blocksuite/affine/block-root/src/widgets/image-toolbar/components/image-toolbar.ts b/blocksuite/affine/block-root/src/widgets/image-toolbar/components/image-toolbar.ts index 382b1fed8c..96cc075e05 100644 --- a/blocksuite/affine/block-root/src/widgets/image-toolbar/components/image-toolbar.ts +++ b/blocksuite/affine/block-root/src/widgets/image-toolbar/components/image-toolbar.ts @@ -4,7 +4,7 @@ import type { MenuItemGroup, } from '@blocksuite/affine-components/toolbar'; import { renderGroups } from '@blocksuite/affine-components/toolbar'; -import { assertExists, noop } from '@blocksuite/global/utils'; +import { noop } from '@blocksuite/global/utils'; import { MoreVerticalIcon } from '@blocksuite/icons/lit'; import { flip, offset } from '@floating-ui/dom'; import { html, LitElement } from 'lit'; @@ -57,7 +57,9 @@ export class AffineImageToolbar extends LitElement { this._currentOpenMenu = this._popMenuAbortController; - assertExists(this._moreButton); + if (!this._moreButton) { + return; + } createLitPortal({ template: html` diff --git a/blocksuite/affine/block-root/src/widgets/image-toolbar/utils.ts b/blocksuite/affine/block-root/src/widgets/image-toolbar/utils.ts index 0ce65d5778..64166f4a49 100644 --- a/blocksuite/affine/block-root/src/widgets/image-toolbar/utils.ts +++ b/blocksuite/affine/block-root/src/widgets/image-toolbar/utils.ts @@ -4,7 +4,6 @@ import { isInsidePageEditor, } from '@blocksuite/affine-shared/utils'; import { BlockSelection } from '@blocksuite/block-std'; -import { assertExists } from '@blocksuite/global/utils'; export function duplicate( block: ImageBlockComponent, @@ -23,7 +22,10 @@ export function duplicate( const { doc } = model; const parent = doc.getParent(model); - assertExists(parent, 'Parent not found'); + if (!parent) { + console.error(`Parent not found for block(${model.flavour}) ${model.id}`); + return; + } const index = parent?.children.indexOf(model); const duplicateId = doc.addBlock( diff --git a/blocksuite/affine/block-root/src/widgets/slash-menu/slash-menu-popover.ts b/blocksuite/affine/block-root/src/widgets/slash-menu/slash-menu-popover.ts index 2702ff1208..3ae91da9bc 100644 --- a/blocksuite/affine/block-root/src/widgets/slash-menu/slash-menu-popover.ts +++ b/blocksuite/affine/block-root/src/widgets/slash-menu/slash-menu-popover.ts @@ -13,11 +13,7 @@ import { isFuzzyMatch, substringMatchScore, } from '@blocksuite/affine-shared/utils'; -import { - assertExists, - throttle, - WithDisposable, -} from '@blocksuite/global/utils'; +import { throttle, WithDisposable } from '@blocksuite/global/utils'; import { autoPlacement, offset } from '@floating-ui/dom'; import { html, LitElement, nothing, type PropertyValues } from 'lit'; import { property, state } from 'lit/decorators.js'; @@ -592,7 +588,11 @@ export class InnerSlashMenu extends WithDisposable(LitElement) { override willUpdate(changedProperties: PropertyValues) { if (changedProperties.has('menu') && this.menu.length !== 0) { const firstItem = getFirstNotDividerItem(this.menu); - assertExists(firstItem); + if (!firstItem) { + console.error('No item found in slash menu'); + return; + } + this._activeItem = firstItem; // this case happen on query updated diff --git a/blocksuite/affine/block-root/src/widgets/surface-ref-toolbar/utils.ts b/blocksuite/affine/block-root/src/widgets/surface-ref-toolbar/utils.ts index 543d3625d9..30970f24d2 100644 --- a/blocksuite/affine/block-root/src/widgets/surface-ref-toolbar/utils.ts +++ b/blocksuite/affine/block-root/src/widgets/surface-ref-toolbar/utils.ts @@ -7,8 +7,8 @@ import { GfxControllerIdentifier, type GfxModel, } from '@blocksuite/block-std/gfx'; +import { BlockSuiteError } from '@blocksuite/global/exceptions'; import { Bound } from '@blocksuite/global/gfx'; -import { assertExists } from '@blocksuite/global/utils'; export const edgelessToBlob = async ( host: EditorHost, @@ -24,24 +24,25 @@ export const edgelessToBlob = async ( const isBlock = isTopLevelBlock(edgelessElement); const gfx = host.std.get(GfxControllerIdentifier); - return exportManager - .edgelessToCanvas( - options.surfaceRenderer, - bound, - gfx, - isBlock ? [edgelessElement] : undefined, - isBlock ? undefined : [edgelessElement], - { zoom: options.surfaceRenderer.viewport.zoom } - ) - .then(canvas => { - assertExists(canvas); - return new Promise((resolve, reject) => { - canvas.toBlob( - blob => (blob ? resolve(blob) : reject(null)), - 'image/png' - ); - }); - }); + const canvas = await exportManager.edgelessToCanvas( + options.surfaceRenderer, + bound, + gfx, + isBlock ? [edgelessElement] : undefined, + isBlock ? undefined : [edgelessElement], + { zoom: options.surfaceRenderer.viewport.zoom } + ); + + if (!canvas) { + throw new BlockSuiteError( + BlockSuiteError.ErrorCode.ValueNotExists, + 'Failed to export edgeless to canvas' + ); + } + + return new Promise((resolve, reject) => { + canvas.toBlob(blob => (blob ? resolve(blob) : reject(null)), 'image/png'); + }); }; export const writeImageBlobToClipboard = async (blob: Blob) => { diff --git a/blocksuite/affine/block-surface-ref/src/surface-ref-block.ts b/blocksuite/affine/block-surface-ref/src/surface-ref-block.ts index d24545b7c6..3e400f1eda 100644 --- a/blocksuite/affine/block-surface-ref/src/surface-ref-block.ts +++ b/blocksuite/affine/block-surface-ref/src/surface-ref-block.ts @@ -41,7 +41,7 @@ import { deserializeXYWH, type SerializedXYWH, } from '@blocksuite/global/gfx'; -import { assertExists, DisposableGroup } from '@blocksuite/global/utils'; +import { DisposableGroup } from '@blocksuite/global/utils'; import { DeleteIcon, EdgelessIcon, FrameIcon } from '@blocksuite/icons/lit'; import type { BaseSelection, Store } from '@blocksuite/store'; import { css, html, nothing, type TemplateResult } from 'lit'; @@ -279,7 +279,7 @@ export class SurfaceRefBlockComponent extends BlockComponent { selection.update(selList => { diff --git a/blocksuite/affine/block-surface/src/__tests__/math-utils.unit.spec.ts b/blocksuite/affine/block-surface/src/__tests__/math-utils.unit.spec.ts index 229b8d0c6c..f9fd55b0f3 100644 --- a/blocksuite/affine/block-surface/src/__tests__/math-utils.unit.spec.ts +++ b/blocksuite/affine/block-surface/src/__tests__/math-utils.unit.spec.ts @@ -12,7 +12,6 @@ import { toDegree, toRadian, } from '@blocksuite/global/gfx'; -import { assertExists } from '@blocksuite/global/utils'; import { describe, expect, it } from 'vitest'; describe('Line', () => { @@ -43,7 +42,7 @@ describe('Line', () => { [0, 1], [0, -1], ]; - assertExists(rst); + if (!rst) throw new Error('Failed to get line ellipse intersects'); expect( rst.every((point, index) => pointAlmostEqual(point, expected[index])) ).toBeTruthy(); @@ -76,7 +75,7 @@ describe('Line', () => { [0, 10], ] ); - assertExists(rst); + if (!rst) throw new Error('Failed to get line polygon intersects'); expect(pointAlmostEqual(rst[0], [10, 5])).toBeTruthy(); }); diff --git a/blocksuite/affine/block-surface/src/managers/connector-manager.ts b/blocksuite/affine/block-surface/src/managers/connector-manager.ts index afe71a7752..fb77b4a3d2 100644 --- a/blocksuite/affine/block-surface/src/managers/connector-manager.ts +++ b/blocksuite/affine/block-surface/src/managers/connector-manager.ts @@ -12,6 +12,7 @@ import type { GfxLocalElementModel, GfxModel, } from '@blocksuite/block-std/gfx'; +import { BlockSuiteError } from '@blocksuite/global/exceptions'; import type { IBound, IVec, IVec3 } from '@blocksuite/global/gfx'; import { almostEqual, @@ -31,12 +32,7 @@ import { toRadian, Vec, } from '@blocksuite/global/gfx'; -import { - assertEquals, - assertExists, - assertType, - last, -} from '@blocksuite/global/utils'; +import { assertEquals, assertType, last } from '@blocksuite/global/utils'; import { effect } from '@preact/signals-core'; import { Overlay } from '../renderer/overlay.js'; @@ -153,7 +149,10 @@ export function getAnchors(ele: GfxModel) { ) .forEach(vec => { const rst = ele.getLineIntersections(bound.center as IVec, vec as IVec); - assertExists(rst); + if (!rst) { + console.error(`Failed to get line intersections for ${ele.id}`); + return; + } const originPoint = getPointFromBoundsWithRotation( { ...bound, rotate: -rotate }, rst[0] @@ -497,9 +496,7 @@ function getConnectablePoints( pushOuterPoints(points, expandStartBound, expandEndBound, outerBound); } - if (startBound && endBound) { - assertExists(expandStartBound); - assertExists(expandEndBound); + if (startBound && endBound && expandStartBound && expandEndBound) { pushGapMidPoint( points, startPoint, @@ -564,8 +561,12 @@ function getConnectablePoints( almostEqual(item[1], point[1], 0.02) ); }) as IVec3[]; - assertExists(startEnds[0]); - assertExists(startEnds[1]); + if (!startEnds[0] || !startEnds[1]) { + throw new BlockSuiteError( + BlockSuiteError.ErrorCode.ValueNotExists, + 'Failed to get start and end points when getting connectable points' + ); + } return { points, nextStartPoint: startEnds[0], lastEndPoint: startEnds[1] }; } @@ -709,7 +710,12 @@ function getNextPoint( result, [bound.maxX + 10, result[1]] ); - assertExists(intersects); + if (!intersects) { + throw new BlockSuiteError( + BlockSuiteError.ErrorCode.ValueNotExists, + 'Failed to get line intersections for getNextPoint' + ); + } result[0] = intersects[0] + offsetX; } else { const intersects = lineIntersects( @@ -718,7 +724,12 @@ function getNextPoint( result, [bound.x - 10, result[1]] ); - assertExists(intersects); + if (!intersects) { + throw new BlockSuiteError( + BlockSuiteError.ErrorCode.ValueNotExists, + 'Failed to get line intersections for getNextPoint' + ); + } result[0] = intersects[0] - offsetX; } } else { @@ -729,7 +740,12 @@ function getNextPoint( result, [result[0], bound.maxY + 10] ); - assertExists(intersects); + if (!intersects) { + throw new BlockSuiteError( + BlockSuiteError.ErrorCode.ValueNotExists, + 'Failed to get line intersections for getNextPoint' + ); + } result[1] = intersects[1] + offsetY; } else { const intersects = lineIntersects( @@ -738,7 +754,12 @@ function getNextPoint( result, [result[0], bound.y - 10] ); - assertExists(intersects); + if (!intersects) { + throw new BlockSuiteError( + BlockSuiteError.ErrorCode.ValueNotExists, + 'Failed to get line intersections for getNextPoint' + ); + } result[1] = intersects[1] - offsetY; } } @@ -1204,9 +1225,14 @@ export class ConnectorPathGenerator extends PathGenerator { let startPoint: PointLocation | null = null; let endPoint: PointLocation | null = null; - if (source.id && !source.position && target.id && !target.position) { - assertExists(start); - assertExists(end); + if ( + source.id && + !source.position && + target.id && + !target.position && + start && + end + ) { const startAnchors = getAnchors(start); const endAnchors = getAnchors(end); let minDist = Infinity; diff --git a/blocksuite/affine/block-surface/src/utils/a-star.ts b/blocksuite/affine/block-surface/src/utils/a-star.ts index 8bfb4495ed..4548442c73 100644 --- a/blocksuite/affine/block-surface/src/utils/a-star.ts +++ b/blocksuite/affine/block-surface/src/utils/a-star.ts @@ -1,6 +1,5 @@ import type { Bound, IVec3 } from '@blocksuite/global/gfx'; import { almostEqual } from '@blocksuite/global/gfx'; -import { assertExists } from '@blocksuite/global/utils'; import { Graph } from './graph.js'; import { PriorityQueue } from './priority-queue.js'; @@ -67,9 +66,10 @@ export class AStarRunner { const froms = this._cameFrom.get(current); if (!froms) return result; const index = nextIndexs.shift(); - assertExists(index); - nextIndexs.push(froms.indexs[index]); - current = froms.from[index]; + if (index !== undefined && index !== null) { + nextIndexs.push(froms.indexs[index]); + current = froms.from[index]; + } } return result; } @@ -107,7 +107,9 @@ export class AStarRunner { private _neighbors(cur: IVec3) { const neighbors = this._graph.neighbors(cur); const cameFroms = this._cameFrom.get(cur); - assertExists(cameFroms); + if (!cameFroms) { + return []; + } cameFroms.from.forEach(from => { const index = neighbors.findIndex(n => pointAlmostEqual(n, from)); @@ -154,17 +156,18 @@ export class AStarRunner { const curDiagoalCounts = this._diagonalCount.get(current); const curPointPrioritys = this._pointPriority.get(current); const cameFroms = this._cameFrom.get(current); - assertExists(curCosts); - assertExists(curDiagoalCounts); - assertExists(curPointPrioritys); - assertExists(cameFroms); + if (!curCosts || !curDiagoalCounts || !curPointPrioritys || !cameFroms) { + continue; + } const newCosts = curCosts.map(co => co + cost(current, next)); const newDiagonalCounts = curDiagoalCounts.map( (count, index) => count + getDiagonalCount(next, current, cameFroms.from[index]) ); - assertExists(next[2]); + if (!next[2]) { + continue; + } const newPointPrioritys = curPointPrioritys.map( pointPriority => pointPriority + next[2] ); diff --git a/blocksuite/affine/components/src/portal/helper.ts b/blocksuite/affine/components/src/portal/helper.ts index ee3f856c61..87f1e0951f 100644 --- a/blocksuite/affine/components/src/portal/helper.ts +++ b/blocksuite/affine/components/src/portal/helper.ts @@ -1,4 +1,5 @@ -import { assertExists, Slot } from '@blocksuite/global/utils'; +import { BlockSuiteError } from '@blocksuite/global/exceptions'; +import { Slot } from '@blocksuite/global/utils'; import { autoUpdate, computePosition, @@ -39,7 +40,12 @@ export function createSimplePortal({ }); const root = shadowDom ? portalRoot.shadowRoot : portalRoot; - assertExists(root); + if (!root) { + throw new BlockSuiteError( + BlockSuiteError.ErrorCode.ValueNotExists, + 'Failed to create portal root' + ); + } let updateId = 0; const updatePortal: (id: number) => void = id => { @@ -55,7 +61,6 @@ export function createSimplePortal({ template instanceof Function ? template({ updatePortal: () => updatePortal(curId) }) : template; - assertExists(templateResult); render(templateResult, root, renderOptions); }; @@ -173,7 +178,6 @@ export function createLitPortal({ ? positionConfigOrFn(portalRoot) : positionConfigOrFn; const { referenceElement, ...options } = computePositionOptions; - assertExists(referenceElement, 'referenceElement is required'); const update = () => { if ( computePositionOptions.abortWhenRefRemoved !== false && diff --git a/blocksuite/affine/components/src/rich-text/format/format-block.ts b/blocksuite/affine/components/src/rich-text/format/format-block.ts index d7f1a97381..3e1dcf9284 100644 --- a/blocksuite/affine/components/src/rich-text/format/format-block.ts +++ b/blocksuite/affine/components/src/rich-text/format/format-block.ts @@ -1,7 +1,6 @@ import { getSelectedBlocksCommand } from '@blocksuite/affine-shared/commands'; import type { AffineTextAttributes } from '@blocksuite/affine-shared/types'; import type { BlockSelection, Command } from '@blocksuite/block-std'; -import { assertExists } from '@blocksuite/global/utils'; import { INLINE_ROOT_ATTR, type InlineRootElement } from '@blocksuite/inline'; import { FORMAT_BLOCK_SUPPORT_FLAVOURS } from './consts.js'; @@ -14,10 +13,12 @@ export const formatBlockCommand: Command<{ mode?: 'replace' | 'merge'; }> = (ctx, next) => { const blockSelections = ctx.blockSelections ?? ctx.currentBlockSelections; - assertExists( - blockSelections, - '`blockSelections` is required, you need to pass it in args or use `getBlockSelections` command before adding this command to the pipeline.' - ); + if (!blockSelections) { + console.error( + '`blockSelections` is required, you need to pass it in args or use `getBlockSelections` command before adding this command to the pipeline.' + ); + return; + } if (blockSelections.length === 0) return; @@ -33,7 +34,12 @@ export const formatBlockCommand: Command<{ }) .pipe((ctx, next) => { const { selectedBlocks } = ctx; - assertExists(selectedBlocks); + if (!selectedBlocks) { + console.error( + '`selectedBlocks` is required, you need to pass it in args or use `getSelectedBlocksCommand` command before adding this command to the pipeline.' + ); + return; + } const selectedInlineEditors = selectedBlocks.flatMap(el => { const inlineRoot = el.querySelector< diff --git a/blocksuite/affine/components/src/rich-text/format/utils.ts b/blocksuite/affine/components/src/rich-text/format/utils.ts index 657199ffee..51660c3566 100644 --- a/blocksuite/affine/components/src/rich-text/format/utils.ts +++ b/blocksuite/affine/components/src/rich-text/format/utils.ts @@ -11,7 +11,6 @@ import { type EditorHost, type InitCommandCtx, } from '@blocksuite/block-std'; -import { assertExists } from '@blocksuite/global/utils'; import { INLINE_ROOT_ATTR, type InlineEditor, @@ -92,7 +91,12 @@ function handleCurrentSelection( }) .pipe((ctx, next) => { const { selectedBlocks } = ctx; - assertExists(selectedBlocks); + if (!selectedBlocks) { + console.error( + '`selectedBlocks` is required, you need to pass it in args or use `getSelectedBlocksCommand` command before adding this command to the pipeline.' + ); + return false; + } const selectedInlineEditors = getSelectedInlineEditors( selectedBlocks, @@ -119,7 +123,12 @@ function handleCurrentSelection( }) .pipe((ctx, next) => { const { selectedBlocks } = ctx; - assertExists(selectedBlocks); + if (!selectedBlocks) { + console.error( + '`selectedBlocks` is required, you need to pass it in args or use `getSelectedBlocksCommand` command before adding this command to the pipeline.' + ); + return false; + } const selectedInlineEditors = getSelectedInlineEditors( selectedBlocks, diff --git a/blocksuite/affine/components/src/rich-text/inline/presets/nodes/reference-node/reference-alias-popup.ts b/blocksuite/affine/components/src/rich-text/inline/presets/nodes/reference-node/reference-alias-popup.ts index 72b76fed67..a55332f9b6 100644 --- a/blocksuite/affine/components/src/rich-text/inline/presets/nodes/reference-node/reference-alias-popup.ts +++ b/blocksuite/affine/components/src/rich-text/inline/presets/nodes/reference-node/reference-alias-popup.ts @@ -8,11 +8,7 @@ import { import { FONT_XS, PANEL_BASE } from '@blocksuite/affine-shared/styles'; import type { AffineTextAttributes } from '@blocksuite/affine-shared/types'; import { type BlockStdScope, ShadowlessElement } from '@blocksuite/block-std'; -import { - assertExists, - SignalWatcher, - WithDisposable, -} from '@blocksuite/global/utils'; +import { SignalWatcher, WithDisposable } from '@blocksuite/global/utils'; import { DoneIcon, ResetIcon } from '@blocksuite/icons/lit'; import type { DeltaInsert, InlineRange } from '@blocksuite/inline'; import { computePosition, inline, offset, shift } from '@floating-ui/dom'; @@ -211,7 +207,9 @@ export class ReferenceAliasPopup extends SignalWatcher( override updated() { const range = this.inlineEditor.toDomRange(this.inlineRange); - assertExists(range); + if (!range) { + return; + } const visualElement = { getBoundingClientRect: () => range.getBoundingClientRect(), diff --git a/blocksuite/affine/components/src/rich-text/inline/presets/nodes/reference-node/reference-popup.ts b/blocksuite/affine/components/src/rich-text/inline/presets/nodes/reference-node/reference-popup.ts index d5d25eb3e7..cc28695e1a 100644 --- a/blocksuite/affine/components/src/rich-text/inline/presets/nodes/reference-node/reference-popup.ts +++ b/blocksuite/affine/components/src/rich-text/inline/presets/nodes/reference-node/reference-popup.ts @@ -16,7 +16,7 @@ import { type BlockComponent, type BlockStdScope, } from '@blocksuite/block-std'; -import { assertExists, WithDisposable } from '@blocksuite/global/utils'; +import { WithDisposable } from '@blocksuite/global/utils'; import { ArrowDownSmallIcon, MoreVerticalIcon } from '@blocksuite/icons/lit'; import type { InlineRange } from '@blocksuite/inline'; import { computePosition, inline, offset, shift } from '@floating-ui/dom'; @@ -51,6 +51,10 @@ export class ReferencePopup extends WithDisposable(LitElement) { static override styles = styles; private readonly _copyLink = () => { + if (!this.std) { + console.error('`std` is not found'); + return; + } const url = this.std .getOptional(GenerateDocUrlProvider) ?.generateDocUrl(this.referenceInfo.pageId, this.referenceInfo.params); @@ -66,6 +70,10 @@ export class ReferencePopup extends WithDisposable(LitElement) { }; private readonly _openDoc = (event?: Partial) => { + if (!this.std) { + console.error('`std` is not found'); + return; + } this.std.getOptional(RefNodeSlotsProvider)?.docLinkClicked.emit({ ...this.referenceInfo, ...event, @@ -89,6 +97,11 @@ export class ReferencePopup extends WithDisposable(LitElement) { abortController, } = this; + if (!std) { + console.error('`std` is not found'); + return; + } + const aliasPopup = new ReferenceAliasPopup(); aliasPopup.std = std; @@ -105,6 +118,10 @@ export class ReferencePopup extends WithDisposable(LitElement) { }; private readonly _toggleViewSelector = (e: Event) => { + if (!this.std) { + console.error('`std` is not found'); + return; + } const opened = (e as CustomEvent).detail; if (!opened) return; @@ -112,6 +129,10 @@ export class ReferencePopup extends WithDisposable(LitElement) { }; private readonly _trackViewSelected = (type: string) => { + if (!this.std) { + console.error('`std` is not found'); + return; + } track(this.std, 'SelectedView', { control: 'select view', type: `${type} view`, @@ -119,6 +140,11 @@ export class ReferencePopup extends WithDisposable(LitElement) { }; get _embedViewButtonDisabled() { + if (!this.block) { + console.error('`block` is not found'); + return true; + } + if ( this.block.doc.readonly || isInsideBlockByFlavour( @@ -131,13 +157,13 @@ export class ReferencePopup extends WithDisposable(LitElement) { } return ( !!this.block.closest('affine-embed-synced-doc-block') || - this.referenceDocId === this.doc.id + this.referenceDocId === this.block.doc.id ); } _openButtonDisabled(openMode?: OpenDocMode) { if (openMode === 'open-in-active-view') { - return this.referenceDocId === this.doc.id; + return this.referenceDocId === this.doc?.id; } return false; } @@ -146,34 +172,32 @@ export class ReferencePopup extends WithDisposable(LitElement) { const block = this.inlineEditor.rootElement?.closest( `[${BLOCK_ID_ATTR}]` ); - assertExists(block); return block; } get doc() { - const doc = this.block.doc; - assertExists(doc); + const doc = this.block?.doc; return doc; } get referenceDocId() { const docId = this.inlineEditor.getFormat(this.targetInlineRange).reference ?.pageId; - assertExists(docId); return docId; } get std() { - const std = this.block.std; - assertExists(std); + const std = this.block?.std; return std; } private _convertToCardView() { const block = this.block; + if (!block) return; + const doc = block.host.doc; const parent = doc.getParent(block.model); - assertExists(parent); + if (!parent) return; const index = parent.children.indexOf(block.model); @@ -197,10 +221,17 @@ export class ReferencePopup extends WithDisposable(LitElement) { private _convertToEmbedView() { const block = this.block; - const std = block.std; + const std = block?.std; + if (!std || !block) { + console.error('`std` or `block` is not found'); + return; + } const doc = block.host.doc; const parent = doc.getParent(block.model); - assertExists(parent); + if (!parent) { + console.error('`parent` is not found'); + return; + } const index = parent.children.indexOf(block.model); const referenceInfo = this.referenceInfo; @@ -242,7 +273,7 @@ export class ReferencePopup extends WithDisposable(LitElement) { type: 'delete', label: 'Delete', icon: DeleteIcon, - disabled: this.doc.readonly, + disabled: this.doc?.readonly, action: () => this._delete(), }, ], @@ -250,6 +281,10 @@ export class ReferencePopup extends WithDisposable(LitElement) { } private _openMenuButton() { + if (!this.std) { + console.error('`std` is not found'); + return nothing; + } const openDocConfig = this.std.get(OpenDocExtensionIdentifier); const buttons: MenuItem[] = openDocConfig.items @@ -330,7 +365,7 @@ export class ReferencePopup extends WithDisposable(LitElement) { type: 'card', label: 'Card view', action: () => this._convertToCardView(), - disabled: this.doc.readonly, + disabled: this.doc?.readonly, }); buttons.push({ @@ -338,7 +373,9 @@ export class ReferencePopup extends WithDisposable(LitElement) { label: 'Embed view', action: () => this._convertToEmbedView(), disabled: - this.doc.readonly || this.isLinkedNode || this._embedViewButtonDisabled, + this.doc?.readonly || + this.isLinkedNode || + this._embedViewButtonDisabled, }); return html` @@ -388,11 +425,14 @@ export class ReferencePopup extends WithDisposable(LitElement) { return; } + if (!this.block) return; + const parent = this.block.host.doc.getParent(this.block.model); - assertExists(parent); + if (!parent) return; this.disposables.add( effect(() => { + if (!this.block) return; const children = parent.children; if (children.includes(this.block.model)) return; this.abortController.abort(); @@ -435,7 +475,7 @@ export class ReferencePopup extends WithDisposable(LitElement) { aria-label="Edit" data-testid="edit" .tooltip=${'Edit'} - ?disabled=${this.doc.readonly} + ?disabled=${this.doc?.readonly} @click=${this._openEditPopup} > ${EditIcon} @@ -479,10 +519,8 @@ export class ReferencePopup extends WithDisposable(LitElement) { } override updated() { - assertExists(this.popupContainer); const range = this.inlineEditor.toDomRange(this.targetInlineRange); - assertExists(range); - + if (!range) return; const visualElement = { getBoundingClientRect: () => range.getBoundingClientRect(), getClientRects: () => range.getClientRects(), diff --git a/blocksuite/affine/components/src/rich-text/rich-text.ts b/blocksuite/affine/components/src/rich-text/rich-text.ts index acc98d86d8..1fcb742c29 100644 --- a/blocksuite/affine/components/src/rich-text/rich-text.ts +++ b/blocksuite/affine/components/src/rich-text/rich-text.ts @@ -1,6 +1,6 @@ import type { AffineTextAttributes } from '@blocksuite/affine-shared/types'; import { ShadowlessElement } from '@blocksuite/block-std'; -import { assertExists, WithDisposable } from '@blocksuite/global/utils'; +import { WithDisposable } from '@blocksuite/global/utils'; import { type AttributeRenderer, type DeltaInsert, @@ -148,7 +148,6 @@ export class RichText extends WithDisposable(ShadowlessElement) { } get inlineEditorContainer() { - assertExists(this._inlineEditorContainer); return this._inlineEditorContainer; } diff --git a/blocksuite/affine/components/src/toolbar/tooltip.ts b/blocksuite/affine/components/src/toolbar/tooltip.ts index 95abb75058..d1bec091b2 100644 --- a/blocksuite/affine/components/src/toolbar/tooltip.ts +++ b/blocksuite/affine/components/src/toolbar/tooltip.ts @@ -1,5 +1,4 @@ import { requestConnectedFrame } from '@blocksuite/affine-shared/utils'; -import { assertExists } from '@blocksuite/global/utils'; import { arrow, type ComputePositionReturn, @@ -193,7 +192,10 @@ export class Tooltip extends LitElement { ); const parent = this.parentElement; - assertExists(parent, 'Tooltip must have a parent element'); + if (!parent) { + console.error('Tooltip must have a parent element'); + return; + } // Wait for render requestConnectedFrame(() => { diff --git a/blocksuite/affine/data-view/src/view-presets/kanban/pc/controller/drag.ts b/blocksuite/affine/data-view/src/view-presets/kanban/pc/controller/drag.ts index decda0736e..543cc6ab9d 100644 --- a/blocksuite/affine/data-view/src/view-presets/kanban/pc/controller/drag.ts +++ b/blocksuite/affine/data-view/src/view-presets/kanban/pc/controller/drag.ts @@ -1,6 +1,5 @@ import type { InsertToPosition } from '@blocksuite/affine-shared/utils'; import { Point, Rect } from '@blocksuite/global/gfx'; -import { assertExists } from '@blocksuite/global/utils'; import { computed } from '@preact/signals-core'; import type { ReactiveController } from 'lit'; @@ -137,7 +136,6 @@ export class KanbanDragController implements ReactiveController { const scrollContainer = this.host.querySelector( '.affine-data-view-kanban-groups' ) as HTMLElement; - assertExists(scrollContainer); return scrollContainer; } @@ -213,7 +211,10 @@ const createDropPreview = () => { card?: KanbanCard ) { const target = card ?? group.querySelector('.add-card'); - assertExists(target); + if (!target) { + console.error('`target` is not found'); + return; + } if (target.previousElementSibling === self || target === self) { div.remove(); return; diff --git a/blocksuite/affine/data-view/src/view-presets/kanban/pc/controller/selection.ts b/blocksuite/affine/data-view/src/view-presets/kanban/pc/controller/selection.ts index 573e5d76cf..8c1ae4b4ae 100644 --- a/blocksuite/affine/data-view/src/view-presets/kanban/pc/controller/selection.ts +++ b/blocksuite/affine/data-view/src/view-presets/kanban/pc/controller/selection.ts @@ -1,5 +1,4 @@ import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; -import { assertExists } from '@blocksuite/global/utils'; import type { ReactiveController } from 'lit'; import type { @@ -611,7 +610,7 @@ function getNextGroupFocusElement( selection.selectionType === 'cell' ? getFocusCell(viewElement, selection) : getSelectedCards(viewElement, selection)[0]; - assertExists(element); + if (!element) return; const rect = element.getBoundingClientRect(); const nextCards = Array.from( nextGroup.querySelectorAll('affine-data-view-kanban-card') diff --git a/blocksuite/affine/data-view/src/view-presets/table/pc/cell.ts b/blocksuite/affine/data-view/src/view-presets/table/pc/cell.ts index 044492124a..97f548c97f 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/pc/cell.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/pc/cell.ts @@ -1,9 +1,5 @@ import { ShadowlessElement } from '@blocksuite/block-std'; -import { - assertExists, - SignalWatcher, - WithDisposable, -} from '@blocksuite/global/utils'; +import { SignalWatcher, WithDisposable } from '@blocksuite/global/utils'; import { computed } from '@preact/signals-core'; import { css } from 'lit'; import { property, state } from 'lit/decorators.js'; @@ -102,7 +98,6 @@ export class DatabaseCellContainer extends SignalWatcher( get table() { const table = this.closest('affine-database-table'); - assertExists(table); return table; } diff --git a/blocksuite/affine/shared/src/adapters/middlewares/paste.ts b/blocksuite/affine/shared/src/adapters/middlewares/paste.ts index 038e1a4a9f..2ca42e780e 100644 --- a/blocksuite/affine/shared/src/adapters/middlewares/paste.ts +++ b/blocksuite/affine/shared/src/adapters/middlewares/paste.ts @@ -15,7 +15,6 @@ import { TextSelection, } from '@blocksuite/block-std'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; -import { assertExists } from '@blocksuite/global/utils'; import { type BlockModel, type BlockSnapshot, @@ -64,9 +63,14 @@ const findLast = (snapshot: SliceSnapshot): BlockSnapshot | null => { }; class PointState { - private readonly _blockFromPath = (path: string) => { - const block = this.std.view.getBlock(path); - assertExists(block); + private readonly _blockFromPath = (id: string) => { + const block = this.std.view.getBlock(id); + if (!block) { + throw new BlockSuiteError( + ErrorCode.TransformerError, + `Block not found when pasting: ${id}` + ); + } return block; }; diff --git a/blocksuite/affine/shared/src/adapters/middlewares/replace-id.ts b/blocksuite/affine/shared/src/adapters/middlewares/replace-id.ts index fa6f02a9b3..3aaa0387ee 100644 --- a/blocksuite/affine/shared/src/adapters/middlewares/replace-id.ts +++ b/blocksuite/affine/shared/src/adapters/middlewares/replace-id.ts @@ -6,7 +6,7 @@ import type { ParagraphBlockModel, SurfaceRefBlockModel, } from '@blocksuite/affine-model'; -import { assertExists } from '@blocksuite/global/utils'; +import { BlockSuiteError } from '@blocksuite/global/exceptions'; import type { DeltaOperation, TransformerMiddleware } from '@blocksuite/store'; export const replaceIdMiddleware = @@ -166,13 +166,23 @@ export const replaceIdMiddleware = let connection = value.source as Record; if (idMap.has(connection.id)) { const newId = idMap.get(connection.id); - assertExists(newId, 'reference id must exist'); + if (!newId) { + throw new BlockSuiteError( + BlockSuiteError.ErrorCode.TransformerError, + `reference id must exist: ${connection.id}` + ); + } connection.id = newId; } connection = value.target as Record; if (idMap.has(connection.id)) { const newId = idMap.get(connection.id); - assertExists(newId, 'reference id must exist'); + if (!newId) { + throw new BlockSuiteError( + BlockSuiteError.ErrorCode.TransformerError, + `reference id must exist: ${connection.id}` + ); + } connection.id = newId; } break; @@ -184,7 +194,12 @@ export const replaceIdMiddleware = if (idMap.has(key)) { delete json[key]; const newKey = idMap.get(key); - assertExists(newKey, 'reference id must exist'); + if (!newKey) { + throw new BlockSuiteError( + BlockSuiteError.ErrorCode.TransformerError, + `reference id must exist: ${key}` + ); + } json[newKey] = value; } }); diff --git a/blocksuite/affine/shared/src/utils/spec/spec-provider.ts b/blocksuite/affine/shared/src/utils/spec/spec-provider.ts index 58b67cf3b0..0fdcfe16ae 100644 --- a/blocksuite/affine/shared/src/utils/spec/spec-provider.ts +++ b/blocksuite/affine/shared/src/utils/spec/spec-provider.ts @@ -1,4 +1,4 @@ -import { assertExists } from '@blocksuite/global/utils'; +import { BlockSuiteError } from '@blocksuite/global/exceptions'; import type { ExtensionType } from '@blocksuite/store'; import { SpecBuilder } from './spec-builder.js'; @@ -45,7 +45,12 @@ export class SpecProvider { getSpec(id: SpecId) { const spec = this.specMap.get(id); - assertExists(spec, `Spec not found for ${id}`); + if (!spec) { + throw new BlockSuiteError( + BlockSuiteError.ErrorCode.ValueNotExists, + `Spec not found for ${id}` + ); + } return new SpecBuilder(spec); } diff --git a/blocksuite/framework/global/src/utils/assert.ts b/blocksuite/framework/global/src/utils/assert.ts index e2ed55c778..84fad2e05e 100644 --- a/blocksuite/framework/global/src/utils/assert.ts +++ b/blocksuite/framework/global/src/utils/assert.ts @@ -10,23 +10,6 @@ export function isPrimitive( export function assertType(_: unknown): asserts _ is T {} -/** - * @deprecated Avoid using this util as escape hatch of error handling. - * For non-framework code, please handle error in application level instead. - */ -export function assertExists( - val: T | null | undefined, - message: string | Error = 'val does not exist', - errorCode = ErrorCode.ValueNotExists -): asserts val is T { - if (val === null || val === undefined) { - if (message instanceof Error) { - throw message; - } - throw new BlockSuiteError(errorCode, message); - } -} - export function assertNotExists( val: T | null | undefined, message = 'val exists', diff --git a/blocksuite/framework/inline/src/components/v-line.ts b/blocksuite/framework/inline/src/components/v-line.ts index 708e40e9f7..0d32fcacad 100644 --- a/blocksuite/framework/inline/src/components/v-line.ts +++ b/blocksuite/framework/inline/src/components/v-line.ts @@ -1,5 +1,4 @@ import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; -import { assertExists } from '@blocksuite/global/utils'; import { html, LitElement, type TemplateResult } from 'lit'; import { property } from 'lit/decorators.js'; import { styleMap } from 'lit/directives/style-map.js'; @@ -14,12 +13,19 @@ export class VLine extends LitElement { const rootElement = this.closest( `[${INLINE_ROOT_ATTR}]` ) as InlineRootElement; - assertExists(rootElement, 'v-line must be inside a v-root'); + if (!rootElement) { + throw new BlockSuiteError( + BlockSuiteError.ErrorCode.ValueNotExists, + 'v-line must be inside a v-root' + ); + } const inlineEditor = rootElement.inlineEditor; - assertExists( - inlineEditor, - 'v-line must be inside a v-root with inline-editor' - ); + if (!inlineEditor) { + throw new BlockSuiteError( + BlockSuiteError.ErrorCode.ValueNotExists, + 'v-line must be inside a v-root with inline-editor' + ); + } return inlineEditor; } diff --git a/blocksuite/framework/inline/src/services/range.ts b/blocksuite/framework/inline/src/services/range.ts index 7dee7f857f..932dcc9a82 100644 --- a/blocksuite/framework/inline/src/services/range.ts +++ b/blocksuite/framework/inline/src/services/range.ts @@ -1,4 +1,4 @@ -import { assertExists } from '@blocksuite/global/utils'; +import { assertInstanceOf } from '@blocksuite/global/utils'; import { effect } from '@preact/signals-core'; import * as Y from 'yjs'; @@ -47,7 +47,7 @@ export class RangeService { return null; } const textNode = text.childNodes[1]; - assertExists(textNode instanceof Text); + assertInstanceOf(textNode, Text); range.setStart(textNode, 0); range.setEnd(textNode, textNode.textContent?.length ?? 0); const inlineRange = this.toInlineRange(range); @@ -158,7 +158,10 @@ export class RangeService { // can not in the first line because if we apply the inline ranage manually the // cursor will jump to the second line. const container = range.commonAncestorContainer.parentElement; - assertExists(container); + if (!container) { + console.error('failed to get container'); + return false; + } const containerRect = container.getBoundingClientRect(); // There will be two rects if the cursor is at the edge of the line: // aaaaaaaa| or aaaaaaaa @@ -200,7 +203,10 @@ export class RangeService { // can not in the first line because if we apply the inline range manually the // cursor will jump to the second line. const container = range.commonAncestorContainer.parentElement; - assertExists(container); + if (!container) { + console.error('failed to get container'); + return false; + } const containerRect = container.getBoundingClientRect(); // There will be two rects if the cursor is at the edge of the line: // aaaaaaaa| or aaaaaaaa diff --git a/blocksuite/framework/inline/src/services/render.ts b/blocksuite/framework/inline/src/services/render.ts index e6549d8a7e..8050a3499e 100644 --- a/blocksuite/framework/inline/src/services/render.ts +++ b/blocksuite/framework/inline/src/services/render.ts @@ -1,5 +1,4 @@ import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; -import { assertExists } from '@blocksuite/global/utils'; import { html, render } from 'lit'; import { repeat } from 'lit/directives/repeat.js'; import * as Y from 'yjs'; @@ -36,7 +35,10 @@ export class RenderService { if (!lastStartRelativePosition || !lastEndRelativePosition) return; const doc = this.editor.yText.doc; - assertExists(doc); + if (!doc) { + console.error('doc is not found when syncing yText'); + return; + } const absoluteStart = Y.createAbsolutePositionFromRelativePosition( lastStartRelativePosition, doc diff --git a/blocksuite/framework/store/src/__tests__/collection.unit.spec.ts b/blocksuite/framework/store/src/__tests__/collection.unit.spec.ts index 138fdd70ce..fd0049c99b 100644 --- a/blocksuite/framework/store/src/__tests__/collection.unit.spec.ts +++ b/blocksuite/framework/store/src/__tests__/collection.unit.spec.ts @@ -13,7 +13,6 @@ import { ParagraphBlockSchemaExtension, RootBlockSchemaExtension, } from './test-schema.js'; -import { assertExists } from './test-utils-dom.js'; function createTestOptions() { const idGenerator = createAutoIncrementIdGenerator(); @@ -207,7 +206,9 @@ describe('basic', () => { const doc2 = collection2.getDoc('space:0', { extensions, }); - assertExists(doc2); + if (!doc2) { + throw new Error('doc2 is not found'); + } applyUpdate(doc2.spaceDoc, update); expect(serializCollection(collection2.doc)['spaces']).toEqual({ 'space:0': { diff --git a/blocksuite/framework/store/src/__tests__/test-utils-dom.ts b/blocksuite/framework/store/src/__tests__/test-utils-dom.ts index 034ed38717..1e02f23c99 100644 --- a/blocksuite/framework/store/src/__tests__/test-utils-dom.ts +++ b/blocksuite/framework/store/src/__tests__/test-utils-dom.ts @@ -65,13 +65,6 @@ export async function runOnce() { testCases = []; } -// XXX: workaround typing issue in blobs/__tests__/test-entry.ts -export function assertExists(val: T | null | undefined): asserts val is T { - if (val === null || val === undefined) { - throw new Error('val does not exist'); - } -} - export async function nextFrame() { return new Promise(resolve => requestAnimationFrame(resolve)); } diff --git a/blocksuite/framework/sync/src/doc/impl/broadcast.ts b/blocksuite/framework/sync/src/doc/impl/broadcast.ts index 42f896d694..7749bc61b6 100644 --- a/blocksuite/framework/sync/src/doc/impl/broadcast.ts +++ b/blocksuite/framework/sync/src/doc/impl/broadcast.ts @@ -1,4 +1,3 @@ -import { assertExists } from '@blocksuite/global/utils'; import { diffUpdate, encodeStateVectorFromUpdate, mergeUpdates } from 'yjs'; import { MANUALLY_STOP } from '../../utils/throw-if-aborted.js'; @@ -66,7 +65,12 @@ export class BroadcastChannelDocSource implements DocSource { this.docMap.set(docId, data); } - assertExists(this.docMap.get(docId)); + const doc = this.docMap.get(docId); + if (!doc) { + console.error('data is not found when syncing broadcast channel'); + return; + } + this.channel.postMessage({ type: 'update', docId, diff --git a/blocksuite/integration-test/src/__tests__/edgeless/group.spec.ts b/blocksuite/integration-test/src/__tests__/edgeless/group.spec.ts index 72f8a57db4..f3bc9638a1 100644 --- a/blocksuite/integration-test/src/__tests__/edgeless/group.spec.ts +++ b/blocksuite/integration-test/src/__tests__/edgeless/group.spec.ts @@ -5,7 +5,6 @@ import { LayoutType, NoteDisplayMode, } from '@blocksuite/blocks'; -import { assertExists } from '@blocksuite/global/utils'; import { beforeEach, describe, expect, test } from 'vitest'; import * as Y from 'yjs'; @@ -68,12 +67,16 @@ describe('group', () => { const shapeId = service.crud.addElement('shape', { shapeType: 'rect', }); - assertExists(shapeId); + if (!shapeId) { + throw new Error('shapeId is not found'); + } map.set(noteId, true); map.set(shapeId, true); const groupId = service.crud.addElement('group', { children: map }); - assertExists(groupId); + if (!groupId) { + throw new Error('groupId is not found'); + } expect(service.elements.length).toBe(2); expect(doc.getBlock(noteId)).toBeDefined(); doc.captureSync(); @@ -92,12 +95,16 @@ describe('group', () => { shapeType: 'rect', xywh: '[0,0,100,100]', }); - assertExists(shape1); + if (!shape1) { + throw new Error('shape1 is not found'); + } const shape2 = service.crud.addElement('shape', { shapeType: 'rect', xywh: '[100,100,100,100]', }); - assertExists(shape2); + if (!shape2) { + throw new Error('shape2 is not found'); + } const note1 = addNote(doc, { displayMode: NoteDisplayMode.DocAndEdgeless, xywh: '[200,200,800,100]', @@ -119,7 +126,9 @@ describe('group', () => { children.set(note1, true); const groupId = service.crud.addElement('group', { children }); - assertExists(groupId); + if (!groupId) { + throw new Error('groupId is not found'); + } const group = service.crud.getElementById(groupId) as GroupElementModel; const assertInitial = () => { @@ -189,7 +198,9 @@ describe('group', () => { test('empty group should have all zero xywh', () => { const map = new Y.Map(); const groupId = service.crud.addElement('group', { children: map }); - assertExists(groupId); + if (!groupId) { + throw new Error('groupId is not found'); + } const group = service.crud.getElementById(groupId) as GroupElementModel; expect(group.x).toBe(0); @@ -253,7 +264,9 @@ describe('mindmap', () => { ], }; const mindmapId = service.crud.addElement('mindmap', { children: tree }); - assertExists(mindmapId); + if (!mindmapId) { + throw new Error('mindmapId is not found'); + } const mindmap = () => service.crud.getElementById(mindmapId) as MindmapElementModel; @@ -304,7 +317,9 @@ describe('mindmap', () => { type: LayoutType.RIGHT, children: tree, }); - assertExists(mindmapId); + if (!mindmapId) { + throw new Error('mindmapId is not found'); + } const mindmap = () => service.crud.getElementById(mindmapId) as MindmapElementModel; @@ -349,7 +364,10 @@ describe('mindmap', () => { type: LayoutType.RIGHT, children: tree, }); - assertExists(mindmapId); + if (!mindmapId) { + throw new Error('mindmapId is not found'); + } + const mindmap = () => service.crud.getElementById(mindmapId) as MindmapElementModel; diff --git a/blocksuite/integration-test/src/__tests__/edgeless/last-props.spec.ts b/blocksuite/integration-test/src/__tests__/edgeless/last-props.spec.ts index 495461f403..7c357158b6 100644 --- a/blocksuite/integration-test/src/__tests__/edgeless/last-props.spec.ts +++ b/blocksuite/integration-test/src/__tests__/edgeless/last-props.spec.ts @@ -19,7 +19,6 @@ import { ShapeType, type TextElementModel, } from '@blocksuite/blocks'; -import { assertExists } from '@blocksuite/global/utils'; import { beforeEach, describe, expect, test } from 'vitest'; import { getDocRootBlock } from '../utils/edgeless.js'; @@ -44,7 +43,9 @@ describe('apply last props', () => { const rectId = service.crud.addElement('shape', { shapeType: ShapeType.Rect, }); - assertExists(rectId); + if (!rectId) { + throw new Error('rectId is not found'); + } const rectShape = service.crud.getElementById(rectId) as ShapeElementModel; expect(rectShape.fillColor).toBe(DefaultTheme.shapeFillColor); service.crud.updateElement(rectId, { @@ -59,7 +60,9 @@ describe('apply last props', () => { const diamondId = service.crud.addElement('shape', { shapeType: ShapeType.Diamond, }); - assertExists(diamondId); + if (!diamondId) { + throw new Error('diamondId is not found'); + } const diamondShape = service.crud.getElementById( diamondId ) as ShapeElementModel; @@ -77,7 +80,9 @@ describe('apply last props', () => { shapeType: ShapeType.Rect, radius: 0.1, }); - assertExists(roundedRectId); + if (!roundedRectId) { + throw new Error('roundedRectId is not found'); + } const roundedRectShape = service.crud.getElementById( roundedRectId ) as ShapeElementModel; @@ -95,7 +100,9 @@ describe('apply last props', () => { const rectId2 = service.crud.addElement('shape', { shapeType: ShapeType.Rect, }); - assertExists(rectId2); + if (!rectId2) { + throw new Error('rectId2 is not found'); + } const rectShape2 = service.crud.getElementById( rectId2 ) as ShapeElementModel; @@ -104,7 +111,9 @@ describe('apply last props', () => { const diamondId2 = service.crud.addElement('shape', { shapeType: ShapeType.Diamond, }); - assertExists(diamondId2); + if (!diamondId2) { + throw new Error('diamondId2 is not found'); + } const diamondShape2 = service.crud.getElementById( diamondId2 ) as ShapeElementModel; @@ -114,7 +123,9 @@ describe('apply last props', () => { shapeType: ShapeType.Rect, radius: 0.1, }); - assertExists(roundedRectId2); + if (!roundedRectId2) { + throw new Error('roundedRectId2 is not found'); + } const roundedRectShape2 = service.crud.getElementById( roundedRectId2 ) as ShapeElementModel; @@ -125,7 +136,9 @@ describe('apply last props', () => { test('connector', () => { const id = service.crud.addElement('connector', { mode: 0 }); - assertExists(id); + if (!id) { + throw new Error('id is not found'); + } const connector = service.crud.getElementById(id) as ConnectorElementModel; expect(connector.stroke).toBe(DefaultTheme.connectorColor); expect(connector.strokeWidth).toBe(2); @@ -135,7 +148,9 @@ describe('apply last props', () => { service.crud.updateElement(id, { strokeWidth: 10 }); const id2 = service.crud.addElement('connector', { mode: 1 }); - assertExists(id2); + if (!id2) { + throw new Error('id2 is not found'); + } const connector2 = service.crud.getElementById( id2 ) as ConnectorElementModel; @@ -148,7 +163,9 @@ describe('apply last props', () => { }); const id3 = service.crud.addElement('connector', { mode: 1 }); - assertExists(id3); + if (!id3) { + throw new Error('id3 is not found'); + } const connector3 = service.crud.getElementById( id3 ) as ConnectorElementModel; @@ -159,7 +176,9 @@ describe('apply last props', () => { test('brush', () => { const id = service.crud.addElement('brush', {}); - assertExists(id); + if (!id) { + throw new Error('id is not found'); + } const brush = service.crud.getElementById(id) as BrushElementModel; expect(brush.color).toEqual(DefaultTheme.black); expect(brush.lineWidth).toBe(4); @@ -172,7 +191,9 @@ describe('apply last props', () => { test('text', () => { const id = service.crud.addElement('text', {}); - assertExists(id); + if (!id) { + throw new Error('id is not found'); + } const text = service.crud.getElementById(id) as TextElementModel; expect(text.fontSize).toBe(24); service.crud.updateElement(id, { fontSize: 36 }); @@ -184,7 +205,9 @@ describe('apply last props', () => { test('mindmap', () => { const id = service.crud.addElement('mindmap', {}); - assertExists(id); + if (!id) { + throw new Error('id is not found'); + } const mindmap = service.crud.getElementById(id) as MindmapElementModel; expect(mindmap.layoutType).toBe(LayoutType.RIGHT); expect(mindmap.style).toBe(MindmapStyle.ONE); @@ -194,7 +217,9 @@ describe('apply last props', () => { }); const id2 = service.crud.addElement('mindmap', {}); - assertExists(id2); + if (!id2) { + throw new Error('id2 is not found'); + } const mindmap2 = service.crud.getElementById(id2) as MindmapElementModel; expect(mindmap2.layoutType).toBe(LayoutType.BALANCE); expect(mindmap2.style).toBe(MindmapStyle.THREE); @@ -203,7 +228,9 @@ describe('apply last props', () => { test('edgeless-text', () => { const surface = getSurfaceBlock(doc); const id = service.crud.addBlock('affine:edgeless-text', {}, surface!.id); - assertExists(id); + if (!id) { + throw new Error('id is not found'); + } const text = service.crud.getElementById(id) as EdgelessTextBlockModel; expect(text.color).toBe(DefaultTheme.textColor); expect(text.fontFamily).toBe(FontFamily.Inter); @@ -213,7 +240,9 @@ describe('apply last props', () => { }); const id2 = service.crud.addBlock('affine:edgeless-text', {}, surface!.id); - assertExists(id2); + if (!id2) { + throw new Error('id2 is not found'); + } const text2 = service.crud.getElementById(id2) as EdgelessTextBlockModel; expect(text2.color).toBe(DefaultTheme.StrokeColorShortMap.Green); expect(text2.fontFamily).toBe(FontFamily.OrelegaOne); @@ -221,7 +250,9 @@ describe('apply last props', () => { test('note', () => { const id = service.crud.addBlock('affine:note', {}, doc.root!.id); - assertExists(id); + if (!id) { + throw new Error('id is not found'); + } const note = service.crud.getElementById(id) as NoteBlockModel; expect(note.background).toEqual(DefaultTheme.noteBackgrounColor); expect(note.edgeless.style.shadowType).toBe(DEFAULT_NOTE_SHADOW); @@ -235,7 +266,9 @@ describe('apply last props', () => { }); const id2 = service.crud.addBlock('affine:note', {}, doc.root!.id); - assertExists(id2); + if (!id2) { + throw new Error('id2 is not found'); + } const note2 = service.crud.getElementById(id2) as NoteBlockModel; expect(note2.background).toEqual( DefaultTheme.NoteBackgroundColorMap.Purple @@ -246,7 +279,9 @@ describe('apply last props', () => { test('frame', () => { const surface = getSurfaceBlock(doc); const id = service.crud.addBlock('affine:frame', {}, surface!.id); - assertExists(id); + if (!id) { + throw new Error('id is not found'); + } const note = service.crud.getElementById(id) as FrameBlockModel; expect(note.background).toBe('transparent'); service.crud.updateElement(id, { @@ -254,7 +289,9 @@ describe('apply last props', () => { }); const id2 = service.crud.addBlock('affine:frame', {}, surface!.id); - assertExists(id2); + if (!id2) { + throw new Error('id2 is not found'); + } const frame2 = service.crud.getElementById(id2) as FrameBlockModel; expect(frame2.background).toBe(DefaultTheme.StrokeColorShortMap.Purple); service.crud.updateElement(id2, { @@ -262,7 +299,9 @@ describe('apply last props', () => { }); const id3 = service.crud.addBlock('affine:frame', {}, surface!.id); - assertExists(id3); + if (!id3) { + throw new Error('id3 is not found'); + } const frame3 = service.crud.getElementById(id3) as FrameBlockModel; expect(frame3.background).toEqual({ normal: '#def4e740' }); service.crud.updateElement(id3, { @@ -270,7 +309,9 @@ describe('apply last props', () => { }); const id4 = service.crud.addBlock('affine:frame', {}, surface!.id); - assertExists(id4); + if (!id4) { + throw new Error('id4 is not found'); + } const frame4 = service.crud.getElementById(id4) as FrameBlockModel; expect(frame4.background).toEqual({ light: '#a381aa23', diff --git a/blocksuite/integration-test/src/__tests__/utils/setup.ts b/blocksuite/integration-test/src/__tests__/utils/setup.ts index cdc8865eb1..648419357b 100644 --- a/blocksuite/integration-test/src/__tests__/utils/setup.ts +++ b/blocksuite/integration-test/src/__tests__/utils/setup.ts @@ -19,7 +19,6 @@ import { StoreExtensions, } from '@blocksuite/blocks'; import { AffineSchemas } from '@blocksuite/blocks/schemas'; -import { assertExists } from '@blocksuite/global/utils'; import { Schema, Text } from '@blocksuite/store'; import { createAutoIncrementIdGenerator, @@ -67,7 +66,9 @@ async function createEditor( ) { const app = document.createElement('div'); const blockCollection = collection.docs.values().next().value; - assertExists(blockCollection, 'Need to create a doc first'); + if (!blockCollection) { + throw new Error('Need to create a doc first'); + } const doc = blockCollection.getStore(); const editor = new TestAffineEditorContainer(); editor.doc = doc; diff --git a/blocksuite/playground/apps/_common/history.ts b/blocksuite/playground/apps/_common/history.ts index 50e5740383..b8c8d37464 100644 --- a/blocksuite/playground/apps/_common/history.ts +++ b/blocksuite/playground/apps/_common/history.ts @@ -1,5 +1,4 @@ import type { DocModeProvider } from '@blocksuite/blocks'; -import { assertExists } from '@blocksuite/global/utils'; import type { TestAffineEditorContainer } from '@blocksuite/integration-test'; import type { Doc, Store, Workspace } from '@blocksuite/store'; @@ -13,14 +12,18 @@ export function getDocFromUrlParams(collection: Workspace, url: URL) { } if (!doc) { const blockCollection = collection.docs.values().next().value as Doc; - assertExists(blockCollection, 'Need to create a doc first'); + if (!blockCollection) { + throw new Error('Need to create a doc first'); + } doc = blockCollection.getStore(); } doc.load(); doc.resetHistory(); - assertExists(doc.root, 'Doc root is not ready'); + if (!doc.root) { + throw new Error('Doc root is not ready'); + } return doc; } diff --git a/blocksuite/playground/apps/_common/sync/websocket/awareness.ts b/blocksuite/playground/apps/_common/sync/websocket/awareness.ts index 0f9a631483..19721425af 100644 --- a/blocksuite/playground/apps/_common/sync/websocket/awareness.ts +++ b/blocksuite/playground/apps/_common/sync/websocket/awareness.ts @@ -1,4 +1,3 @@ -import { assertExists } from '@blocksuite/global/utils'; import type { AwarenessSource } from '@blocksuite/sync'; import type { Awareness } from 'y-protocols/awareness'; import { @@ -21,7 +20,9 @@ export class WebSocketAwarenessSource implements AwarenessSource { res.concat(cur) ); - assertExists(this.awareness); + if (!this.awareness) { + throw new Error('awareness is not found'); + } const update = encodeAwarenessUpdate(this.awareness, changedClients); this.ws.send( JSON.stringify({ @@ -42,12 +43,16 @@ export class WebSocketAwarenessSource implements AwarenessSource { if (type === 'update') { const update = data.payload.update; - assertExists(this.awareness); + if (!this.awareness) { + throw new Error('awareness is not found'); + } applyAwarenessUpdate(this.awareness, new Uint8Array(update), 'remote'); } if (type === 'connect') { - assertExists(this.awareness); + if (!this.awareness) { + throw new Error('awareness is not found'); + } this.ws.send( JSON.stringify({ channel: 'awareness', diff --git a/blocksuite/playground/apps/_common/sync/websocket/doc.ts b/blocksuite/playground/apps/_common/sync/websocket/doc.ts index 37c1094caf..ca08c154e8 100644 --- a/blocksuite/playground/apps/_common/sync/websocket/doc.ts +++ b/blocksuite/playground/apps/_common/sync/websocket/doc.ts @@ -1,4 +1,3 @@ -import { assertExists } from '@blocksuite/global/utils'; import type { DocSource } from '@blocksuite/sync'; import { diffUpdate, encodeStateVectorFromUpdate, mergeUpdates } from 'yjs'; @@ -69,7 +68,9 @@ export class WebSocketDocSource implements DocSource { } const latest = this.docMap.get(docId); - assertExists(latest); + if (!latest) { + throw new Error('latest is not found'); + } this.ws.send( JSON.stringify({ channel: 'doc', diff --git a/blocksuite/playground/apps/starter/data/database.ts b/blocksuite/playground/apps/starter/data/database.ts index 1a03a54492..1b87410938 100644 --- a/blocksuite/playground/apps/starter/data/database.ts +++ b/blocksuite/playground/apps/starter/data/database.ts @@ -8,7 +8,6 @@ import { import { groupTraitKey } from '@blocksuite/data-view'; import { propertyPresets } from '@blocksuite/data-view/property-presets'; import { viewPresets } from '@blocksuite/data-view/view-presets'; -import { assertExists } from '@blocksuite/global/utils'; import { Text, type Workspace } from '@blocksuite/store'; import type { InitFn } from './utils.js'; @@ -27,7 +26,9 @@ export const database: InitFn = (collection: Workspace, id: string) => { const noteId = doc.addBlock('affine:note', {}, rootId); const pId = doc.addBlock('affine:paragraph', {}, noteId); const model = doc.getBlockById(pId); - assertExists(model); + if (!model) { + throw new Error('model is not found'); + } const addDatabase = (title: string, group = true) => { const databaseId = doc.addBlock( 'affine:database', diff --git a/blocksuite/tests-legacy/e2e/bookmark.spec.ts b/blocksuite/tests-legacy/e2e/bookmark.spec.ts index aebdb444af..58e80e21e9 100644 --- a/blocksuite/tests-legacy/e2e/bookmark.spec.ts +++ b/blocksuite/tests-legacy/e2e/bookmark.spec.ts @@ -36,7 +36,6 @@ import { assertBlockCount, assertBlockFlavour, assertBlockSelections, - assertExists, assertParentBlockFlavour, assertRichTextInlineRange, } from './utils/asserts.js'; @@ -261,7 +260,9 @@ test.describe('embed card toolbar', () => { await cardStyleListButton.click(); await waitNextFrame(page); const listStyleBookmarkBox = await bookmark.boundingBox(); - assertExists(listStyleBookmarkBox); + if (!listStyleBookmarkBox) { + throw new Error('listStyleBookmarkBox is not found'); + } assertAlmostEqual(listStyleBookmarkBox.width, 752, 2); assertAlmostEqual(listStyleBookmarkBox.height, 48, 2); @@ -269,7 +270,9 @@ test.describe('embed card toolbar', () => { await cardStyleHorizontalButton.click(); await waitNextFrame(page); const horizontalStyleBookmarkBox = await bookmark.boundingBox(); - assertExists(horizontalStyleBookmarkBox); + if (!horizontalStyleBookmarkBox) { + throw new Error('horizontalStyleBookmarkBox is not found'); + } assertAlmostEqual(horizontalStyleBookmarkBox.width, 752, 2); assertAlmostEqual(horizontalStyleBookmarkBox.height, 116, 2); }); diff --git a/blocksuite/tests-legacy/e2e/clipboard/clipboard.spec.ts b/blocksuite/tests-legacy/e2e/clipboard/clipboard.spec.ts index f7519838c8..f844f46c16 100644 --- a/blocksuite/tests-legacy/e2e/clipboard/clipboard.spec.ts +++ b/blocksuite/tests-legacy/e2e/clipboard/clipboard.spec.ts @@ -34,7 +34,6 @@ import { import { assertBlockTypes, assertClipItems, - assertExists, assertRichTexts, assertText, assertTitle, @@ -127,8 +126,12 @@ test(scoped`split block when paste`, async ({ page }) => { const bottomRight789 = await getEditorLocator(page) .locator('[data-block-id="4"] .inline-editor') .boundingBox(); - assertExists(topLeft123); - assertExists(bottomRight789); + if (!topLeft123) { + throw new Error('topLeft123 is not found'); + } + if (!bottomRight789) { + throw new Error('bottomRight789 is not found'); + } await dragBetweenCoords(page, topLeft123, bottomRight789); // FIXME see https://github.com/toeverything/blocksuite/pull/878 diff --git a/blocksuite/tests-legacy/e2e/clipboard/list.spec.ts b/blocksuite/tests-legacy/e2e/clipboard/list.spec.ts index 3db626d1e3..e59fb0fbcf 100644 --- a/blocksuite/tests-legacy/e2e/clipboard/list.spec.ts +++ b/blocksuite/tests-legacy/e2e/clipboard/list.spec.ts @@ -51,7 +51,6 @@ import { assertBlockTypes, assertEdgelessNoteBackground, assertEdgelessSelectedModelRect, - assertExists, assertRichTextModelType, assertRichTexts, assertText, @@ -111,7 +110,9 @@ test('copy a nested list by clicking button, the clipboard data should be comple await pasteContent(page, clipData); const rootListBound = await page.locator('affine-list').first().boundingBox(); - assertExists(rootListBound); + if (!rootListBound) { + throw new Error('rootListBound is not found'); + } // use drag element to test. await dragBetweenCoords( diff --git a/blocksuite/tests-legacy/e2e/edgeless/auto-complete.spec.ts b/blocksuite/tests-legacy/e2e/edgeless/auto-complete.spec.ts index e4aa9ce9e1..4c8b2ce422 100644 --- a/blocksuite/tests-legacy/e2e/edgeless/auto-complete.spec.ts +++ b/blocksuite/tests-legacy/e2e/edgeless/auto-complete.spec.ts @@ -28,7 +28,6 @@ import { assertConnectorStrokeColor, assertEdgelessCanvasText, assertEdgelessNoteBackground, - assertExists, assertRichTexts, assertSelectedBound, } from '../utils/asserts.js'; @@ -159,7 +158,9 @@ test.describe('auto-complete', () => { const note = document.body.querySelector('affine-edgeless-note'); return note?.getAttribute('data-block-id'); }); - assertExists(noteId); + if (!noteId) { + throw new Error('noteId is not found'); + } await assertEdgelessNoteBackground( page, noteId, @@ -167,7 +168,9 @@ test.describe('auto-complete', () => { ); const rect = await edgelessNote.boundingBox(); - assertExists(rect); + if (!rect) { + throw new Error('rect is not found'); + } // blur note block await page.mouse.click(rect.x + rect.width / 2, rect.y + rect.height * 3); @@ -220,7 +223,9 @@ test.describe('auto-complete', () => { const note = document.body.querySelectorAll('affine-edgeless-note')[1]; return note?.getAttribute('data-block-id'); }); - assertExists(noteId2); + if (!noteId2) { + throw new Error('noteId2 is not found'); + } await assertEdgelessNoteBackground( page, noteId, diff --git a/blocksuite/tests-legacy/e2e/edgeless/auto-connect.spec.ts b/blocksuite/tests-legacy/e2e/edgeless/auto-connect.spec.ts index 8c8ea5843f..7489cc8a74 100644 --- a/blocksuite/tests-legacy/e2e/edgeless/auto-connect.spec.ts +++ b/blocksuite/tests-legacy/e2e/edgeless/auto-connect.spec.ts @@ -1,4 +1,3 @@ -import { assertExists } from '@blocksuite/global/utils'; import { expect, type Page } from '@playwright/test'; import { @@ -142,7 +141,9 @@ test.describe('auto-connect', () => { const noteBound = await getNoteBoundBoxInEdgeless(page, id2); const edgelessOnlyIndexLabelBound = await edgelessOnlyIndexLabel.boundingBox(); - assertExists(edgelessOnlyIndexLabelBound); + if (!edgelessOnlyIndexLabelBound) { + throw new Error('edgelessOnlyIndexLabelBound is not found'); + } const border = 1; const offset = 16; expect(edgelessOnlyIndexLabelBound.x).toBeCloseTo( @@ -166,7 +167,9 @@ test.describe('auto-connect', () => { const newNoteBound = await getNoteBoundBoxInEdgeless(page, id2); const newEdgelessOnlyIndexLabelBound = await edgelessOnlyIndexLabel.boundingBox(); - assertExists(newEdgelessOnlyIndexLabelBound); + if (!newEdgelessOnlyIndexLabelBound) { + throw new Error('newEdgelessOnlyIndexLabelBound is not found'); + } expect(newEdgelessOnlyIndexLabelBound.x).toBeCloseTo( newNoteBound.x + newNoteBound.width / 2 - diff --git a/blocksuite/tests-legacy/e2e/edgeless/basic.spec.ts b/blocksuite/tests-legacy/e2e/edgeless/basic.spec.ts index 643aeb9e19..c013a2c1c0 100644 --- a/blocksuite/tests-legacy/e2e/edgeless/basic.spec.ts +++ b/blocksuite/tests-legacy/e2e/edgeless/basic.spec.ts @@ -1,4 +1,3 @@ -import { assertExists } from '@blocksuite/global/utils'; import { expect } from '@playwright/test'; import { @@ -323,7 +322,9 @@ test('the tooltip of more button should be hidden when the action menu is shown' const moreButtonBox = await moreButton.boundingBox(); const tooltip = page.locator('.affine-tooltip'); - assertExists(moreButtonBox); + if (!moreButtonBox) { + throw new Error('moreButtonBox is not found'); + } // need to wait for previous tooltip to be hidden await page.waitForTimeout(100); @@ -383,8 +384,7 @@ test('should close zoom bar when click blank area', async ({ page }) => { await initEmptyEdgelessState(page); await switchEditorMode(page); - const screenWidth = page.viewportSize()?.width; - assertExists(screenWidth); + const screenWidth = page.viewportSize()?.width ?? 0; if (screenWidth > ZOOM_BAR_RESPONSIVE_SCREEN_WIDTH) { await page.setViewportSize({ width: 1000, diff --git a/blocksuite/tests-legacy/e2e/edgeless/connector/connector.spec.ts b/blocksuite/tests-legacy/e2e/edgeless/connector/connector.spec.ts index f614216ad8..6daffc482d 100644 --- a/blocksuite/tests-legacy/e2e/edgeless/connector/connector.spec.ts +++ b/blocksuite/tests-legacy/e2e/edgeless/connector/connector.spec.ts @@ -21,7 +21,6 @@ import { assertConnectorPath, assertEdgelessNonSelectedRect, assertEdgelessSelectedRect, - assertExists, } from '../../utils/asserts.js'; import { test } from '../../utils/playwright.js'; @@ -223,7 +222,9 @@ test.describe('quick connect', () => { }); const bounds = await quickConnectBtn.boundingBox(); - assertExists(bounds); + if (!bounds) { + throw new Error('bounds is not found'); + } await quickConnectBtn.click(); @@ -290,7 +291,9 @@ test.describe('quick connect', () => { name: 'Draw connector', }); const bounds = await quickConnectBtn.boundingBox(); - assertExists(bounds); + if (!bounds) { + throw new Error('bounds is not found'); + } await quickConnectBtn.click(); // at right diff --git a/blocksuite/tests-legacy/e2e/edgeless/connector/label.spec.ts b/blocksuite/tests-legacy/e2e/edgeless/connector/label.spec.ts index dd6a33f31b..2709afd2b8 100644 --- a/blocksuite/tests-legacy/e2e/edgeless/connector/label.spec.ts +++ b/blocksuite/tests-legacy/e2e/edgeless/connector/label.spec.ts @@ -1,4 +1,3 @@ -import { assertExists } from '@blocksuite/global/utils'; import { expect, type Page } from '@playwright/test'; import { @@ -28,7 +27,9 @@ test.describe('connector label with straight shape', () => { const bounds = await page .locator('edgeless-connector-label-editor rich-text') .boundingBox(); - assertExists(bounds); + if (!bounds) { + throw new Error('bounds is not found'); + } const cx = bounds.x + bounds.width / 2; const cy = bounds.y + bounds.height / 2; return [cx, cy]; diff --git a/blocksuite/tests-legacy/e2e/edgeless/linked-doc.spec.ts b/blocksuite/tests-legacy/e2e/edgeless/linked-doc.spec.ts index 2ae9ba391e..249f26fc7a 100644 --- a/blocksuite/tests-legacy/e2e/edgeless/linked-doc.spec.ts +++ b/blocksuite/tests-legacy/e2e/edgeless/linked-doc.spec.ts @@ -20,7 +20,7 @@ import { type, waitNextFrame, } from '../utils/actions/index.js'; -import { assertConnectorPath, assertExists } from '../utils/asserts.js'; +import { assertConnectorPath } from '../utils/asserts.js'; import { test } from '../utils/playwright.js'; test.describe('note to linked doc', () => { @@ -39,12 +39,16 @@ test.describe('note to linked doc', () => { await waitNextFrame(page, 200); const embedSyncedBlock = page.locator('affine-embed-synced-doc-block'); - assertExists(embedSyncedBlock); + if (!embedSyncedBlock) { + throw new Error('embedSyncedBlock is not found'); + } await triggerComponentToolbarAction(page, 'openLinkedDoc'); await waitNextFrame(page, 200); const noteBlock = page.locator('affine-edgeless-note'); - assertExists(noteBlock); + if (!noteBlock) { + throw new Error('noteBlock is not found'); + } const noteContent = await noteBlock.innerText(); expect(noteContent).toBe('Hello\nWorld'); }); @@ -62,7 +66,9 @@ test.describe('note to linked doc', () => { await waitNextFrame(page, 200); const embedSyncedBlock = page.locator('affine-embed-synced-doc-block'); - assertExists(embedSyncedBlock); + if (!embedSyncedBlock) { + throw new Error('embedSyncedBlock is not found'); + } await assertConnectorPath(page, [connectorPath[0], connectorPath[1]], 0); }); @@ -117,7 +123,9 @@ test.describe('single edgeless element to linked doc', () => { await triggerComponentToolbarAction(page, 'createLinkedDoc'); await waitNextFrame(page, 200); const linkedSyncedBlock = page.locator('affine-linked-synced-doc-block'); - assertExists(linkedSyncedBlock); + if (!linkedSyncedBlock) { + throw new Error('linkedSyncedBlock is not found'); + } await triggerComponentToolbarAction(page, 'openLinkedDoc'); await waitNextFrame(page, 200); @@ -140,7 +148,9 @@ test.describe('single edgeless element to linked doc', () => { await triggerComponentToolbarAction(page, 'createLinkedDoc'); await waitNextFrame(page, 200); const linkedSyncedBlock = page.locator('affine-linked-synced-doc-block'); - assertExists(linkedSyncedBlock); + if (!linkedSyncedBlock) { + throw new Error('linkedSyncedBlock is not found'); + } await triggerComponentToolbarAction(page, 'openLinkedDoc'); await waitNextFrame(page, 200); @@ -157,7 +167,9 @@ test.describe('single edgeless element to linked doc', () => { await triggerComponentToolbarAction(page, 'createLinkedDoc'); await waitNextFrame(page, 200); const linkedSyncedBlock = page.locator('affine-linked-synced-doc-block'); - assertExists(linkedSyncedBlock); + if (!linkedSyncedBlock) { + throw new Error('linkedSyncedBlock is not found'); + } await triggerComponentToolbarAction(page, 'openLinkedDoc'); await waitNextFrame(page, 200); @@ -185,7 +197,9 @@ test.describe('single edgeless element to linked doc', () => { await triggerComponentToolbarAction(page, 'createLinkedDoc'); await waitNextFrame(page, 200); const linkedSyncedBlock = page.locator('affine-linked-synced-doc-block'); - assertExists(linkedSyncedBlock); + if (!linkedSyncedBlock) { + throw new Error('linkedSyncedBlock is not found'); + } await triggerComponentToolbarAction(page, 'openLinkedDoc'); await waitNextFrame(page, 200); @@ -222,7 +236,9 @@ test.describe('single edgeless element to linked doc', () => { await triggerComponentToolbarAction(page, 'createLinkedDoc'); await waitNextFrame(page, 200); const linkedSyncedBlock = page.locator('affine-linked-synced-doc-block'); - assertExists(linkedSyncedBlock); + if (!linkedSyncedBlock) { + throw new Error('linkedSyncedBlock is not found'); + } await triggerComponentToolbarAction(page, 'openLinkedDoc'); await waitNextFrame(page, 200); @@ -269,7 +285,9 @@ test.describe('multiple edgeless elements to linked doc', () => { await triggerComponentToolbarAction(page, 'createLinkedDoc'); await waitNextFrame(page, 200); const linkedSyncedBlock = page.locator('affine-linked-synced-doc-block'); - assertExists(linkedSyncedBlock); + if (!linkedSyncedBlock) { + throw new Error('linkedSyncedBlock is not found'); + } await triggerComponentToolbarAction(page, 'openLinkedDoc'); await waitNextFrame(page, 200); @@ -305,7 +323,9 @@ test.describe('multiple edgeless elements to linked doc', () => { await triggerComponentToolbarAction(page, 'createLinkedDoc'); await waitNextFrame(page, 200); const linkedSyncedBlock = page.locator('affine-linked-synced-doc-block'); - assertExists(linkedSyncedBlock); + if (!linkedSyncedBlock) { + throw new Error('linkedSyncedBlock is not found'); + } await triggerComponentToolbarAction(page, 'openLinkedDoc'); await waitNextFrame(page, 200); @@ -334,7 +354,9 @@ test.describe('multiple edgeless elements to linked doc', () => { await triggerComponentToolbarAction(page, 'createLinkedDoc'); await waitNextFrame(page, 200); const linkedSyncedBlock = page.locator('affine-linked-synced-doc-block'); - assertExists(linkedSyncedBlock); + if (!linkedSyncedBlock) { + throw new Error('linkedSyncedBlock is not found'); + } await triggerComponentToolbarAction(page, 'openLinkedDoc'); await waitNextFrame(page, 200); diff --git a/blocksuite/tests-legacy/e2e/edgeless/note/note.spec.ts b/blocksuite/tests-legacy/e2e/edgeless/note/note.spec.ts index 5c3fbbf586..022f88a090 100644 --- a/blocksuite/tests-legacy/e2e/edgeless/note/note.spec.ts +++ b/blocksuite/tests-legacy/e2e/edgeless/note/note.spec.ts @@ -42,7 +42,6 @@ import { assertEdgelessNonSelectedRect, assertEdgelessNoteBackground, assertEdgelessSelectedRect, - assertExists, assertNoteSequence, assertNoteXYWH, assertRichTextInlineRange, @@ -386,7 +385,9 @@ test.fixme( const paragraphBlock = await page .locator(`[data-block-id="3"]`) .boundingBox(); - assertExists(paragraphBlock); + if (!paragraphBlock) { + throw new Error('paragraphBlock is not found'); + } await page.mouse.dblclick(paragraphBlock.x, paragraphBlock.y); await waitNextFrame(page); await page.mouse.move( @@ -397,7 +398,9 @@ test.fixme( const handle = await page .locator('.affine-drag-handle-container') .boundingBox(); - assertExists(handle); + if (!handle) { + throw new Error('handle is not found'); + } await page.mouse.move( handle.x + handle.width / 2, handle.y + handle.height / 2, @@ -414,7 +417,9 @@ test.fixme( // Click at empty note block to add a paragraph block const emptyNote = await page.locator(`[data-block-id="2"]`).boundingBox(); - assertExists(emptyNote); + if (!emptyNote) { + throw new Error('emptyNote is not found'); + } await page.mouse.click( emptyNote.x + emptyNote.width / 2, emptyNote.y + emptyNote.height / 2 @@ -445,7 +450,9 @@ test('Should focus at closest text block when note collapse', async ({ const notePortalBox = await page .locator('affine-edgeless-note') .boundingBox(); - assertExists(notePortalBox); + if (!notePortalBox) { + throw new Error('notePortalBox is not found'); + } await page.mouse.click(notePortalBox.x + 10, notePortalBox.y + 10); await waitNextFrame(page, 200); const selectedRect = page @@ -455,7 +462,9 @@ test('Should focus at closest text block when note collapse', async ({ // Collapse the note const selectedBox = await selectedRect.boundingBox(); - assertExists(selectedBox); + if (!selectedBox) { + throw new Error('selectedBox is not found'); + } await page.mouse.move( selectedBox.x + selectedBox.width / 2, selectedBox.y + selectedBox.height diff --git a/blocksuite/tests-legacy/e2e/edgeless/shape.spec.ts b/blocksuite/tests-legacy/e2e/edgeless/shape.spec.ts index b10d6689b1..c27502833d 100644 --- a/blocksuite/tests-legacy/e2e/edgeless/shape.spec.ts +++ b/blocksuite/tests-legacy/e2e/edgeless/shape.spec.ts @@ -40,7 +40,6 @@ import { assertEdgelessColorSameWithHexColor, assertEdgelessNonSelectedRect, assertEdgelessSelectedRect, - assertExists, assertRichTexts, } from '../utils/asserts.js'; import { test } from '../utils/playwright.js'; @@ -218,7 +217,9 @@ test('the tooltip of shape tool button should be hidden when the shape menu is s const shapeToolBox = await shapeTool.boundingBox(); const tooltip = page.locator('.affine-tooltip'); - assertExists(shapeToolBox); + if (!shapeToolBox) { + throw new Error('shapeToolBox is not found'); + } await page.mouse.move(shapeToolBox.x + 2, shapeToolBox.y + 2); await expect(tooltip).toBeVisible(); @@ -275,7 +276,9 @@ test('edgeless toolbar shape menu shows up and close normally', async ({ const shapeTool = await locatorEdgelessToolButton(page, 'shape'); const shapeToolBox = await shapeTool.boundingBox(); - assertExists(shapeToolBox); + if (!shapeToolBox) { + throw new Error('shapeToolBox is not found'); + } await page.mouse.click(shapeToolBox.x + 2, shapeToolBox.y + 2); diff --git a/blocksuite/tests-legacy/e2e/embed-synced-doc.spec.ts b/blocksuite/tests-legacy/e2e/embed-synced-doc.spec.ts index 792ccce1e1..2382db0637 100644 --- a/blocksuite/tests-legacy/e2e/embed-synced-doc.spec.ts +++ b/blocksuite/tests-legacy/e2e/embed-synced-doc.spec.ts @@ -1,5 +1,4 @@ import type { DatabaseBlockModel } from '@blocksuite/affine-model'; -import { assertExists } from '@blocksuite/global/utils'; import { expect, type Page } from '@playwright/test'; import { switchEditorMode } from './utils/actions/edgeless.js'; @@ -22,7 +21,9 @@ test.describe('Embed synced doc', () => { const { createLinkedDoc } = getLinkedDocPopover(page); const linkedDoc = await createLinkedDoc('page1'); const lickedDocBox = await linkedDoc.boundingBox(); - assertExists(lickedDocBox); + if (!lickedDocBox) { + throw new Error('lickedDocBox is not found'); + } await page.mouse.move( lickedDocBox.x + lickedDocBox.width / 2, lickedDocBox.y + lickedDocBox.height / 2 @@ -60,7 +61,9 @@ test.describe('Embed synced doc', () => { const syncedDoc = page.locator(`affine-embed-synced-doc-block`); const syncedDocBox = await syncedDoc.boundingBox(); - assertExists(syncedDocBox); + if (!syncedDocBox) { + throw new Error('syncedDocBox is not found'); + } await page.mouse.click( syncedDocBox.x + syncedDocBox.width / 2, syncedDocBox.y + syncedDocBox.height / 2 @@ -95,7 +98,9 @@ test.describe('Embed synced doc', () => { // Focus on the embed synced doc const embedSyncedBlock = page.locator('affine-embed-synced-doc-block'); let embedSyncedBox = await embedSyncedBlock.boundingBox(); - assertExists(embedSyncedBox); + if (!embedSyncedBox) { + throw new Error('embedSyncedBox is not found'); + } await page.mouse.click( embedSyncedBox.x + embedSyncedBox.width / 2, embedSyncedBox.y + embedSyncedBox.height / 2 @@ -108,13 +113,17 @@ test.describe('Embed synced doc', () => { // Double click on note to enter edit status const noteBlock = page.locator('affine-edgeless-note'); const noteBlockBox = await noteBlock.boundingBox(); - assertExists(noteBlockBox); + if (!noteBlockBox) { + throw new Error('noteBlockBox is not found'); + } await page.mouse.dblclick(noteBlockBox.x + 10, noteBlockBox.y + 10); await waitNextFrame(page, 200); // Drag the embed synced doc to whiteboard embedSyncedBox = await embedSyncedBlock.boundingBox(); - assertExists(embedSyncedBox); + if (!embedSyncedBox) { + throw new Error('embedSyncedBox is not found'); + } const height = embedSyncedBox.height; await page.mouse.move(embedSyncedBox.x - 10, embedSyncedBox.y - 100); await page.mouse.move(embedSyncedBox.x - 10, embedSyncedBox.y + 10); @@ -129,7 +138,9 @@ test.describe('Embed synced doc', () => { ); const EmbedSyncedDocBlockBox = await EmbedSyncedDocBlock.boundingBox(); const border = 1; - assertExists(EmbedSyncedDocBlockBox); + if (!EmbedSyncedDocBlockBox) { + throw new Error('EmbedSyncedDocBlockBox is not found'); + } expect(EmbedSyncedDocBlockBox.height).toBeCloseTo(height + 2 * border, 1); } ); diff --git a/blocksuite/tests-legacy/e2e/format-bar.spec.ts b/blocksuite/tests-legacy/e2e/format-bar.spec.ts index 970fc47a55..7ccb2ec57a 100644 --- a/blocksuite/tests-legacy/e2e/format-bar.spec.ts +++ b/blocksuite/tests-legacy/e2e/format-bar.spec.ts @@ -38,7 +38,6 @@ import { import { assertAlmostEqual, assertBlockChildrenIds, - assertExists, assertLocatorVisible, assertRichImage, assertRichTextInlineRange, @@ -85,7 +84,9 @@ test('should format quick bar show when clicking drag handle', async ({ await locator.hover(); const dragHandle = page.locator('.affine-drag-handle-grabber'); const dragHandleRect = await dragHandle.boundingBox(); - assertExists(dragHandleRect); + if (!dragHandleRect) { + throw new Error('dragHandleRect is not found'); + } await dragHandle.click(); const { formatBar } = getFormatBar(page); @@ -534,8 +535,12 @@ test('should format quick bar work in single block selection', async ({ const formatRect = await formatBar.boundingBox(); const selectionRect = await blockSelections.boundingBox(); - assertExists(formatRect); - assertExists(selectionRect); + if (!formatRect) { + throw new Error('formatRect is not found'); + } + if (!selectionRect) { + throw new Error('selectionRect is not found'); + } assertAlmostEqual(formatRect.x - selectionRect.x, 147.5, 10); assertAlmostEqual(formatRect.y - selectionRect.y, 33, 10); @@ -588,7 +593,9 @@ test('should format quick bar work in multiple block selection', async ({ throw new Error("formatBar doesn't exist"); } const rect = await blockSelections.first().boundingBox(); - assertExists(rect); + if (!rect) { + throw new Error('rect is not found'); + } assertAlmostEqual(box.x - rect.x, 147.5, 10); assertAlmostEqual(box.y - rect.y, 99, 10); @@ -955,7 +962,9 @@ test('create linked doc from block selection with format bar', async ({ await expect(linkedDocBlock).toHaveCount(1); const linkedDocBox = await linkedDocBlock.boundingBox(); - assertExists(linkedDocBox); + if (!linkedDocBox) { + throw new Error('linkedDocBox is not found'); + } await page.mouse.dblclick( linkedDocBox.x + linkedDocBox.width / 2, linkedDocBox.y + linkedDocBox.height / 2 diff --git a/blocksuite/tests-legacy/e2e/linked-page.spec.ts b/blocksuite/tests-legacy/e2e/linked-page.spec.ts index 1c9ae1a704..a4b51c1e03 100644 --- a/blocksuite/tests-legacy/e2e/linked-page.spec.ts +++ b/blocksuite/tests-legacy/e2e/linked-page.spec.ts @@ -32,7 +32,6 @@ import { waitNextFrame, } from './utils/actions/misc.js'; import { - assertExists, assertParentBlockFlavour, assertRichTexts, assertTitle, @@ -43,7 +42,9 @@ async function createAndConvertToEmbedLinkedDoc(page: Page) { const { createLinkedDoc } = getLinkedDocPopover(page); const linkedDoc = await createLinkedDoc('page1'); const lickedDocBox = await linkedDoc.boundingBox(); - assertExists(lickedDocBox); + if (!lickedDocBox) { + throw new Error('lickedDocBox is not found'); + } await page.mouse.move( lickedDocBox.x + lickedDocBox.width / 2, lickedDocBox.y + lickedDocBox.height / 2 diff --git a/blocksuite/tests-legacy/e2e/selection/native.spec.ts b/blocksuite/tests-legacy/e2e/selection/native.spec.ts index 7976aa8229..f1ab91d50c 100644 --- a/blocksuite/tests-legacy/e2e/selection/native.spec.ts +++ b/blocksuite/tests-legacy/e2e/selection/native.spec.ts @@ -55,7 +55,6 @@ import { assertBlockSelections, assertClipItems, assertDivider, - assertExists, assertNativeSelectionRangeCount, assertRichTextInlineRange, assertRichTexts, @@ -847,7 +846,9 @@ test('the cursor should move to closest editor block when clicking outside conta const text2 = page.locator('[data-block-id="3"] .inline-editor'); const rect = await text2.boundingBox(); - assertExists(rect); + if (!rect) { + throw new Error('rect is not found'); + } // The behavior of mouse click is similar to touch in mobile device // await page.mouse.click(rect.x - 50, rect.y + 5); @@ -1760,7 +1761,9 @@ test('unexpected scroll when clicking padding area', async ({ page }) => { const list = page.locator('[data-block-id="34"]'); const listRect = await list.boundingBox(); - assertExists(listRect); + if (!listRect) { + throw new Error('listRect is not found'); + } await page.mouse.click(listRect.x - 30, listRect.y + 5); const newListRect = await list.boundingBox(); // not scroll @@ -1770,7 +1773,9 @@ test('unexpected scroll when clicking padding area', async ({ page }) => { await type(page, '/tableview\n'); const database = page.locator('affine-database'); const databaseRect = await database.boundingBox(); - assertExists(databaseRect); + if (!databaseRect) { + throw new Error('databaseRect is not found'); + } await page.mouse.click( databaseRect.x + databaseRect.width + 10, databaseRect.y + 100 diff --git a/blocksuite/tests-legacy/e2e/slash-menu.spec.ts b/blocksuite/tests-legacy/e2e/slash-menu.spec.ts index 311949935a..d3375b706a 100644 --- a/blocksuite/tests-legacy/e2e/slash-menu.spec.ts +++ b/blocksuite/tests-legacy/e2e/slash-menu.spec.ts @@ -32,7 +32,6 @@ import { import { assertAlmostEqual, assertBlockCount, - assertExists, assertRichTexts, } from './utils/asserts.js'; import { test } from './utils/playwright.js'; @@ -344,7 +343,9 @@ test.describe('slash menu should show and hide correctly', () => { const subMenu = page.locator('.slash-menu[data-testid=sub-menu-1]'); let rect = await slashItems.nth(4).boundingBox(); - assertExists(rect); + if (!rect) { + throw new Error('rect is not found'); + } await page.mouse.move(rect.x + 10, rect.y + 10); await expect(slashMenu).toBeVisible(); await expect(slashItems.nth(4)).toHaveAttribute('hover', 'true'); @@ -354,7 +355,9 @@ test.describe('slash menu should show and hide correctly', () => { await expect(subMenu).toBeVisible(); rect = await slashItems.nth(3).boundingBox(); - assertExists(rect); + if (!rect) { + throw new Error('rect is not found'); + } await page.mouse.move(rect.x + 10, rect.y + 10); await expect(slashMenu).toBeVisible(); await expect(slashItems.nth(3)).toHaveAttribute('hover', 'true'); diff --git a/blocksuite/tests-legacy/e2e/utils/actions/edgeless.ts b/blocksuite/tests-legacy/e2e/utils/actions/edgeless.ts index 9ae4f4b444..d342b229d3 100644 --- a/blocksuite/tests-legacy/e2e/utils/actions/edgeless.ts +++ b/blocksuite/tests-legacy/e2e/utils/actions/edgeless.ts @@ -2,7 +2,7 @@ import '../declare-test-window.js'; import type { NoteBlockModel, NoteDisplayMode } from '@blocksuite/affine-model'; import type { IPoint, IVec } from '@blocksuite/global/gfx'; -import { assertExists, sleep } from '@blocksuite/global/utils'; +import { sleep } from '@blocksuite/global/utils'; import type { Locator, Page } from '@playwright/test'; import { expect } from '@playwright/test'; @@ -253,8 +253,7 @@ export async function locatorEdgelessZoomToolButton( fitToScreen: 'Fit to screen', }[type]; - const screenWidth = page.viewportSize()?.width; - assertExists(screenWidth); + const screenWidth = page.viewportSize()?.width ?? 0; let zoomBarClass = 'horizontal'; if (screenWidth < ZOOM_BAR_RESPONSIVE_SCREEN_WIDTH) { await toggleZoomBarWhenSmallScreenWidth(page); @@ -958,8 +957,7 @@ export async function zoomInByKeyboard(page: Page) { } export async function getZoomLevel(page: Page) { - const screenWidth = page.viewportSize()?.width; - assertExists(screenWidth); + const screenWidth = page.viewportSize()?.width ?? 0; let zoomBarClass = 'horizontal'; if (screenWidth < ZOOM_BAR_RESPONSIVE_SCREEN_WIDTH) { await toggleZoomBarWhenSmallScreenWidth(page); @@ -1456,7 +1454,9 @@ export function getEdgelessLineWidthPanel(page: Page) { export async function changeShapeStrokeWidth(page: Page) { const lineWidthPanel = getEdgelessLineWidthPanel(page); const lineWidthPanelRect = await lineWidthPanel.boundingBox(); - assertExists(lineWidthPanelRect); + if (!lineWidthPanelRect) { + throw new Error('lineWidthPanelRect is not found'); + } // click line width panel by position const x = lineWidthPanelRect.x + 40; const y = lineWidthPanelRect.y + 10; @@ -1907,7 +1907,9 @@ export async function createNote( export async function hoverOnNote(page: Page, id: string, offset = [0, 0]) { const blockRect = await page.locator(`[data-block-id="${id}"]`).boundingBox(); - assertExists(blockRect); + if (!blockRect) { + throw new Error('blockRect is not found'); + } await page.mouse.move( blockRect.x + blockRect.width / 2 + offset[0], diff --git a/blocksuite/tests-legacy/e2e/utils/actions/misc.ts b/blocksuite/tests-legacy/e2e/utils/actions/misc.ts index 210ea7b214..d0217e297c 100644 --- a/blocksuite/tests-legacy/e2e/utils/actions/misc.ts +++ b/blocksuite/tests-legacy/e2e/utils/actions/misc.ts @@ -5,7 +5,6 @@ import type { ListType, RichText, } from '@blocksuite/blocks'; -import { assertExists } from '@blocksuite/global/utils'; import type { InlineRange, InlineRootElement } from '@blocksuite/inline'; import type { TestAffineEditorContainer } from '@blocksuite/integration-test'; import type { BlockModel } from '@blocksuite/store'; @@ -42,7 +41,9 @@ export const getSelectionRect = async (page: Page): Promise => { const rect = await page.evaluate(() => { return getSelection()?.getRangeAt(0).getBoundingClientRect(); }); - assertExists(rect); + if (!rect) { + throw new Error('rect is not found'); + } return rect; }; @@ -864,7 +865,9 @@ export async function getClipboardSnapshot(page: Page) { page, 'BLOCKSUITE/SNAPSHOT' ); - assertExists(dataInClipboard); + if (!dataInClipboard) { + throw new Error('dataInClipboard is not found'); + } const json = JSON.parse(dataInClipboard as string); return json; } diff --git a/blocksuite/tests-legacy/e2e/utils/asserts.ts b/blocksuite/tests-legacy/e2e/utils/asserts.ts index d9bdfb0ac8..dc58c4008e 100644 --- a/blocksuite/tests-legacy/e2e/utils/asserts.ts +++ b/blocksuite/tests-legacy/e2e/utils/asserts.ts @@ -12,7 +12,6 @@ import type { RichText, RootBlockModel, } from '@blocksuite/blocks'; -import { assertExists } from '@blocksuite/global/utils'; import type { InlineRootElement } from '@blocksuite/inline'; import type { BlockModel } from '@blocksuite/store'; import { expect, type Locator, type Page } from '@playwright/test'; @@ -53,8 +52,6 @@ import { } from './actions/misc.js'; import { getStringFromRichText } from './inline-editor.js'; -export { assertExists }; - const BLOCK_ID_ATTR = 'data-block-id'; export const defaultStore = { diff --git a/eslint.config.mjs b/eslint.config.mjs index 477cf4e788..d252525d63 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -191,7 +191,7 @@ export default tseslint.config( { group: ['@blocksuite/store'], message: "Import from '@blocksuite/global/utils'", - importNames: ['assertExists', 'assertEquals'], + importNames: ['assertEquals'], }, ], }, diff --git a/packages/frontend/core/src/blocksuite/ai/actions/doc-handler.ts b/packages/frontend/core/src/blocksuite/ai/actions/doc-handler.ts index 0c8addbd49..1c3f39d801 100644 --- a/packages/frontend/core/src/blocksuite/ai/actions/doc-handler.ts +++ b/packages/frontend/core/src/blocksuite/ai/actions/doc-handler.ts @@ -3,7 +3,6 @@ import { AIStarIconWithAnimation, createLitPortal, } from '@blocksuite/affine/blocks'; -import { assertExists } from '@blocksuite/affine/global/utils'; import { flip, offset } from '@floating-ui/dom'; import { html, type TemplateResult } from 'lit'; @@ -169,7 +168,7 @@ function updateAIPanelConfig( trackerOptions?: BlockSuitePresets.TrackerOptions ) { const { config, host } = aiPanel; - assertExists(config); + if (!config) return; config.generateAnswer = actionToGenerateAnswer( host, id, @@ -203,7 +202,7 @@ export function actionToHandler( const { selectedBlocks: blocks } = getSelections(aiPanel.host); if (!blocks || blocks.length === 0) return; const block = blocks.at(-1); - assertExists(block); + if (!block) return; aiPanel.toggle(block, ''); }; } diff --git a/packages/frontend/core/src/blocksuite/ai/actions/edgeless-handler.ts b/packages/frontend/core/src/blocksuite/ai/actions/edgeless-handler.ts index 4bde9c62dc..9339daf701 100644 --- a/packages/frontend/core/src/blocksuite/ai/actions/edgeless-handler.ts +++ b/packages/frontend/core/src/blocksuite/ai/actions/edgeless-handler.ts @@ -14,7 +14,6 @@ import { splitElements, TextElementModel, } from '@blocksuite/affine/blocks'; -import { assertExists } from '@blocksuite/affine/global/utils'; import { Slice } from '@blocksuite/affine/store'; import type { TemplateResult } from 'lit'; @@ -319,7 +318,7 @@ function updateEdgelessAIPanelConfig< ) { const host = aiPanel.host; const { config } = aiPanel; - assertExists(config); + if (!config) return; config.answerRenderer = actionToAnswerRenderer(id, host, ctx); config.generateAnswer = actionToGeneration( id, @@ -414,7 +413,7 @@ export function actionToHandler( referenceElement = getElementToolbar(host); } else if (!isEmpty) { const lastSelected = selectedElements.at(-1)?.id; - assertExists(lastSelected); + if (!lastSelected) return; const noteAnchor = getSelectedNoteAnchor(host, lastSelected); referenceElement = noteAnchor; } diff --git a/packages/frontend/core/src/blocksuite/ai/actions/edgeless-response.ts b/packages/frontend/core/src/blocksuite/ai/actions/edgeless-response.ts index b31d1e1fd9..3f108544d4 100644 --- a/packages/frontend/core/src/blocksuite/ai/actions/edgeless-response.ts +++ b/packages/frontend/core/src/blocksuite/ai/actions/edgeless-response.ts @@ -23,7 +23,6 @@ import { TelemetryProvider, } from '@blocksuite/affine/blocks'; import { Bound } from '@blocksuite/affine/global/gfx'; -import { assertExists } from '@blocksuite/affine/global/utils'; import { html, type TemplateResult } from 'lit'; import { styleMap } from 'lit/directives/style-map.js'; @@ -238,7 +237,7 @@ function createBlockAndInsert( const doc = host.doc; const edgelessCopilot = getEdgelessCopilotWidget(host); doc.transact(() => { - assertExists(doc.root); + if (!doc.root) return; let blockId = ''; const bounds = edgelessCopilot.determineInsertionBounds( EDGELESS_TEXT_BLOCK_MIN_WIDTH, @@ -280,8 +279,7 @@ function createBlockAndInsert( const defaultHandler = (host: EditorHost) => { const panel = getAIPanelWidget(host); const selectedElements = getCopilotSelectedElems(host); - - assertExists(panel.answer); + if (!panel.answer) return; if ( selectedElements.length === 1 && selectedElements[0] instanceof EdgelessTextBlockModel diff --git a/packages/frontend/core/src/blocksuite/ai/ai-panel.ts b/packages/frontend/core/src/blocksuite/ai/ai-panel.ts index 021941362c..924a5cc443 100644 --- a/packages/frontend/core/src/blocksuite/ai/ai-panel.ts +++ b/packages/frontend/core/src/blocksuite/ai/ai-panel.ts @@ -9,7 +9,6 @@ import { NoteDisplayMode, } from '@blocksuite/affine/blocks'; import { Bound } from '@blocksuite/affine/global/gfx'; -import { assertExists } from '@blocksuite/affine/global/utils'; import type { FrameworkProvider } from '@toeverything/infra'; import type { TemplateResult } from 'lit'; @@ -98,7 +97,7 @@ function createNewNote(host: EditorHost): AIItemConfig { const panel = getAIPanelWidget(host); const gfx = host.std.get(GfxControllerIdentifier); doc.transact(() => { - assertExists(doc.root); + if (!doc.root || !panel.answer) return; const noteBlockId = doc.addBlock( 'affine:note', { @@ -109,7 +108,6 @@ function createNewNote(host: EditorHost): AIItemConfig { doc.root.id ); - assertExists(panel.answer); insertFromMarkdown(host, panel.answer, doc, noteBlockId) .then(() => { gfx.selection.set({ diff --git a/packages/frontend/core/src/blocksuite/ai/entries/slash-menu/setup-slash-menu.ts b/packages/frontend/core/src/blocksuite/ai/entries/slash-menu/setup-slash-menu.ts index 794d731606..987146f846 100644 --- a/packages/frontend/core/src/blocksuite/ai/entries/slash-menu/setup-slash-menu.ts +++ b/packages/frontend/core/src/blocksuite/ai/entries/slash-menu/setup-slash-menu.ts @@ -7,14 +7,12 @@ import { AIStarIcon, DocModeProvider, } from '@blocksuite/affine/blocks'; -import { assertExists } from '@blocksuite/affine/global/utils'; import { MoreHorizontalIcon } from '@blocksuite/icons/lit'; import { html } from 'lit'; import { pageAIGroups } from '../../_common/config'; import { handleInlineAskAIAction } from '../../actions/doc-handler'; import type { AIItemConfig } from '../../components/ai-item/types'; -import { AIProvider } from '../../provider'; import { AFFINE_AI_PANEL_WIDGET, type AffineAIPanelWidget, @@ -55,10 +53,9 @@ export function setupSlashMenuAIEntry(slashMenu: AffineSlashMenuWidget) { }); const subMenuWrapper = (item: AIItemConfig): AffineSlashSubMenu => { - assertExists(item.subItem); return { ...basicItemConfig(item), - subMenu: item.subItem.map( + subMenu: (item.subItem ?? []).map( ({ type, handler }) => ({ name: type, action: ({ rootComponent }) => handler?.(rootComponent.host), @@ -87,9 +84,6 @@ export function setupSlashMenuAIEntry(slashMenu: AffineSlashMenuWidget) { AFFINE_AI_PANEL_WIDGET, rootComponent.model.id ) as AffineAIPanelWidget; - assertExists(affineAIPanelWidget); - assertExists(AIProvider.actions.chat); - assertExists(affineAIPanelWidget.host); handleInlineAskAIAction(affineAIPanelWidget.host); }, }); diff --git a/packages/frontend/core/src/blocksuite/ai/provider/request.ts b/packages/frontend/core/src/blocksuite/ai/provider/request.ts index ce5946f8e2..039dae2136 100644 --- a/packages/frontend/core/src/blocksuite/ai/provider/request.ts +++ b/packages/frontend/core/src/blocksuite/ai/provider/request.ts @@ -1,4 +1,3 @@ -import { assertExists } from '@blocksuite/affine/global/utils'; import { partition } from 'lodash-es'; import { AIProvider } from './ai-provider'; @@ -146,7 +145,6 @@ export function textToText({ if (retry) { const retrySessionId = (await sessionId) ?? AIProvider.LAST_ACTION_SESSIONID; - assertExists(retrySessionId, 'retry sessionId is required'); _sessionId = retrySessionId; _messageId = undefined; } else { @@ -220,7 +218,6 @@ export function textToText({ if (retry) { const retrySessionId = (await sessionId) ?? AIProvider.LAST_ACTION_SESSIONID; - assertExists(retrySessionId, 'retry sessionId is required'); _sessionId = retrySessionId; _messageId = undefined; } else { @@ -275,7 +272,6 @@ export function toImage({ if (retry) { const retrySessionId = (await sessionId) ?? AIProvider.LAST_ACTION_SESSIONID; - assertExists(retrySessionId, 'retry sessionId is required'); _sessionId = retrySessionId; _messageId = undefined; } else { diff --git a/packages/frontend/core/src/blocksuite/ai/provider/setup-provider.tsx b/packages/frontend/core/src/blocksuite/ai/provider/setup-provider.tsx index 45c214eb31..e45579472c 100644 --- a/packages/frontend/core/src/blocksuite/ai/provider/setup-provider.tsx +++ b/packages/frontend/core/src/blocksuite/ai/provider/setup-provider.tsx @@ -5,7 +5,6 @@ import { type getCopilotHistoriesQuery, type RequestOptions, } from '@affine/graphql'; -import { assertExists } from '@blocksuite/affine/global/utils'; import { z } from 'zod'; import { AIProvider } from './ai-provider'; @@ -234,7 +233,9 @@ export function setupAIProvider( }); AIProvider.provide('expandMindmap', options => { - assertExists(options.input, 'expandMindmap action requires input'); + if (!options.input) { + throw new Error('expandMindmap action requires input'); + } return textToText({ ...options, client, diff --git a/packages/frontend/core/src/blocksuite/ai/utils/ai-widgets.ts b/packages/frontend/core/src/blocksuite/ai/utils/ai-widgets.ts index f478533b4b..04ea194219 100644 --- a/packages/frontend/core/src/blocksuite/ai/utils/ai-widgets.ts +++ b/packages/frontend/core/src/blocksuite/ai/utils/ai-widgets.ts @@ -1,5 +1,4 @@ import type { EditorHost } from '@blocksuite/affine/block-std'; -import { assertExists } from '@blocksuite/affine/global/utils'; import { AFFINE_AI_PANEL_WIDGET, @@ -8,9 +7,10 @@ import { export const getAIPanelWidget = (host: EditorHost): AffineAIPanelWidget => { const rootBlockId = host.doc.root?.id; - assertExists(rootBlockId); + if (!rootBlockId) { + throw new Error('rootBlockId is not found'); + } const aiPanel = host.view.getWidget(AFFINE_AI_PANEL_WIDGET, rootBlockId); - assertExists(aiPanel); if (!(aiPanel instanceof AffineAIPanelWidget)) { throw new Error('AI panel not found'); } diff --git a/packages/frontend/core/src/blocksuite/ai/utils/connector.ts b/packages/frontend/core/src/blocksuite/ai/utils/connector.ts index 6b5fc8c649..8426e8c2b0 100644 --- a/packages/frontend/core/src/blocksuite/ai/utils/connector.ts +++ b/packages/frontend/core/src/blocksuite/ai/utils/connector.ts @@ -3,7 +3,6 @@ import { type EdgelessRootService, SurfaceBlockComponent, } from '@blocksuite/affine/blocks'; -import { assertExists } from '@blocksuite/affine/global/utils'; export const getConnectorFromId = ( id: string, @@ -68,7 +67,9 @@ export const findTree = ( }; }; const tree = run(rootId); - assertExists(tree); + if (!tree) { + throw new Error('tree is not found'); + } return tree; }; export const findLeaf = ( diff --git a/packages/frontend/core/src/blocksuite/ai/utils/image.ts b/packages/frontend/core/src/blocksuite/ai/utils/image.ts index 4997275b81..f9eed67b15 100644 --- a/packages/frontend/core/src/blocksuite/ai/utils/image.ts +++ b/packages/frontend/core/src/blocksuite/ai/utils/image.ts @@ -1,5 +1,4 @@ import { FetchUtils } from '@blocksuite/affine/blocks'; -import { assertExists } from '@blocksuite/affine/global/utils'; export async function fetchImageToFile( url: string, @@ -26,14 +25,17 @@ function fetchImageFallback( url: string, filename: string ): Promise { - return new Promise(resolve => { + return new Promise((resolve, reject) => { const img = new Image(); img.onload = () => { const c = document.createElement('canvas'); c.width = img.width; c.height = img.height; const ctx = c.getContext('2d'); - assertExists(ctx); + if (!ctx) { + reject(); + return; + } ctx.imageSmoothingEnabled = true; ctx.imageSmoothingQuality = 'high'; ctx.drawImage(img, 0, 0); @@ -51,7 +53,7 @@ function fetchImageFallback( } function convertToPng(blob: Blob): Promise { - return new Promise(resolve => { + return new Promise((resolve, reject) => { const reader = new FileReader(); reader.addEventListener('load', _ => { const img = new Image(); @@ -60,7 +62,10 @@ function convertToPng(blob: Blob): Promise { c.width = img.width; c.height = img.height; const ctx = c.getContext('2d'); - assertExists(ctx); + if (!ctx) { + reject(); + return; + } ctx.imageSmoothingEnabled = true; ctx.imageSmoothingQuality = 'high'; ctx.drawImage(img, 0, 0); diff --git a/packages/frontend/core/src/blocksuite/ai/utils/template-job.ts b/packages/frontend/core/src/blocksuite/ai/utils/template-job.ts index eee588e229..321b194764 100644 --- a/packages/frontend/core/src/blocksuite/ai/utils/template-job.ts +++ b/packages/frontend/core/src/blocksuite/ai/utils/template-job.ts @@ -6,11 +6,12 @@ import { TemplateMiddlewares, } from '@blocksuite/affine/blocks'; import { Bound, getCommonBound } from '@blocksuite/affine/global/gfx'; -import { assertExists } from '@blocksuite/affine/global/utils'; export function createTemplateJob(host: EditorHost) { const surface = getSurfaceBlock(host.doc); - assertExists(surface); + if (!surface) { + throw new Error('surface is not found'); + } const middlewares: ((job: TemplateJob) => void)[] = []; const layer = new LayerManager(host.doc, surface, { diff --git a/packages/frontend/core/src/blocksuite/ai/widgets/ai-panel/ai-panel.ts b/packages/frontend/core/src/blocksuite/ai/widgets/ai-panel/ai-panel.ts index 858d4869de..0278e40092 100644 --- a/packages/frontend/core/src/blocksuite/ai/widgets/ai-panel/ai-panel.ts +++ b/packages/frontend/core/src/blocksuite/ai/widgets/ai-panel/ai-panel.ts @@ -13,7 +13,6 @@ import { stopPropagation, ThemeProvider, } from '@blocksuite/affine/blocks'; -import { assertExists } from '@blocksuite/affine/global/utils'; import type { BaseSelection } from '@blocksuite/affine/store'; import { autoPlacement, @@ -176,10 +175,16 @@ export class AffineAIPanelWidget extends WidgetComponent { generate = () => { this.restoreSelection(); - assertExists(this.config); const text = this._inputText; - assertExists(text); - assertExists(this.config.generateAnswer); + if (!this.config) { + throw new Error('config is not found'); + } + if (text === null || text === undefined) { + throw new Error('text is not found'); + } + if (!this.config.generateAnswer) { + throw new Error('generateAnswer is not found'); + } this._resetAbortController(); @@ -193,7 +198,9 @@ export class AffineAIPanelWidget extends WidgetComponent { const finish = (type: 'success' | 'error' | 'aborted', err?: AIError) => { if (type === 'aborted') return; - assertExists(this.config); + if (!this.config) { + throw new Error('config is not found when finish'); + } if (type === 'error') { this.state = 'error'; this.config.errorStateConfig.error = err; diff --git a/packages/frontend/core/src/components/hooks/use-app-config-storage.ts b/packages/frontend/core/src/components/hooks/use-app-config-storage.ts index 7b7f080cd8..63ca7260ff 100644 --- a/packages/frontend/core/src/components/hooks/use-app-config-storage.ts +++ b/packages/frontend/core/src/components/hooks/use-app-config-storage.ts @@ -1,5 +1,4 @@ import { apis } from '@affine/electron-api'; -import { assertExists } from '@blocksuite/affine/global/utils'; import type { AppConfigSchema } from '@toeverything/infra'; import { AppConfigStorage, defaultAppConfig } from '@toeverything/infra'; import type { Dispatch } from 'react'; @@ -12,12 +11,16 @@ class AppConfigProxy { value: AppConfigSchema = defaultAppConfig; async getSync(): Promise { - assertExists(apis); + if (!apis) { + throw new Error('electron apis is not found'); + } return (this.value = await apis.configStorage.get()); } async setSync(): Promise { - assertExists(apis); + if (!apis) { + throw new Error('electron apis is not found'); + } await apis.configStorage.set(this.value); } diff --git a/packages/frontend/core/src/components/page-list/__tests__/filter.spec.tsx b/packages/frontend/core/src/components/page-list/__tests__/filter.spec.tsx index 9644a1df71..6858378e9c 100644 --- a/packages/frontend/core/src/components/page-list/__tests__/filter.spec.tsx +++ b/packages/frontend/core/src/components/page-list/__tests__/filter.spec.tsx @@ -11,7 +11,6 @@ import type { VariableMap, } from '@affine/env/filter'; import { getOrCreateI18n, I18nextProvider } from '@affine/i18n'; -import { assertExists } from '@blocksuite/affine/global/utils'; import { render } from '@testing-library/react'; import type { ReactElement } from 'react'; import { useState } from 'react'; @@ -77,7 +76,9 @@ describe('match filter', () => { describe('eval filter', () => { test('before', async () => { const before = filterMatcher.findData(v => v.name === 'before'); - assertExists(before); + if (!before) { + throw new Error('before is not found'); + } const filter1 = filter(before, ref('Created'), [ new Date(2023, 5, 28).getTime(), ]); @@ -96,7 +97,9 @@ describe('eval filter', () => { }); test('after', async () => { const after = filterMatcher.findData(v => v.name === 'after'); - assertExists(after); + if (!after) { + throw new Error('after is not found'); + } const filter1 = filter(after, ref('Created'), [ new Date(2023, 5, 28).getTime(), ]); @@ -115,7 +118,9 @@ describe('eval filter', () => { }); test('is', async () => { const is = filterMatcher.findData(v => v.name === 'is'); - assertExists(is); + if (!is) { + throw new Error('is is not found'); + } const filter1 = filter(is, ref('Is Favourited'), [false]); const filter2 = filter(is, ref('Is Favourited'), [true]); const varMap = mockVariableMap({ @@ -130,7 +135,9 @@ describe('render filter', () => { test('boolean condition value change', async () => { const is = filterMatcher.match(tBoolean.create()); const i18n = getOrCreateI18n(); - assertExists(is); + if (!is) { + throw new Error('is is not found'); + } const Wrapper = () => { const [value, onChange] = useState( filter(is, ref('Is Favourited'), [true]) @@ -169,7 +176,9 @@ describe('render filter', () => { test('date condition function change', async () => { const dateFunction = filterMatcher.match(tDate.create()); - assertExists(dateFunction); + if (!dateFunction) { + throw new Error('dateFunction is not found'); + } const Wrapper = WrapperCreator(dateFunction); const result = render(); const dom = await result.findByTestId('filter-name'); @@ -179,7 +188,9 @@ describe('render filter', () => { }); test('date condition variable change', async () => { const dateFunction = filterMatcher.match(tDate.create()); - assertExists(dateFunction); + if (!dateFunction) { + throw new Error('dateFunction is not found'); + } const Wrapper = WrapperCreator(dateFunction); const result = render(); const dom = await result.findByTestId('variable-name'); diff --git a/packages/frontend/core/src/components/page-list/__tests__/use-block-suite-page-preview.spec.ts b/packages/frontend/core/src/components/page-list/__tests__/use-block-suite-page-preview.spec.ts index ccb130b520..1ed1e86f11 100644 --- a/packages/frontend/core/src/components/page-list/__tests__/use-block-suite-page-preview.spec.ts +++ b/packages/frontend/core/src/components/page-list/__tests__/use-block-suite-page-preview.spec.ts @@ -4,7 +4,6 @@ import 'fake-indexeddb/auto'; import { StoreExtensions } from '@blocksuite/affine/blocks'; -import { assertExists } from '@blocksuite/affine/global/utils'; import { type Store, Text } from '@blocksuite/affine/store'; import { TestWorkspace } from '@blocksuite/affine/store/test'; import { renderHook } from '@testing-library/react'; @@ -23,7 +22,6 @@ beforeEach(async () => { const initPage = async (page: Store) => { page.load(); expect(page).not.toBeNull(); - assertExists(page); const pageBlockId = page.addBlock('affine:page', { title: new Text(''), }); diff --git a/packages/frontend/core/src/components/page-list/page-group.tsx b/packages/frontend/core/src/components/page-list/page-group.tsx index bd8b65fd48..cf11ad93e8 100644 --- a/packages/frontend/core/src/components/page-list/page-group.tsx +++ b/packages/frontend/core/src/components/page-list/page-group.tsx @@ -2,7 +2,6 @@ import { shallowEqual } from '@affine/component'; import { DocDisplayMetaService } from '@affine/core/modules/doc-display-meta'; import type { Tag } from '@affine/env/filter'; import { useI18n } from '@affine/i18n'; -import { assertExists } from '@blocksuite/affine/global/utils'; import type { DocMeta, Workspace } from '@blocksuite/affine/store'; import { ToggleRightIcon, ViewLayersIcon } from '@blocksuite/icons/rc'; import * as Collapsible from '@radix-ui/react-collapsible'; @@ -301,7 +300,9 @@ function pageMetaToListItemProp( ): PageListItemProps { const toggleSelection = props.onSelectedIdsChange ? () => { - assertExists(props.selectedIds); + if (!props.selectedIds) { + throw new Error('selectedIds is not found'); + } const prevSelected = props.selectedIds.includes(item.id); const shouldAdd = !prevSelected; const shouldRemove = prevSelected; @@ -345,7 +346,9 @@ function collectionMetaToListItemProp( ): CollectionListItemProps { const toggleSelection = props.onSelectedIdsChange ? () => { - assertExists(props.selectedIds); + if (!props.selectedIds) { + throw new Error('selectedIds is not found'); + } const prevSelected = props.selectedIds.includes(item.id); const shouldAdd = !prevSelected; const shouldRemove = prevSelected; @@ -382,7 +385,9 @@ function tagMetaToListItemProp( ): TagListItemProps { const toggleSelection = props.onSelectedIdsChange ? () => { - assertExists(props.selectedIds); + if (!props.selectedIds) { + throw new Error('selectedIds is not found'); + } const prevSelected = props.selectedIds.includes(item.id); const shouldAdd = !prevSelected; const shouldRemove = prevSelected; diff --git a/packages/frontend/core/src/components/providers/swr-config-provider.tsx b/packages/frontend/core/src/components/providers/swr-config-provider.tsx index fa20135f10..9d2a185256 100644 --- a/packages/frontend/core/src/components/providers/swr-config-provider.tsx +++ b/packages/frontend/core/src/components/providers/swr-config-provider.tsx @@ -1,6 +1,5 @@ import { notify } from '@affine/component'; import { GraphQLError } from '@affine/graphql'; -import { assertExists } from '@blocksuite/affine/global/utils'; import type { PropsWithChildren, ReactNode } from 'react'; import { useCallback } from 'react'; import type { SWRConfiguration } from 'swr'; @@ -12,7 +11,9 @@ const swrConfig: SWRConfiguration = { useSWRNext => (key, fetcher, config) => { const fetcherWrapper = useCallback( async (...args: any[]) => { - assertExists(fetcher); + if (!fetcher) { + throw new Error('fetcher is not found'); + } const d = fetcher(...args); if (d instanceof Promise) { return d.catch(e => { diff --git a/packages/frontend/core/src/desktop/pages/workspace/trash-page.tsx b/packages/frontend/core/src/desktop/pages/workspace/trash-page.tsx index 73fb215a67..d5ac6947f7 100644 --- a/packages/frontend/core/src/desktop/pages/workspace/trash-page.tsx +++ b/packages/frontend/core/src/desktop/pages/workspace/trash-page.tsx @@ -8,7 +8,6 @@ import { GlobalContextService } from '@affine/core/modules/global-context'; import { WorkspacePermissionService } from '@affine/core/modules/permissions'; import { WorkspaceService } from '@affine/core/modules/workspace'; import { useI18n } from '@affine/i18n'; -import { assertExists } from '@blocksuite/affine/global/utils'; import { DeleteIcon } from '@blocksuite/icons/rc'; import { useLiveData, useService } from '@toeverything/infra'; import { useEffect } from 'react'; @@ -44,7 +43,6 @@ export const TrashPage = () => { const isAdmin = useLiveData(permissionService.permission.isAdmin$); const isOwner = useLiveData(permissionService.permission.isOwner$); const docCollection = currentWorkspace.docCollection; - assertExists(docCollection); const pageMetas = useBlockSuiteDocMeta(docCollection); const filteredPageMetas = useFilteredPageMetas(pageMetas, { diff --git a/packages/frontend/core/src/modules/open-in-app/views/open-in-app-guard.tsx b/packages/frontend/core/src/modules/open-in-app/views/open-in-app-guard.tsx index e8f8e546cd..8116a48f01 100644 --- a/packages/frontend/core/src/modules/open-in-app/views/open-in-app-guard.tsx +++ b/packages/frontend/core/src/modules/open-in-app/views/open-in-app-guard.tsx @@ -1,4 +1,3 @@ -import { assertExists } from '@blocksuite/affine/global/utils'; import { useLiveData, useService } from '@toeverything/infra'; import { Fragment, useCallback, useEffect } from 'react'; @@ -9,10 +8,9 @@ import { OpenInAppPage } from './open-in-app-page'; * Web only guard to open the URL in desktop app for different conditions */ const WebOpenInAppGuard = ({ children }: { children: React.ReactNode }) => { - assertExists( - BUILD_CONFIG.isWeb, - 'WebOpenInAppGuard should only be used in web' - ); + if (BUILD_CONFIG.isWeb === undefined || BUILD_CONFIG.isWeb === null) { + throw new Error('WebOpenInAppGuard should only be used in web'); + } const service = useService(OpenInAppService); const shouldOpenInApp = useLiveData(service.showOpenInAppPage$);