diff --git a/blocksuite/affine/block-latex/src/commands.ts b/blocksuite/affine/block-latex/src/commands.ts index 5bd02cb05a..d30a27a1c3 100644 --- a/blocksuite/affine/block-latex/src/commands.ts +++ b/blocksuite/affine/block-latex/src/commands.ts @@ -1,6 +1,5 @@ import type { LatexProps } from '@blocksuite/affine-model'; import type { Command } from '@blocksuite/block-std'; -import { assertInstanceOf } from '@blocksuite/global/utils'; import type { BlockModel } from '@blocksuite/store'; import { LatexBlockComponent } from './latex-block.js'; @@ -46,9 +45,10 @@ export const insertLatexBlockCommand: Command< insertedLatexBlockId: std.host.updateComplete.then(async () => { if (!latex) { const blockComponent = std.view.getBlock(result[0]); - assertInstanceOf(blockComponent, LatexBlockComponent); - await blockComponent.updateComplete; - blockComponent.toggleEditor(); + if (blockComponent instanceof LatexBlockComponent) { + await blockComponent.updateComplete; + blockComponent.toggleEditor(); + } } return result[0]; }), diff --git a/blocksuite/affine/block-root/src/edgeless/components/auto-complete/auto-complete-panel.ts b/blocksuite/affine/block-root/src/edgeless/components/auto-complete/auto-complete-panel.ts index 6e9097ae51..77290877c3 100644 --- a/blocksuite/affine/block-root/src/edgeless/components/auto-complete/auto-complete-panel.ts +++ b/blocksuite/affine/block-root/src/edgeless/components/auto-complete/auto-complete-panel.ts @@ -26,7 +26,10 @@ import { FeatureFlagService, ThemeProvider, } from '@blocksuite/affine-shared/services'; -import { captureEventTarget } from '@blocksuite/affine-shared/utils'; +import { + captureEventTarget, + matchModels, +} from '@blocksuite/affine-shared/utils'; import { type BlockStdScope, stdContext } from '@blocksuite/block-std'; import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx'; import type { XYWH } from '@blocksuite/global/gfx'; @@ -38,7 +41,7 @@ import { toDegree, Vec, } from '@blocksuite/global/gfx'; -import { assertInstanceOf, WithDisposable } from '@blocksuite/global/utils'; +import { WithDisposable } from '@blocksuite/global/utils'; import { FrameIcon, PageIcon } from '@blocksuite/icons/lit'; import { consume } from '@lit/context'; import { baseTheme } from '@toeverything/theme'; @@ -192,7 +195,9 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) { doc.root?.id ); const note = doc.getBlock(id)?.model; - assertInstanceOf(note, NoteBlockModel); + if (!matchModels(note, [NoteBlockModel])) { + return; + } doc.addBlock('affine:paragraph', { type: 'text' }, id); const group = this.currentSource.group; @@ -285,7 +290,9 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) { }); if (!textId) return; const textElement = this.crud.getElementById(textId); - assertInstanceOf(textElement, TextElementModel); + if (!(textElement instanceof TextElementModel)) { + return; + } this.crud.updateElement(this.connector.id, { target: { id: textId, position }, diff --git a/blocksuite/affine/block-root/src/edgeless/components/toolbar/mindmap/basket-elements.ts b/blocksuite/affine/block-root/src/edgeless/components/toolbar/mindmap/basket-elements.ts index bb549e0a0c..3b39549578 100644 --- a/blocksuite/affine/block-root/src/edgeless/components/toolbar/mindmap/basket-elements.ts +++ b/blocksuite/affine/block-root/src/edgeless/components/toolbar/mindmap/basket-elements.ts @@ -13,7 +13,6 @@ import { } from '@blocksuite/affine-shared/services'; import { openFileOrFiles } from '@blocksuite/affine-shared/utils'; import { Bound } from '@blocksuite/global/gfx'; -import { assertInstanceOf } from '@blocksuite/global/utils'; import type { TemplateResult } from 'lit'; import * as Y from 'yjs'; @@ -143,7 +142,10 @@ export const textRender: DraggableTool['render'] = async ( edgeless.doc.captureSync(); const textElement = edgeless.service.crud.getElementById(id); - assertInstanceOf(textElement, TextElementModel); + if (!(textElement instanceof TextElementModel)) { + console.error('Cannot mount text editor on a non-text element'); + return null; + } mountTextElementEditor(textElement, edgeless); } diff --git a/blocksuite/affine/block-root/src/edgeless/utils/text.ts b/blocksuite/affine/block-root/src/edgeless/utils/text.ts index 38dceb771c..a4b18a9509 100644 --- a/blocksuite/affine/block-root/src/edgeless/utils/text.ts +++ b/blocksuite/affine/block-root/src/edgeless/utils/text.ts @@ -14,7 +14,6 @@ import type { PointerEventState } from '@blocksuite/block-std'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; import type { IVec } from '@blocksuite/global/gfx'; import { Bound } from '@blocksuite/global/gfx'; -import { assertInstanceOf } from '@blocksuite/global/utils'; import * as Y from 'yjs'; import { EdgelessConnectorLabelEditor } from '../components/text/edgeless-connector-label-editor.js'; @@ -82,11 +81,10 @@ export function mountShapeTextEditor( const updatedElement = edgeless.service.crud.getElementById(shapeElement.id); - assertInstanceOf( - updatedElement, - ShapeElementModel, - 'Cannot mount text editor on a non-shape element' - ); + if (!(updatedElement instanceof ShapeElementModel)) { + console.error('Cannot mount text editor on a non-shape element'); + return; + } const shapeEditor = new EdgelessShapeTextEditor(); shapeEditor.element = updatedElement; diff --git a/blocksuite/affine/block-root/src/widgets/page-dragging-area/page-dragging-area.ts b/blocksuite/affine/block-root/src/widgets/page-dragging-area/page-dragging-area.ts index 5a68c08e58..8cd24e00f8 100644 --- a/blocksuite/affine/block-root/src/widgets/page-dragging-area/page-dragging-area.ts +++ b/blocksuite/affine/block-root/src/widgets/page-dragging-area/page-dragging-area.ts @@ -11,7 +11,6 @@ import { type PointerEventState, WidgetComponent, } from '@blocksuite/block-std'; -import { assertInstanceOf } from '@blocksuite/global/utils'; import { html, nothing } from 'lit'; import { state } from 'lit/decorators.js'; import { styleMap } from 'lit/directives/style-map.js'; @@ -443,9 +442,14 @@ function getSelectingBlockPaths(blockInfos: BlockInfo[], userRect: Rect) { function isDragArea(e: PointerEventState) { const el = e.raw.target; - assertInstanceOf(el, Element); + if (!(el instanceof Element)) { + return false; + } const block = el.closest(`[${BLOCK_ID_ATTR}]`); - return block && matchModels(block.model, [RootBlockModel, NoteBlockModel]); + if (!block) { + return false; + } + return matchModels(block.model, [RootBlockModel, NoteBlockModel]); } declare global { diff --git a/blocksuite/affine/block-surface/src/managers/connector-manager.ts b/blocksuite/affine/block-surface/src/managers/connector-manager.ts index fb77b4a3d2..91adad08a3 100644 --- a/blocksuite/affine/block-surface/src/managers/connector-manager.ts +++ b/blocksuite/affine/block-surface/src/managers/connector-manager.ts @@ -32,7 +32,7 @@ import { toRadian, Vec, } from '@blocksuite/global/gfx'; -import { assertEquals, assertType, last } from '@blocksuite/global/utils'; +import { assertType, last } from '@blocksuite/global/utils'; import { effect } from '@preact/signals-core'; import { Overlay } from '../renderer/overlay.js'; @@ -606,13 +606,10 @@ function mergePath(points: IVec[] | IVec3[]) { for (let i = 0; i < result.length - 1; i++) { const cur = result[i]; const next = result[i + 1]; - try { - assertEquals( - almostEqual(cur[0], next[0], 0.02) || - almostEqual(cur[1], next[1], 0.02), - true - ); - } catch { + const isAlmostEqual = + almostEqual(cur[0], next[0], 0.02) || almostEqual(cur[1], next[1], 0.02); + if (!isAlmostEqual) { + console.warn('Expected equal points'); console.warn(points); console.warn(result); } diff --git a/blocksuite/affine/data-view/src/view-presets/table/pc/controller/drag-to-fill.ts b/blocksuite/affine/data-view/src/view-presets/table/pc/controller/drag-to-fill.ts index 6799584ed1..3cc21fffc4 100644 --- a/blocksuite/affine/data-view/src/view-presets/table/pc/controller/drag-to-fill.ts +++ b/blocksuite/affine/data-view/src/view-presets/table/pc/controller/drag-to-fill.ts @@ -1,5 +1,5 @@ import { ShadowlessElement } from '@blocksuite/block-std'; -import { assertEquals } from '@blocksuite/global/utils'; +import { isEqual } from '@blocksuite/global/utils'; import { type Text } from '@blocksuite/store'; import { css, html } from 'lit'; import { state } from 'lit/decorators.js'; @@ -63,11 +63,10 @@ export function fillSelectionWithFocusCellData( if (!focusCell) return; if (rowsSelection && columnsSelection) { - assertEquals( - columnsSelection.start, - columnsSelection.end, - 'expected selections on a single column' - ); + if (!isEqual(columnsSelection.start, columnsSelection.end)) { + console.error('expected selections on a single column'); + return; + } const curCol = focusCell.column; // we are sure that we are always in the same column while iterating through rows const cell = focusCell.cell$.value; diff --git a/blocksuite/affine/shared/src/utils/model/checker.ts b/blocksuite/affine/shared/src/utils/model/checker.ts index 4509712684..147268d6f3 100644 --- a/blocksuite/affine/shared/src/utils/model/checker.ts +++ b/blocksuite/affine/shared/src/utils/model/checker.ts @@ -11,10 +11,11 @@ type ModelList = export function matchModels< const Model extends ConstructorType[], U extends ModelList[number] = ModelList[number], ->(model: BlockModel | null, expected: Model): model is U { - return ( - !!model && expected.some(expectedModel => model instanceof expectedModel) - ); +>(model: BlockModel | null | undefined, expected: Model): model is U { + if (model === null || model === undefined) { + return false; + } + return expected.some(expectedModel => model instanceof expectedModel); } export function isInsideBlockByFlavour( diff --git a/blocksuite/framework/global/src/utils/index.ts b/blocksuite/framework/global/src/utils/index.ts index fed9102456..004cfaa694 100644 --- a/blocksuite/framework/global/src/utils/index.ts +++ b/blocksuite/framework/global/src/utils/index.ts @@ -1,7 +1,7 @@ -export * from './assert.js'; export * from './crypto.js'; export * from './disposable.js'; export * from './function.js'; +export * from './is-equal.js'; export * from './iterable.js'; export * from './logger.js'; export * from './signal-watcher.js'; diff --git a/blocksuite/framework/global/src/utils/assert.ts b/blocksuite/framework/global/src/utils/is-equal.ts similarity index 60% rename from blocksuite/framework/global/src/utils/assert.ts rename to blocksuite/framework/global/src/utils/is-equal.ts index 84fad2e05e..ef61a8de9b 100644 --- a/blocksuite/framework/global/src/utils/assert.ts +++ b/blocksuite/framework/global/src/utils/is-equal.ts @@ -1,7 +1,4 @@ // https://stackoverflow.com/questions/31538010/test-if-a-variable-is-a-primitive-rather-than-an-object -import { ErrorCode } from '../exceptions/code.js'; -import { BlockSuiteError } from '../exceptions/index.js'; - export function isPrimitive( a: unknown ): a is null | undefined | boolean | number | string { @@ -10,16 +7,6 @@ export function isPrimitive( export function assertType(_: unknown): asserts _ is T {} -export function assertNotExists( - val: T | null | undefined, - message = 'val exists', - errorCode = ErrorCode.ValueNotExists -): asserts val is null | undefined { - if (val !== null && val !== undefined) { - throw new BlockSuiteError(errorCode, message); - } -} - export type Equals = /// (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 @@ -65,26 +52,3 @@ export function isEqual( } return true as Equals; } -export function assertEquals( - val: T, - expected: U, - message = 'val is not same as expected', - errorCode = ErrorCode.ValueNotEqual -): asserts val is U { - if (!isEqual(val, expected)) { - throw new BlockSuiteError(errorCode, message); - } -} - -type Class = new (...args: any[]) => T; - -export function assertInstanceOf( - val: unknown, - expected: Class, - message = 'val is not instance of expected', - errorCode = ErrorCode.ValueNotInstanceOf -): asserts val is T { - if (!(val instanceof expected)) { - throw new BlockSuiteError(errorCode, message); - } -} diff --git a/blocksuite/framework/inline/src/services/range.ts b/blocksuite/framework/inline/src/services/range.ts index 932dcc9a82..b8cdedd7cb 100644 --- a/blocksuite/framework/inline/src/services/range.ts +++ b/blocksuite/framework/inline/src/services/range.ts @@ -1,4 +1,3 @@ -import { assertInstanceOf } from '@blocksuite/global/utils'; import { effect } from '@preact/signals-core'; import * as Y from 'yjs'; @@ -47,7 +46,9 @@ export class RangeService { return null; } const textNode = text.childNodes[1]; - assertInstanceOf(textNode, Text); + if (!(textNode instanceof Text)) { + return null; + } range.setStart(textNode, 0); range.setEnd(textNode, textNode.textContent?.length ?? 0); const inlineRange = this.toInlineRange(range); diff --git a/blocksuite/integration-test/vitest.config.ts b/blocksuite/integration-test/vitest.config.ts index 875d8ad4f6..07aeaa76cb 100644 --- a/blocksuite/integration-test/vitest.config.ts +++ b/blocksuite/integration-test/vitest.config.ts @@ -33,7 +33,7 @@ export default defineConfig(_configEnv => coverage: { provider: 'istanbul', // or 'c8' reporter: ['lcov'], - reportsDirectory: '../../.coverage/presets', + reportsDirectory: '../../.coverage/integration-test', }, deps: { interopDefault: true, diff --git a/blocksuite/tests-legacy/e2e/edgeless/linked-doc.spec.ts b/blocksuite/tests-legacy/e2e/edgeless/linked-doc.spec.ts index 249f26fc7a..a50f2b3bfe 100644 --- a/blocksuite/tests-legacy/e2e/edgeless/linked-doc.spec.ts +++ b/blocksuite/tests-legacy/e2e/edgeless/linked-doc.spec.ts @@ -1,4 +1,3 @@ -import { assertNotExists } from '@blocksuite/global/utils'; import { expect } from '@playwright/test'; import { @@ -90,7 +89,7 @@ test.describe('note to linked doc', () => { const moreButton = locatorComponentToolbarMoreButton(page); await moreButton.click(); const turnButton = page.locator('.turn-into-linked-doc'); - assertNotExists(turnButton); + expect(turnButton).toBeNull(); }); // TODO FIX ME @@ -111,7 +110,7 @@ test.describe('note to linked doc', () => { const moreButton = locatorComponentToolbarMoreButton(page); await moreButton.click(); const turnButton = page.locator('.turn-into-linked-doc'); - assertNotExists(turnButton); + expect(turnButton).toBeNull(); }); }); diff --git a/eslint.config.mjs b/eslint.config.mjs index fb1deee2f6..7e8b7d6bf5 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -188,11 +188,6 @@ export default tseslint.config( message: "Don't import from src", allowTypeImports: false, }, - { - group: ['@blocksuite/store'], - message: "Import from '@blocksuite/global/utils'", - importNames: ['assertEquals'], - }, ], }, ], diff --git a/packages/frontend/core/src/components/affine/page-history-modal/data.ts b/packages/frontend/core/src/components/affine/page-history-modal/data.ts index ad2a6ea758..0000f593b3 100644 --- a/packages/frontend/core/src/components/affine/page-history-modal/data.ts +++ b/packages/frontend/core/src/components/affine/page-history-modal/data.ts @@ -11,7 +11,6 @@ import { DebugLogger } from '@affine/debug'; import type { ListHistoryQuery } from '@affine/graphql'; import { listHistoryQuery, recoverDocMutation } from '@affine/graphql'; import { i18nTime } from '@affine/i18n'; -import { assertEquals } from '@blocksuite/affine/global/utils'; import type { Workspace } from '@blocksuite/affine/store'; import { useService } from '@toeverything/infra'; import { useEffect, useMemo } from 'react'; @@ -291,7 +290,9 @@ export const useRestorePage = (docCollection: Workspace, pageId: string) => { } const pageDocId = page.spaceDoc.guid; revertUpdate(page.spaceDoc, update, key => { - assertEquals(key, 'blocks'); // only expect this value is 'blocks' + if (key !== 'blocks') { + throw new Error('Only expect this value is "blocks"'); + } return 'Map'; }); diff --git a/packages/frontend/core/src/modules/workspace/services/transform.ts b/packages/frontend/core/src/modules/workspace/services/transform.ts index 3588963396..ed26e4d750 100644 --- a/packages/frontend/core/src/modules/workspace/services/transform.ts +++ b/packages/frontend/core/src/modules/workspace/services/transform.ts @@ -1,4 +1,3 @@ -import { assertEquals } from '@blocksuite/affine/global/utils'; import { Service } from '@toeverything/infra'; import { applyUpdate } from 'yjs'; @@ -26,7 +25,11 @@ export class WorkspaceTransformService extends Service { accountId: string, flavour: string ): Promise => { - assertEquals(local.flavour, 'local'); + if (local.flavour !== 'local') { + throw new Error( + 'Only local workspace can be transformed to cloud workspace' + ); + } const localDocStorage = local.engine.doc.storage; const localDocList = Array.from(local.docCollection.docs.keys()); diff --git a/packages/frontend/core/src/utils/toast.ts b/packages/frontend/core/src/utils/toast.ts index d07e485ac3..16c1a3682c 100644 --- a/packages/frontend/core/src/utils/toast.ts +++ b/packages/frontend/core/src/utils/toast.ts @@ -1,13 +1,10 @@ import type { ToastOptions } from '@affine/component'; import { toast as basicToast } from '@affine/component'; -import { assertEquals } from '@blocksuite/affine/global/utils'; export const toast = (message: string, options?: ToastOptions) => { - const modal = document.querySelector( - '[role=presentation]' - ) as HTMLDivElement | null; - if (modal) { - assertEquals(modal.constructor, HTMLDivElement, 'modal should be div'); + const modal = document.querySelector('[role=presentation]'); + if (modal && !(modal instanceof HTMLDivElement)) { + throw new Error('modal should be div'); } return basicToast(message, { portal: modal || document.body,