refactor: split document session runtime

This commit is contained in:
lix-2026
2026-05-26 01:23:27 +08:00
parent 87a4a92c35
commit ff9a779a6c
5 changed files with 1465 additions and 1370 deletions
@@ -124,13 +124,13 @@ cargo test --manifest-path rust/Cargo.toml -p mnote-web --lib routes::tests::mno
- [x] B3. `document-resource-tab-runtime.js`resource tab registry、MRU、close guard、resource text/image/frame editor mount。
- [x] B4. `document-mindmap-host-runtime.js`primary mindmap object shell、mindmap resource tab mount/unmount。
- [x] B5. `document-slash-position-runtime.js`slash menu active root、positioning、mutation observer。
- [ ] B6. entrypoint 只负责读取 bootstrap、加载 runtime、装配各子模块。
- [x] B6. entrypoint 只负责读取 bootstrap、加载 runtime、装配各子模块。
验收标准:
- [ ] 每个新 JS 文件少于 1,500 行。
- [ ] entrypoint 少于 900 行。
- [ ] `document_editor_adapter` 相关测试不再依赖在 Rust raw string 中字面搜索。
- [x] 每个新 JS 文件少于 1,500 行。
- [x] entrypoint 少于 900 行。
- [x] `document_editor_adapter` 相关测试不再依赖在 Rust raw string 中字面搜索。
验收命令:
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+5
View File
@@ -154,6 +154,10 @@ pub fn build_router(state: AppState) -> Router {
"/api/mnote-browser-runtime/document-resource-tab-runtime.js",
get(web_shell::document_resource_tab_runtime_asset),
)
.route(
"/api/mnote-browser-runtime/document-session-runtime.js",
get(web_shell::document_session_runtime_asset),
)
.route(
"/api/mnote-browser-runtime/document-slash-position-runtime.js",
get(web_shell::document_slash_position_runtime_asset),
@@ -582,6 +586,7 @@ mod tests {
"/api/mnote-browser-runtime/document-pane-runtime.js",
"/api/mnote-browser-runtime/document-mindmap-host-runtime.js",
"/api/mnote-browser-runtime/document-resource-tab-runtime.js",
"/api/mnote-browser-runtime/document-session-runtime.js",
"/api/mnote-browser-runtime/document-slash-position-runtime.js",
"/api/mnote-browser-runtime/document-tiptap-conversion-runtime.js",
"/api/mnote-browser-runtime/document-editor-adapter-runtime.js",
+66 -44
View File
@@ -897,6 +897,20 @@ pub async fn document_resource_tab_runtime_asset() -> Response {
.unwrap_or_else(|_| Response::new(Body::empty()))
}
pub async fn document_session_runtime_asset() -> Response {
const JS: &str = include_str!("../../browser/document-session-runtime.js");
Response::builder()
.status(StatusCode::OK)
.header(
header::CONTENT_TYPE,
"application/javascript; charset=utf-8",
)
.header(header::CACHE_CONTROL, "no-store")
.header(HEADER_MNOTE_WEB_OWNER, "mnote-web")
.body(Body::from(JS))
.unwrap_or_else(|_| Response::new(Body::empty()))
}
pub async fn document_slash_position_runtime_asset() -> Response {
const JS: &str = include_str!("../../browser/document-slash-position-runtime.js");
Response::builder()
@@ -1353,6 +1367,8 @@ mod tests {
const DOCUMENT_PANE_RUNTIME_JS: &str = include_str!("../../browser/document-pane-runtime.js");
const DOCUMENT_RESOURCE_TAB_RUNTIME_JS: &str =
include_str!("../../browser/document-resource-tab-runtime.js");
const DOCUMENT_SESSION_RUNTIME_JS: &str =
include_str!("../../browser/document-session-runtime.js");
const DOCUMENT_SLASH_POSITION_RUNTIME_JS: &str =
include_str!("../../browser/document-slash-position-runtime.js");
const DOCUMENT_TIPTAP_CONVERSION_RUNTIME_JS: &str =
@@ -1649,7 +1665,8 @@ mod tests {
assert!(html.contains("mnote.tree_live_bootstrap.v1"));
assert!(html.contains("/api/tree/events"));
assert!(html.contains("/api/realtime/ws"));
assert!(runtime.contains("syncPageAggregateScript(session, nextAggregate);"));
let session_runtime = DOCUMENT_SESSION_RUNTIME_JS;
assert!(session_runtime.contains("syncPageAggregateScript(session, nextAggregate);"));
let conversion_runtime = DOCUMENT_TIPTAP_CONVERSION_RUNTIME_JS;
assert!(conversion_runtime.contains(
"const pageBodyTiptapDocument = (body, fallbackText = '', context = null) => {"
@@ -1658,17 +1675,17 @@ mod tests {
assert!(
conversion_runtime.contains("localizeTiptapAssetUrls(toTiptapDocument(body.content")
);
assert!(runtime
assert!(session_runtime
.contains("const nextTiptapDocument = pageBodyTiptapDocument(nextBody, '', session);"));
assert!(runtime.contains(
assert!(session_runtime.contains(
"const tiptapDocument = pageBodyTiptapDocument(pageBody, '', runtimeDescriptor.bootstrap);"
));
assert!(runtime.contains("mnote.localFolder.selfChangeSuppressions.v1"));
assert!(runtime.contains("ensureLocalFolderSelfChangeSuppressions()"));
assert!(runtime.contains("markLocalFolderSelfChangeSuppression(session);"));
assert!(runtime.contains("const suppressibleSelfWrite = kind.includes('Create')"));
assert!(runtime.contains("|| kind.includes('Modify(Data')"));
assert!(runtime.contains("|| kind.includes('Modify(Any')"));
assert!(session_runtime.contains("mnote.localFolder.selfChangeSuppressions.v1"));
assert!(session_runtime.contains("ensureLocalFolderSelfChangeSuppressions()"));
assert!(session_runtime.contains("markLocalFolderSelfChangeSuppression(session);"));
assert!(session_runtime.contains("const suppressibleSelfWrite = kind.includes('Create')"));
assert!(session_runtime.contains("|| kind.includes('Modify(Data')"));
assert!(session_runtime.contains("|| kind.includes('Modify(Any')"));
assert!(!runtime.contains("mnote-web-document-shell"));
// Resource open resolver contract
@@ -2020,42 +2037,43 @@ mod tests {
assert!(html.contains("/api/mnote-browser-runtime/filetree-runtime.js"));
assert!(html.contains(r#"<script type="module" src="/api/mnote-browser-runtime/document-editor-adapter-runtime.js"></script>"#));
assert!(html.contains("data-mnote-action=\"open-local-folder\""));
let runtime = DOCUMENT_EDITOR_ADAPTER_RUNTIME_JS;
assert!(runtime.contains("refreshSessionFromExternalFileChange"));
assert!(runtime.contains("refreshSessionFromExternalChange"));
assert!(runtime.contains("treeExternalConflictMessage"));
assert!(runtime.contains("tree:delta"));
assert!(runtime.contains("tree:resync"));
assert!(runtime.contains("mnote-web-tree-live"));
assert!(runtime.contains("refreshMindmapRuntimesFromTreePayload"));
assert!(runtime.contains("__MNOTE_LEPTOS_MINDMAP_BRIDGES__"));
assert!(runtime.contains("/api/local-folder/events"));
assert!(runtime.contains("localFolderEventChannelKey"));
assert!(runtime.contains("url.searchParams.set('documentId', session.documentId);"));
assert!(runtime.contains("if (!documentId) return;"));
assert!(runtime.contains("new EventSource(url.toString())"));
assert!(runtime.contains("localFolderEventRegistry"));
assert!(runtime
let session_runtime = DOCUMENT_SESSION_RUNTIME_JS;
assert!(session_runtime.contains("refreshSessionFromExternalFileChange"));
assert!(session_runtime.contains("refreshSessionFromExternalChange"));
assert!(session_runtime.contains("treeExternalConflictMessage"));
assert!(session_runtime.contains("tree:delta"));
assert!(session_runtime.contains("tree:resync"));
assert!(session_runtime.contains("mnote-web-tree-live"));
assert!(session_runtime.contains("refreshMindmapRuntimesFromTreePayload"));
assert!(session_runtime.contains("__MNOTE_LEPTOS_MINDMAP_BRIDGES__"));
assert!(session_runtime.contains("/api/local-folder/events"));
assert!(session_runtime.contains("localFolderEventChannelKey"));
assert!(session_runtime.contains("url.searchParams.set('documentId', session.documentId);"));
assert!(session_runtime.contains("if (!documentId) return;"));
assert!(session_runtime.contains("new EventSource(url.toString())"));
assert!(session_runtime.contains("localFolderEventRegistry"));
assert!(session_runtime
.contains("if (!response.ok) {\n if (session.sourceKind === 'local_folder')"));
assert!(runtime.contains("shouldSuppressLocalFolderSelfChange"));
assert!(runtime.contains("kind.includes('Modify(Name')"));
assert!(runtime.contains("targetSession.views.size === 0"));
assert!(runtime.contains("session.views.size === 0"));
assert!(runtime.contains("targetSession.saving"));
assert!(runtime.contains("lastSelfSaveSignalAt"));
assert!(runtime.contains("clearSessionConflictSurface(view.session);"));
assert!(runtime.contains("command: 'replaceContent'"));
assert!(runtime.contains("external-change-conflict"));
assert!(runtime.contains("mnote-editor-conflict-panel"));
assert!(runtime.contains("mnote-conflict-accept-disk"));
assert!(runtime.contains("mnote-conflict-keep-current"));
assert!(runtime.contains("mnote-conflict-open-diff"));
assert!(runtime.contains("mnote-conflict-merge-text"));
assert!(runtime.contains("mnote-conflict-merge-save"));
assert!(runtime
assert!(session_runtime.contains("shouldSuppressLocalFolderSelfChange"));
assert!(session_runtime.contains("kind.includes('Modify(Name')"));
assert!(session_runtime.contains("targetSession.views.size === 0"));
assert!(session_runtime.contains("session.views.size === 0"));
assert!(session_runtime.contains("targetSession.saving"));
assert!(session_runtime.contains("lastSelfSaveSignalAt"));
assert!(DOCUMENT_EDITOR_ADAPTER_RUNTIME_JS
.contains("clearSessionConflictSurface(view.session);"));
assert!(session_runtime.contains("command: 'replaceContent'"));
assert!(session_runtime.contains("external-change-conflict"));
assert!(session_runtime.contains("mnote-editor-conflict-panel"));
assert!(session_runtime.contains("mnote-conflict-accept-disk"));
assert!(session_runtime.contains("mnote-conflict-keep-current"));
assert!(session_runtime.contains("mnote-conflict-open-diff"));
assert!(session_runtime.contains("mnote-conflict-merge-text"));
assert!(session_runtime.contains("mnote-conflict-merge-save"));
assert!(session_runtime
.contains("runtime.mountSessionConflictPanel(view.runtimeDescriptor.root, panel)"));
assert!(runtime.contains("agent run"));
assert!(!runtime.contains(
assert!(session_runtime.contains("agent run"));
assert!(!session_runtime.contains(
"setInterval(() => {\n void pollLocalMarkdownExternalChange();\n }, 1200);"
));
}
@@ -2120,6 +2138,10 @@ mod tests {
assert!(DOCUMENT_RESOURCE_TAB_RUNTIME_JS.contains("openResourceInActiveTab"));
assert!(DOCUMENT_RESOURCE_TAB_RUNTIME_JS.contains("buildOpenEditorsSnapshot"));
assert!(DOCUMENT_RESOURCE_TAB_RUNTIME_JS.contains("bindMainEditorTabStrip"));
assert!(DOCUMENT_EDITOR_ADAPTER_RUNTIME_JS.contains("document-session-runtime.js"));
assert!(DOCUMENT_SESSION_RUNTIME_JS.contains("createDocumentSessionRuntime"));
assert!(DOCUMENT_SESSION_RUNTIME_JS.contains("getOrCreateDocumentSession"));
assert!(DOCUMENT_SESSION_RUNTIME_JS.contains("persistSession"));
assert!(DOCUMENT_EDITOR_ADAPTER_RUNTIME_JS.contains("document-slash-position-runtime.js"));
assert!(DOCUMENT_SLASH_POSITION_RUNTIME_JS.contains("observeSlashMenuPosition"));
assert!(DOCUMENT_SLASH_POSITION_RUNTIME_JS.contains("scheduleSlashMenuPosition"));
@@ -2287,7 +2309,7 @@ mod tests {
assert!(runtime.contains("typeof payload.text === 'string'"));
assert!(runtime.contains("payload.type === 'hard_break'"));
assert!(runtime.contains("typeof body?.fileVersion === 'string'"));
assert!(DOCUMENT_EDITOR_ADAPTER_RUNTIME_JS
assert!(DOCUMENT_SESSION_RUNTIME_JS
.contains("expectedFileVersion: session.conflictDetectionKey"));
assert!(runtime.contains("node?.attrs?.mnoteBlockType === 'mindmap'"));
assert!(runtime.contains("blockType: 'mindmap'"));