refactor(editor): remove assertExists (#10615)

This commit is contained in:
Saul-Mirone
2025-03-05 00:13:08 +00:00
parent a6692f70aa
commit b8ecfbdae6
106 changed files with 863 additions and 517 deletions
@@ -10,7 +10,8 @@ import {
import type { EditorHost } from '@blocksuite/block-std'; import type { EditorHost } from '@blocksuite/block-std';
import { DataSourceBase, type PropertyMetaConfig } from '@blocksuite/data-view'; import { DataSourceBase, type PropertyMetaConfig } from '@blocksuite/data-view';
import { propertyPresets } from '@blocksuite/data-view/property-presets'; 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 { Block, Store } from '@blocksuite/store';
import type { BlockMeta } from './block-meta/base.js'; import type { BlockMeta } from './block-meta/base.js';
@@ -95,7 +96,12 @@ export class BlockQueryDataSource extends DataSourceBase {
private getProperty(propertyId: string) { private getProperty(propertyId: string) {
const property = this.meta.properties.find(v => v.key === propertyId); 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; return property;
} }
@@ -18,7 +18,6 @@ import {
createIcon, createIcon,
} from '@blocksuite/data-view'; } from '@blocksuite/data-view';
import { IS_MAC } from '@blocksuite/global/env'; import { IS_MAC } from '@blocksuite/global/env';
import { assertExists } from '@blocksuite/global/utils';
import type { DeltaInsert } from '@blocksuite/inline'; import type { DeltaInsert } from '@blocksuite/inline';
import type { BlockSnapshot } from '@blocksuite/store'; import type { BlockSnapshot } from '@blocksuite/store';
import { Text } from '@blocksuite/store'; import { Text } from '@blocksuite/store';
@@ -338,7 +337,7 @@ export class RichTextCellEditing extends BaseRichTextCell {
private readonly _onSoftEnter = () => { private readonly _onSoftEnter = () => {
if (this.value && this.inlineEditor) { if (this.value && this.inlineEditor) {
const inlineRange = this.inlineEditor.getInlineRange(); const inlineRange = this.inlineEditor.getInlineRange();
assertExists(inlineRange); if (!inlineRange) return;
const text = new Text(this.inlineEditor.yText); const text = new Text(this.inlineEditor.yText);
text.replace(inlineRange.index, inlineRange.length, '\n'); text.replace(inlineRange.index, inlineRange.length, '\n');
@@ -351,7 +350,7 @@ export class RichTextCellEditing extends BaseRichTextCell {
private readonly _onCopy = (e: ClipboardEvent) => { private readonly _onCopy = (e: ClipboardEvent) => {
const inlineEditor = this.inlineEditor; const inlineEditor = this.inlineEditor;
assertExists(inlineEditor); if (!inlineEditor) return;
const inlineRange = inlineEditor.getInlineRange(); const inlineRange = inlineEditor.getInlineRange();
if (!inlineRange) return; if (!inlineRange) return;
@@ -368,7 +367,7 @@ export class RichTextCellEditing extends BaseRichTextCell {
private readonly _onCut = (e: ClipboardEvent) => { private readonly _onCut = (e: ClipboardEvent) => {
const inlineEditor = this.inlineEditor; const inlineEditor = this.inlineEditor;
assertExists(inlineEditor); if (!inlineEditor) return;
const inlineRange = inlineEditor.getInlineRange(); const inlineRange = inlineEditor.getInlineRange();
if (!inlineRange) return; if (!inlineRange) return;
@@ -13,7 +13,6 @@ import {
} from '@blocksuite/affine-shared/utils'; } from '@blocksuite/affine-shared/utils';
import { BaseCellRenderer } from '@blocksuite/data-view'; import { BaseCellRenderer } from '@blocksuite/data-view';
import { IS_MAC } from '@blocksuite/global/env'; import { IS_MAC } from '@blocksuite/global/env';
import { assertExists } from '@blocksuite/global/utils';
import { LinkedPageIcon } from '@blocksuite/icons/lit'; import { LinkedPageIcon } from '@blocksuite/icons/lit';
import type { DeltaInsert } from '@blocksuite/inline'; import type { DeltaInsert } from '@blocksuite/inline';
import type { BlockSnapshot, Text } from '@blocksuite/store'; import type { BlockSnapshot, Text } from '@blocksuite/store';
@@ -205,7 +204,7 @@ export class HeaderAreaTextCell extends BaseTextCell {
export class HeaderAreaTextCellEditing extends BaseTextCell { export class HeaderAreaTextCellEditing extends BaseTextCell {
private readonly _onCopy = (e: ClipboardEvent) => { private readonly _onCopy = (e: ClipboardEvent) => {
const inlineEditor = this.inlineEditor; const inlineEditor = this.inlineEditor;
assertExists(inlineEditor); if (!inlineEditor) return;
const inlineRange = inlineEditor.getInlineRange(); const inlineRange = inlineEditor.getInlineRange();
if (!inlineRange) return; if (!inlineRange) return;
@@ -222,7 +221,7 @@ export class HeaderAreaTextCellEditing extends BaseTextCell {
private readonly _onCut = (e: ClipboardEvent) => { private readonly _onCut = (e: ClipboardEvent) => {
const inlineEditor = this.inlineEditor; const inlineEditor = this.inlineEditor;
assertExists(inlineEditor); if (!inlineEditor) return;
const inlineRange = inlineEditor.getInlineRange(); const inlineRange = inlineEditor.getInlineRange();
if (!inlineRange) return; if (!inlineRange) return;
@@ -11,7 +11,6 @@ import { EMBED_CARD_HEIGHT } from '@blocksuite/affine-shared/consts';
import { NotificationProvider } from '@blocksuite/affine-shared/services'; import { NotificationProvider } from '@blocksuite/affine-shared/services';
import { matchModels, SpecProvider } from '@blocksuite/affine-shared/utils'; import { matchModels, SpecProvider } from '@blocksuite/affine-shared/utils';
import { BlockStdScope } from '@blocksuite/block-std'; import { BlockStdScope } from '@blocksuite/block-std';
import { assertExists } from '@blocksuite/global/utils';
import { import {
type BlockModel, type BlockModel,
type BlockSnapshot, type BlockSnapshot,
@@ -36,10 +35,12 @@ export function renderLinkedDocInCard(
card: EmbedLinkedDocBlockComponent | EmbedSyncedDocCard card: EmbedLinkedDocBlockComponent | EmbedSyncedDocCard
) { ) {
const linkedDoc = card.linkedDoc; const linkedDoc = card.linkedDoc;
assertExists( if (!linkedDoc) {
linkedDoc, console.error(
`Trying to load page ${card.model.pageId} in linked page block, but the page is not found.` `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 // eslint-disable-next-line sonarjs/no-collapsible-if
if ('bannerContainer' in card) { if ('bannerContainer' in card) {
@@ -59,10 +60,12 @@ export function renderLinkedDocInCard(
async function renderPageAsBanner(card: EmbedSyncedDocCard) { async function renderPageAsBanner(card: EmbedSyncedDocCard) {
const linkedDoc = card.linkedDoc; const linkedDoc = card.linkedDoc;
assertExists( if (!linkedDoc) {
linkedDoc, console.error(
`Trying to load page ${card.model.pageId} in linked page block, but the page is not found.` `Trying to load page ${card.model.pageId} in linked page block, but the page is not found.`
); );
return;
}
const notes = getNotesFromDoc(linkedDoc); const notes = getNotesFromDoc(linkedDoc);
if (!notes) { if (!notes) {
@@ -126,10 +129,12 @@ async function renderNoteContent(
card.isNoteContentEmpty = true; card.isNoteContentEmpty = true;
const doc = card.linkedDoc; const doc = card.linkedDoc;
assertExists( if (!doc) {
doc, console.error(
`Trying to load page ${card.model.pageId} in linked page block, but the page is not found.` `Trying to load page ${card.model.pageId} in linked page block, but the page is not found.`
); );
return;
}
const notes = getNotesFromDoc(doc); const notes = getNotesFromDoc(doc);
if (!notes) { if (!notes) {
@@ -4,7 +4,6 @@ import type {
} from '@blocksuite/affine-model'; } from '@blocksuite/affine-model';
import type { LinkPreviewerService } from '@blocksuite/affine-shared/services'; import type { LinkPreviewerService } from '@blocksuite/affine-shared/services';
import { isAbortError } from '@blocksuite/affine-shared/utils'; import { isAbortError } from '@blocksuite/affine-shared/utils';
import { assertExists } from '@blocksuite/global/utils';
import { nothing } from 'lit'; import { nothing } from 'lit';
import type { EmbedGithubBlockComponent } from './embed-github-block.js'; import type { EmbedGithubBlockComponent } from './embed-github-block.js';
@@ -89,8 +88,14 @@ export async function refreshEmbedGithubUrlData(
try { try {
embedGithubElement.loading = true; embedGithubElement.loading = true;
// TODO(@mirone): remove service
const queryUrlData = embedGithubElement.service?.queryUrlData; 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); const githubUrlData = await queryUrlData(embedGithubElement.model);
({ ({
@@ -126,8 +131,15 @@ export async function refreshEmbedGithubStatus(
embedGithubElement: EmbedGithubBlockComponent, embedGithubElement: EmbedGithubBlockComponent,
signal?: AbortSignal signal?: AbortSignal
) { ) {
// TODO(@mirone): remove service
const queryApiData = embedGithubElement.service?.queryApiData; 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); const githubApiData = await queryApiData(embedGithubElement.model, signal);
if (!githubApiData.status || signal?.aborted) return; if (!githubApiData.status || signal?.aborted) return;
@@ -35,7 +35,6 @@ import {
GfxExtension, GfxExtension,
} from '@blocksuite/block-std/gfx'; } from '@blocksuite/block-std/gfx';
import { Bound, getCommonBound } from '@blocksuite/global/gfx'; import { Bound, getCommonBound } from '@blocksuite/global/gfx';
import { assertExists } from '@blocksuite/global/utils';
import { type GetBlocksOptions, type Query, Text } from '@blocksuite/store'; import { type GetBlocksOptions, type Query, Text } from '@blocksuite/store';
import { computed, signal } from '@preact/signals-core'; import { computed, signal } from '@preact/signals-core';
import { html, nothing, type PropertyValues } from 'lit'; import { html, nothing, type PropertyValues } from 'lit';
@@ -284,7 +283,12 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
const { doc, caption } = this.model; const { doc, caption } = this.model;
const parent = doc.getParent(this.model); const parent = doc.getParent(this.model);
assertExists(parent); if (!parent) {
console.error(
`Trying to convert synced doc to card, but the parent is not found.`
);
return;
}
const index = parent.children.indexOf(this.model); const index = parent.children.indexOf(this.model);
doc.addBlock( doc.addBlock(
@@ -301,7 +305,12 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
covertToInline = () => { covertToInline = () => {
const { doc } = this.model; const { doc } = this.model;
const parent = doc.getParent(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 index = parent.children.indexOf(this.model);
const yText = new Y.Text(); const yText = new Y.Text();
@@ -4,7 +4,6 @@ import type {
} from '@blocksuite/affine-model'; } from '@blocksuite/affine-model';
import type { LinkPreviewerService } from '@blocksuite/affine-shared/services'; import type { LinkPreviewerService } from '@blocksuite/affine-shared/services';
import { isAbortError } from '@blocksuite/affine-shared/utils'; import { isAbortError } from '@blocksuite/affine-shared/utils';
import { assertExists } from '@blocksuite/global/utils';
import type { EmbedYoutubeBlockComponent } from './embed-youtube-block.js'; import type { EmbedYoutubeBlockComponent } from './embed-youtube-block.js';
@@ -73,8 +72,14 @@ export async function refreshEmbedYoutubeUrlData(
try { try {
embedYoutubeElement.loading = true; embedYoutubeElement.loading = true;
// TODO(@mirone): remove service
const queryUrlData = embedYoutubeElement.service?.queryUrlData; 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( const youtubeUrlData = await queryUrlData(
embedYoutubeElement.model, embedYoutubeElement.model,
@@ -5,7 +5,6 @@ import {
} from '@blocksuite/affine-shared/utils'; } from '@blocksuite/affine-shared/utils';
import type { BlockComponent, PointerEventState } from '@blocksuite/block-std'; import type { BlockComponent, PointerEventState } from '@blocksuite/block-std';
import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx'; import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx';
import { assertExists } from '@blocksuite/global/utils';
export class ImageResizeManager { export class ImageResizeManager {
private _activeComponent: BlockComponent | null = null; private _activeComponent: BlockComponent | null = null;
@@ -19,8 +18,9 @@ export class ImageResizeManager {
private _zoom = 1; private _zoom = 1;
onEnd() { onEnd() {
assertExists(this._activeComponent); if (!this._activeComponent || !this._imageContainer) {
assertExists(this._imageContainer); return;
}
const dragModel = getModelByElement(this._activeComponent); const dragModel = getModelByElement(this._activeComponent);
dragModel?.doc.captureSync(); dragModel?.doc.captureSync();
@@ -32,12 +32,16 @@ export class ImageResizeManager {
} }
onMove(e: PointerEventState) { onMove(e: PointerEventState) {
assertExists(this._activeComponent);
const activeComponent = this._activeComponent; const activeComponent = this._activeComponent;
const activeImgContainer = this._imageContainer; const activeImgContainer = this._imageContainer;
assertExists(activeImgContainer); if (!activeComponent || !activeImgContainer) {
return;
}
const activeImg = activeComponent.querySelector('img'); const activeImg = activeComponent.querySelector('img');
assertExists(activeImg); if (!activeImg) {
return;
}
let width = 0; let width = 0;
if (this._dragMoveTarget === 'right') { if (this._dragMoveTarget === 'right') {
@@ -84,7 +88,9 @@ export class ImageResizeManager {
} }
this._imageContainer = eventTarget.closest('.resizable-img'); this._imageContainer = eventTarget.closest('.resizable-img');
assertExists(this._imageContainer); if (!this._imageContainer) {
return;
}
const rect = this._imageContainer.getBoundingClientRect() as DOMRect; const rect = this._imageContainer.getBoundingClientRect() as DOMRect;
this._imageCenterX = rect.left + rect.width / 2; this._imageCenterX = rect.left + rect.width / 2;
if (eventTarget.className.includes('right')) { if (eventTarget.className.includes('right')) {
@@ -1,5 +1,4 @@
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import { assertExists } from '@blocksuite/global/utils';
import type { import type {
BlockSnapshot, BlockSnapshot,
DocSnapshot, DocSnapshot,
@@ -50,7 +49,12 @@ export class ClipboardAdapter extends BaseAdapter<string> {
): Promise<FromSliceSnapshotResult<string>> { ): Promise<FromSliceSnapshotResult<string>> {
const snapshot = payload.snapshot; const snapshot = payload.snapshot;
const assets = payload.assets; const assets = payload.assets;
assertExists(assets); if (!assets) {
throw new BlockSuiteError(
ErrorCode.ValueNotExists,
'ClipboardAdapter.fromSliceSnapshot: assets is not found'
);
}
const map = assets.getAssets(); const map = assets.getAssets();
const blobs: Record<string, FileSnapshot> = await encodeClipboardBlobs(map); const blobs: Record<string, FileSnapshot> = await encodeClipboardBlobs(map);
return { return {
@@ -1,5 +1,4 @@
import { toast } from '@blocksuite/affine-components/toast'; import { toast } from '@blocksuite/affine-components/toast';
import { assertExists } from '@blocksuite/global/utils';
import type { FileSnapshot } from './adapter.js'; import type { FileSnapshot } from './adapter.js';
@@ -113,12 +112,17 @@ export function decodeClipboardBlobs(
blobs: Record<string, FileSnapshot>, blobs: Record<string, FileSnapshot>,
map: Map<string, Blob> | undefined map: Map<string, Blob> | undefined
) { ) {
if (!map) {
console.error(
`Trying to decode clipboard blobs, but the map is not found.`
);
return;
}
Object.entries<FileSnapshot>(blobs).forEach(([sourceId, file]) => { Object.entries<FileSnapshot>(blobs).forEach(([sourceId, file]) => {
const blob = new Blob([decode(file.content)]); const blob = new Blob([decode(file.content)]);
const f = new File([blob], file.name, { const f = new File([blob], file.name, {
type: file.type, type: file.type,
}); });
assertExists(map);
map.set(sourceId, f); map.set(sourceId, f);
}); });
} }
@@ -57,12 +57,7 @@ import {
type SerializedXYWH, type SerializedXYWH,
Vec, Vec,
} from '@blocksuite/global/gfx'; } from '@blocksuite/global/gfx';
import { import { assertType, DisposableGroup, nToLast } from '@blocksuite/global/utils';
assertExists,
assertType,
DisposableGroup,
nToLast,
} from '@blocksuite/global/utils';
import { import {
type BlockSnapshot, type BlockSnapshot,
BlockSnapshotSchema, BlockSnapshotSchema,
@@ -519,17 +514,19 @@ export class EdgelessClipboardController extends PageClipboard {
clipboardData: SerializedElement, clipboardData: SerializedElement,
context: CreationContext, context: CreationContext,
newXYWH: SerializedXYWH newXYWH: SerializedXYWH
) { ): GfxPrimitiveElementModel | null {
if (clipboardData.type === GROUP) { if (clipboardData.type === GROUP) {
const yMap = new Y.Map(); const yMap = new Y.Map();
const children = clipboardData.children ?? {}; const children = clipboardData.children ?? {};
for (const [key, value] of Object.entries(children)) { for (const [key, value] of Object.entries(children)) {
const newKey = context.oldToNewIdMap.get(key); const newKey = context.oldToNewIdMap.get(key);
assertExists( if (!newKey) {
newKey, console.error(
'Copy failed: cannot find the copied child in group' `Copy failed: cannot find the copied child in group, key: ${key}`
); );
return null;
}
yMap.set(newKey, value); yMap.set(newKey, value);
} }
clipboardData.children = yMap; clipboardData.children = yMap;
@@ -543,17 +540,21 @@ export class EdgelessClipboardController extends PageClipboard {
const newValue = { const newValue = {
...oldValue, ...oldValue,
}; };
assertExists( if (!newKey) {
newKey, console.error(
'Copy failed: cannot find the copied node in mind map' `Copy failed: cannot find the copied node in mind map, key: ${oldKey}`
); );
return null;
}
if (oldValue.parent) { if (oldValue.parent) {
const newParent = context.oldToNewIdMap.get(oldValue.parent); const newParent = context.oldToNewIdMap.get(oldValue.parent);
assertExists( if (!newParent) {
newParent, console.error(
'Copy failed: cannot find the copied node in mind map' `Copy failed: cannot find the copied node in mind map, parent: ${oldValue.parent}`
); );
return null;
}
newValue.parent = newParent; newValue.parent = newParent;
} }
@@ -603,7 +604,10 @@ export class EdgelessClipboardController extends PageClipboard {
type: clipboardData.type as string, type: clipboardData.type as string,
}); });
const element = this.crud.getElementById(id) as GfxPrimitiveElementModel; 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; return element;
} }
@@ -898,7 +902,7 @@ export class EdgelessClipboardController extends PageClipboard {
const editorMode = isInsidePageEditor(host); const editorMode = isInsidePageEditor(host);
const rootComponent = getRootByEditorHost(host); const rootComponent = getRootByEditorHost(host);
assertExists(rootComponent); if (!rootComponent) return;
const container = rootComponent.querySelector( const container = rootComponent.querySelector(
'.affine-block-children-container' '.affine-block-children-container'
@@ -1355,7 +1359,10 @@ export class EdgelessClipboardController extends PageClipboard {
bounds.push(shape.elementBound); bounds.push(shape.elementBound);
}); });
const bound = getCommonBound(bounds); const bound = getCommonBound(bounds);
assertExists(bound, 'bound not exist'); if (!bound) {
console.error('bound not exist');
return;
}
const canvas = await this._edgelessToCanvas( const canvas = await this._edgelessToCanvas(
this.host, this.host,
@@ -27,11 +27,7 @@ import { type BlockStdScope, stdContext } from '@blocksuite/block-std';
import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx'; import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx';
import type { Bound, IVec } from '@blocksuite/global/gfx'; import type { Bound, IVec } from '@blocksuite/global/gfx';
import { Vec } from '@blocksuite/global/gfx'; import { Vec } from '@blocksuite/global/gfx';
import { import { DisposableGroup, WithDisposable } from '@blocksuite/global/utils';
assertExists,
DisposableGroup,
WithDisposable,
} from '@blocksuite/global/utils';
import { import {
ArrowUpBigIcon, ArrowUpBigIcon,
PlusIcon, PlusIcon,
@@ -194,7 +190,9 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) {
); );
} }
if (this._isMoving) { if (this._isMoving) {
assertExists(connector); if (!connector) {
return;
}
const otherSideId = connector.source.id; const otherSideId = connector.source.id;
connector.target = this.connectionOverlay.renderConnector( connector.target = this.connectionOverlay.renderConnector(
@@ -382,7 +380,9 @@ export class EdgelessAutoComplete extends WithDisposable(LitElement) {
); );
} else { } else {
const model = doc.getBlockById(id); const model = doc.getBlockById(id);
assertExists(model); if (!model) {
return;
}
const [x, y] = service.viewport.toViewCoord( const [x, y] = service.viewport.toViewCoord(
bound.center[0], bound.center[0],
bound.y + DEFAULT_NOTE_HEIGHT / 2 bound.y + DEFAULT_NOTE_HEIGHT / 2
@@ -7,7 +7,6 @@ import {
type PointLocation, type PointLocation,
rotatePoints, rotatePoints,
} from '@blocksuite/global/gfx'; } from '@blocksuite/global/gfx';
import { assertExists } from '@blocksuite/global/utils';
import type { SelectableProps } from '../../utils/query.js'; import type { SelectableProps } from '../../utils/query.js';
import { HandleDirection, type ResizeMode } from './resize-handles.js'; import { HandleDirection, type ResizeMode } from './resize-handles.js';
@@ -113,7 +112,9 @@ export class HandleResizeManager {
const rect = this._target const rect = this._target
.closest('.affine-edgeless-selected-rect') .closest('.affine-edgeless-selected-rect')
?.getBoundingClientRect(); ?.getBoundingClientRect();
assertExists(rect); if (!rect) {
return;
}
const { left, top, right, bottom } = rect; const { left, top, right, bottom } = rect;
const x = (left + right) / 2; const x = (left + right) / 2;
const y = (top + bottom) / 2; const y = (top + bottom) / 2;
@@ -207,12 +208,10 @@ export class HandleResizeManager {
_rotate, _rotate,
_resizeMode, _resizeMode,
_zoom, _zoom,
_target,
_originalRect, _originalRect,
_currentRect, _currentRect,
} = this; } = this;
proportion ||= this._proportion; proportion ||= this._proportion;
assertExists(_target);
const isAll = _resizeMode === 'all'; const isAll = _resizeMode === 'all';
const isCorner = _resizeMode === 'corner'; const isCorner = _resizeMode === 'corner';
@@ -11,7 +11,7 @@ import {
ShadowlessElement, ShadowlessElement,
} from '@blocksuite/block-std'; } from '@blocksuite/block-std';
import { Bound, Vec } from '@blocksuite/global/gfx'; 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 { css, html, nothing } from 'lit';
import { property, query } from 'lit/decorators.js'; import { property, query } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js'; import { styleMap } from 'lit/directives/style-map.js';
@@ -94,12 +94,11 @@ export class EdgelessConnectorLabelEditor extends WithDisposable(
}; };
get inlineEditor() { get inlineEditor() {
assertExists(this.richText.inlineEditor);
return this.richText.inlineEditor; return this.richText.inlineEditor;
} }
get inlineEditorContainer() { get inlineEditorContainer() {
return this.inlineEditor.rootElement; return this.inlineEditor?.rootElement;
} }
override connectedCallback() { override connectedCallback() {
@@ -116,7 +115,6 @@ export class EdgelessConnectorLabelEditor extends WithDisposable(
override firstUpdated() { override firstUpdated() {
const { edgeless, connector } = this; const { edgeless, connector } = this;
const { dispatcher } = edgeless; const { dispatcher } = edgeless;
assertExists(dispatcher);
this._resizeObserver = new ResizeObserver(() => { this._resizeObserver = new ResizeObserver(() => {
this._updateLabelRect(); this._updateLabelRect();
@@ -126,6 +124,7 @@ export class EdgelessConnectorLabelEditor extends WithDisposable(
this.updateComplete this.updateComplete
.then(() => { .then(() => {
if (!this.inlineEditor) return;
this.inlineEditor.selectAll(); this.inlineEditor.selectAll();
this.inlineEditor.slots.renderComplete.on(() => { this.inlineEditor.slots.renderComplete.on(() => {
@@ -10,7 +10,7 @@ import {
ShadowlessElement, ShadowlessElement,
} from '@blocksuite/block-std'; } from '@blocksuite/block-std';
import { Bound } from '@blocksuite/global/gfx'; 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 { cssVarV2 } from '@toeverything/theme/v2';
import { css, html, nothing } from 'lit'; import { css, html, nothing } from 'lit';
import { property, query } from 'lit/decorators.js'; import { property, query } from 'lit/decorators.js';
@@ -63,7 +63,6 @@ export class EdgelessFrameTitleEditor extends WithDisposable(
override firstUpdated(): void { override firstUpdated(): void {
const dispatcher = this.edgeless.dispatcher; const dispatcher = this.edgeless.dispatcher;
assertExists(dispatcher);
this.updateComplete this.updateComplete
.then(() => { .then(() => {
if (!this.inlineEditor) return; if (!this.inlineEditor) return;
@@ -10,7 +10,7 @@ import {
ShadowlessElement, ShadowlessElement,
} from '@blocksuite/block-std'; } from '@blocksuite/block-std';
import { Bound } from '@blocksuite/global/gfx'; 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 { html, nothing } from 'lit';
import { property, query } from 'lit/decorators.js'; import { property, query } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js'; import { styleMap } from 'lit/directives/style-map.js';
@@ -21,12 +21,11 @@ export class EdgelessGroupTitleEditor extends WithDisposable(
ShadowlessElement ShadowlessElement
) { ) {
get inlineEditor() { get inlineEditor() {
assertExists(this.richText.inlineEditor);
return this.richText.inlineEditor; return this.richText.inlineEditor;
} }
get inlineEditorContainer() { get inlineEditorContainer() {
return this.inlineEditor.rootElement; return this.inlineEditor?.rootElement;
} }
private _unmount() { private _unmount() {
@@ -47,10 +46,10 @@ export class EdgelessGroupTitleEditor extends WithDisposable(
override firstUpdated(): void { override firstUpdated(): void {
const dispatcher = this.edgeless.dispatcher; const dispatcher = this.edgeless.dispatcher;
assertExists(dispatcher);
this.updateComplete this.updateComplete
.then(() => { .then(() => {
if (!this.inlineEditor) return;
this.inlineEditor.selectAll(); this.inlineEditor.selectAll();
this.group.showTitle = false; this.group.showTitle = false;
@@ -12,7 +12,7 @@ import {
ShadowlessElement, ShadowlessElement,
} from '@blocksuite/block-std'; } from '@blocksuite/block-std';
import { Bound, toRadian, Vec } from '@blocksuite/global/gfx'; 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 { html, nothing } from 'lit';
import { property, query } from 'lit/decorators.js'; import { property, query } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js'; import { styleMap } from 'lit/directives/style-map.js';
@@ -32,12 +32,11 @@ export class EdgelessShapeTextEditor extends WithDisposable(ShadowlessElement) {
private _resizeObserver: ResizeObserver | null = null; private _resizeObserver: ResizeObserver | null = null;
get inlineEditor() { get inlineEditor() {
assertExists(this.richText.inlineEditor);
return this.richText.inlineEditor; return this.richText.inlineEditor;
} }
get inlineEditorContainer() { get inlineEditorContainer() {
return this.inlineEditor.rootElement; return this.inlineEditor?.rootElement;
} }
get isMindMapNode() { get isMindMapNode() {
@@ -175,7 +174,6 @@ export class EdgelessShapeTextEditor extends WithDisposable(ShadowlessElement) {
override firstUpdated(): void { override firstUpdated(): void {
const dispatcher = this.edgeless.dispatcher; const dispatcher = this.edgeless.dispatcher;
assertExists(dispatcher);
this.element.textDisplay = false; this.element.textDisplay = false;
@@ -202,6 +200,7 @@ export class EdgelessShapeTextEditor extends WithDisposable(ShadowlessElement) {
this.updateComplete this.updateComplete
.then(() => { .then(() => {
if (!this.inlineEditor) return;
if (this.element.group instanceof MindmapElementModel) { if (this.element.group instanceof MindmapElementModel) {
this.inlineEditor.selectAll(); this.inlineEditor.selectAll();
} else { } else {
@@ -11,7 +11,7 @@ import {
ShadowlessElement, ShadowlessElement,
} from '@blocksuite/block-std'; } from '@blocksuite/block-std';
import { Bound, toRadian, Vec } from '@blocksuite/global/gfx'; 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 { css, html, nothing } from 'lit';
import { property, query } from 'lit/decorators.js'; import { property, query } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js'; import { styleMap } from 'lit/directives/style-map.js';
@@ -144,12 +144,11 @@ export class EdgelessTextEditor extends WithDisposable(ShadowlessElement) {
}; };
get inlineEditor() { get inlineEditor() {
assertExists(this.richText.inlineEditor);
return this.richText.inlineEditor; return this.richText.inlineEditor;
} }
get inlineEditorContainer() { get inlineEditorContainer() {
return this.inlineEditor.rootElement; return this.inlineEditor?.rootElement;
} }
override connectedCallback(): void { override connectedCallback(): void {
@@ -170,10 +169,10 @@ export class EdgelessTextEditor extends WithDisposable(ShadowlessElement) {
const edgeless = this.edgeless; const edgeless = this.edgeless;
const element = this.element; const element = this.element;
const { dispatcher } = this.edgeless; const { dispatcher } = this.edgeless;
assertExists(dispatcher);
this.updateComplete this.updateComplete
.then(() => { .then(() => {
if (!this.inlineEditor) return;
this.inlineEditor.slots.renderComplete.on(() => { this.inlineEditor.slots.renderComplete.on(() => {
this._updateRect(); this._updateRect();
this.requestUpdate(); this.requestUpdate();
@@ -1,4 +1,4 @@
import { assertExists } from '@blocksuite/global/utils'; import { BlockSuiteError } from '@blocksuite/global/exceptions';
// more than 100% due to the shadow // more than 100% due to the shadow
const leaveToPercent = `calc(100% + 10px)`; const leaveToPercent = `calc(100% + 10px)`;
@@ -28,26 +28,31 @@ export function createPopper<T extends keyof HTMLElementTagNameMap>(
onDispose?: () => void; onDispose?: () => void;
setProps?: (ele: HTMLElementTagNameMap[T]) => void; setProps?: (ele: HTMLElementTagNameMap[T]) => void;
} }
) { ): MenuPopper<HTMLElementTagNameMap[T]> {
const duration = options?.duration ?? 230; const duration = options?.duration ?? 230;
if (!popMap.has(reference)) popMap.set(reference, new Map()); if (!popMap.has(reference)) popMap.set(reference, new Map());
const elMap = popMap.get(reference); const elMap = popMap.get(reference);
assertExists(elMap);
// if there is already a popper, cancel leave transition and apply enter transition // 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); const popper = elMap.get(tagName);
assertExists(popper); if (popper) {
popper.cancel?.(); popper.cancel?.();
requestAnimationFrame(() => animateEnter(popper.element)); requestAnimationFrame(() => animateEnter(popper.element));
return popper as MenuPopper<HTMLElementTagNameMap[T]>; return popper as MenuPopper<HTMLElementTagNameMap[T]>;
}
} }
const clipWrapper = document.createElement('div'); const clipWrapper = document.createElement('div');
const menu = document.createElement(tagName); const menu = document.createElement(tagName);
options?.setProps?.(menu); options?.setProps?.(menu);
assertExists(reference.shadowRoot);
clipWrapper.append(menu); clipWrapper.append(menu);
if (!reference.shadowRoot) {
throw new BlockSuiteError(
BlockSuiteError.ErrorCode.ValueNotExists,
'reference must be a shadow root'
);
}
reference.shadowRoot.append(clipWrapper); reference.shadowRoot.append(clipWrapper);
// apply enter transition // apply enter transition
@@ -3,7 +3,6 @@ import {
ThemeProvider, ThemeProvider,
} from '@blocksuite/affine-shared/services'; } from '@blocksuite/affine-shared/services';
import { Bound } from '@blocksuite/global/gfx'; import { Bound } from '@blocksuite/global/gfx';
import { assertExists } from '@blocksuite/global/utils';
import { import {
type ReactiveController, type ReactiveController,
type ReactiveControllerHost, type ReactiveControllerHost,
@@ -200,8 +199,7 @@ export class EdgelessDraggableElementController<T>
} }
const { overlay } = this; const { overlay } = this;
assertExists(overlay); if (!overlay) return;
const { x, y } = e; const { x, y } = e;
const { startPos, scopeRect } = info; const { startPos, scopeRect } = info;
const offsetX = x - startPos.x; const offsetX = x - startPos.x;
@@ -12,7 +12,7 @@ import {
TelemetryProvider, TelemetryProvider,
ThemeProvider, ThemeProvider,
} from '@blocksuite/affine-shared/services'; } 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 { css, html, LitElement, nothing } from 'lit';
import { property, query, state } from 'lit/decorators.js'; import { property, query, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js'; import { classMap } from 'lit/directives/class-map.js';
@@ -248,7 +248,10 @@ export class EdgelessToolbarShapeDraggable extends EdgelessToolbarToolMixin(
const el = this.shapeContainer.querySelector( const el = this.shapeContainer.querySelector(
`.shape.${this.draggingShape}` `.shape.${this.draggingShape}`
) as HTMLElement; ) 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 { x, y } = service.gfx.tool.lastMousePos$.peek();
const { left, top } = this.edgeless.viewport; const { left, top } = this.edgeless.viewport;
const clientPos = { x: x + left, y: y + top }; const clientPos = { x: x + left, y: y + top };
@@ -1,7 +1,6 @@
import type { CursorType, StandardCursor } from '@blocksuite/block-std/gfx'; import type { CursorType, StandardCursor } from '@blocksuite/block-std/gfx';
import type { IVec } from '@blocksuite/global/gfx'; import type { IVec } from '@blocksuite/global/gfx';
import { normalizeDegAngle, Vec } from '@blocksuite/global/gfx'; import { normalizeDegAngle, Vec } from '@blocksuite/global/gfx';
import { assertExists } from '@blocksuite/global/utils';
import { css, html } from 'lit'; import { css, html } from 'lit';
export function generateCursorUrl( export function generateCursorUrl(
@@ -89,7 +88,11 @@ export function calcAngle(target: HTMLElement, point: IVec, offset = 0) {
const rect = target const rect = target
.closest('.affine-edgeless-selected-rect') .closest('.affine-edgeless-selected-rect')
?.getBoundingClientRect(); ?.getBoundingClientRect();
assertExists(rect);
if (!rect) {
console.error('rect not found when calc angle');
return 0;
}
const { left, top, right, bottom } = rect; const { left, top, right, bottom } = rect;
const center = Vec.med([left, top], [right, bottom]); const center = Vec.med([left, top], [right, bottom]);
return normalizeDegAngle( return normalizeDegAngle(
@@ -104,9 +107,7 @@ export function calcAngleWithRotation(
rotate: number rotate: number
) { ) {
const handle = target.parentElement; const handle = target.parentElement;
assertExists(handle); const ariaLabel = handle?.getAttribute('aria-label');
const ariaLabel = handle.getAttribute('aria-label');
assertExists(ariaLabel);
const { left, top, right, bottom, width, height } = rect; const { left, top, right, bottom, width, height } = rect;
const size = Math.min(width, height); const size = Math.min(width, height);
const sx = size / width; const sx = size / width;
@@ -160,9 +161,7 @@ export function calcAngleWithRotation(
export function calcAngleEdgeWithRotation(target: HTMLElement, rotate: number) { export function calcAngleEdgeWithRotation(target: HTMLElement, rotate: number) {
let angleWithEdge = 0; let angleWithEdge = 0;
const handle = target.parentElement; const handle = target.parentElement;
assertExists(handle); const ariaLabel = handle?.getAttribute('aria-label');
const ariaLabel = handle.getAttribute('aria-label');
assertExists(ariaLabel);
switch (ariaLabel) { switch (ariaLabel) {
case 'top': { case 'top': {
angleWithEdge = 270; angleWithEdge = 270;
@@ -187,9 +186,7 @@ export function calcAngleEdgeWithRotation(target: HTMLElement, rotate: number) {
export function getResizeLabel(target: HTMLElement) { export function getResizeLabel(target: HTMLElement) {
const handle = target.parentElement; const handle = target.parentElement;
assertExists(handle); const ariaLabel = handle?.getAttribute('aria-label');
const ariaLabel = handle.getAttribute('aria-label');
assertExists(ariaLabel);
return ariaLabel; return ariaLabel;
} }
@@ -39,8 +39,8 @@ import {
type GfxViewportElement, type GfxViewportElement,
} from '@blocksuite/block-std/gfx'; } from '@blocksuite/block-std/gfx';
import { IS_WINDOWS } from '@blocksuite/global/env'; import { IS_WINDOWS } from '@blocksuite/global/env';
import { BlockSuiteError } from '@blocksuite/global/exceptions';
import { Bound, Point, Vec } from '@blocksuite/global/gfx'; import { Bound, Point, Vec } from '@blocksuite/global/gfx';
import { assertExists } from '@blocksuite/global/utils';
import { effect } from '@preact/signals-core'; import { effect } from '@preact/signals-core';
import { css, html } from 'lit'; import { css, html } from 'lit';
import { query } from 'lit/decorators.js'; import { query } from 'lit/decorators.js';
@@ -191,7 +191,12 @@ export class EdgelessRootBlockComponent extends BlockComponent<
this._viewportElement = this.host.closest( this._viewportElement = this.host.closest(
'.affine-edgeless-viewport' '.affine-edgeless-viewport'
) as HTMLElement | null; ) 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; return this._viewportElement;
} }
@@ -17,7 +17,7 @@ import {
SurfaceSelection, SurfaceSelection,
} from '@blocksuite/block-std'; } from '@blocksuite/block-std';
import type { GfxViewportElement } from '@blocksuite/block-std/gfx'; 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 { css, html } from 'lit';
import { query, state } from 'lit/decorators.js'; import { query, state } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js'; import { styleMap } from 'lit/directives/style-map.js';
@@ -104,7 +104,12 @@ export class EdgelessRootPreviewBlockComponent
this._viewportElement = this.host.closest( this._viewportElement = this.host.closest(
this.editorViewportSelector this.editorViewportSelector
) as HTMLElement | null; ) 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; return this._viewportElement;
} }
@@ -4,7 +4,6 @@ import { TelemetryProvider } from '@blocksuite/affine-shared/services';
import type { PointerEventState } from '@blocksuite/block-std'; import type { PointerEventState } from '@blocksuite/block-std';
import { BaseTool } from '@blocksuite/block-std/gfx'; import { BaseTool } from '@blocksuite/block-std/gfx';
import type { IVec } from '@blocksuite/global/gfx'; import type { IVec } from '@blocksuite/global/gfx';
import { assertExists } from '@blocksuite/global/utils';
export class BrushTool extends BaseTool { export class BrushTool extends BaseTool {
static BRUSH_POP_GAP = 20; static BRUSH_POP_GAP = 20;
@@ -40,8 +39,10 @@ export class BrushTool extends BaseTool {
: 'vertical'; : 'vertical';
} }
private _tryGetPressurePoints(e: PointerEventState) { private _tryGetPressurePoints(e: PointerEventState): number[][] {
assertExists(this._draggingPathPressures); if (!this._draggingPathPressures) {
return [];
}
const pressures = [...this._draggingPathPressures, e.pressure]; const pressures = [...this._draggingPathPressures, e.pressure];
this._draggingPathPressures = pressures; this._draggingPathPressures = pressures;
@@ -56,8 +57,10 @@ export class BrushTool extends BaseTool {
this._pressureSupportedPointerIds.add(pointerId); this._pressureSupportedPointerIds.add(pointerId);
} }
assertExists(this._draggingPathPoints);
const points = this._draggingPathPoints; const points = this._draggingPathPoints;
if (!points) {
return [];
}
if (this._pressureSupportedPointerIds.has(pointerId)) { if (this._pressureSupportedPointerIds.has(pointerId)) {
return points.map(([x, y], i) => [x, y, pressures[i]]); return points.map(([x, y], i) => [x, y, pressures[i]]);
} else { } else {
@@ -83,12 +86,14 @@ export class BrushTool extends BaseTool {
} }
override dragMove(e: PointerEventState) { override dragMove(e: PointerEventState) {
if (!this._draggingElementId || !this._draggingElement || !this.gfx.surface) if (
!this._draggingElementId ||
!this._draggingElement ||
!this.gfx.surface ||
!this._draggingPathPoints
)
return; return;
assertExists(this._draggingElementId);
assertExists(this._draggingPathPoints);
let pointX = e.point.x; let pointX = e.point.x;
let pointY = e.point.y; let pointY = e.point.y;
const holdingShiftKey = e.keys.shift || this.gfx.keyboard.shiftKey$.peek(); const holdingShiftKey = e.keys.shift || this.gfx.keyboard.shiftKey$.peek();
@@ -1,7 +1,7 @@
import { generateElementId, sortIndex } from '@blocksuite/affine-block-surface'; import { generateElementId, sortIndex } from '@blocksuite/affine-block-surface';
import type { ConnectorElementModel } from '@blocksuite/affine-model'; import type { ConnectorElementModel } from '@blocksuite/affine-model';
import { Bound } from '@blocksuite/global/gfx'; 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 { BlockSnapshot, SnapshotNode } from '@blocksuite/store';
import type { SlotBlockPayload, TemplateJob } from './template.js'; import type { SlotBlockPayload, TemplateJob } from './template.js';
@@ -154,8 +154,6 @@ export const createInsertPlaceMiddleware = (targetPlace: Bound) => {
const ignoreType = new Set(['group', 'connector']); const ignoreType = new Set(['group', 'connector']);
const changePosition = (blockJson: BlockSnapshot) => { const changePosition = (blockJson: BlockSnapshot) => {
assertExists(templateBound);
if (blockJson.props.xywh) { if (blockJson.props.xywh) {
const bound = Bound.deserialize(blockJson.props['xywh'] as string); const bound = Bound.deserialize(blockJson.props['xywh'] as string);
@@ -4,7 +4,7 @@ import type {
} from '@blocksuite/affine-block-surface'; } from '@blocksuite/affine-block-surface';
import type { ConnectorElementModel } from '@blocksuite/affine-model'; import type { ConnectorElementModel } from '@blocksuite/affine-model';
import { Bound, getCommonBound } from '@blocksuite/global/gfx'; import { Bound, getCommonBound } from '@blocksuite/global/gfx';
import { assertExists, assertType, Slot } from '@blocksuite/global/utils'; import { assertType, Slot } from '@blocksuite/global/utils';
import { import {
type BlockModel, type BlockModel,
type BlockSnapshot, type BlockSnapshot,
@@ -194,7 +194,9 @@ export class TemplateJob {
return; return;
} }
assertExists(modelData); if (!modelData) {
return;
}
doc.addBlock( doc.addBlock(
modelData.flavour, modelData.flavour,
@@ -8,7 +8,7 @@ import {
import { SpecProvider } from '@blocksuite/affine-shared/utils'; import { SpecProvider } from '@blocksuite/affine-shared/utils';
import { Container } from '@blocksuite/global/di'; import { Container } from '@blocksuite/global/di';
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; 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 type { Schema, Store, Workspace } from '@blocksuite/store';
import { extMimeMap, Transformer } from '@blocksuite/store'; import { extMimeMap, Transformer } from '@blocksuite/store';
@@ -112,7 +112,12 @@ async function importMarkdownToBlock({
pageId: doc.id, 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); const blocks = snapshot.content.flatMap(x => x.children);
@@ -16,7 +16,6 @@ import {
} from '@blocksuite/affine-shared/commands'; } from '@blocksuite/affine-shared/commands';
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types'; import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import type { EditorHost } from '@blocksuite/block-std'; import type { EditorHost } from '@blocksuite/block-std';
import { assertExists } from '@blocksuite/global/utils';
import { computePosition, flip, offset, shift } from '@floating-ui/dom'; import { computePosition, flip, offset, shift } from '@floating-ui/dom';
import { html } from 'lit'; import { html } from 'lit';
import { ref, type RefOrCallback } from 'lit/directives/ref.js'; import { ref, type RefOrCallback } from 'lit/directives/ref.js';
@@ -125,8 +124,9 @@ export const HighlightButton = (formatBar: AffineFormatBarWidget) => {
formatBar.shadowRoot?.querySelector<HTMLElement>('.highlight-button'); formatBar.shadowRoot?.querySelector<HTMLElement>('.highlight-button');
const panel = const panel =
formatBar.shadowRoot?.querySelector<HTMLElement>('.highlight-panel'); formatBar.shadowRoot?.querySelector<HTMLElement>('.highlight-panel');
assertExists(button); if (!button || !panel) {
assertExists(panel); return;
}
panel.style.display = 'flex'; panel.style.display = 'flex';
computePosition(button, panel, { computePosition(button, panel, {
placement: 'bottom', placement: 'bottom',
@@ -3,7 +3,6 @@ import { ArrowDownIcon } from '@blocksuite/affine-components/icons';
import { textConversionConfigs } from '@blocksuite/affine-components/rich-text'; import { textConversionConfigs } from '@blocksuite/affine-components/rich-text';
import type { ParagraphBlockModel } from '@blocksuite/affine-model'; import type { ParagraphBlockModel } from '@blocksuite/affine-model';
import type { EditorHost } from '@blocksuite/block-std'; import type { EditorHost } from '@blocksuite/block-std';
import { assertExists } from '@blocksuite/global/utils';
import { computePosition, flip, offset, shift } from '@floating-ui/dom'; import { computePosition, flip, offset, shift } from '@floating-ui/dom';
import { html } from 'lit'; import { html } from 'lit';
import { ref, type RefOrCallback } from 'lit/directives/ref.js'; import { ref, type RefOrCallback } from 'lit/directives/ref.js';
@@ -85,13 +84,11 @@ export const ParagraphButton = (formatBar: AffineFormatBarWidget) => {
return; return;
} }
const formatQuickBarElement = formatBar.formatBarElement; const formatQuickBarElement = formatBar.formatBarElement;
const button =
formatBar.shadowRoot?.querySelector<HTMLElement>('.paragraph-button');
const panel = const panel =
formatBar.shadowRoot?.querySelector<HTMLElement>('.paragraph-panel'); formatBar.shadowRoot?.querySelector<HTMLElement>('.paragraph-panel');
assertExists(button); if (!panel || !formatQuickBarElement) {
assertExists(panel); return;
assertExists(formatQuickBarElement, 'format quick bar should exist'); }
panel.style.display = 'flex'; panel.style.display = 'flex';
computePosition(formatQuickBarElement, panel, { computePosition(formatQuickBarElement, panel, {
placement: 'top-start', placement: 'top-start',
@@ -62,7 +62,6 @@ import type {
InitCommandCtx, InitCommandCtx,
} from '@blocksuite/block-std'; } from '@blocksuite/block-std';
import { tableViewMeta } from '@blocksuite/data-view/view-presets'; import { tableViewMeta } from '@blocksuite/data-view/view-presets';
import { assertExists } from '@blocksuite/global/utils';
import { MoreVerticalIcon } from '@blocksuite/icons/lit'; import { MoreVerticalIcon } from '@blocksuite/icons/lit';
import { Slice, toDraftModel } from '@blocksuite/store'; import { Slice, toDraftModel } from '@blocksuite/store';
import { html, type TemplateResult } from 'lit'; import { html, type TemplateResult } from 'lit';
@@ -377,13 +376,17 @@ export const BUILT_IN_GROUPS: MenuItemGroup<FormatBarContext>[] = [
.try<{ currentSelectionPath: string }>(cmd => [ .try<{ currentSelectionPath: string }>(cmd => [
cmd.pipe(getTextSelectionCommand).pipe((ctx, next) => { cmd.pipe(getTextSelectionCommand).pipe((ctx, next) => {
const textSelection = ctx.currentTextSelection; const textSelection = ctx.currentTextSelection;
assertExists(textSelection); if (!textSelection) {
return;
}
const end = textSelection.to ?? textSelection.from; const end = textSelection.to ?? textSelection.from;
next({ currentSelectionPath: end.blockId }); next({ currentSelectionPath: end.blockId });
}), }),
cmd.pipe(getBlockSelectionsCommand).pipe((ctx, next) => { cmd.pipe(getBlockSelectionsCommand).pipe((ctx, next) => {
const currentBlockSelections = ctx.currentBlockSelections; const currentBlockSelections = ctx.currentBlockSelections;
assertExists(currentBlockSelections); if (!currentBlockSelections) {
return;
}
const blockSelection = currentBlockSelections.at(-1); const blockSelection = currentBlockSelections.at(-1);
if (!blockSelection) { if (!blockSelection) {
return; return;
@@ -29,11 +29,7 @@ import {
TextSelection, TextSelection,
WidgetComponent, WidgetComponent,
} from '@blocksuite/block-std'; } from '@blocksuite/block-std';
import { import { DisposableGroup, nextTick } from '@blocksuite/global/utils';
assertExists,
DisposableGroup,
nextTick,
} from '@blocksuite/global/utils';
import type { BaseSelection } from '@blocksuite/store'; import type { BaseSelection } from '@blocksuite/store';
import { import {
autoUpdate, autoUpdate,
@@ -239,7 +235,9 @@ export class AffineFormatBarWidget extends WidgetComponent {
private _listenFloatingElement() { private _listenFloatingElement() {
const formatQuickBarElement = this.formatBarElement; const formatQuickBarElement = this.formatBarElement;
assertExists(formatQuickBarElement, 'format quick bar should exist'); if (!formatQuickBarElement) {
return;
}
const listenFloatingElement = ( const listenFloatingElement = (
getElement: () => ReferenceElement | void getElement: () => ReferenceElement | void
@@ -249,7 +247,10 @@ export class AffineFormatBarWidget extends WidgetComponent {
return; return;
} }
assertExists(this._floatDisposables); if (!this._floatDisposables) {
return;
}
HoverController.globalAbortController?.abort(); HoverController.globalAbortController?.abort();
this._floatDisposables.add( this._floatDisposables.add(
autoUpdate( autoUpdate(
@@ -512,7 +513,9 @@ export class AffineFormatBarWidget extends WidgetComponent {
this._abortController = new AbortController(); this._abortController = new AbortController();
const rootComponent = this.block; const rootComponent = this.block;
assertExists(rootComponent); if (!rootComponent) {
return;
}
const widgets = rootComponent.widgets; const widgets = rootComponent.widgets;
// check if the host use the format bar widget // check if the host use the format bar widget
@@ -4,7 +4,7 @@ import type {
MenuItemGroup, MenuItemGroup,
} from '@blocksuite/affine-components/toolbar'; } from '@blocksuite/affine-components/toolbar';
import { renderGroups } 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 { MoreVerticalIcon } from '@blocksuite/icons/lit';
import { flip, offset } from '@floating-ui/dom'; import { flip, offset } from '@floating-ui/dom';
import { html, LitElement } from 'lit'; import { html, LitElement } from 'lit';
@@ -57,7 +57,9 @@ export class AffineImageToolbar extends LitElement {
this._currentOpenMenu = this._popMenuAbortController; this._currentOpenMenu = this._popMenuAbortController;
assertExists(this._moreButton); if (!this._moreButton) {
return;
}
createLitPortal({ createLitPortal({
template: html` template: html`
@@ -4,7 +4,6 @@ import {
isInsidePageEditor, isInsidePageEditor,
} from '@blocksuite/affine-shared/utils'; } from '@blocksuite/affine-shared/utils';
import { BlockSelection } from '@blocksuite/block-std'; import { BlockSelection } from '@blocksuite/block-std';
import { assertExists } from '@blocksuite/global/utils';
export function duplicate( export function duplicate(
block: ImageBlockComponent, block: ImageBlockComponent,
@@ -23,7 +22,10 @@ export function duplicate(
const { doc } = model; const { doc } = model;
const parent = doc.getParent(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 index = parent?.children.indexOf(model);
const duplicateId = doc.addBlock( const duplicateId = doc.addBlock(
@@ -13,11 +13,7 @@ import {
isFuzzyMatch, isFuzzyMatch,
substringMatchScore, substringMatchScore,
} from '@blocksuite/affine-shared/utils'; } from '@blocksuite/affine-shared/utils';
import { import { throttle, WithDisposable } from '@blocksuite/global/utils';
assertExists,
throttle,
WithDisposable,
} from '@blocksuite/global/utils';
import { autoPlacement, offset } from '@floating-ui/dom'; import { autoPlacement, offset } from '@floating-ui/dom';
import { html, LitElement, nothing, type PropertyValues } from 'lit'; import { html, LitElement, nothing, type PropertyValues } from 'lit';
import { property, state } from 'lit/decorators.js'; import { property, state } from 'lit/decorators.js';
@@ -592,7 +588,11 @@ export class InnerSlashMenu extends WithDisposable(LitElement) {
override willUpdate(changedProperties: PropertyValues<this>) { override willUpdate(changedProperties: PropertyValues<this>) {
if (changedProperties.has('menu') && this.menu.length !== 0) { if (changedProperties.has('menu') && this.menu.length !== 0) {
const firstItem = getFirstNotDividerItem(this.menu); const firstItem = getFirstNotDividerItem(this.menu);
assertExists(firstItem); if (!firstItem) {
console.error('No item found in slash menu');
return;
}
this._activeItem = firstItem; this._activeItem = firstItem;
// this case happen on query updated // this case happen on query updated
@@ -7,8 +7,8 @@ import {
GfxControllerIdentifier, GfxControllerIdentifier,
type GfxModel, type GfxModel,
} from '@blocksuite/block-std/gfx'; } from '@blocksuite/block-std/gfx';
import { BlockSuiteError } from '@blocksuite/global/exceptions';
import { Bound } from '@blocksuite/global/gfx'; import { Bound } from '@blocksuite/global/gfx';
import { assertExists } from '@blocksuite/global/utils';
export const edgelessToBlob = async ( export const edgelessToBlob = async (
host: EditorHost, host: EditorHost,
@@ -24,24 +24,25 @@ export const edgelessToBlob = async (
const isBlock = isTopLevelBlock(edgelessElement); const isBlock = isTopLevelBlock(edgelessElement);
const gfx = host.std.get(GfxControllerIdentifier); const gfx = host.std.get(GfxControllerIdentifier);
return exportManager const canvas = await exportManager.edgelessToCanvas(
.edgelessToCanvas( options.surfaceRenderer,
options.surfaceRenderer, bound,
bound, gfx,
gfx, isBlock ? [edgelessElement] : undefined,
isBlock ? [edgelessElement] : undefined, isBlock ? undefined : [edgelessElement],
isBlock ? undefined : [edgelessElement], { zoom: options.surfaceRenderer.viewport.zoom }
{ zoom: options.surfaceRenderer.viewport.zoom } );
)
.then(canvas => { if (!canvas) {
assertExists(canvas); throw new BlockSuiteError(
return new Promise((resolve, reject) => { BlockSuiteError.ErrorCode.ValueNotExists,
canvas.toBlob( 'Failed to export edgeless to canvas'
blob => (blob ? resolve(blob) : reject(null)), );
'image/png' }
);
}); return new Promise((resolve, reject) => {
}); canvas.toBlob(blob => (blob ? resolve(blob) : reject(null)), 'image/png');
});
}; };
export const writeImageBlobToClipboard = async (blob: Blob) => { export const writeImageBlobToClipboard = async (blob: Blob) => {
@@ -41,7 +41,7 @@ import {
deserializeXYWH, deserializeXYWH,
type SerializedXYWH, type SerializedXYWH,
} from '@blocksuite/global/gfx'; } 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 { DeleteIcon, EdgelessIcon, FrameIcon } from '@blocksuite/icons/lit';
import type { BaseSelection, Store } from '@blocksuite/store'; import type { BaseSelection, Store } from '@blocksuite/store';
import { css, html, nothing, type TemplateResult } from 'lit'; import { css, html, nothing, type TemplateResult } from 'lit';
@@ -279,7 +279,7 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
}, },
]); ]);
const model = this.doc.getBlockById(paragraphId); const model = this.doc.getBlockById(paragraphId);
assertExists(model, `Failed to add paragraph block.`); if (!model) return;
requestConnectedFrame(() => { requestConnectedFrame(() => {
selection.update(selList => { selection.update(selList => {
@@ -12,7 +12,6 @@ import {
toDegree, toDegree,
toRadian, toRadian,
} from '@blocksuite/global/gfx'; } from '@blocksuite/global/gfx';
import { assertExists } from '@blocksuite/global/utils';
import { describe, expect, it } from 'vitest'; import { describe, expect, it } from 'vitest';
describe('Line', () => { describe('Line', () => {
@@ -43,7 +42,7 @@ describe('Line', () => {
[0, 1], [0, 1],
[0, -1], [0, -1],
]; ];
assertExists(rst); if (!rst) throw new Error('Failed to get line ellipse intersects');
expect( expect(
rst.every((point, index) => pointAlmostEqual(point, expected[index])) rst.every((point, index) => pointAlmostEqual(point, expected[index]))
).toBeTruthy(); ).toBeTruthy();
@@ -76,7 +75,7 @@ describe('Line', () => {
[0, 10], [0, 10],
] ]
); );
assertExists(rst); if (!rst) throw new Error('Failed to get line polygon intersects');
expect(pointAlmostEqual(rst[0], [10, 5])).toBeTruthy(); expect(pointAlmostEqual(rst[0], [10, 5])).toBeTruthy();
}); });
@@ -12,6 +12,7 @@ import type {
GfxLocalElementModel, GfxLocalElementModel,
GfxModel, GfxModel,
} from '@blocksuite/block-std/gfx'; } from '@blocksuite/block-std/gfx';
import { BlockSuiteError } from '@blocksuite/global/exceptions';
import type { IBound, IVec, IVec3 } from '@blocksuite/global/gfx'; import type { IBound, IVec, IVec3 } from '@blocksuite/global/gfx';
import { import {
almostEqual, almostEqual,
@@ -31,12 +32,7 @@ import {
toRadian, toRadian,
Vec, Vec,
} from '@blocksuite/global/gfx'; } from '@blocksuite/global/gfx';
import { import { assertEquals, assertType, last } from '@blocksuite/global/utils';
assertEquals,
assertExists,
assertType,
last,
} from '@blocksuite/global/utils';
import { effect } from '@preact/signals-core'; import { effect } from '@preact/signals-core';
import { Overlay } from '../renderer/overlay.js'; import { Overlay } from '../renderer/overlay.js';
@@ -153,7 +149,10 @@ export function getAnchors(ele: GfxModel) {
) )
.forEach(vec => { .forEach(vec => {
const rst = ele.getLineIntersections(bound.center as IVec, vec as IVec); 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( const originPoint = getPointFromBoundsWithRotation(
{ ...bound, rotate: -rotate }, { ...bound, rotate: -rotate },
rst[0] rst[0]
@@ -497,9 +496,7 @@ function getConnectablePoints(
pushOuterPoints(points, expandStartBound, expandEndBound, outerBound); pushOuterPoints(points, expandStartBound, expandEndBound, outerBound);
} }
if (startBound && endBound) { if (startBound && endBound && expandStartBound && expandEndBound) {
assertExists(expandStartBound);
assertExists(expandEndBound);
pushGapMidPoint( pushGapMidPoint(
points, points,
startPoint, startPoint,
@@ -564,8 +561,12 @@ function getConnectablePoints(
almostEqual(item[1], point[1], 0.02) almostEqual(item[1], point[1], 0.02)
); );
}) as IVec3[]; }) as IVec3[];
assertExists(startEnds[0]); if (!startEnds[0] || !startEnds[1]) {
assertExists(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] }; return { points, nextStartPoint: startEnds[0], lastEndPoint: startEnds[1] };
} }
@@ -709,7 +710,12 @@ function getNextPoint(
result, result,
[bound.maxX + 10, result[1]] [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; result[0] = intersects[0] + offsetX;
} else { } else {
const intersects = lineIntersects( const intersects = lineIntersects(
@@ -718,7 +724,12 @@ function getNextPoint(
result, result,
[bound.x - 10, result[1]] [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; result[0] = intersects[0] - offsetX;
} }
} else { } else {
@@ -729,7 +740,12 @@ function getNextPoint(
result, result,
[result[0], bound.maxY + 10] [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; result[1] = intersects[1] + offsetY;
} else { } else {
const intersects = lineIntersects( const intersects = lineIntersects(
@@ -738,7 +754,12 @@ function getNextPoint(
result, result,
[result[0], bound.y - 10] [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; result[1] = intersects[1] - offsetY;
} }
} }
@@ -1204,9 +1225,14 @@ export class ConnectorPathGenerator extends PathGenerator {
let startPoint: PointLocation | null = null; let startPoint: PointLocation | null = null;
let endPoint: PointLocation | null = null; let endPoint: PointLocation | null = null;
if (source.id && !source.position && target.id && !target.position) { if (
assertExists(start); source.id &&
assertExists(end); !source.position &&
target.id &&
!target.position &&
start &&
end
) {
const startAnchors = getAnchors(start); const startAnchors = getAnchors(start);
const endAnchors = getAnchors(end); const endAnchors = getAnchors(end);
let minDist = Infinity; let minDist = Infinity;
@@ -1,6 +1,5 @@
import type { Bound, IVec3 } from '@blocksuite/global/gfx'; import type { Bound, IVec3 } from '@blocksuite/global/gfx';
import { almostEqual } from '@blocksuite/global/gfx'; import { almostEqual } from '@blocksuite/global/gfx';
import { assertExists } from '@blocksuite/global/utils';
import { Graph } from './graph.js'; import { Graph } from './graph.js';
import { PriorityQueue } from './priority-queue.js'; import { PriorityQueue } from './priority-queue.js';
@@ -67,9 +66,10 @@ export class AStarRunner {
const froms = this._cameFrom.get(current); const froms = this._cameFrom.get(current);
if (!froms) return result; if (!froms) return result;
const index = nextIndexs.shift(); const index = nextIndexs.shift();
assertExists(index); if (index !== undefined && index !== null) {
nextIndexs.push(froms.indexs[index]); nextIndexs.push(froms.indexs[index]);
current = froms.from[index]; current = froms.from[index];
}
} }
return result; return result;
} }
@@ -107,7 +107,9 @@ export class AStarRunner {
private _neighbors(cur: IVec3) { private _neighbors(cur: IVec3) {
const neighbors = this._graph.neighbors(cur); const neighbors = this._graph.neighbors(cur);
const cameFroms = this._cameFrom.get(cur); const cameFroms = this._cameFrom.get(cur);
assertExists(cameFroms); if (!cameFroms) {
return [];
}
cameFroms.from.forEach(from => { cameFroms.from.forEach(from => {
const index = neighbors.findIndex(n => pointAlmostEqual(n, from)); const index = neighbors.findIndex(n => pointAlmostEqual(n, from));
@@ -154,17 +156,18 @@ export class AStarRunner {
const curDiagoalCounts = this._diagonalCount.get(current); const curDiagoalCounts = this._diagonalCount.get(current);
const curPointPrioritys = this._pointPriority.get(current); const curPointPrioritys = this._pointPriority.get(current);
const cameFroms = this._cameFrom.get(current); const cameFroms = this._cameFrom.get(current);
assertExists(curCosts); if (!curCosts || !curDiagoalCounts || !curPointPrioritys || !cameFroms) {
assertExists(curDiagoalCounts); continue;
assertExists(curPointPrioritys); }
assertExists(cameFroms);
const newCosts = curCosts.map(co => co + cost(current, next)); const newCosts = curCosts.map(co => co + cost(current, next));
const newDiagonalCounts = curDiagoalCounts.map( const newDiagonalCounts = curDiagoalCounts.map(
(count, index) => (count, index) =>
count + getDiagonalCount(next, current, cameFroms.from[index]) count + getDiagonalCount(next, current, cameFroms.from[index])
); );
assertExists(next[2]); if (!next[2]) {
continue;
}
const newPointPrioritys = curPointPrioritys.map( const newPointPrioritys = curPointPrioritys.map(
pointPriority => pointPriority + next[2] pointPriority => pointPriority + next[2]
); );
@@ -1,4 +1,5 @@
import { assertExists, Slot } from '@blocksuite/global/utils'; import { BlockSuiteError } from '@blocksuite/global/exceptions';
import { Slot } from '@blocksuite/global/utils';
import { import {
autoUpdate, autoUpdate,
computePosition, computePosition,
@@ -39,7 +40,12 @@ export function createSimplePortal({
}); });
const root = shadowDom ? portalRoot.shadowRoot : portalRoot; const root = shadowDom ? portalRoot.shadowRoot : portalRoot;
assertExists(root); if (!root) {
throw new BlockSuiteError(
BlockSuiteError.ErrorCode.ValueNotExists,
'Failed to create portal root'
);
}
let updateId = 0; let updateId = 0;
const updatePortal: (id: number) => void = id => { const updatePortal: (id: number) => void = id => {
@@ -55,7 +61,6 @@ export function createSimplePortal({
template instanceof Function template instanceof Function
? template({ updatePortal: () => updatePortal(curId) }) ? template({ updatePortal: () => updatePortal(curId) })
: template; : template;
assertExists(templateResult);
render(templateResult, root, renderOptions); render(templateResult, root, renderOptions);
}; };
@@ -173,7 +178,6 @@ export function createLitPortal({
? positionConfigOrFn(portalRoot) ? positionConfigOrFn(portalRoot)
: positionConfigOrFn; : positionConfigOrFn;
const { referenceElement, ...options } = computePositionOptions; const { referenceElement, ...options } = computePositionOptions;
assertExists(referenceElement, 'referenceElement is required');
const update = () => { const update = () => {
if ( if (
computePositionOptions.abortWhenRefRemoved !== false && computePositionOptions.abortWhenRefRemoved !== false &&
@@ -1,7 +1,6 @@
import { getSelectedBlocksCommand } from '@blocksuite/affine-shared/commands'; import { getSelectedBlocksCommand } from '@blocksuite/affine-shared/commands';
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types'; import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import type { BlockSelection, Command } from '@blocksuite/block-std'; import type { BlockSelection, Command } from '@blocksuite/block-std';
import { assertExists } from '@blocksuite/global/utils';
import { INLINE_ROOT_ATTR, type InlineRootElement } from '@blocksuite/inline'; import { INLINE_ROOT_ATTR, type InlineRootElement } from '@blocksuite/inline';
import { FORMAT_BLOCK_SUPPORT_FLAVOURS } from './consts.js'; import { FORMAT_BLOCK_SUPPORT_FLAVOURS } from './consts.js';
@@ -14,10 +13,12 @@ export const formatBlockCommand: Command<{
mode?: 'replace' | 'merge'; mode?: 'replace' | 'merge';
}> = (ctx, next) => { }> = (ctx, next) => {
const blockSelections = ctx.blockSelections ?? ctx.currentBlockSelections; const blockSelections = ctx.blockSelections ?? ctx.currentBlockSelections;
assertExists( if (!blockSelections) {
blockSelections, console.error(
'`blockSelections` is required, you need to pass it in args or use `getBlockSelections` command before adding this command to the pipeline.' '`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; if (blockSelections.length === 0) return;
@@ -33,7 +34,12 @@ export const formatBlockCommand: Command<{
}) })
.pipe((ctx, next) => { .pipe((ctx, next) => {
const { selectedBlocks } = ctx; 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 selectedInlineEditors = selectedBlocks.flatMap(el => {
const inlineRoot = el.querySelector< const inlineRoot = el.querySelector<
@@ -11,7 +11,6 @@ import {
type EditorHost, type EditorHost,
type InitCommandCtx, type InitCommandCtx,
} from '@blocksuite/block-std'; } from '@blocksuite/block-std';
import { assertExists } from '@blocksuite/global/utils';
import { import {
INLINE_ROOT_ATTR, INLINE_ROOT_ATTR,
type InlineEditor, type InlineEditor,
@@ -92,7 +91,12 @@ function handleCurrentSelection(
}) })
.pipe((ctx, next) => { .pipe((ctx, next) => {
const { selectedBlocks } = ctx; 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( const selectedInlineEditors = getSelectedInlineEditors(
selectedBlocks, selectedBlocks,
@@ -119,7 +123,12 @@ function handleCurrentSelection(
}) })
.pipe((ctx, next) => { .pipe((ctx, next) => {
const { selectedBlocks } = ctx; 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( const selectedInlineEditors = getSelectedInlineEditors(
selectedBlocks, selectedBlocks,
@@ -8,11 +8,7 @@ import {
import { FONT_XS, PANEL_BASE } from '@blocksuite/affine-shared/styles'; import { FONT_XS, PANEL_BASE } from '@blocksuite/affine-shared/styles';
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types'; import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import { type BlockStdScope, ShadowlessElement } from '@blocksuite/block-std'; import { type BlockStdScope, ShadowlessElement } from '@blocksuite/block-std';
import { import { SignalWatcher, WithDisposable } from '@blocksuite/global/utils';
assertExists,
SignalWatcher,
WithDisposable,
} from '@blocksuite/global/utils';
import { DoneIcon, ResetIcon } from '@blocksuite/icons/lit'; import { DoneIcon, ResetIcon } from '@blocksuite/icons/lit';
import type { DeltaInsert, InlineRange } from '@blocksuite/inline'; import type { DeltaInsert, InlineRange } from '@blocksuite/inline';
import { computePosition, inline, offset, shift } from '@floating-ui/dom'; import { computePosition, inline, offset, shift } from '@floating-ui/dom';
@@ -211,7 +207,9 @@ export class ReferenceAliasPopup extends SignalWatcher(
override updated() { override updated() {
const range = this.inlineEditor.toDomRange(this.inlineRange); const range = this.inlineEditor.toDomRange(this.inlineRange);
assertExists(range); if (!range) {
return;
}
const visualElement = { const visualElement = {
getBoundingClientRect: () => range.getBoundingClientRect(), getBoundingClientRect: () => range.getBoundingClientRect(),
@@ -16,7 +16,7 @@ import {
type BlockComponent, type BlockComponent,
type BlockStdScope, type BlockStdScope,
} from '@blocksuite/block-std'; } 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 { ArrowDownSmallIcon, MoreVerticalIcon } from '@blocksuite/icons/lit';
import type { InlineRange } from '@blocksuite/inline'; import type { InlineRange } from '@blocksuite/inline';
import { computePosition, inline, offset, shift } from '@floating-ui/dom'; import { computePosition, inline, offset, shift } from '@floating-ui/dom';
@@ -51,6 +51,10 @@ export class ReferencePopup extends WithDisposable(LitElement) {
static override styles = styles; static override styles = styles;
private readonly _copyLink = () => { private readonly _copyLink = () => {
if (!this.std) {
console.error('`std` is not found');
return;
}
const url = this.std const url = this.std
.getOptional(GenerateDocUrlProvider) .getOptional(GenerateDocUrlProvider)
?.generateDocUrl(this.referenceInfo.pageId, this.referenceInfo.params); ?.generateDocUrl(this.referenceInfo.pageId, this.referenceInfo.params);
@@ -66,6 +70,10 @@ export class ReferencePopup extends WithDisposable(LitElement) {
}; };
private readonly _openDoc = (event?: Partial<DocLinkClickedEvent>) => { private readonly _openDoc = (event?: Partial<DocLinkClickedEvent>) => {
if (!this.std) {
console.error('`std` is not found');
return;
}
this.std.getOptional(RefNodeSlotsProvider)?.docLinkClicked.emit({ this.std.getOptional(RefNodeSlotsProvider)?.docLinkClicked.emit({
...this.referenceInfo, ...this.referenceInfo,
...event, ...event,
@@ -89,6 +97,11 @@ export class ReferencePopup extends WithDisposable(LitElement) {
abortController, abortController,
} = this; } = this;
if (!std) {
console.error('`std` is not found');
return;
}
const aliasPopup = new ReferenceAliasPopup(); const aliasPopup = new ReferenceAliasPopup();
aliasPopup.std = std; aliasPopup.std = std;
@@ -105,6 +118,10 @@ export class ReferencePopup extends WithDisposable(LitElement) {
}; };
private readonly _toggleViewSelector = (e: Event) => { private readonly _toggleViewSelector = (e: Event) => {
if (!this.std) {
console.error('`std` is not found');
return;
}
const opened = (e as CustomEvent<boolean>).detail; const opened = (e as CustomEvent<boolean>).detail;
if (!opened) return; if (!opened) return;
@@ -112,6 +129,10 @@ export class ReferencePopup extends WithDisposable(LitElement) {
}; };
private readonly _trackViewSelected = (type: string) => { private readonly _trackViewSelected = (type: string) => {
if (!this.std) {
console.error('`std` is not found');
return;
}
track(this.std, 'SelectedView', { track(this.std, 'SelectedView', {
control: 'select view', control: 'select view',
type: `${type} view`, type: `${type} view`,
@@ -119,6 +140,11 @@ export class ReferencePopup extends WithDisposable(LitElement) {
}; };
get _embedViewButtonDisabled() { get _embedViewButtonDisabled() {
if (!this.block) {
console.error('`block` is not found');
return true;
}
if ( if (
this.block.doc.readonly || this.block.doc.readonly ||
isInsideBlockByFlavour( isInsideBlockByFlavour(
@@ -131,13 +157,13 @@ export class ReferencePopup extends WithDisposable(LitElement) {
} }
return ( return (
!!this.block.closest('affine-embed-synced-doc-block') || !!this.block.closest('affine-embed-synced-doc-block') ||
this.referenceDocId === this.doc.id this.referenceDocId === this.block.doc.id
); );
} }
_openButtonDisabled(openMode?: OpenDocMode) { _openButtonDisabled(openMode?: OpenDocMode) {
if (openMode === 'open-in-active-view') { if (openMode === 'open-in-active-view') {
return this.referenceDocId === this.doc.id; return this.referenceDocId === this.doc?.id;
} }
return false; return false;
} }
@@ -146,34 +172,32 @@ export class ReferencePopup extends WithDisposable(LitElement) {
const block = this.inlineEditor.rootElement?.closest<BlockComponent>( const block = this.inlineEditor.rootElement?.closest<BlockComponent>(
`[${BLOCK_ID_ATTR}]` `[${BLOCK_ID_ATTR}]`
); );
assertExists(block);
return block; return block;
} }
get doc() { get doc() {
const doc = this.block.doc; const doc = this.block?.doc;
assertExists(doc);
return doc; return doc;
} }
get referenceDocId() { get referenceDocId() {
const docId = this.inlineEditor.getFormat(this.targetInlineRange).reference const docId = this.inlineEditor.getFormat(this.targetInlineRange).reference
?.pageId; ?.pageId;
assertExists(docId);
return docId; return docId;
} }
get std() { get std() {
const std = this.block.std; const std = this.block?.std;
assertExists(std);
return std; return std;
} }
private _convertToCardView() { private _convertToCardView() {
const block = this.block; const block = this.block;
if (!block) return;
const doc = block.host.doc; const doc = block.host.doc;
const parent = doc.getParent(block.model); const parent = doc.getParent(block.model);
assertExists(parent); if (!parent) return;
const index = parent.children.indexOf(block.model); const index = parent.children.indexOf(block.model);
@@ -197,10 +221,17 @@ export class ReferencePopup extends WithDisposable(LitElement) {
private _convertToEmbedView() { private _convertToEmbedView() {
const block = this.block; 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 doc = block.host.doc;
const parent = doc.getParent(block.model); 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 index = parent.children.indexOf(block.model);
const referenceInfo = this.referenceInfo; const referenceInfo = this.referenceInfo;
@@ -242,7 +273,7 @@ export class ReferencePopup extends WithDisposable(LitElement) {
type: 'delete', type: 'delete',
label: 'Delete', label: 'Delete',
icon: DeleteIcon, icon: DeleteIcon,
disabled: this.doc.readonly, disabled: this.doc?.readonly,
action: () => this._delete(), action: () => this._delete(),
}, },
], ],
@@ -250,6 +281,10 @@ export class ReferencePopup extends WithDisposable(LitElement) {
} }
private _openMenuButton() { private _openMenuButton() {
if (!this.std) {
console.error('`std` is not found');
return nothing;
}
const openDocConfig = this.std.get(OpenDocExtensionIdentifier); const openDocConfig = this.std.get(OpenDocExtensionIdentifier);
const buttons: MenuItem[] = openDocConfig.items const buttons: MenuItem[] = openDocConfig.items
@@ -330,7 +365,7 @@ export class ReferencePopup extends WithDisposable(LitElement) {
type: 'card', type: 'card',
label: 'Card view', label: 'Card view',
action: () => this._convertToCardView(), action: () => this._convertToCardView(),
disabled: this.doc.readonly, disabled: this.doc?.readonly,
}); });
buttons.push({ buttons.push({
@@ -338,7 +373,9 @@ export class ReferencePopup extends WithDisposable(LitElement) {
label: 'Embed view', label: 'Embed view',
action: () => this._convertToEmbedView(), action: () => this._convertToEmbedView(),
disabled: disabled:
this.doc.readonly || this.isLinkedNode || this._embedViewButtonDisabled, this.doc?.readonly ||
this.isLinkedNode ||
this._embedViewButtonDisabled,
}); });
return html` return html`
@@ -388,11 +425,14 @@ export class ReferencePopup extends WithDisposable(LitElement) {
return; return;
} }
if (!this.block) return;
const parent = this.block.host.doc.getParent(this.block.model); const parent = this.block.host.doc.getParent(this.block.model);
assertExists(parent); if (!parent) return;
this.disposables.add( this.disposables.add(
effect(() => { effect(() => {
if (!this.block) return;
const children = parent.children; const children = parent.children;
if (children.includes(this.block.model)) return; if (children.includes(this.block.model)) return;
this.abortController.abort(); this.abortController.abort();
@@ -435,7 +475,7 @@ export class ReferencePopup extends WithDisposable(LitElement) {
aria-label="Edit" aria-label="Edit"
data-testid="edit" data-testid="edit"
.tooltip=${'Edit'} .tooltip=${'Edit'}
?disabled=${this.doc.readonly} ?disabled=${this.doc?.readonly}
@click=${this._openEditPopup} @click=${this._openEditPopup}
> >
${EditIcon} ${EditIcon}
@@ -479,10 +519,8 @@ export class ReferencePopup extends WithDisposable(LitElement) {
} }
override updated() { override updated() {
assertExists(this.popupContainer);
const range = this.inlineEditor.toDomRange(this.targetInlineRange); const range = this.inlineEditor.toDomRange(this.targetInlineRange);
assertExists(range); if (!range) return;
const visualElement = { const visualElement = {
getBoundingClientRect: () => range.getBoundingClientRect(), getBoundingClientRect: () => range.getBoundingClientRect(),
getClientRects: () => range.getClientRects(), getClientRects: () => range.getClientRects(),
@@ -1,6 +1,6 @@
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types'; import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
import { ShadowlessElement } from '@blocksuite/block-std'; import { ShadowlessElement } from '@blocksuite/block-std';
import { assertExists, WithDisposable } from '@blocksuite/global/utils'; import { WithDisposable } from '@blocksuite/global/utils';
import { import {
type AttributeRenderer, type AttributeRenderer,
type DeltaInsert, type DeltaInsert,
@@ -148,7 +148,6 @@ export class RichText extends WithDisposable(ShadowlessElement) {
} }
get inlineEditorContainer() { get inlineEditorContainer() {
assertExists(this._inlineEditorContainer);
return this._inlineEditorContainer; return this._inlineEditorContainer;
} }
@@ -1,5 +1,4 @@
import { requestConnectedFrame } from '@blocksuite/affine-shared/utils'; import { requestConnectedFrame } from '@blocksuite/affine-shared/utils';
import { assertExists } from '@blocksuite/global/utils';
import { import {
arrow, arrow,
type ComputePositionReturn, type ComputePositionReturn,
@@ -193,7 +192,10 @@ export class Tooltip extends LitElement {
); );
const parent = this.parentElement; 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 // Wait for render
requestConnectedFrame(() => { requestConnectedFrame(() => {
@@ -1,6 +1,5 @@
import type { InsertToPosition } from '@blocksuite/affine-shared/utils'; import type { InsertToPosition } from '@blocksuite/affine-shared/utils';
import { Point, Rect } from '@blocksuite/global/gfx'; import { Point, Rect } from '@blocksuite/global/gfx';
import { assertExists } from '@blocksuite/global/utils';
import { computed } from '@preact/signals-core'; import { computed } from '@preact/signals-core';
import type { ReactiveController } from 'lit'; import type { ReactiveController } from 'lit';
@@ -137,7 +136,6 @@ export class KanbanDragController implements ReactiveController {
const scrollContainer = this.host.querySelector( const scrollContainer = this.host.querySelector(
'.affine-data-view-kanban-groups' '.affine-data-view-kanban-groups'
) as HTMLElement; ) as HTMLElement;
assertExists(scrollContainer);
return scrollContainer; return scrollContainer;
} }
@@ -213,7 +211,10 @@ const createDropPreview = () => {
card?: KanbanCard card?: KanbanCard
) { ) {
const target = card ?? group.querySelector('.add-card'); const target = card ?? group.querySelector('.add-card');
assertExists(target); if (!target) {
console.error('`target` is not found');
return;
}
if (target.previousElementSibling === self || target === self) { if (target.previousElementSibling === self || target === self) {
div.remove(); div.remove();
return; return;
@@ -1,5 +1,4 @@
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import { assertExists } from '@blocksuite/global/utils';
import type { ReactiveController } from 'lit'; import type { ReactiveController } from 'lit';
import type { import type {
@@ -611,7 +610,7 @@ function getNextGroupFocusElement(
selection.selectionType === 'cell' selection.selectionType === 'cell'
? getFocusCell(viewElement, selection) ? getFocusCell(viewElement, selection)
: getSelectedCards(viewElement, selection)[0]; : getSelectedCards(viewElement, selection)[0];
assertExists(element); if (!element) return;
const rect = element.getBoundingClientRect(); const rect = element.getBoundingClientRect();
const nextCards = Array.from( const nextCards = Array.from(
nextGroup.querySelectorAll('affine-data-view-kanban-card') nextGroup.querySelectorAll('affine-data-view-kanban-card')
@@ -1,9 +1,5 @@
import { ShadowlessElement } from '@blocksuite/block-std'; import { ShadowlessElement } from '@blocksuite/block-std';
import { import { SignalWatcher, WithDisposable } from '@blocksuite/global/utils';
assertExists,
SignalWatcher,
WithDisposable,
} from '@blocksuite/global/utils';
import { computed } from '@preact/signals-core'; import { computed } from '@preact/signals-core';
import { css } from 'lit'; import { css } from 'lit';
import { property, state } from 'lit/decorators.js'; import { property, state } from 'lit/decorators.js';
@@ -102,7 +98,6 @@ export class DatabaseCellContainer extends SignalWatcher(
get table() { get table() {
const table = this.closest('affine-database-table'); const table = this.closest('affine-database-table');
assertExists(table);
return table; return table;
} }
@@ -15,7 +15,6 @@ import {
TextSelection, TextSelection,
} from '@blocksuite/block-std'; } from '@blocksuite/block-std';
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import { assertExists } from '@blocksuite/global/utils';
import { import {
type BlockModel, type BlockModel,
type BlockSnapshot, type BlockSnapshot,
@@ -64,9 +63,14 @@ const findLast = (snapshot: SliceSnapshot): BlockSnapshot | null => {
}; };
class PointState { class PointState {
private readonly _blockFromPath = (path: string) => { private readonly _blockFromPath = (id: string) => {
const block = this.std.view.getBlock(path); const block = this.std.view.getBlock(id);
assertExists(block); if (!block) {
throw new BlockSuiteError(
ErrorCode.TransformerError,
`Block not found when pasting: ${id}`
);
}
return block; return block;
}; };
@@ -6,7 +6,7 @@ import type {
ParagraphBlockModel, ParagraphBlockModel,
SurfaceRefBlockModel, SurfaceRefBlockModel,
} from '@blocksuite/affine-model'; } from '@blocksuite/affine-model';
import { assertExists } from '@blocksuite/global/utils'; import { BlockSuiteError } from '@blocksuite/global/exceptions';
import type { DeltaOperation, TransformerMiddleware } from '@blocksuite/store'; import type { DeltaOperation, TransformerMiddleware } from '@blocksuite/store';
export const replaceIdMiddleware = export const replaceIdMiddleware =
@@ -166,13 +166,23 @@ export const replaceIdMiddleware =
let connection = value.source as Record<string, string>; let connection = value.source as Record<string, string>;
if (idMap.has(connection.id)) { if (idMap.has(connection.id)) {
const newId = idMap.get(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.id = newId;
} }
connection = value.target as Record<string, string>; connection = value.target as Record<string, string>;
if (idMap.has(connection.id)) { if (idMap.has(connection.id)) {
const newId = idMap.get(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.id = newId;
} }
break; break;
@@ -184,7 +194,12 @@ export const replaceIdMiddleware =
if (idMap.has(key)) { if (idMap.has(key)) {
delete json[key]; delete json[key];
const newKey = idMap.get(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; json[newKey] = value;
} }
}); });
@@ -1,4 +1,4 @@
import { assertExists } from '@blocksuite/global/utils'; import { BlockSuiteError } from '@blocksuite/global/exceptions';
import type { ExtensionType } from '@blocksuite/store'; import type { ExtensionType } from '@blocksuite/store';
import { SpecBuilder } from './spec-builder.js'; import { SpecBuilder } from './spec-builder.js';
@@ -45,7 +45,12 @@ export class SpecProvider {
getSpec(id: SpecId) { getSpec(id: SpecId) {
const spec = this.specMap.get(id); 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); return new SpecBuilder(spec);
} }
@@ -10,23 +10,6 @@ export function isPrimitive(
export function assertType<T>(_: unknown): asserts _ is T {} export function assertType<T>(_: 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<T>(
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<T>( export function assertNotExists<T>(
val: T | null | undefined, val: T | null | undefined,
message = 'val exists', message = 'val exists',
@@ -1,5 +1,4 @@
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import { assertExists } from '@blocksuite/global/utils';
import { html, LitElement, type TemplateResult } from 'lit'; import { html, LitElement, type TemplateResult } from 'lit';
import { property } from 'lit/decorators.js'; import { property } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js'; import { styleMap } from 'lit/directives/style-map.js';
@@ -14,12 +13,19 @@ export class VLine extends LitElement {
const rootElement = this.closest( const rootElement = this.closest(
`[${INLINE_ROOT_ATTR}]` `[${INLINE_ROOT_ATTR}]`
) as InlineRootElement; ) 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; const inlineEditor = rootElement.inlineEditor;
assertExists( if (!inlineEditor) {
inlineEditor, throw new BlockSuiteError(
'v-line must be inside a v-root with inline-editor' BlockSuiteError.ErrorCode.ValueNotExists,
); 'v-line must be inside a v-root with inline-editor'
);
}
return inlineEditor; return inlineEditor;
} }
@@ -1,4 +1,4 @@
import { assertExists } from '@blocksuite/global/utils'; import { assertInstanceOf } from '@blocksuite/global/utils';
import { effect } from '@preact/signals-core'; import { effect } from '@preact/signals-core';
import * as Y from 'yjs'; import * as Y from 'yjs';
@@ -47,7 +47,7 @@ export class RangeService<TextAttributes extends BaseTextAttributes> {
return null; return null;
} }
const textNode = text.childNodes[1]; const textNode = text.childNodes[1];
assertExists(textNode instanceof Text); assertInstanceOf(textNode, Text);
range.setStart(textNode, 0); range.setStart(textNode, 0);
range.setEnd(textNode, textNode.textContent?.length ?? 0); range.setEnd(textNode, textNode.textContent?.length ?? 0);
const inlineRange = this.toInlineRange(range); const inlineRange = this.toInlineRange(range);
@@ -158,7 +158,10 @@ export class RangeService<TextAttributes extends BaseTextAttributes> {
// can not in the first line because if we apply the inline ranage manually the // can not in the first line because if we apply the inline ranage manually the
// cursor will jump to the second line. // cursor will jump to the second line.
const container = range.commonAncestorContainer.parentElement; const container = range.commonAncestorContainer.parentElement;
assertExists(container); if (!container) {
console.error('failed to get container');
return false;
}
const containerRect = container.getBoundingClientRect(); const containerRect = container.getBoundingClientRect();
// There will be two rects if the cursor is at the edge of the line: // There will be two rects if the cursor is at the edge of the line:
// aaaaaaaa| or aaaaaaaa // aaaaaaaa| or aaaaaaaa
@@ -200,7 +203,10 @@ export class RangeService<TextAttributes extends BaseTextAttributes> {
// can not in the first line because if we apply the inline range manually the // can not in the first line because if we apply the inline range manually the
// cursor will jump to the second line. // cursor will jump to the second line.
const container = range.commonAncestorContainer.parentElement; const container = range.commonAncestorContainer.parentElement;
assertExists(container); if (!container) {
console.error('failed to get container');
return false;
}
const containerRect = container.getBoundingClientRect(); const containerRect = container.getBoundingClientRect();
// There will be two rects if the cursor is at the edge of the line: // There will be two rects if the cursor is at the edge of the line:
// aaaaaaaa| or aaaaaaaa // aaaaaaaa| or aaaaaaaa
@@ -1,5 +1,4 @@
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import { assertExists } from '@blocksuite/global/utils';
import { html, render } from 'lit'; import { html, render } from 'lit';
import { repeat } from 'lit/directives/repeat.js'; import { repeat } from 'lit/directives/repeat.js';
import * as Y from 'yjs'; import * as Y from 'yjs';
@@ -36,7 +35,10 @@ export class RenderService<TextAttributes extends BaseTextAttributes> {
if (!lastStartRelativePosition || !lastEndRelativePosition) return; if (!lastStartRelativePosition || !lastEndRelativePosition) return;
const doc = this.editor.yText.doc; const doc = this.editor.yText.doc;
assertExists(doc); if (!doc) {
console.error('doc is not found when syncing yText');
return;
}
const absoluteStart = Y.createAbsolutePositionFromRelativePosition( const absoluteStart = Y.createAbsolutePositionFromRelativePosition(
lastStartRelativePosition, lastStartRelativePosition,
doc doc
@@ -13,7 +13,6 @@ import {
ParagraphBlockSchemaExtension, ParagraphBlockSchemaExtension,
RootBlockSchemaExtension, RootBlockSchemaExtension,
} from './test-schema.js'; } from './test-schema.js';
import { assertExists } from './test-utils-dom.js';
function createTestOptions() { function createTestOptions() {
const idGenerator = createAutoIncrementIdGenerator(); const idGenerator = createAutoIncrementIdGenerator();
@@ -207,7 +206,9 @@ describe('basic', () => {
const doc2 = collection2.getDoc('space:0', { const doc2 = collection2.getDoc('space:0', {
extensions, extensions,
}); });
assertExists(doc2); if (!doc2) {
throw new Error('doc2 is not found');
}
applyUpdate(doc2.spaceDoc, update); applyUpdate(doc2.spaceDoc, update);
expect(serializCollection(collection2.doc)['spaces']).toEqual({ expect(serializCollection(collection2.doc)['spaces']).toEqual({
'space:0': { 'space:0': {
@@ -65,13 +65,6 @@ export async function runOnce() {
testCases = []; testCases = [];
} }
// XXX: workaround typing issue in blobs/__tests__/test-entry.ts
export function assertExists<T>(val: T | null | undefined): asserts val is T {
if (val === null || val === undefined) {
throw new Error('val does not exist');
}
}
export async function nextFrame() { export async function nextFrame() {
return new Promise(resolve => requestAnimationFrame(resolve)); return new Promise(resolve => requestAnimationFrame(resolve));
} }
@@ -1,4 +1,3 @@
import { assertExists } from '@blocksuite/global/utils';
import { diffUpdate, encodeStateVectorFromUpdate, mergeUpdates } from 'yjs'; import { diffUpdate, encodeStateVectorFromUpdate, mergeUpdates } from 'yjs';
import { MANUALLY_STOP } from '../../utils/throw-if-aborted.js'; import { MANUALLY_STOP } from '../../utils/throw-if-aborted.js';
@@ -66,7 +65,12 @@ export class BroadcastChannelDocSource implements DocSource {
this.docMap.set(docId, data); 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({ this.channel.postMessage({
type: 'update', type: 'update',
docId, docId,
@@ -5,7 +5,6 @@ import {
LayoutType, LayoutType,
NoteDisplayMode, NoteDisplayMode,
} from '@blocksuite/blocks'; } from '@blocksuite/blocks';
import { assertExists } from '@blocksuite/global/utils';
import { beforeEach, describe, expect, test } from 'vitest'; import { beforeEach, describe, expect, test } from 'vitest';
import * as Y from 'yjs'; import * as Y from 'yjs';
@@ -68,12 +67,16 @@ describe('group', () => {
const shapeId = service.crud.addElement('shape', { const shapeId = service.crud.addElement('shape', {
shapeType: 'rect', shapeType: 'rect',
}); });
assertExists(shapeId); if (!shapeId) {
throw new Error('shapeId is not found');
}
map.set(noteId, true); map.set(noteId, true);
map.set(shapeId, true); map.set(shapeId, true);
const groupId = service.crud.addElement('group', { children: map }); 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(service.elements.length).toBe(2);
expect(doc.getBlock(noteId)).toBeDefined(); expect(doc.getBlock(noteId)).toBeDefined();
doc.captureSync(); doc.captureSync();
@@ -92,12 +95,16 @@ describe('group', () => {
shapeType: 'rect', shapeType: 'rect',
xywh: '[0,0,100,100]', xywh: '[0,0,100,100]',
}); });
assertExists(shape1); if (!shape1) {
throw new Error('shape1 is not found');
}
const shape2 = service.crud.addElement('shape', { const shape2 = service.crud.addElement('shape', {
shapeType: 'rect', shapeType: 'rect',
xywh: '[100,100,100,100]', xywh: '[100,100,100,100]',
}); });
assertExists(shape2); if (!shape2) {
throw new Error('shape2 is not found');
}
const note1 = addNote(doc, { const note1 = addNote(doc, {
displayMode: NoteDisplayMode.DocAndEdgeless, displayMode: NoteDisplayMode.DocAndEdgeless,
xywh: '[200,200,800,100]', xywh: '[200,200,800,100]',
@@ -119,7 +126,9 @@ describe('group', () => {
children.set(note1, true); children.set(note1, true);
const groupId = service.crud.addElement('group', { children }); 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 group = service.crud.getElementById(groupId) as GroupElementModel;
const assertInitial = () => { const assertInitial = () => {
@@ -189,7 +198,9 @@ describe('group', () => {
test('empty group should have all zero xywh', () => { test('empty group should have all zero xywh', () => {
const map = new Y.Map<boolean>(); const map = new Y.Map<boolean>();
const groupId = service.crud.addElement('group', { children: 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; const group = service.crud.getElementById(groupId) as GroupElementModel;
expect(group.x).toBe(0); expect(group.x).toBe(0);
@@ -253,7 +264,9 @@ describe('mindmap', () => {
], ],
}; };
const mindmapId = service.crud.addElement('mindmap', { children: tree }); const mindmapId = service.crud.addElement('mindmap', { children: tree });
assertExists(mindmapId); if (!mindmapId) {
throw new Error('mindmapId is not found');
}
const mindmap = () => const mindmap = () =>
service.crud.getElementById(mindmapId) as MindmapElementModel; service.crud.getElementById(mindmapId) as MindmapElementModel;
@@ -304,7 +317,9 @@ describe('mindmap', () => {
type: LayoutType.RIGHT, type: LayoutType.RIGHT,
children: tree, children: tree,
}); });
assertExists(mindmapId); if (!mindmapId) {
throw new Error('mindmapId is not found');
}
const mindmap = () => const mindmap = () =>
service.crud.getElementById(mindmapId) as MindmapElementModel; service.crud.getElementById(mindmapId) as MindmapElementModel;
@@ -349,7 +364,10 @@ describe('mindmap', () => {
type: LayoutType.RIGHT, type: LayoutType.RIGHT,
children: tree, children: tree,
}); });
assertExists(mindmapId); if (!mindmapId) {
throw new Error('mindmapId is not found');
}
const mindmap = () => const mindmap = () =>
service.crud.getElementById(mindmapId) as MindmapElementModel; service.crud.getElementById(mindmapId) as MindmapElementModel;
@@ -19,7 +19,6 @@ import {
ShapeType, ShapeType,
type TextElementModel, type TextElementModel,
} from '@blocksuite/blocks'; } from '@blocksuite/blocks';
import { assertExists } from '@blocksuite/global/utils';
import { beforeEach, describe, expect, test } from 'vitest'; import { beforeEach, describe, expect, test } from 'vitest';
import { getDocRootBlock } from '../utils/edgeless.js'; import { getDocRootBlock } from '../utils/edgeless.js';
@@ -44,7 +43,9 @@ describe('apply last props', () => {
const rectId = service.crud.addElement('shape', { const rectId = service.crud.addElement('shape', {
shapeType: ShapeType.Rect, shapeType: ShapeType.Rect,
}); });
assertExists(rectId); if (!rectId) {
throw new Error('rectId is not found');
}
const rectShape = service.crud.getElementById(rectId) as ShapeElementModel; const rectShape = service.crud.getElementById(rectId) as ShapeElementModel;
expect(rectShape.fillColor).toBe(DefaultTheme.shapeFillColor); expect(rectShape.fillColor).toBe(DefaultTheme.shapeFillColor);
service.crud.updateElement(rectId, { service.crud.updateElement(rectId, {
@@ -59,7 +60,9 @@ describe('apply last props', () => {
const diamondId = service.crud.addElement('shape', { const diamondId = service.crud.addElement('shape', {
shapeType: ShapeType.Diamond, shapeType: ShapeType.Diamond,
}); });
assertExists(diamondId); if (!diamondId) {
throw new Error('diamondId is not found');
}
const diamondShape = service.crud.getElementById( const diamondShape = service.crud.getElementById(
diamondId diamondId
) as ShapeElementModel; ) as ShapeElementModel;
@@ -77,7 +80,9 @@ describe('apply last props', () => {
shapeType: ShapeType.Rect, shapeType: ShapeType.Rect,
radius: 0.1, radius: 0.1,
}); });
assertExists(roundedRectId); if (!roundedRectId) {
throw new Error('roundedRectId is not found');
}
const roundedRectShape = service.crud.getElementById( const roundedRectShape = service.crud.getElementById(
roundedRectId roundedRectId
) as ShapeElementModel; ) as ShapeElementModel;
@@ -95,7 +100,9 @@ describe('apply last props', () => {
const rectId2 = service.crud.addElement('shape', { const rectId2 = service.crud.addElement('shape', {
shapeType: ShapeType.Rect, shapeType: ShapeType.Rect,
}); });
assertExists(rectId2); if (!rectId2) {
throw new Error('rectId2 is not found');
}
const rectShape2 = service.crud.getElementById( const rectShape2 = service.crud.getElementById(
rectId2 rectId2
) as ShapeElementModel; ) as ShapeElementModel;
@@ -104,7 +111,9 @@ describe('apply last props', () => {
const diamondId2 = service.crud.addElement('shape', { const diamondId2 = service.crud.addElement('shape', {
shapeType: ShapeType.Diamond, shapeType: ShapeType.Diamond,
}); });
assertExists(diamondId2); if (!diamondId2) {
throw new Error('diamondId2 is not found');
}
const diamondShape2 = service.crud.getElementById( const diamondShape2 = service.crud.getElementById(
diamondId2 diamondId2
) as ShapeElementModel; ) as ShapeElementModel;
@@ -114,7 +123,9 @@ describe('apply last props', () => {
shapeType: ShapeType.Rect, shapeType: ShapeType.Rect,
radius: 0.1, radius: 0.1,
}); });
assertExists(roundedRectId2); if (!roundedRectId2) {
throw new Error('roundedRectId2 is not found');
}
const roundedRectShape2 = service.crud.getElementById( const roundedRectShape2 = service.crud.getElementById(
roundedRectId2 roundedRectId2
) as ShapeElementModel; ) as ShapeElementModel;
@@ -125,7 +136,9 @@ describe('apply last props', () => {
test('connector', () => { test('connector', () => {
const id = service.crud.addElement('connector', { mode: 0 }); 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; const connector = service.crud.getElementById(id) as ConnectorElementModel;
expect(connector.stroke).toBe(DefaultTheme.connectorColor); expect(connector.stroke).toBe(DefaultTheme.connectorColor);
expect(connector.strokeWidth).toBe(2); expect(connector.strokeWidth).toBe(2);
@@ -135,7 +148,9 @@ describe('apply last props', () => {
service.crud.updateElement(id, { strokeWidth: 10 }); service.crud.updateElement(id, { strokeWidth: 10 });
const id2 = service.crud.addElement('connector', { mode: 1 }); const id2 = service.crud.addElement('connector', { mode: 1 });
assertExists(id2); if (!id2) {
throw new Error('id2 is not found');
}
const connector2 = service.crud.getElementById( const connector2 = service.crud.getElementById(
id2 id2
) as ConnectorElementModel; ) as ConnectorElementModel;
@@ -148,7 +163,9 @@ describe('apply last props', () => {
}); });
const id3 = service.crud.addElement('connector', { mode: 1 }); const id3 = service.crud.addElement('connector', { mode: 1 });
assertExists(id3); if (!id3) {
throw new Error('id3 is not found');
}
const connector3 = service.crud.getElementById( const connector3 = service.crud.getElementById(
id3 id3
) as ConnectorElementModel; ) as ConnectorElementModel;
@@ -159,7 +176,9 @@ describe('apply last props', () => {
test('brush', () => { test('brush', () => {
const id = service.crud.addElement('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; const brush = service.crud.getElementById(id) as BrushElementModel;
expect(brush.color).toEqual(DefaultTheme.black); expect(brush.color).toEqual(DefaultTheme.black);
expect(brush.lineWidth).toBe(4); expect(brush.lineWidth).toBe(4);
@@ -172,7 +191,9 @@ describe('apply last props', () => {
test('text', () => { test('text', () => {
const id = service.crud.addElement('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; const text = service.crud.getElementById(id) as TextElementModel;
expect(text.fontSize).toBe(24); expect(text.fontSize).toBe(24);
service.crud.updateElement(id, { fontSize: 36 }); service.crud.updateElement(id, { fontSize: 36 });
@@ -184,7 +205,9 @@ describe('apply last props', () => {
test('mindmap', () => { test('mindmap', () => {
const id = service.crud.addElement('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; const mindmap = service.crud.getElementById(id) as MindmapElementModel;
expect(mindmap.layoutType).toBe(LayoutType.RIGHT); expect(mindmap.layoutType).toBe(LayoutType.RIGHT);
expect(mindmap.style).toBe(MindmapStyle.ONE); expect(mindmap.style).toBe(MindmapStyle.ONE);
@@ -194,7 +217,9 @@ describe('apply last props', () => {
}); });
const id2 = service.crud.addElement('mindmap', {}); 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; const mindmap2 = service.crud.getElementById(id2) as MindmapElementModel;
expect(mindmap2.layoutType).toBe(LayoutType.BALANCE); expect(mindmap2.layoutType).toBe(LayoutType.BALANCE);
expect(mindmap2.style).toBe(MindmapStyle.THREE); expect(mindmap2.style).toBe(MindmapStyle.THREE);
@@ -203,7 +228,9 @@ describe('apply last props', () => {
test('edgeless-text', () => { test('edgeless-text', () => {
const surface = getSurfaceBlock(doc); const surface = getSurfaceBlock(doc);
const id = service.crud.addBlock('affine:edgeless-text', {}, surface!.id); 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; const text = service.crud.getElementById(id) as EdgelessTextBlockModel;
expect(text.color).toBe(DefaultTheme.textColor); expect(text.color).toBe(DefaultTheme.textColor);
expect(text.fontFamily).toBe(FontFamily.Inter); expect(text.fontFamily).toBe(FontFamily.Inter);
@@ -213,7 +240,9 @@ describe('apply last props', () => {
}); });
const id2 = service.crud.addBlock('affine:edgeless-text', {}, surface!.id); 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; const text2 = service.crud.getElementById(id2) as EdgelessTextBlockModel;
expect(text2.color).toBe(DefaultTheme.StrokeColorShortMap.Green); expect(text2.color).toBe(DefaultTheme.StrokeColorShortMap.Green);
expect(text2.fontFamily).toBe(FontFamily.OrelegaOne); expect(text2.fontFamily).toBe(FontFamily.OrelegaOne);
@@ -221,7 +250,9 @@ describe('apply last props', () => {
test('note', () => { test('note', () => {
const id = service.crud.addBlock('affine:note', {}, doc.root!.id); 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; const note = service.crud.getElementById(id) as NoteBlockModel;
expect(note.background).toEqual(DefaultTheme.noteBackgrounColor); expect(note.background).toEqual(DefaultTheme.noteBackgrounColor);
expect(note.edgeless.style.shadowType).toBe(DEFAULT_NOTE_SHADOW); 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); 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; const note2 = service.crud.getElementById(id2) as NoteBlockModel;
expect(note2.background).toEqual( expect(note2.background).toEqual(
DefaultTheme.NoteBackgroundColorMap.Purple DefaultTheme.NoteBackgroundColorMap.Purple
@@ -246,7 +279,9 @@ describe('apply last props', () => {
test('frame', () => { test('frame', () => {
const surface = getSurfaceBlock(doc); const surface = getSurfaceBlock(doc);
const id = service.crud.addBlock('affine:frame', {}, surface!.id); 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; const note = service.crud.getElementById(id) as FrameBlockModel;
expect(note.background).toBe('transparent'); expect(note.background).toBe('transparent');
service.crud.updateElement(id, { service.crud.updateElement(id, {
@@ -254,7 +289,9 @@ describe('apply last props', () => {
}); });
const id2 = service.crud.addBlock('affine:frame', {}, surface!.id); 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; const frame2 = service.crud.getElementById(id2) as FrameBlockModel;
expect(frame2.background).toBe(DefaultTheme.StrokeColorShortMap.Purple); expect(frame2.background).toBe(DefaultTheme.StrokeColorShortMap.Purple);
service.crud.updateElement(id2, { service.crud.updateElement(id2, {
@@ -262,7 +299,9 @@ describe('apply last props', () => {
}); });
const id3 = service.crud.addBlock('affine:frame', {}, surface!.id); 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; const frame3 = service.crud.getElementById(id3) as FrameBlockModel;
expect(frame3.background).toEqual({ normal: '#def4e740' }); expect(frame3.background).toEqual({ normal: '#def4e740' });
service.crud.updateElement(id3, { service.crud.updateElement(id3, {
@@ -270,7 +309,9 @@ describe('apply last props', () => {
}); });
const id4 = service.crud.addBlock('affine:frame', {}, surface!.id); 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; const frame4 = service.crud.getElementById(id4) as FrameBlockModel;
expect(frame4.background).toEqual({ expect(frame4.background).toEqual({
light: '#a381aa23', light: '#a381aa23',
@@ -19,7 +19,6 @@ import {
StoreExtensions, StoreExtensions,
} from '@blocksuite/blocks'; } from '@blocksuite/blocks';
import { AffineSchemas } from '@blocksuite/blocks/schemas'; import { AffineSchemas } from '@blocksuite/blocks/schemas';
import { assertExists } from '@blocksuite/global/utils';
import { Schema, Text } from '@blocksuite/store'; import { Schema, Text } from '@blocksuite/store';
import { import {
createAutoIncrementIdGenerator, createAutoIncrementIdGenerator,
@@ -67,7 +66,9 @@ async function createEditor(
) { ) {
const app = document.createElement('div'); const app = document.createElement('div');
const blockCollection = collection.docs.values().next().value; 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 doc = blockCollection.getStore();
const editor = new TestAffineEditorContainer(); const editor = new TestAffineEditorContainer();
editor.doc = doc; editor.doc = doc;
@@ -1,5 +1,4 @@
import type { DocModeProvider } from '@blocksuite/blocks'; import type { DocModeProvider } from '@blocksuite/blocks';
import { assertExists } from '@blocksuite/global/utils';
import type { TestAffineEditorContainer } from '@blocksuite/integration-test'; import type { TestAffineEditorContainer } from '@blocksuite/integration-test';
import type { Doc, Store, Workspace } from '@blocksuite/store'; import type { Doc, Store, Workspace } from '@blocksuite/store';
@@ -13,14 +12,18 @@ export function getDocFromUrlParams(collection: Workspace, url: URL) {
} }
if (!doc) { if (!doc) {
const blockCollection = collection.docs.values().next().value as 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 = blockCollection.getStore();
} }
doc.load(); doc.load();
doc.resetHistory(); doc.resetHistory();
assertExists(doc.root, 'Doc root is not ready'); if (!doc.root) {
throw new Error('Doc root is not ready');
}
return doc; return doc;
} }
@@ -1,4 +1,3 @@
import { assertExists } from '@blocksuite/global/utils';
import type { AwarenessSource } from '@blocksuite/sync'; import type { AwarenessSource } from '@blocksuite/sync';
import type { Awareness } from 'y-protocols/awareness'; import type { Awareness } from 'y-protocols/awareness';
import { import {
@@ -21,7 +20,9 @@ export class WebSocketAwarenessSource implements AwarenessSource {
res.concat(cur) res.concat(cur)
); );
assertExists(this.awareness); if (!this.awareness) {
throw new Error('awareness is not found');
}
const update = encodeAwarenessUpdate(this.awareness, changedClients); const update = encodeAwarenessUpdate(this.awareness, changedClients);
this.ws.send( this.ws.send(
JSON.stringify({ JSON.stringify({
@@ -42,12 +43,16 @@ export class WebSocketAwarenessSource implements AwarenessSource {
if (type === 'update') { if (type === 'update') {
const update = data.payload.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'); applyAwarenessUpdate(this.awareness, new Uint8Array(update), 'remote');
} }
if (type === 'connect') { if (type === 'connect') {
assertExists(this.awareness); if (!this.awareness) {
throw new Error('awareness is not found');
}
this.ws.send( this.ws.send(
JSON.stringify({ JSON.stringify({
channel: 'awareness', channel: 'awareness',
@@ -1,4 +1,3 @@
import { assertExists } from '@blocksuite/global/utils';
import type { DocSource } from '@blocksuite/sync'; import type { DocSource } from '@blocksuite/sync';
import { diffUpdate, encodeStateVectorFromUpdate, mergeUpdates } from 'yjs'; import { diffUpdate, encodeStateVectorFromUpdate, mergeUpdates } from 'yjs';
@@ -69,7 +68,9 @@ export class WebSocketDocSource implements DocSource {
} }
const latest = this.docMap.get(docId); const latest = this.docMap.get(docId);
assertExists(latest); if (!latest) {
throw new Error('latest is not found');
}
this.ws.send( this.ws.send(
JSON.stringify({ JSON.stringify({
channel: 'doc', channel: 'doc',
@@ -8,7 +8,6 @@ import {
import { groupTraitKey } from '@blocksuite/data-view'; import { groupTraitKey } from '@blocksuite/data-view';
import { propertyPresets } from '@blocksuite/data-view/property-presets'; import { propertyPresets } from '@blocksuite/data-view/property-presets';
import { viewPresets } from '@blocksuite/data-view/view-presets'; import { viewPresets } from '@blocksuite/data-view/view-presets';
import { assertExists } from '@blocksuite/global/utils';
import { Text, type Workspace } from '@blocksuite/store'; import { Text, type Workspace } from '@blocksuite/store';
import type { InitFn } from './utils.js'; 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 noteId = doc.addBlock('affine:note', {}, rootId);
const pId = doc.addBlock('affine:paragraph', {}, noteId); const pId = doc.addBlock('affine:paragraph', {}, noteId);
const model = doc.getBlockById(pId); const model = doc.getBlockById(pId);
assertExists(model); if (!model) {
throw new Error('model is not found');
}
const addDatabase = (title: string, group = true) => { const addDatabase = (title: string, group = true) => {
const databaseId = doc.addBlock( const databaseId = doc.addBlock(
'affine:database', 'affine:database',
+6 -3
View File
@@ -36,7 +36,6 @@ import {
assertBlockCount, assertBlockCount,
assertBlockFlavour, assertBlockFlavour,
assertBlockSelections, assertBlockSelections,
assertExists,
assertParentBlockFlavour, assertParentBlockFlavour,
assertRichTextInlineRange, assertRichTextInlineRange,
} from './utils/asserts.js'; } from './utils/asserts.js';
@@ -261,7 +260,9 @@ test.describe('embed card toolbar', () => {
await cardStyleListButton.click(); await cardStyleListButton.click();
await waitNextFrame(page); await waitNextFrame(page);
const listStyleBookmarkBox = await bookmark.boundingBox(); const listStyleBookmarkBox = await bookmark.boundingBox();
assertExists(listStyleBookmarkBox); if (!listStyleBookmarkBox) {
throw new Error('listStyleBookmarkBox is not found');
}
assertAlmostEqual(listStyleBookmarkBox.width, 752, 2); assertAlmostEqual(listStyleBookmarkBox.width, 752, 2);
assertAlmostEqual(listStyleBookmarkBox.height, 48, 2); assertAlmostEqual(listStyleBookmarkBox.height, 48, 2);
@@ -269,7 +270,9 @@ test.describe('embed card toolbar', () => {
await cardStyleHorizontalButton.click(); await cardStyleHorizontalButton.click();
await waitNextFrame(page); await waitNextFrame(page);
const horizontalStyleBookmarkBox = await bookmark.boundingBox(); const horizontalStyleBookmarkBox = await bookmark.boundingBox();
assertExists(horizontalStyleBookmarkBox); if (!horizontalStyleBookmarkBox) {
throw new Error('horizontalStyleBookmarkBox is not found');
}
assertAlmostEqual(horizontalStyleBookmarkBox.width, 752, 2); assertAlmostEqual(horizontalStyleBookmarkBox.width, 752, 2);
assertAlmostEqual(horizontalStyleBookmarkBox.height, 116, 2); assertAlmostEqual(horizontalStyleBookmarkBox.height, 116, 2);
}); });
@@ -34,7 +34,6 @@ import {
import { import {
assertBlockTypes, assertBlockTypes,
assertClipItems, assertClipItems,
assertExists,
assertRichTexts, assertRichTexts,
assertText, assertText,
assertTitle, assertTitle,
@@ -127,8 +126,12 @@ test(scoped`split block when paste`, async ({ page }) => {
const bottomRight789 = await getEditorLocator(page) const bottomRight789 = await getEditorLocator(page)
.locator('[data-block-id="4"] .inline-editor') .locator('[data-block-id="4"] .inline-editor')
.boundingBox(); .boundingBox();
assertExists(topLeft123); if (!topLeft123) {
assertExists(bottomRight789); throw new Error('topLeft123 is not found');
}
if (!bottomRight789) {
throw new Error('bottomRight789 is not found');
}
await dragBetweenCoords(page, topLeft123, bottomRight789); await dragBetweenCoords(page, topLeft123, bottomRight789);
// FIXME see https://github.com/toeverything/blocksuite/pull/878 // FIXME see https://github.com/toeverything/blocksuite/pull/878
@@ -51,7 +51,6 @@ import {
assertBlockTypes, assertBlockTypes,
assertEdgelessNoteBackground, assertEdgelessNoteBackground,
assertEdgelessSelectedModelRect, assertEdgelessSelectedModelRect,
assertExists,
assertRichTextModelType, assertRichTextModelType,
assertRichTexts, assertRichTexts,
assertText, assertText,
@@ -111,7 +110,9 @@ test('copy a nested list by clicking button, the clipboard data should be comple
await pasteContent(page, clipData); await pasteContent(page, clipData);
const rootListBound = await page.locator('affine-list').first().boundingBox(); 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. // use drag element to test.
await dragBetweenCoords( await dragBetweenCoords(
@@ -28,7 +28,6 @@ import {
assertConnectorStrokeColor, assertConnectorStrokeColor,
assertEdgelessCanvasText, assertEdgelessCanvasText,
assertEdgelessNoteBackground, assertEdgelessNoteBackground,
assertExists,
assertRichTexts, assertRichTexts,
assertSelectedBound, assertSelectedBound,
} from '../utils/asserts.js'; } from '../utils/asserts.js';
@@ -159,7 +158,9 @@ test.describe('auto-complete', () => {
const note = document.body.querySelector('affine-edgeless-note'); const note = document.body.querySelector('affine-edgeless-note');
return note?.getAttribute('data-block-id'); return note?.getAttribute('data-block-id');
}); });
assertExists(noteId); if (!noteId) {
throw new Error('noteId is not found');
}
await assertEdgelessNoteBackground( await assertEdgelessNoteBackground(
page, page,
noteId, noteId,
@@ -167,7 +168,9 @@ test.describe('auto-complete', () => {
); );
const rect = await edgelessNote.boundingBox(); const rect = await edgelessNote.boundingBox();
assertExists(rect); if (!rect) {
throw new Error('rect is not found');
}
// blur note block // blur note block
await page.mouse.click(rect.x + rect.width / 2, rect.y + rect.height * 3); 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]; const note = document.body.querySelectorAll('affine-edgeless-note')[1];
return note?.getAttribute('data-block-id'); return note?.getAttribute('data-block-id');
}); });
assertExists(noteId2); if (!noteId2) {
throw new Error('noteId2 is not found');
}
await assertEdgelessNoteBackground( await assertEdgelessNoteBackground(
page, page,
noteId, noteId,
@@ -1,4 +1,3 @@
import { assertExists } from '@blocksuite/global/utils';
import { expect, type Page } from '@playwright/test'; import { expect, type Page } from '@playwright/test';
import { import {
@@ -142,7 +141,9 @@ test.describe('auto-connect', () => {
const noteBound = await getNoteBoundBoxInEdgeless(page, id2); const noteBound = await getNoteBoundBoxInEdgeless(page, id2);
const edgelessOnlyIndexLabelBound = const edgelessOnlyIndexLabelBound =
await edgelessOnlyIndexLabel.boundingBox(); await edgelessOnlyIndexLabel.boundingBox();
assertExists(edgelessOnlyIndexLabelBound); if (!edgelessOnlyIndexLabelBound) {
throw new Error('edgelessOnlyIndexLabelBound is not found');
}
const border = 1; const border = 1;
const offset = 16; const offset = 16;
expect(edgelessOnlyIndexLabelBound.x).toBeCloseTo( expect(edgelessOnlyIndexLabelBound.x).toBeCloseTo(
@@ -166,7 +167,9 @@ test.describe('auto-connect', () => {
const newNoteBound = await getNoteBoundBoxInEdgeless(page, id2); const newNoteBound = await getNoteBoundBoxInEdgeless(page, id2);
const newEdgelessOnlyIndexLabelBound = const newEdgelessOnlyIndexLabelBound =
await edgelessOnlyIndexLabel.boundingBox(); await edgelessOnlyIndexLabel.boundingBox();
assertExists(newEdgelessOnlyIndexLabelBound); if (!newEdgelessOnlyIndexLabelBound) {
throw new Error('newEdgelessOnlyIndexLabelBound is not found');
}
expect(newEdgelessOnlyIndexLabelBound.x).toBeCloseTo( expect(newEdgelessOnlyIndexLabelBound.x).toBeCloseTo(
newNoteBound.x + newNoteBound.x +
newNoteBound.width / 2 - newNoteBound.width / 2 -
@@ -1,4 +1,3 @@
import { assertExists } from '@blocksuite/global/utils';
import { expect } from '@playwright/test'; import { expect } from '@playwright/test';
import { 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 moreButtonBox = await moreButton.boundingBox();
const tooltip = page.locator('.affine-tooltip'); 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 // need to wait for previous tooltip to be hidden
await page.waitForTimeout(100); await page.waitForTimeout(100);
@@ -383,8 +384,7 @@ test('should close zoom bar when click blank area', async ({ page }) => {
await initEmptyEdgelessState(page); await initEmptyEdgelessState(page);
await switchEditorMode(page); await switchEditorMode(page);
const screenWidth = page.viewportSize()?.width; const screenWidth = page.viewportSize()?.width ?? 0;
assertExists(screenWidth);
if (screenWidth > ZOOM_BAR_RESPONSIVE_SCREEN_WIDTH) { if (screenWidth > ZOOM_BAR_RESPONSIVE_SCREEN_WIDTH) {
await page.setViewportSize({ await page.setViewportSize({
width: 1000, width: 1000,
@@ -21,7 +21,6 @@ import {
assertConnectorPath, assertConnectorPath,
assertEdgelessNonSelectedRect, assertEdgelessNonSelectedRect,
assertEdgelessSelectedRect, assertEdgelessSelectedRect,
assertExists,
} from '../../utils/asserts.js'; } from '../../utils/asserts.js';
import { test } from '../../utils/playwright.js'; import { test } from '../../utils/playwright.js';
@@ -223,7 +222,9 @@ test.describe('quick connect', () => {
}); });
const bounds = await quickConnectBtn.boundingBox(); const bounds = await quickConnectBtn.boundingBox();
assertExists(bounds); if (!bounds) {
throw new Error('bounds is not found');
}
await quickConnectBtn.click(); await quickConnectBtn.click();
@@ -290,7 +291,9 @@ test.describe('quick connect', () => {
name: 'Draw connector', name: 'Draw connector',
}); });
const bounds = await quickConnectBtn.boundingBox(); const bounds = await quickConnectBtn.boundingBox();
assertExists(bounds); if (!bounds) {
throw new Error('bounds is not found');
}
await quickConnectBtn.click(); await quickConnectBtn.click();
// at right // at right
@@ -1,4 +1,3 @@
import { assertExists } from '@blocksuite/global/utils';
import { expect, type Page } from '@playwright/test'; import { expect, type Page } from '@playwright/test';
import { import {
@@ -28,7 +27,9 @@ test.describe('connector label with straight shape', () => {
const bounds = await page const bounds = await page
.locator('edgeless-connector-label-editor rich-text') .locator('edgeless-connector-label-editor rich-text')
.boundingBox(); .boundingBox();
assertExists(bounds); if (!bounds) {
throw new Error('bounds is not found');
}
const cx = bounds.x + bounds.width / 2; const cx = bounds.x + bounds.width / 2;
const cy = bounds.y + bounds.height / 2; const cy = bounds.y + bounds.height / 2;
return [cx, cy]; return [cx, cy];
@@ -20,7 +20,7 @@ import {
type, type,
waitNextFrame, waitNextFrame,
} from '../utils/actions/index.js'; } from '../utils/actions/index.js';
import { assertConnectorPath, assertExists } from '../utils/asserts.js'; import { assertConnectorPath } from '../utils/asserts.js';
import { test } from '../utils/playwright.js'; import { test } from '../utils/playwright.js';
test.describe('note to linked doc', () => { test.describe('note to linked doc', () => {
@@ -39,12 +39,16 @@ test.describe('note to linked doc', () => {
await waitNextFrame(page, 200); await waitNextFrame(page, 200);
const embedSyncedBlock = page.locator('affine-embed-synced-doc-block'); 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 triggerComponentToolbarAction(page, 'openLinkedDoc');
await waitNextFrame(page, 200); await waitNextFrame(page, 200);
const noteBlock = page.locator('affine-edgeless-note'); const noteBlock = page.locator('affine-edgeless-note');
assertExists(noteBlock); if (!noteBlock) {
throw new Error('noteBlock is not found');
}
const noteContent = await noteBlock.innerText(); const noteContent = await noteBlock.innerText();
expect(noteContent).toBe('Hello\nWorld'); expect(noteContent).toBe('Hello\nWorld');
}); });
@@ -62,7 +66,9 @@ test.describe('note to linked doc', () => {
await waitNextFrame(page, 200); await waitNextFrame(page, 200);
const embedSyncedBlock = page.locator('affine-embed-synced-doc-block'); 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); 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 triggerComponentToolbarAction(page, 'createLinkedDoc');
await waitNextFrame(page, 200); await waitNextFrame(page, 200);
const linkedSyncedBlock = page.locator('affine-linked-synced-doc-block'); 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 triggerComponentToolbarAction(page, 'openLinkedDoc');
await waitNextFrame(page, 200); await waitNextFrame(page, 200);
@@ -140,7 +148,9 @@ test.describe('single edgeless element to linked doc', () => {
await triggerComponentToolbarAction(page, 'createLinkedDoc'); await triggerComponentToolbarAction(page, 'createLinkedDoc');
await waitNextFrame(page, 200); await waitNextFrame(page, 200);
const linkedSyncedBlock = page.locator('affine-linked-synced-doc-block'); 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 triggerComponentToolbarAction(page, 'openLinkedDoc');
await waitNextFrame(page, 200); await waitNextFrame(page, 200);
@@ -157,7 +167,9 @@ test.describe('single edgeless element to linked doc', () => {
await triggerComponentToolbarAction(page, 'createLinkedDoc'); await triggerComponentToolbarAction(page, 'createLinkedDoc');
await waitNextFrame(page, 200); await waitNextFrame(page, 200);
const linkedSyncedBlock = page.locator('affine-linked-synced-doc-block'); 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 triggerComponentToolbarAction(page, 'openLinkedDoc');
await waitNextFrame(page, 200); await waitNextFrame(page, 200);
@@ -185,7 +197,9 @@ test.describe('single edgeless element to linked doc', () => {
await triggerComponentToolbarAction(page, 'createLinkedDoc'); await triggerComponentToolbarAction(page, 'createLinkedDoc');
await waitNextFrame(page, 200); await waitNextFrame(page, 200);
const linkedSyncedBlock = page.locator('affine-linked-synced-doc-block'); 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 triggerComponentToolbarAction(page, 'openLinkedDoc');
await waitNextFrame(page, 200); await waitNextFrame(page, 200);
@@ -222,7 +236,9 @@ test.describe('single edgeless element to linked doc', () => {
await triggerComponentToolbarAction(page, 'createLinkedDoc'); await triggerComponentToolbarAction(page, 'createLinkedDoc');
await waitNextFrame(page, 200); await waitNextFrame(page, 200);
const linkedSyncedBlock = page.locator('affine-linked-synced-doc-block'); 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 triggerComponentToolbarAction(page, 'openLinkedDoc');
await waitNextFrame(page, 200); await waitNextFrame(page, 200);
@@ -269,7 +285,9 @@ test.describe('multiple edgeless elements to linked doc', () => {
await triggerComponentToolbarAction(page, 'createLinkedDoc'); await triggerComponentToolbarAction(page, 'createLinkedDoc');
await waitNextFrame(page, 200); await waitNextFrame(page, 200);
const linkedSyncedBlock = page.locator('affine-linked-synced-doc-block'); 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 triggerComponentToolbarAction(page, 'openLinkedDoc');
await waitNextFrame(page, 200); await waitNextFrame(page, 200);
@@ -305,7 +323,9 @@ test.describe('multiple edgeless elements to linked doc', () => {
await triggerComponentToolbarAction(page, 'createLinkedDoc'); await triggerComponentToolbarAction(page, 'createLinkedDoc');
await waitNextFrame(page, 200); await waitNextFrame(page, 200);
const linkedSyncedBlock = page.locator('affine-linked-synced-doc-block'); 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 triggerComponentToolbarAction(page, 'openLinkedDoc');
await waitNextFrame(page, 200); await waitNextFrame(page, 200);
@@ -334,7 +354,9 @@ test.describe('multiple edgeless elements to linked doc', () => {
await triggerComponentToolbarAction(page, 'createLinkedDoc'); await triggerComponentToolbarAction(page, 'createLinkedDoc');
await waitNextFrame(page, 200); await waitNextFrame(page, 200);
const linkedSyncedBlock = page.locator('affine-linked-synced-doc-block'); 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 triggerComponentToolbarAction(page, 'openLinkedDoc');
await waitNextFrame(page, 200); await waitNextFrame(page, 200);
@@ -42,7 +42,6 @@ import {
assertEdgelessNonSelectedRect, assertEdgelessNonSelectedRect,
assertEdgelessNoteBackground, assertEdgelessNoteBackground,
assertEdgelessSelectedRect, assertEdgelessSelectedRect,
assertExists,
assertNoteSequence, assertNoteSequence,
assertNoteXYWH, assertNoteXYWH,
assertRichTextInlineRange, assertRichTextInlineRange,
@@ -386,7 +385,9 @@ test.fixme(
const paragraphBlock = await page const paragraphBlock = await page
.locator(`[data-block-id="3"]`) .locator(`[data-block-id="3"]`)
.boundingBox(); .boundingBox();
assertExists(paragraphBlock); if (!paragraphBlock) {
throw new Error('paragraphBlock is not found');
}
await page.mouse.dblclick(paragraphBlock.x, paragraphBlock.y); await page.mouse.dblclick(paragraphBlock.x, paragraphBlock.y);
await waitNextFrame(page); await waitNextFrame(page);
await page.mouse.move( await page.mouse.move(
@@ -397,7 +398,9 @@ test.fixme(
const handle = await page const handle = await page
.locator('.affine-drag-handle-container') .locator('.affine-drag-handle-container')
.boundingBox(); .boundingBox();
assertExists(handle); if (!handle) {
throw new Error('handle is not found');
}
await page.mouse.move( await page.mouse.move(
handle.x + handle.width / 2, handle.x + handle.width / 2,
handle.y + handle.height / 2, handle.y + handle.height / 2,
@@ -414,7 +417,9 @@ test.fixme(
// Click at empty note block to add a paragraph block // Click at empty note block to add a paragraph block
const emptyNote = await page.locator(`[data-block-id="2"]`).boundingBox(); 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( await page.mouse.click(
emptyNote.x + emptyNote.width / 2, emptyNote.x + emptyNote.width / 2,
emptyNote.y + emptyNote.height / 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 const notePortalBox = await page
.locator('affine-edgeless-note') .locator('affine-edgeless-note')
.boundingBox(); .boundingBox();
assertExists(notePortalBox); if (!notePortalBox) {
throw new Error('notePortalBox is not found');
}
await page.mouse.click(notePortalBox.x + 10, notePortalBox.y + 10); await page.mouse.click(notePortalBox.x + 10, notePortalBox.y + 10);
await waitNextFrame(page, 200); await waitNextFrame(page, 200);
const selectedRect = page const selectedRect = page
@@ -455,7 +462,9 @@ test('Should focus at closest text block when note collapse', async ({
// Collapse the note // Collapse the note
const selectedBox = await selectedRect.boundingBox(); const selectedBox = await selectedRect.boundingBox();
assertExists(selectedBox); if (!selectedBox) {
throw new Error('selectedBox is not found');
}
await page.mouse.move( await page.mouse.move(
selectedBox.x + selectedBox.width / 2, selectedBox.x + selectedBox.width / 2,
selectedBox.y + selectedBox.height selectedBox.y + selectedBox.height
@@ -40,7 +40,6 @@ import {
assertEdgelessColorSameWithHexColor, assertEdgelessColorSameWithHexColor,
assertEdgelessNonSelectedRect, assertEdgelessNonSelectedRect,
assertEdgelessSelectedRect, assertEdgelessSelectedRect,
assertExists,
assertRichTexts, assertRichTexts,
} from '../utils/asserts.js'; } from '../utils/asserts.js';
import { test } from '../utils/playwright.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 shapeToolBox = await shapeTool.boundingBox();
const tooltip = page.locator('.affine-tooltip'); 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 page.mouse.move(shapeToolBox.x + 2, shapeToolBox.y + 2);
await expect(tooltip).toBeVisible(); 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 shapeTool = await locatorEdgelessToolButton(page, 'shape');
const shapeToolBox = await shapeTool.boundingBox(); 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); await page.mouse.click(shapeToolBox.x + 2, shapeToolBox.y + 2);
@@ -1,5 +1,4 @@
import type { DatabaseBlockModel } from '@blocksuite/affine-model'; import type { DatabaseBlockModel } from '@blocksuite/affine-model';
import { assertExists } from '@blocksuite/global/utils';
import { expect, type Page } from '@playwright/test'; import { expect, type Page } from '@playwright/test';
import { switchEditorMode } from './utils/actions/edgeless.js'; import { switchEditorMode } from './utils/actions/edgeless.js';
@@ -22,7 +21,9 @@ test.describe('Embed synced doc', () => {
const { createLinkedDoc } = getLinkedDocPopover(page); const { createLinkedDoc } = getLinkedDocPopover(page);
const linkedDoc = await createLinkedDoc('page1'); const linkedDoc = await createLinkedDoc('page1');
const lickedDocBox = await linkedDoc.boundingBox(); const lickedDocBox = await linkedDoc.boundingBox();
assertExists(lickedDocBox); if (!lickedDocBox) {
throw new Error('lickedDocBox is not found');
}
await page.mouse.move( await page.mouse.move(
lickedDocBox.x + lickedDocBox.width / 2, lickedDocBox.x + lickedDocBox.width / 2,
lickedDocBox.y + lickedDocBox.height / 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 syncedDoc = page.locator(`affine-embed-synced-doc-block`);
const syncedDocBox = await syncedDoc.boundingBox(); const syncedDocBox = await syncedDoc.boundingBox();
assertExists(syncedDocBox); if (!syncedDocBox) {
throw new Error('syncedDocBox is not found');
}
await page.mouse.click( await page.mouse.click(
syncedDocBox.x + syncedDocBox.width / 2, syncedDocBox.x + syncedDocBox.width / 2,
syncedDocBox.y + syncedDocBox.height / 2 syncedDocBox.y + syncedDocBox.height / 2
@@ -95,7 +98,9 @@ test.describe('Embed synced doc', () => {
// Focus on the embed synced doc // Focus on the embed synced doc
const embedSyncedBlock = page.locator('affine-embed-synced-doc-block'); const embedSyncedBlock = page.locator('affine-embed-synced-doc-block');
let embedSyncedBox = await embedSyncedBlock.boundingBox(); let embedSyncedBox = await embedSyncedBlock.boundingBox();
assertExists(embedSyncedBox); if (!embedSyncedBox) {
throw new Error('embedSyncedBox is not found');
}
await page.mouse.click( await page.mouse.click(
embedSyncedBox.x + embedSyncedBox.width / 2, embedSyncedBox.x + embedSyncedBox.width / 2,
embedSyncedBox.y + embedSyncedBox.height / 2 embedSyncedBox.y + embedSyncedBox.height / 2
@@ -108,13 +113,17 @@ test.describe('Embed synced doc', () => {
// Double click on note to enter edit status // Double click on note to enter edit status
const noteBlock = page.locator('affine-edgeless-note'); const noteBlock = page.locator('affine-edgeless-note');
const noteBlockBox = await noteBlock.boundingBox(); 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 page.mouse.dblclick(noteBlockBox.x + 10, noteBlockBox.y + 10);
await waitNextFrame(page, 200); await waitNextFrame(page, 200);
// Drag the embed synced doc to whiteboard // Drag the embed synced doc to whiteboard
embedSyncedBox = await embedSyncedBlock.boundingBox(); embedSyncedBox = await embedSyncedBlock.boundingBox();
assertExists(embedSyncedBox); if (!embedSyncedBox) {
throw new Error('embedSyncedBox is not found');
}
const height = embedSyncedBox.height; const height = embedSyncedBox.height;
await page.mouse.move(embedSyncedBox.x - 10, embedSyncedBox.y - 100); await page.mouse.move(embedSyncedBox.x - 10, embedSyncedBox.y - 100);
await page.mouse.move(embedSyncedBox.x - 10, embedSyncedBox.y + 10); 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 EmbedSyncedDocBlockBox = await EmbedSyncedDocBlock.boundingBox();
const border = 1; const border = 1;
assertExists(EmbedSyncedDocBlockBox); if (!EmbedSyncedDocBlockBox) {
throw new Error('EmbedSyncedDocBlockBox is not found');
}
expect(EmbedSyncedDocBlockBox.height).toBeCloseTo(height + 2 * border, 1); expect(EmbedSyncedDocBlockBox.height).toBeCloseTo(height + 2 * border, 1);
} }
); );
+15 -6
View File
@@ -38,7 +38,6 @@ import {
import { import {
assertAlmostEqual, assertAlmostEqual,
assertBlockChildrenIds, assertBlockChildrenIds,
assertExists,
assertLocatorVisible, assertLocatorVisible,
assertRichImage, assertRichImage,
assertRichTextInlineRange, assertRichTextInlineRange,
@@ -85,7 +84,9 @@ test('should format quick bar show when clicking drag handle', async ({
await locator.hover(); await locator.hover();
const dragHandle = page.locator('.affine-drag-handle-grabber'); const dragHandle = page.locator('.affine-drag-handle-grabber');
const dragHandleRect = await dragHandle.boundingBox(); const dragHandleRect = await dragHandle.boundingBox();
assertExists(dragHandleRect); if (!dragHandleRect) {
throw new Error('dragHandleRect is not found');
}
await dragHandle.click(); await dragHandle.click();
const { formatBar } = getFormatBar(page); 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 formatRect = await formatBar.boundingBox();
const selectionRect = await blockSelections.boundingBox(); const selectionRect = await blockSelections.boundingBox();
assertExists(formatRect); if (!formatRect) {
assertExists(selectionRect); 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.x - selectionRect.x, 147.5, 10);
assertAlmostEqual(formatRect.y - selectionRect.y, 33, 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"); throw new Error("formatBar doesn't exist");
} }
const rect = await blockSelections.first().boundingBox(); 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.x - rect.x, 147.5, 10);
assertAlmostEqual(box.y - rect.y, 99, 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); await expect(linkedDocBlock).toHaveCount(1);
const linkedDocBox = await linkedDocBlock.boundingBox(); const linkedDocBox = await linkedDocBlock.boundingBox();
assertExists(linkedDocBox); if (!linkedDocBox) {
throw new Error('linkedDocBox is not found');
}
await page.mouse.dblclick( await page.mouse.dblclick(
linkedDocBox.x + linkedDocBox.width / 2, linkedDocBox.x + linkedDocBox.width / 2,
linkedDocBox.y + linkedDocBox.height / 2 linkedDocBox.y + linkedDocBox.height / 2
@@ -32,7 +32,6 @@ import {
waitNextFrame, waitNextFrame,
} from './utils/actions/misc.js'; } from './utils/actions/misc.js';
import { import {
assertExists,
assertParentBlockFlavour, assertParentBlockFlavour,
assertRichTexts, assertRichTexts,
assertTitle, assertTitle,
@@ -43,7 +42,9 @@ async function createAndConvertToEmbedLinkedDoc(page: Page) {
const { createLinkedDoc } = getLinkedDocPopover(page); const { createLinkedDoc } = getLinkedDocPopover(page);
const linkedDoc = await createLinkedDoc('page1'); const linkedDoc = await createLinkedDoc('page1');
const lickedDocBox = await linkedDoc.boundingBox(); const lickedDocBox = await linkedDoc.boundingBox();
assertExists(lickedDocBox); if (!lickedDocBox) {
throw new Error('lickedDocBox is not found');
}
await page.mouse.move( await page.mouse.move(
lickedDocBox.x + lickedDocBox.width / 2, lickedDocBox.x + lickedDocBox.width / 2,
lickedDocBox.y + lickedDocBox.height / 2 lickedDocBox.y + lickedDocBox.height / 2
@@ -55,7 +55,6 @@ import {
assertBlockSelections, assertBlockSelections,
assertClipItems, assertClipItems,
assertDivider, assertDivider,
assertExists,
assertNativeSelectionRangeCount, assertNativeSelectionRangeCount,
assertRichTextInlineRange, assertRichTextInlineRange,
assertRichTexts, 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 text2 = page.locator('[data-block-id="3"] .inline-editor');
const rect = await text2.boundingBox(); 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 // The behavior of mouse click is similar to touch in mobile device
// await page.mouse.click(rect.x - 50, rect.y + 5); // 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 list = page.locator('[data-block-id="34"]');
const listRect = await list.boundingBox(); 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); await page.mouse.click(listRect.x - 30, listRect.y + 5);
const newListRect = await list.boundingBox(); const newListRect = await list.boundingBox();
// not scroll // not scroll
@@ -1770,7 +1773,9 @@ test('unexpected scroll when clicking padding area', async ({ page }) => {
await type(page, '/tableview\n'); await type(page, '/tableview\n');
const database = page.locator('affine-database'); const database = page.locator('affine-database');
const databaseRect = await database.boundingBox(); const databaseRect = await database.boundingBox();
assertExists(databaseRect); if (!databaseRect) {
throw new Error('databaseRect is not found');
}
await page.mouse.click( await page.mouse.click(
databaseRect.x + databaseRect.width + 10, databaseRect.x + databaseRect.width + 10,
databaseRect.y + 100 databaseRect.y + 100
@@ -32,7 +32,6 @@ import {
import { import {
assertAlmostEqual, assertAlmostEqual,
assertBlockCount, assertBlockCount,
assertExists,
assertRichTexts, assertRichTexts,
} from './utils/asserts.js'; } from './utils/asserts.js';
import { test } from './utils/playwright.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]'); const subMenu = page.locator('.slash-menu[data-testid=sub-menu-1]');
let rect = await slashItems.nth(4).boundingBox(); 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 page.mouse.move(rect.x + 10, rect.y + 10);
await expect(slashMenu).toBeVisible(); await expect(slashMenu).toBeVisible();
await expect(slashItems.nth(4)).toHaveAttribute('hover', 'true'); 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(); await expect(subMenu).toBeVisible();
rect = await slashItems.nth(3).boundingBox(); 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 page.mouse.move(rect.x + 10, rect.y + 10);
await expect(slashMenu).toBeVisible(); await expect(slashMenu).toBeVisible();
await expect(slashItems.nth(3)).toHaveAttribute('hover', 'true'); await expect(slashItems.nth(3)).toHaveAttribute('hover', 'true');
@@ -2,7 +2,7 @@ import '../declare-test-window.js';
import type { NoteBlockModel, NoteDisplayMode } from '@blocksuite/affine-model'; import type { NoteBlockModel, NoteDisplayMode } from '@blocksuite/affine-model';
import type { IPoint, IVec } from '@blocksuite/global/gfx'; 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 type { Locator, Page } from '@playwright/test';
import { expect } from '@playwright/test'; import { expect } from '@playwright/test';
@@ -253,8 +253,7 @@ export async function locatorEdgelessZoomToolButton(
fitToScreen: 'Fit to screen', fitToScreen: 'Fit to screen',
}[type]; }[type];
const screenWidth = page.viewportSize()?.width; const screenWidth = page.viewportSize()?.width ?? 0;
assertExists(screenWidth);
let zoomBarClass = 'horizontal'; let zoomBarClass = 'horizontal';
if (screenWidth < ZOOM_BAR_RESPONSIVE_SCREEN_WIDTH) { if (screenWidth < ZOOM_BAR_RESPONSIVE_SCREEN_WIDTH) {
await toggleZoomBarWhenSmallScreenWidth(page); await toggleZoomBarWhenSmallScreenWidth(page);
@@ -958,8 +957,7 @@ export async function zoomInByKeyboard(page: Page) {
} }
export async function getZoomLevel(page: Page) { export async function getZoomLevel(page: Page) {
const screenWidth = page.viewportSize()?.width; const screenWidth = page.viewportSize()?.width ?? 0;
assertExists(screenWidth);
let zoomBarClass = 'horizontal'; let zoomBarClass = 'horizontal';
if (screenWidth < ZOOM_BAR_RESPONSIVE_SCREEN_WIDTH) { if (screenWidth < ZOOM_BAR_RESPONSIVE_SCREEN_WIDTH) {
await toggleZoomBarWhenSmallScreenWidth(page); await toggleZoomBarWhenSmallScreenWidth(page);
@@ -1456,7 +1454,9 @@ export function getEdgelessLineWidthPanel(page: Page) {
export async function changeShapeStrokeWidth(page: Page) { export async function changeShapeStrokeWidth(page: Page) {
const lineWidthPanel = getEdgelessLineWidthPanel(page); const lineWidthPanel = getEdgelessLineWidthPanel(page);
const lineWidthPanelRect = await lineWidthPanel.boundingBox(); const lineWidthPanelRect = await lineWidthPanel.boundingBox();
assertExists(lineWidthPanelRect); if (!lineWidthPanelRect) {
throw new Error('lineWidthPanelRect is not found');
}
// click line width panel by position // click line width panel by position
const x = lineWidthPanelRect.x + 40; const x = lineWidthPanelRect.x + 40;
const y = lineWidthPanelRect.y + 10; const y = lineWidthPanelRect.y + 10;
@@ -1907,7 +1907,9 @@ export async function createNote(
export async function hoverOnNote(page: Page, id: string, offset = [0, 0]) { export async function hoverOnNote(page: Page, id: string, offset = [0, 0]) {
const blockRect = await page.locator(`[data-block-id="${id}"]`).boundingBox(); 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( await page.mouse.move(
blockRect.x + blockRect.width / 2 + offset[0], blockRect.x + blockRect.width / 2 + offset[0],
@@ -5,7 +5,6 @@ import type {
ListType, ListType,
RichText, RichText,
} from '@blocksuite/blocks'; } from '@blocksuite/blocks';
import { assertExists } from '@blocksuite/global/utils';
import type { InlineRange, InlineRootElement } from '@blocksuite/inline'; import type { InlineRange, InlineRootElement } from '@blocksuite/inline';
import type { TestAffineEditorContainer } from '@blocksuite/integration-test'; import type { TestAffineEditorContainer } from '@blocksuite/integration-test';
import type { BlockModel } from '@blocksuite/store'; import type { BlockModel } from '@blocksuite/store';
@@ -42,7 +41,9 @@ export const getSelectionRect = async (page: Page): Promise<DOMRect> => {
const rect = await page.evaluate(() => { const rect = await page.evaluate(() => {
return getSelection()?.getRangeAt(0).getBoundingClientRect(); return getSelection()?.getRangeAt(0).getBoundingClientRect();
}); });
assertExists(rect); if (!rect) {
throw new Error('rect is not found');
}
return rect; return rect;
}; };
@@ -864,7 +865,9 @@ export async function getClipboardSnapshot(page: Page) {
page, page,
'BLOCKSUITE/SNAPSHOT' 'BLOCKSUITE/SNAPSHOT'
); );
assertExists(dataInClipboard); if (!dataInClipboard) {
throw new Error('dataInClipboard is not found');
}
const json = JSON.parse(dataInClipboard as string); const json = JSON.parse(dataInClipboard as string);
return json; return json;
} }
@@ -12,7 +12,6 @@ import type {
RichText, RichText,
RootBlockModel, RootBlockModel,
} from '@blocksuite/blocks'; } from '@blocksuite/blocks';
import { assertExists } from '@blocksuite/global/utils';
import type { InlineRootElement } from '@blocksuite/inline'; import type { InlineRootElement } from '@blocksuite/inline';
import type { BlockModel } from '@blocksuite/store'; import type { BlockModel } from '@blocksuite/store';
import { expect, type Locator, type Page } from '@playwright/test'; import { expect, type Locator, type Page } from '@playwright/test';
@@ -53,8 +52,6 @@ import {
} from './actions/misc.js'; } from './actions/misc.js';
import { getStringFromRichText } from './inline-editor.js'; import { getStringFromRichText } from './inline-editor.js';
export { assertExists };
const BLOCK_ID_ATTR = 'data-block-id'; const BLOCK_ID_ATTR = 'data-block-id';
export const defaultStore = { export const defaultStore = {
+1 -1
View File
@@ -191,7 +191,7 @@ export default tseslint.config(
{ {
group: ['@blocksuite/store'], group: ['@blocksuite/store'],
message: "Import from '@blocksuite/global/utils'", message: "Import from '@blocksuite/global/utils'",
importNames: ['assertExists', 'assertEquals'], importNames: ['assertEquals'],
}, },
], ],
}, },
@@ -3,7 +3,6 @@ import {
AIStarIconWithAnimation, AIStarIconWithAnimation,
createLitPortal, createLitPortal,
} from '@blocksuite/affine/blocks'; } from '@blocksuite/affine/blocks';
import { assertExists } from '@blocksuite/affine/global/utils';
import { flip, offset } from '@floating-ui/dom'; import { flip, offset } from '@floating-ui/dom';
import { html, type TemplateResult } from 'lit'; import { html, type TemplateResult } from 'lit';
@@ -169,7 +168,7 @@ function updateAIPanelConfig<T extends keyof BlockSuitePresets.AIActions>(
trackerOptions?: BlockSuitePresets.TrackerOptions trackerOptions?: BlockSuitePresets.TrackerOptions
) { ) {
const { config, host } = aiPanel; const { config, host } = aiPanel;
assertExists(config); if (!config) return;
config.generateAnswer = actionToGenerateAnswer( config.generateAnswer = actionToGenerateAnswer(
host, host,
id, id,
@@ -203,7 +202,7 @@ export function actionToHandler<T extends keyof BlockSuitePresets.AIActions>(
const { selectedBlocks: blocks } = getSelections(aiPanel.host); const { selectedBlocks: blocks } = getSelections(aiPanel.host);
if (!blocks || blocks.length === 0) return; if (!blocks || blocks.length === 0) return;
const block = blocks.at(-1); const block = blocks.at(-1);
assertExists(block); if (!block) return;
aiPanel.toggle(block, ''); aiPanel.toggle(block, '');
}; };
} }
@@ -14,7 +14,6 @@ import {
splitElements, splitElements,
TextElementModel, TextElementModel,
} from '@blocksuite/affine/blocks'; } from '@blocksuite/affine/blocks';
import { assertExists } from '@blocksuite/affine/global/utils';
import { Slice } from '@blocksuite/affine/store'; import { Slice } from '@blocksuite/affine/store';
import type { TemplateResult } from 'lit'; import type { TemplateResult } from 'lit';
@@ -319,7 +318,7 @@ function updateEdgelessAIPanelConfig<
) { ) {
const host = aiPanel.host; const host = aiPanel.host;
const { config } = aiPanel; const { config } = aiPanel;
assertExists(config); if (!config) return;
config.answerRenderer = actionToAnswerRenderer(id, host, ctx); config.answerRenderer = actionToAnswerRenderer(id, host, ctx);
config.generateAnswer = actionToGeneration( config.generateAnswer = actionToGeneration(
id, id,
@@ -414,7 +413,7 @@ export function actionToHandler<T extends keyof BlockSuitePresets.AIActions>(
referenceElement = getElementToolbar(host); referenceElement = getElementToolbar(host);
} else if (!isEmpty) { } else if (!isEmpty) {
const lastSelected = selectedElements.at(-1)?.id; const lastSelected = selectedElements.at(-1)?.id;
assertExists(lastSelected); if (!lastSelected) return;
const noteAnchor = getSelectedNoteAnchor(host, lastSelected); const noteAnchor = getSelectedNoteAnchor(host, lastSelected);
referenceElement = noteAnchor; referenceElement = noteAnchor;
} }
@@ -23,7 +23,6 @@ import {
TelemetryProvider, TelemetryProvider,
} from '@blocksuite/affine/blocks'; } from '@blocksuite/affine/blocks';
import { Bound } from '@blocksuite/affine/global/gfx'; import { Bound } from '@blocksuite/affine/global/gfx';
import { assertExists } from '@blocksuite/affine/global/utils';
import { html, type TemplateResult } from 'lit'; import { html, type TemplateResult } from 'lit';
import { styleMap } from 'lit/directives/style-map.js'; import { styleMap } from 'lit/directives/style-map.js';
@@ -238,7 +237,7 @@ function createBlockAndInsert(
const doc = host.doc; const doc = host.doc;
const edgelessCopilot = getEdgelessCopilotWidget(host); const edgelessCopilot = getEdgelessCopilotWidget(host);
doc.transact(() => { doc.transact(() => {
assertExists(doc.root); if (!doc.root) return;
let blockId = ''; let blockId = '';
const bounds = edgelessCopilot.determineInsertionBounds( const bounds = edgelessCopilot.determineInsertionBounds(
EDGELESS_TEXT_BLOCK_MIN_WIDTH, EDGELESS_TEXT_BLOCK_MIN_WIDTH,
@@ -280,8 +279,7 @@ function createBlockAndInsert(
const defaultHandler = (host: EditorHost) => { const defaultHandler = (host: EditorHost) => {
const panel = getAIPanelWidget(host); const panel = getAIPanelWidget(host);
const selectedElements = getCopilotSelectedElems(host); const selectedElements = getCopilotSelectedElems(host);
if (!panel.answer) return;
assertExists(panel.answer);
if ( if (
selectedElements.length === 1 && selectedElements.length === 1 &&
selectedElements[0] instanceof EdgelessTextBlockModel selectedElements[0] instanceof EdgelessTextBlockModel
@@ -9,7 +9,6 @@ import {
NoteDisplayMode, NoteDisplayMode,
} from '@blocksuite/affine/blocks'; } from '@blocksuite/affine/blocks';
import { Bound } from '@blocksuite/affine/global/gfx'; import { Bound } from '@blocksuite/affine/global/gfx';
import { assertExists } from '@blocksuite/affine/global/utils';
import type { FrameworkProvider } from '@toeverything/infra'; import type { FrameworkProvider } from '@toeverything/infra';
import type { TemplateResult } from 'lit'; import type { TemplateResult } from 'lit';
@@ -98,7 +97,7 @@ function createNewNote(host: EditorHost): AIItemConfig {
const panel = getAIPanelWidget(host); const panel = getAIPanelWidget(host);
const gfx = host.std.get(GfxControllerIdentifier); const gfx = host.std.get(GfxControllerIdentifier);
doc.transact(() => { doc.transact(() => {
assertExists(doc.root); if (!doc.root || !panel.answer) return;
const noteBlockId = doc.addBlock( const noteBlockId = doc.addBlock(
'affine:note', 'affine:note',
{ {
@@ -109,7 +108,6 @@ function createNewNote(host: EditorHost): AIItemConfig {
doc.root.id doc.root.id
); );
assertExists(panel.answer);
insertFromMarkdown(host, panel.answer, doc, noteBlockId) insertFromMarkdown(host, panel.answer, doc, noteBlockId)
.then(() => { .then(() => {
gfx.selection.set({ gfx.selection.set({
@@ -7,14 +7,12 @@ import {
AIStarIcon, AIStarIcon,
DocModeProvider, DocModeProvider,
} from '@blocksuite/affine/blocks'; } from '@blocksuite/affine/blocks';
import { assertExists } from '@blocksuite/affine/global/utils';
import { MoreHorizontalIcon } from '@blocksuite/icons/lit'; import { MoreHorizontalIcon } from '@blocksuite/icons/lit';
import { html } from 'lit'; import { html } from 'lit';
import { pageAIGroups } from '../../_common/config'; import { pageAIGroups } from '../../_common/config';
import { handleInlineAskAIAction } from '../../actions/doc-handler'; import { handleInlineAskAIAction } from '../../actions/doc-handler';
import type { AIItemConfig } from '../../components/ai-item/types'; import type { AIItemConfig } from '../../components/ai-item/types';
import { AIProvider } from '../../provider';
import { import {
AFFINE_AI_PANEL_WIDGET, AFFINE_AI_PANEL_WIDGET,
type AffineAIPanelWidget, type AffineAIPanelWidget,
@@ -55,10 +53,9 @@ export function setupSlashMenuAIEntry(slashMenu: AffineSlashMenuWidget) {
}); });
const subMenuWrapper = (item: AIItemConfig): AffineSlashSubMenu => { const subMenuWrapper = (item: AIItemConfig): AffineSlashSubMenu => {
assertExists(item.subItem);
return { return {
...basicItemConfig(item), ...basicItemConfig(item),
subMenu: item.subItem.map<AffineSlashMenuActionItem>( subMenu: (item.subItem ?? []).map<AffineSlashMenuActionItem>(
({ type, handler }) => ({ ({ type, handler }) => ({
name: type, name: type,
action: ({ rootComponent }) => handler?.(rootComponent.host), action: ({ rootComponent }) => handler?.(rootComponent.host),
@@ -87,9 +84,6 @@ export function setupSlashMenuAIEntry(slashMenu: AffineSlashMenuWidget) {
AFFINE_AI_PANEL_WIDGET, AFFINE_AI_PANEL_WIDGET,
rootComponent.model.id rootComponent.model.id
) as AffineAIPanelWidget; ) as AffineAIPanelWidget;
assertExists(affineAIPanelWidget);
assertExists(AIProvider.actions.chat);
assertExists(affineAIPanelWidget.host);
handleInlineAskAIAction(affineAIPanelWidget.host); handleInlineAskAIAction(affineAIPanelWidget.host);
}, },
}); });
@@ -1,4 +1,3 @@
import { assertExists } from '@blocksuite/affine/global/utils';
import { partition } from 'lodash-es'; import { partition } from 'lodash-es';
import { AIProvider } from './ai-provider'; import { AIProvider } from './ai-provider';
@@ -146,7 +145,6 @@ export function textToText({
if (retry) { if (retry) {
const retrySessionId = const retrySessionId =
(await sessionId) ?? AIProvider.LAST_ACTION_SESSIONID; (await sessionId) ?? AIProvider.LAST_ACTION_SESSIONID;
assertExists(retrySessionId, 'retry sessionId is required');
_sessionId = retrySessionId; _sessionId = retrySessionId;
_messageId = undefined; _messageId = undefined;
} else { } else {
@@ -220,7 +218,6 @@ export function textToText({
if (retry) { if (retry) {
const retrySessionId = const retrySessionId =
(await sessionId) ?? AIProvider.LAST_ACTION_SESSIONID; (await sessionId) ?? AIProvider.LAST_ACTION_SESSIONID;
assertExists(retrySessionId, 'retry sessionId is required');
_sessionId = retrySessionId; _sessionId = retrySessionId;
_messageId = undefined; _messageId = undefined;
} else { } else {
@@ -275,7 +272,6 @@ export function toImage({
if (retry) { if (retry) {
const retrySessionId = const retrySessionId =
(await sessionId) ?? AIProvider.LAST_ACTION_SESSIONID; (await sessionId) ?? AIProvider.LAST_ACTION_SESSIONID;
assertExists(retrySessionId, 'retry sessionId is required');
_sessionId = retrySessionId; _sessionId = retrySessionId;
_messageId = undefined; _messageId = undefined;
} else { } else {
@@ -5,7 +5,6 @@ import {
type getCopilotHistoriesQuery, type getCopilotHistoriesQuery,
type RequestOptions, type RequestOptions,
} from '@affine/graphql'; } from '@affine/graphql';
import { assertExists } from '@blocksuite/affine/global/utils';
import { z } from 'zod'; import { z } from 'zod';
import { AIProvider } from './ai-provider'; import { AIProvider } from './ai-provider';
@@ -234,7 +233,9 @@ export function setupAIProvider(
}); });
AIProvider.provide('expandMindmap', options => { AIProvider.provide('expandMindmap', options => {
assertExists(options.input, 'expandMindmap action requires input'); if (!options.input) {
throw new Error('expandMindmap action requires input');
}
return textToText({ return textToText({
...options, ...options,
client, client,
@@ -1,5 +1,4 @@
import type { EditorHost } from '@blocksuite/affine/block-std'; import type { EditorHost } from '@blocksuite/affine/block-std';
import { assertExists } from '@blocksuite/affine/global/utils';
import { import {
AFFINE_AI_PANEL_WIDGET, AFFINE_AI_PANEL_WIDGET,
@@ -8,9 +7,10 @@ import {
export const getAIPanelWidget = (host: EditorHost): AffineAIPanelWidget => { export const getAIPanelWidget = (host: EditorHost): AffineAIPanelWidget => {
const rootBlockId = host.doc.root?.id; 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); const aiPanel = host.view.getWidget(AFFINE_AI_PANEL_WIDGET, rootBlockId);
assertExists(aiPanel);
if (!(aiPanel instanceof AffineAIPanelWidget)) { if (!(aiPanel instanceof AffineAIPanelWidget)) {
throw new Error('AI panel not found'); throw new Error('AI panel not found');
} }
@@ -3,7 +3,6 @@ import {
type EdgelessRootService, type EdgelessRootService,
SurfaceBlockComponent, SurfaceBlockComponent,
} from '@blocksuite/affine/blocks'; } from '@blocksuite/affine/blocks';
import { assertExists } from '@blocksuite/affine/global/utils';
export const getConnectorFromId = ( export const getConnectorFromId = (
id: string, id: string,
@@ -68,7 +67,9 @@ export const findTree = (
}; };
}; };
const tree = run(rootId); const tree = run(rootId);
assertExists(tree); if (!tree) {
throw new Error('tree is not found');
}
return tree; return tree;
}; };
export const findLeaf = ( export const findLeaf = (
@@ -1,5 +1,4 @@
import { FetchUtils } from '@blocksuite/affine/blocks'; import { FetchUtils } from '@blocksuite/affine/blocks';
import { assertExists } from '@blocksuite/affine/global/utils';
export async function fetchImageToFile( export async function fetchImageToFile(
url: string, url: string,
@@ -26,14 +25,17 @@ function fetchImageFallback(
url: string, url: string,
filename: string filename: string
): Promise<File | void> { ): Promise<File | void> {
return new Promise(resolve => { return new Promise((resolve, reject) => {
const img = new Image(); const img = new Image();
img.onload = () => { img.onload = () => {
const c = document.createElement('canvas'); const c = document.createElement('canvas');
c.width = img.width; c.width = img.width;
c.height = img.height; c.height = img.height;
const ctx = c.getContext('2d'); const ctx = c.getContext('2d');
assertExists(ctx); if (!ctx) {
reject();
return;
}
ctx.imageSmoothingEnabled = true; ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = 'high'; ctx.imageSmoothingQuality = 'high';
ctx.drawImage(img, 0, 0); ctx.drawImage(img, 0, 0);
@@ -51,7 +53,7 @@ function fetchImageFallback(
} }
function convertToPng(blob: Blob): Promise<Blob | null> { function convertToPng(blob: Blob): Promise<Blob | null> {
return new Promise(resolve => { return new Promise((resolve, reject) => {
const reader = new FileReader(); const reader = new FileReader();
reader.addEventListener('load', _ => { reader.addEventListener('load', _ => {
const img = new Image(); const img = new Image();
@@ -60,7 +62,10 @@ function convertToPng(blob: Blob): Promise<Blob | null> {
c.width = img.width; c.width = img.width;
c.height = img.height; c.height = img.height;
const ctx = c.getContext('2d'); const ctx = c.getContext('2d');
assertExists(ctx); if (!ctx) {
reject();
return;
}
ctx.imageSmoothingEnabled = true; ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = 'high'; ctx.imageSmoothingQuality = 'high';
ctx.drawImage(img, 0, 0); ctx.drawImage(img, 0, 0);
@@ -6,11 +6,12 @@ import {
TemplateMiddlewares, TemplateMiddlewares,
} from '@blocksuite/affine/blocks'; } from '@blocksuite/affine/blocks';
import { Bound, getCommonBound } from '@blocksuite/affine/global/gfx'; import { Bound, getCommonBound } from '@blocksuite/affine/global/gfx';
import { assertExists } from '@blocksuite/affine/global/utils';
export function createTemplateJob(host: EditorHost) { export function createTemplateJob(host: EditorHost) {
const surface = getSurfaceBlock(host.doc); const surface = getSurfaceBlock(host.doc);
assertExists(surface); if (!surface) {
throw new Error('surface is not found');
}
const middlewares: ((job: TemplateJob) => void)[] = []; const middlewares: ((job: TemplateJob) => void)[] = [];
const layer = new LayerManager(host.doc, surface, { const layer = new LayerManager(host.doc, surface, {
@@ -13,7 +13,6 @@ import {
stopPropagation, stopPropagation,
ThemeProvider, ThemeProvider,
} from '@blocksuite/affine/blocks'; } from '@blocksuite/affine/blocks';
import { assertExists } from '@blocksuite/affine/global/utils';
import type { BaseSelection } from '@blocksuite/affine/store'; import type { BaseSelection } from '@blocksuite/affine/store';
import { import {
autoPlacement, autoPlacement,
@@ -176,10 +175,16 @@ export class AffineAIPanelWidget extends WidgetComponent {
generate = () => { generate = () => {
this.restoreSelection(); this.restoreSelection();
assertExists(this.config);
const text = this._inputText; const text = this._inputText;
assertExists(text); if (!this.config) {
assertExists(this.config.generateAnswer); 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(); this._resetAbortController();
@@ -193,7 +198,9 @@ export class AffineAIPanelWidget extends WidgetComponent {
const finish = (type: 'success' | 'error' | 'aborted', err?: AIError) => { const finish = (type: 'success' | 'error' | 'aborted', err?: AIError) => {
if (type === 'aborted') return; if (type === 'aborted') return;
assertExists(this.config); if (!this.config) {
throw new Error('config is not found when finish');
}
if (type === 'error') { if (type === 'error') {
this.state = 'error'; this.state = 'error';
this.config.errorStateConfig.error = err; this.config.errorStateConfig.error = err;
@@ -1,5 +1,4 @@
import { apis } from '@affine/electron-api'; import { apis } from '@affine/electron-api';
import { assertExists } from '@blocksuite/affine/global/utils';
import type { AppConfigSchema } from '@toeverything/infra'; import type { AppConfigSchema } from '@toeverything/infra';
import { AppConfigStorage, defaultAppConfig } from '@toeverything/infra'; import { AppConfigStorage, defaultAppConfig } from '@toeverything/infra';
import type { Dispatch } from 'react'; import type { Dispatch } from 'react';
@@ -12,12 +11,16 @@ class AppConfigProxy {
value: AppConfigSchema = defaultAppConfig; value: AppConfigSchema = defaultAppConfig;
async getSync(): Promise<AppConfigSchema> { async getSync(): Promise<AppConfigSchema> {
assertExists(apis); if (!apis) {
throw new Error('electron apis is not found');
}
return (this.value = await apis.configStorage.get()); return (this.value = await apis.configStorage.get());
} }
async setSync(): Promise<void> { async setSync(): Promise<void> {
assertExists(apis); if (!apis) {
throw new Error('electron apis is not found');
}
await apis.configStorage.set(this.value); await apis.configStorage.set(this.value);
} }

Some files were not shown because too many files have changed in this diff Show More