mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-11 14:08:55 +08:00
refactor(infra): directory structure (#4615)
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
import type { CallbackMap } from '@affine/sdk/entry';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import { atomWithStorage } from 'jotai/utils';
|
||||
import { atom } from 'jotai/vanilla';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import type { packageJsonOutputSchema } from '../type.js';
|
||||
|
||||
export const builtinPluginPaths = new Set([
|
||||
'/plugins/copilot',
|
||||
'/plugins/hello-world',
|
||||
'/plugins/image-preview',
|
||||
'/plugins/vue-hello-world',
|
||||
'/plugins/outline',
|
||||
]);
|
||||
|
||||
const pluginCleanupMap = new Map<string, Set<() => void>>();
|
||||
|
||||
export function addCleanup(
|
||||
pluginName: string,
|
||||
cleanup: () => void
|
||||
): () => void {
|
||||
if (!pluginCleanupMap.has(pluginName)) {
|
||||
pluginCleanupMap.set(pluginName, new Set());
|
||||
}
|
||||
const cleanupSet = pluginCleanupMap.get(pluginName);
|
||||
assertExists(cleanupSet);
|
||||
cleanupSet.add(cleanup);
|
||||
return () => {
|
||||
cleanupSet.delete(cleanup);
|
||||
};
|
||||
}
|
||||
|
||||
export function invokeCleanup(pluginName: string) {
|
||||
pluginCleanupMap.get(pluginName)?.forEach(cleanup => cleanup());
|
||||
pluginCleanupMap.delete(pluginName);
|
||||
}
|
||||
|
||||
export const pluginPackageJson = atom<
|
||||
z.infer<typeof packageJsonOutputSchema>[]
|
||||
>([]);
|
||||
|
||||
export const enabledPluginAtom = atomWithStorage('affine-enabled-plugin', [
|
||||
'@affine/image-preview-plugin',
|
||||
'@affine/outline-plugin',
|
||||
]);
|
||||
|
||||
export const pluginHeaderItemAtom = atom<
|
||||
Record<string, CallbackMap['headerItem']>
|
||||
>({});
|
||||
|
||||
export const pluginSettingAtom = atom<Record<string, CallbackMap['setting']>>(
|
||||
{}
|
||||
);
|
||||
|
||||
export const pluginEditorAtom = atom<Record<string, CallbackMap['editor']>>({});
|
||||
|
||||
export const pluginWindowAtom = atom<
|
||||
Record<string, (root: HTMLElement) => () => void>
|
||||
>({});
|
||||
@@ -0,0 +1,79 @@
|
||||
import type { ActiveDocProvider, Workspace } from '@blocksuite/store';
|
||||
import type { PassiveDocProvider } from '@blocksuite/store';
|
||||
import type { Atom } from 'jotai/vanilla';
|
||||
import { atom } from 'jotai/vanilla';
|
||||
import { atomEffect } from 'jotai-effect';
|
||||
|
||||
/**
|
||||
* Map: guid -> Workspace
|
||||
*/
|
||||
export const INTERNAL_BLOCKSUITE_HASH_MAP = new Map<string, Workspace>([]);
|
||||
|
||||
const workspaceActiveAtomWeakMap = new WeakMap<
|
||||
Workspace,
|
||||
Atom<Promise<Workspace>>
|
||||
>();
|
||||
|
||||
const workspaceActiveWeakMap = new WeakMap<Workspace, boolean>();
|
||||
const workspaceEffectAtomWeakMap = new WeakMap<Workspace, Atom<void>>();
|
||||
|
||||
export async function waitForWorkspace(workspace: Workspace) {
|
||||
if (workspaceActiveWeakMap.get(workspace) !== true) {
|
||||
const providers = workspace.providers.filter(
|
||||
(provider): provider is ActiveDocProvider =>
|
||||
'active' in provider && provider.active === true
|
||||
);
|
||||
for (const provider of providers) {
|
||||
provider.sync();
|
||||
// we will wait for the necessary providers to be ready
|
||||
await provider.whenReady;
|
||||
}
|
||||
// timeout is INFINITE
|
||||
workspaceActiveWeakMap.set(workspace, true);
|
||||
}
|
||||
}
|
||||
|
||||
export function getWorkspace(id: string) {
|
||||
if (!INTERNAL_BLOCKSUITE_HASH_MAP.has(id)) {
|
||||
throw new Error('Workspace not found');
|
||||
}
|
||||
return INTERNAL_BLOCKSUITE_HASH_MAP.get(id) as Workspace;
|
||||
}
|
||||
|
||||
export function getBlockSuiteWorkspaceAtom(
|
||||
id: string
|
||||
): [workspaceAtom: Atom<Promise<Workspace>>, workspaceEffectAtom: Atom<void>] {
|
||||
if (!INTERNAL_BLOCKSUITE_HASH_MAP.has(id)) {
|
||||
throw new Error('Workspace not found');
|
||||
}
|
||||
const workspace = INTERNAL_BLOCKSUITE_HASH_MAP.get(id) as Workspace;
|
||||
if (!workspaceActiveAtomWeakMap.has(workspace)) {
|
||||
const baseAtom = atom(async () => {
|
||||
await waitForWorkspace(workspace);
|
||||
return workspace;
|
||||
});
|
||||
workspaceActiveAtomWeakMap.set(workspace, baseAtom);
|
||||
}
|
||||
if (!workspaceEffectAtomWeakMap.has(workspace)) {
|
||||
const effectAtom = atomEffect(() => {
|
||||
const providers = workspace.providers.filter(
|
||||
(provider): provider is PassiveDocProvider =>
|
||||
'passive' in provider && provider.passive === true
|
||||
);
|
||||
providers.forEach(provider => {
|
||||
provider.connect();
|
||||
});
|
||||
return () => {
|
||||
providers.forEach(provider => {
|
||||
provider.disconnect();
|
||||
});
|
||||
};
|
||||
});
|
||||
workspaceEffectAtomWeakMap.set(workspace, effectAtom);
|
||||
}
|
||||
|
||||
return [
|
||||
workspaceActiveAtomWeakMap.get(workspace) as Atom<Promise<Workspace>>,
|
||||
workspaceEffectAtomWeakMap.get(workspace) as Atom<void>,
|
||||
];
|
||||
}
|
||||
Reference in New Issue
Block a user