mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-13 08:06:24 +08:00
refactor(editor): remove dependency of command global types (#9903)
Closes: [BS-2216](https://linear.app/affine-design/issue/BS-2216/remove-global-types-in-command)
This commit is contained in:
@@ -4,33 +4,15 @@ import type { Command } from '../command/index.js';
|
||||
import { CommandManager } from '../command/index.js';
|
||||
|
||||
type Command1 = Command<
|
||||
never,
|
||||
'commandData1',
|
||||
{
|
||||
command1Option?: string;
|
||||
},
|
||||
{
|
||||
commandData1: string;
|
||||
}
|
||||
>;
|
||||
|
||||
type Command2 = Command<'commandData1', 'commandData2'>;
|
||||
|
||||
type Command3 = Command<'commandData1' | 'commandData2', 'commandData3'>;
|
||||
|
||||
declare global {
|
||||
namespace BlockSuite {
|
||||
interface CommandContext {
|
||||
commandData1?: string;
|
||||
commandData2?: string;
|
||||
commandData3?: string;
|
||||
}
|
||||
|
||||
interface Commands {
|
||||
command1: Command1;
|
||||
command2: Command2;
|
||||
command3: Command3;
|
||||
command4: Command;
|
||||
}
|
||||
}
|
||||
}
|
||||
type Command2 = Command<{ commandData1: string }, { commandData2: string }>;
|
||||
|
||||
describe('CommandManager', () => {
|
||||
let std: BlockSuite.Std;
|
||||
@@ -43,13 +25,15 @@ describe('CommandManager', () => {
|
||||
});
|
||||
|
||||
test('can add and execute a command', () => {
|
||||
const command1: Command = vi.fn((_ctx, next) => next());
|
||||
const command2: Command = vi.fn((_ctx, _next) => {});
|
||||
commandManager.add('command1', command1);
|
||||
commandManager.add('command2', command2);
|
||||
const command1: Command1 = vi.fn((_ctx, next) => next());
|
||||
const command2: Command2 = vi.fn((_ctx, _next) => {});
|
||||
|
||||
const [success1] = commandManager.chain().command1().run();
|
||||
const [success2] = commandManager.chain().command2().run();
|
||||
const [success1] = commandManager.chain().pipe(command1, {}).run();
|
||||
const [success2] = commandManager
|
||||
.chain()
|
||||
.pipe(command1, {})
|
||||
.pipe(command2)
|
||||
.run();
|
||||
|
||||
expect(command1).toHaveBeenCalled();
|
||||
expect(command2).toHaveBeenCalled();
|
||||
@@ -62,15 +46,11 @@ describe('CommandManager', () => {
|
||||
const command2: Command = vi.fn((_ctx, next) => next());
|
||||
const command3: Command = vi.fn((_ctx, next) => next());
|
||||
|
||||
commandManager.add('command1', command1);
|
||||
commandManager.add('command2', command2);
|
||||
commandManager.add('command3', command3);
|
||||
|
||||
const [success] = commandManager
|
||||
.chain()
|
||||
.command1()
|
||||
.command2()
|
||||
.command3()
|
||||
.pipe(command1)
|
||||
.pipe(command2)
|
||||
.pipe(command3)
|
||||
.run();
|
||||
|
||||
expect(command1).toHaveBeenCalled();
|
||||
@@ -84,15 +64,11 @@ describe('CommandManager', () => {
|
||||
const command2: Command = vi.fn((_ctx, _next) => {});
|
||||
const command3: Command = vi.fn((_ctx, next) => next());
|
||||
|
||||
commandManager.add('command1', command1);
|
||||
commandManager.add('command2', command2);
|
||||
commandManager.add('command3', command3);
|
||||
|
||||
const [success] = commandManager
|
||||
.chain()
|
||||
.command1()
|
||||
.command2()
|
||||
.command3()
|
||||
.pipe(command1)
|
||||
.pipe(command2)
|
||||
.pipe(command3)
|
||||
.run();
|
||||
|
||||
expect(command1).toHaveBeenCalled();
|
||||
@@ -110,15 +86,11 @@ describe('CommandManager', () => {
|
||||
});
|
||||
const command3: Command = vi.fn((_ctx, next) => next());
|
||||
|
||||
commandManager.add('command1', command1);
|
||||
commandManager.add('command2', command2);
|
||||
commandManager.add('command3', command3);
|
||||
|
||||
const [success] = commandManager
|
||||
.chain()
|
||||
.command1()
|
||||
.command2()
|
||||
.command3()
|
||||
.pipe(command1)
|
||||
.pipe(command2)
|
||||
.pipe(command3)
|
||||
.run();
|
||||
|
||||
expect(command1).toHaveBeenCalled();
|
||||
@@ -129,13 +101,11 @@ describe('CommandManager', () => {
|
||||
});
|
||||
|
||||
test('can pass data to command when calling a command', () => {
|
||||
const command1: Command = vi.fn((_ctx, next) => next());
|
||||
|
||||
commandManager.add('command1', command1);
|
||||
const command1: Command1 = vi.fn((_ctx, next) => next());
|
||||
|
||||
const [success] = commandManager
|
||||
.chain()
|
||||
.command1({ command1Option: 'test' })
|
||||
.pipe(command1, { command1Option: 'test' })
|
||||
.run();
|
||||
|
||||
expect(command1).toHaveBeenCalledWith(
|
||||
@@ -146,14 +116,14 @@ describe('CommandManager', () => {
|
||||
});
|
||||
|
||||
test('can add data to the command chain with `with` method', () => {
|
||||
const command1: Command = vi.fn((_ctx, next) => next());
|
||||
|
||||
commandManager.add('command1', command1);
|
||||
const command1: Command<{ commandData1: string }> = vi.fn((_ctx, next) =>
|
||||
next()
|
||||
);
|
||||
|
||||
const [success, ctx] = commandManager
|
||||
.chain()
|
||||
.with({ commandData1: 'test' })
|
||||
.command1()
|
||||
.pipe(command1)
|
||||
.run();
|
||||
|
||||
expect(command1).toHaveBeenCalledWith(
|
||||
@@ -165,18 +135,19 @@ describe('CommandManager', () => {
|
||||
});
|
||||
|
||||
test('passes and updates context across commands', () => {
|
||||
const command1: Command<'std', 'commandData1'> = vi.fn((_ctx, next) =>
|
||||
next({ commandData1: '123' })
|
||||
const command1: Command<{}, { commandData1: string }> = vi.fn(
|
||||
(_ctx, next) => next({ commandData1: '123' })
|
||||
);
|
||||
const command2: Command<'commandData1'> = vi.fn((ctx, next) => {
|
||||
const command2: Command<{ commandData1: string }> = vi.fn((ctx, next) => {
|
||||
expect(ctx.commandData1).toBe('123');
|
||||
next({ commandData1: '456' });
|
||||
});
|
||||
|
||||
commandManager.add('command1', command1);
|
||||
commandManager.add('command2', command2);
|
||||
|
||||
const [success, ctx] = commandManager.chain().command1().command2().run();
|
||||
const [success, ctx] = commandManager
|
||||
.chain()
|
||||
.pipe(command1)
|
||||
.pipe(command2)
|
||||
.run();
|
||||
|
||||
expect(command1).toHaveBeenCalled();
|
||||
expect(command2).toHaveBeenCalled();
|
||||
@@ -184,57 +155,15 @@ describe('CommandManager', () => {
|
||||
expect(ctx.commandData1).toBe('456');
|
||||
});
|
||||
|
||||
test('can execute an inline command', () => {
|
||||
const inlineCommand: Command = vi.fn((_ctx, next) => next());
|
||||
|
||||
const success = commandManager.chain().inline(inlineCommand).run();
|
||||
|
||||
expect(inlineCommand).toHaveBeenCalled();
|
||||
expect(success).toBeTruthy();
|
||||
});
|
||||
|
||||
test('can execute a single command with `exec`', () => {
|
||||
const command1: Command1 = vi.fn((_ctx, next) =>
|
||||
next({ commandData1: (_ctx.command1Option ?? '') + '123' })
|
||||
);
|
||||
const command2: Command2 = vi.fn((_ctx, next) =>
|
||||
next({ commandData2: 'cmd2' })
|
||||
);
|
||||
const command3: Command3 = vi.fn((_ctx, next) => next());
|
||||
|
||||
commandManager.add('command1', command1);
|
||||
commandManager.add('command2', command2);
|
||||
commandManager.add('command3', command3);
|
||||
|
||||
const result1 = commandManager.exec('command1');
|
||||
const result2 = commandManager.exec('command1', {
|
||||
command1Option: 'test',
|
||||
});
|
||||
const result3 = commandManager.exec('command2');
|
||||
const result4 = commandManager.exec('command3');
|
||||
|
||||
expect(command1).toHaveBeenCalled();
|
||||
expect(command2).toHaveBeenCalled();
|
||||
expect(command3).toHaveBeenCalled();
|
||||
expect(result1).toEqual({ commandData1: '123', success: true });
|
||||
expect(result2).toEqual({ commandData1: 'test123', success: true });
|
||||
expect(result3).toEqual({ commandData2: 'cmd2', success: true });
|
||||
expect(result4).toEqual({ success: true });
|
||||
});
|
||||
|
||||
test('should not continue with the rest of the chain if all commands in `try` fail', () => {
|
||||
const command1: Command<never, 'commandData1'> = vi.fn((_ctx, _next) => {});
|
||||
const command1: Command = vi.fn((_ctx, _next) => {});
|
||||
const command2: Command = vi.fn((_ctx, _next) => {});
|
||||
const command3: Command = vi.fn((_ctx, next) => next());
|
||||
|
||||
commandManager.add('command1', command1);
|
||||
commandManager.add('command2', command2);
|
||||
commandManager.add('command3', command3);
|
||||
|
||||
const [success] = commandManager
|
||||
.chain()
|
||||
.try(cmd => [cmd.command1(), cmd.command2()])
|
||||
.command3()
|
||||
.try(chain => [chain.pipe(command1), chain.pipe(command2)])
|
||||
.pipe(command3)
|
||||
.run();
|
||||
|
||||
expect(command1).toHaveBeenCalled();
|
||||
@@ -244,20 +173,16 @@ describe('CommandManager', () => {
|
||||
});
|
||||
|
||||
test('should not re-execute previous commands in the chain before `try`', () => {
|
||||
const command1: Command1 = vi.fn((_ctx, next) =>
|
||||
next({ commandData1: '123' })
|
||||
const command1: Command<{}, { commandData1: string }> = vi.fn(
|
||||
(_ctx, next) => next({ commandData1: '123' })
|
||||
);
|
||||
const command2: Command = vi.fn((_ctx, _next) => {});
|
||||
const command3: Command = vi.fn((_ctx, next) => next());
|
||||
|
||||
commandManager.add('command1', command1);
|
||||
commandManager.add('command2', command2);
|
||||
commandManager.add('command3', command3);
|
||||
|
||||
const [success, ctx] = commandManager
|
||||
.chain()
|
||||
.command1()
|
||||
.try(cmd => [cmd.command2(), cmd.command3()])
|
||||
.pipe(command1)
|
||||
.try(chain => [chain.pipe(command2), chain.pipe(command3)])
|
||||
.run();
|
||||
|
||||
expect(command1).toHaveBeenCalledTimes(1);
|
||||
@@ -268,22 +193,22 @@ describe('CommandManager', () => {
|
||||
});
|
||||
|
||||
test('should continue with the rest of the chain if one command in `try` succeeds', () => {
|
||||
const command1: Command1 = vi.fn((_ctx, _next) => {});
|
||||
const command2: Command2 = vi.fn((_ctx, next) =>
|
||||
next({ commandData2: '123' })
|
||||
const command1: Command<
|
||||
{},
|
||||
{ commandData1?: string; commandData2?: string }
|
||||
> = vi.fn((_ctx, _next) => {});
|
||||
const command2: Command<
|
||||
{},
|
||||
{ commandData1?: string; commandData2?: string }
|
||||
> = vi.fn((_ctx, next) => next({ commandData2: '123' }));
|
||||
const command3: Command<{}, { commandData3: string }> = vi.fn(
|
||||
(_ctx, next) => next({ commandData3: '456' })
|
||||
);
|
||||
const command3: Command3 = vi.fn((_ctx, next) =>
|
||||
next({ commandData3: '456' })
|
||||
);
|
||||
|
||||
commandManager.add('command1', command1);
|
||||
commandManager.add('command2', command2);
|
||||
commandManager.add('command3', command3);
|
||||
|
||||
const [success, ctx] = commandManager
|
||||
.chain()
|
||||
.try(cmd => [cmd.command1(), cmd.command2()])
|
||||
.command3()
|
||||
.try(chain => [chain.pipe(command1), chain.pipe(command2)])
|
||||
.pipe(command3)
|
||||
.run();
|
||||
|
||||
expect(command1).toHaveBeenCalled();
|
||||
@@ -296,19 +221,18 @@ describe('CommandManager', () => {
|
||||
});
|
||||
|
||||
test('should not execute any further commands in `try` after one succeeds', () => {
|
||||
const command1: Command1 = vi.fn((_ctx, next) =>
|
||||
next({ commandData1: '123' })
|
||||
);
|
||||
const command2: Command2 = vi.fn((_ctx, next) =>
|
||||
next({ commandData2: '456' })
|
||||
);
|
||||
|
||||
commandManager.add('command1', command1);
|
||||
commandManager.add('command2', command2);
|
||||
const command1: Command<
|
||||
{},
|
||||
{ commandData1?: string; commandData2?: string }
|
||||
> = vi.fn((_ctx, next) => next({ commandData1: '123' }));
|
||||
const command2: Command<
|
||||
{},
|
||||
{ commandData1?: string; commandData2?: string }
|
||||
> = vi.fn((_ctx, next) => next({ commandData2: '456' }));
|
||||
|
||||
const [success, ctx] = commandManager
|
||||
.chain()
|
||||
.try(cmd => [cmd.command1(), cmd.command2()])
|
||||
.try(chain => [chain.pipe(command1), chain.pipe(command2)])
|
||||
.run();
|
||||
|
||||
expect(command1).toHaveBeenCalled();
|
||||
@@ -322,31 +246,23 @@ describe('CommandManager', () => {
|
||||
const command1: Command = vi.fn((_ctx, next) =>
|
||||
next({ commandData1: 'fromCommand1', commandData2: 'fromCommand1' })
|
||||
);
|
||||
const command2: Command<'commandData1' | 'commandData2'> = vi.fn(
|
||||
(ctx, next) => {
|
||||
expect(ctx.commandData1).toBe('fromCommand1');
|
||||
expect(ctx.commandData2).toBe('fromCommand1');
|
||||
// override commandData2
|
||||
next({ commandData2: 'fromCommand2' });
|
||||
}
|
||||
);
|
||||
const command3: Command<'commandData1' | 'commandData2'> = vi.fn(
|
||||
(ctx, next) => {
|
||||
expect(ctx.commandData1).toBe('fromCommand1');
|
||||
expect(ctx.commandData2).toBe('fromCommand2');
|
||||
next();
|
||||
}
|
||||
);
|
||||
|
||||
commandManager.add('command1', command1);
|
||||
commandManager.add('command2', command2);
|
||||
commandManager.add('command3', command3);
|
||||
const command2: Command = vi.fn((ctx, next) => {
|
||||
expect(ctx.commandData1).toBe('fromCommand1');
|
||||
expect(ctx.commandData2).toBe('fromCommand1');
|
||||
// override commandData2
|
||||
next({ commandData2: 'fromCommand2' });
|
||||
});
|
||||
const command3: Command = vi.fn((ctx, next) => {
|
||||
expect(ctx.commandData1).toBe('fromCommand1');
|
||||
expect(ctx.commandData2).toBe('fromCommand2');
|
||||
next();
|
||||
});
|
||||
|
||||
const [success] = commandManager
|
||||
.chain()
|
||||
.command1()
|
||||
.try(cmd => [cmd.command2()])
|
||||
.command3()
|
||||
.pipe(command1)
|
||||
.try(chain => [chain.pipe(command2)])
|
||||
.pipe(command3)
|
||||
.run();
|
||||
|
||||
expect(command1).toHaveBeenCalled();
|
||||
@@ -360,14 +276,10 @@ describe('CommandManager', () => {
|
||||
const command2: Command = vi.fn((_ctx, next) => next());
|
||||
const command3: Command = vi.fn((_ctx, next) => next());
|
||||
|
||||
commandManager.add('command1', command1);
|
||||
commandManager.add('command2', command2);
|
||||
commandManager.add('command3', command3);
|
||||
|
||||
const [success] = commandManager
|
||||
.chain()
|
||||
.tryAll(cmd => [cmd.command1(), cmd.command2()])
|
||||
.command3()
|
||||
.tryAll(chain => [chain.pipe(command1), chain.pipe(command2)])
|
||||
.pipe(command3)
|
||||
.run();
|
||||
|
||||
expect(command1).toHaveBeenCalled();
|
||||
@@ -377,23 +289,26 @@ describe('CommandManager', () => {
|
||||
});
|
||||
|
||||
test('should execute all commands in `tryAll` even if one has already succeeded', () => {
|
||||
const command1: Command1 = vi.fn((_ctx, next) =>
|
||||
next({ commandData1: '123' })
|
||||
);
|
||||
const command2: Command2 = vi.fn((_ctx, next) =>
|
||||
next({ commandData2: '456' })
|
||||
);
|
||||
const command3: Command3 = vi.fn((_ctx, next) =>
|
||||
next({ commandData3: '789' })
|
||||
);
|
||||
|
||||
commandManager.add('command1', command1);
|
||||
commandManager.add('command2', command2);
|
||||
commandManager.add('command3', command3);
|
||||
const command1: Command<
|
||||
{},
|
||||
{ commandData1?: string; commandData2?: string; commandData3?: string }
|
||||
> = vi.fn((_ctx, next) => next({ commandData1: '123' }));
|
||||
const command2: Command<
|
||||
{},
|
||||
{ commandData1?: string; commandData2?: string; commandData3?: string }
|
||||
> = vi.fn((_ctx, next) => next({ commandData2: '456' }));
|
||||
const command3: Command<
|
||||
{},
|
||||
{ commandData1?: string; commandData2?: string; commandData3?: string }
|
||||
> = vi.fn((_ctx, next) => next({ commandData3: '789' }));
|
||||
|
||||
const [success, ctx] = commandManager
|
||||
.chain()
|
||||
.tryAll(cmd => [cmd.command1(), cmd.command2(), cmd.command3()])
|
||||
.tryAll(chain => [
|
||||
chain.pipe(command1),
|
||||
chain.pipe(command2),
|
||||
chain.pipe(command3),
|
||||
])
|
||||
.run();
|
||||
|
||||
expect(command1).toHaveBeenCalled();
|
||||
@@ -406,20 +321,16 @@ describe('CommandManager', () => {
|
||||
});
|
||||
|
||||
test('should not continue with the rest of the chain if all commands in `tryAll` fail', () => {
|
||||
const command1: Command1 = vi.fn((_ctx, _next) => {});
|
||||
const command2: Command2 = vi.fn((_ctx, _next) => {});
|
||||
const command3: Command3 = vi.fn((_ctx, next) =>
|
||||
next({ commandData3: '123' })
|
||||
const command1: Command = vi.fn((_ctx, _next) => {});
|
||||
const command2: Command = vi.fn((_ctx, _next) => {});
|
||||
const command3: Command<{}, { commandData3: string }> = vi.fn(
|
||||
(_ctx, next) => next({ commandData3: '123' })
|
||||
);
|
||||
|
||||
commandManager.add('command1', command1);
|
||||
commandManager.add('command2', command2);
|
||||
commandManager.add('command3', command3);
|
||||
|
||||
const [success, ctx] = commandManager
|
||||
.chain()
|
||||
.tryAll(cmd => [cmd.command1(), cmd.command2()])
|
||||
.command3()
|
||||
.tryAll(chain => [chain.pipe(command1), chain.pipe(command2)])
|
||||
.pipe(command3)
|
||||
.run();
|
||||
|
||||
expect(command1).toHaveBeenCalled();
|
||||
@@ -430,43 +341,44 @@ describe('CommandManager', () => {
|
||||
});
|
||||
|
||||
test('should pass context correctly in `tryAll` when at least one command succeeds', () => {
|
||||
const command1: Command = vi.fn((_ctx, next) =>
|
||||
next({ commandData1: 'fromCommand1' })
|
||||
const command1: Command<{}, { commandData1: string }> = vi.fn(
|
||||
(_ctx, next) => next({ commandData1: 'fromCommand1' })
|
||||
);
|
||||
const command2: Command<'commandData1'> = vi.fn((ctx, next) => {
|
||||
const command2: Command<
|
||||
{ commandData1: string; commandData2?: string },
|
||||
{ commandData2: string; commandData3: string }
|
||||
> = vi.fn((ctx, next) => {
|
||||
expect(ctx.commandData1).toBe('fromCommand1');
|
||||
// override commandData1
|
||||
next({ commandData1: 'fromCommand2', commandData2: 'fromCommand2' });
|
||||
});
|
||||
const command3: Command<'commandData1' | 'commandData2'> = vi.fn(
|
||||
(ctx, next) => {
|
||||
expect(ctx.commandData1).toBe('fromCommand2');
|
||||
expect(ctx.commandData2).toBe('fromCommand2');
|
||||
next({
|
||||
// override commandData2
|
||||
commandData2: 'fromCommand3',
|
||||
commandData3: 'fromCommand3',
|
||||
});
|
||||
}
|
||||
);
|
||||
const command4: Command<'commandData1' | 'commandData2' | 'commandData3'> =
|
||||
vi.fn((ctx, next) => {
|
||||
expect(ctx.commandData1).toBe('fromCommand2');
|
||||
expect(ctx.commandData2).toBe('fromCommand3');
|
||||
expect(ctx.commandData3).toBe('fromCommand3');
|
||||
next();
|
||||
const command3: Command<
|
||||
{ commandData1: string; commandData2?: string },
|
||||
{ commandData2: string; commandData3: string }
|
||||
> = vi.fn((ctx, next) => {
|
||||
expect(ctx.commandData1).toBe('fromCommand2');
|
||||
expect(ctx.commandData2).toBe('fromCommand2');
|
||||
next({
|
||||
// override commandData2
|
||||
commandData2: 'fromCommand3',
|
||||
commandData3: 'fromCommand3',
|
||||
});
|
||||
|
||||
commandManager.add('command1', command1);
|
||||
commandManager.add('command2', command2);
|
||||
commandManager.add('command3', command3);
|
||||
commandManager.add('command4', command4);
|
||||
});
|
||||
const command4: Command<
|
||||
{ commandData1: string; commandData2: string; commandData3: string },
|
||||
{}
|
||||
> = vi.fn((ctx, next) => {
|
||||
expect(ctx.commandData1).toBe('fromCommand2');
|
||||
expect(ctx.commandData2).toBe('fromCommand3');
|
||||
expect(ctx.commandData3).toBe('fromCommand3');
|
||||
next();
|
||||
});
|
||||
|
||||
const [success, ctx] = commandManager
|
||||
.chain()
|
||||
.command1()
|
||||
.tryAll(cmd => [cmd.command2(), cmd.command3()])
|
||||
.command4()
|
||||
.pipe(command1)
|
||||
.tryAll(chain => [chain.pipe(command2), chain.pipe(command3)])
|
||||
.pipe(command4)
|
||||
.run();
|
||||
|
||||
expect(command1).toHaveBeenCalled();
|
||||
@@ -485,16 +397,11 @@ describe('CommandManager', () => {
|
||||
const command3: Command = vi.fn((_ctx, _next) => {});
|
||||
const command4: Command = vi.fn((_ctx, next) => next());
|
||||
|
||||
commandManager.add('command1', command1);
|
||||
commandManager.add('command2', command2);
|
||||
commandManager.add('command3', command3);
|
||||
commandManager.add('command4', command4);
|
||||
|
||||
const [success] = commandManager
|
||||
.chain()
|
||||
.command1()
|
||||
.tryAll(cmd => [cmd.command2(), cmd.command3()])
|
||||
.command4()
|
||||
.pipe(command1)
|
||||
.tryAll(chain => [chain.pipe(command2), chain.pipe(command3)])
|
||||
.pipe(command4)
|
||||
.run();
|
||||
|
||||
expect(command1).toHaveBeenCalledTimes(1);
|
||||
|
||||
Reference in New Issue
Block a user