Feature/#587 implement vscode extension#588
Conversation
…mplement-vscode-extension
|
|
||
| if (content === lastSavedContentRef.current) return; | ||
|
|
||
| debounceTimerRef.current = setTimeout(() => { |
There was a problem hiding this comment.
🔴 Debounce timer no se limpia entre renders ni en early-returns
El efecto depende de [canvasSchema]. Cuando el schema cambia rápido, cada render entra en este useEffect, asigna un timer nuevo a debounceTimerRef.current y deja al anterior huérfano (la cleanup function solo corre cuando el efecto se va a re-ejecutar o el componente se desmonta, y para entonces ya hemos pisado la referencia). Además, las early-returns de las líneas 19, 25 y 28 tampoco limpian un timer en vuelo, así que pueden disparar un SAVE con contenido obsoleto capturado en el closure.
Sugerencia: limpiar el timer previo antes de programar el nuevo y al inicio del efecto:
useEffect(() => {
if (debounceTimerRef.current) {
clearTimeout(debounceTimerRef.current);
debounceTimerRef.current = null;
}
if (!isVSCodeEnv() || !hasReceivedFileRef.current) return;
// ...resto igual
});|
|
||
| export const sendToExtension = (msg: AppMessage): void => { | ||
| if (!isVSCodeEnv()) return; | ||
| window.parent.postMessage(msg, '*'); |
There was a problem hiding this comment.
🔴 postMessage con origen wildcard
window.parent.postMessage(msg, '*') envía el payload (schema completo, contenido del archivo en cada SAVE) a cualquier frame padre. Si la página padre no es la esperada — o si el webview de VS Code se anida en algún contexto inesperado — el contenido se filtra.
Sugerencia: usar un origen concreto. El webview de VS Code expone el origen del host vía acquireVsCodeApi (lado del bridge en webview/bridge.ts), pero desde el iframe podemos restringir al origen del padre conocido — o, como mínimo, validar event.origin en el listener inverso y reciclar ese mismo origen como target.
| case APP_MESSAGE_TYPE.SAVE: | ||
| doc.content = msg.payload.content; | ||
| await writeFile(doc.uri, doc.content); | ||
| postMessage({ type: HOST_MESSAGE_TYPE.SAVED }); |
There was a problem hiding this comment.
🟠 SAVE escribe a disco pero nunca dispara _onDidChangeCustomDocument
El handler escribe el archivo y emite SAVED, pero el provider expone _onDidChangeCustomDocument (provider.ts:39) que jamás se .fire(). Consecuencias en el ciclo CustomEditorProvider de VS Code:
- El tab nunca aparece como modificado.
saveCustomDocument/saveCustomDocumentAs/backupCustomDocumentdefinidos en el provider son código muerto: VS Code solo los invoca cuando el documento está dirty.- Hot-exit y revert nativo no funcionan.
Sugerencia: o bien disparar _onDidChangeCustomDocument.fire({ document: doc }) desde aquí (pasando el provider/event al handler), o bien documentar explícitamente que el editor hace auto-save bypaseando el ciclo nativo y eliminar los métodos del provider que no se van a usar.
| this.panels.set(key, [...(this.panels.get(key) ?? []), panel]); | ||
| panel.onDidDispose(() => { | ||
| const remaining = (this.panels.get(key) ?? []).filter(p => p !== panel); | ||
| this.panels.set(key, remaining); |
There was a problem hiding this comment.
🟠 Leak en el mapa panels cuando se cierran todos los paneles de un documento
Al cerrar el último panel, remaining queda como [] y se guarda en el mapa para siempre. Cada archivo abierto y cerrado acumula una entrada huérfana.
Sugerencia:
panel.onDidDispose(() => {
const remaining = (this.panels.get(key) ?? []).filter(p => p !== panel);
if (remaining.length === 0) {
this.panels.delete(key);
} else {
this.panels.set(key, remaining);
}
});| }; | ||
| window.addEventListener('message', onIframeReady); | ||
|
|
||
| const observer = new MutationObserver(sendTheme); |
There was a problem hiding this comment.
🟠 MutationObserver no se debouncea y la cleanup retornada no se captura
MutationObserver sobre document.body dispara sendTheme() por cada mutación de class/style sin debouncing — en escenarios con animaciones o cambios de estado dinámicos esto puede ser muy frecuente.
Además, setupThemeSync retorna una función de cleanup (líneas 48-51) que webview/main.ts:22 no captura ni invoca, así que el listener message y el observer nunca se desmontan.
Sugerencias:
- Debouncear
sendTheme(≈150ms consetTimeout/clearTimeout). - Capturar la cleanup en
main.ts(al menos asignarla a una variable, idealmente registrarla en algún teardown del webview).
| import { onMessage } from './vscode-bridge.helpers'; | ||
|
|
||
| const CSS_VAR_MAP: Record<keyof ThemePayload, readonly string[]> = { | ||
| background: ['--bg-canvas', '--background-800', '--background-900'], |
There was a problem hiding this comment.
🟡 Mapeo background → tres variables CSS con tonos distintos
--bg-canvas, --background-800 y --background-900 reciben el mismo valor. En el sistema de diseño actual --background-800 y --background-900 son tonos diferentes; aplanarlos al mismo color puede romper jerarquía visual (mismo gris para canvas, paneles y bordes). Lo mismo con backgroundSecondary y sus cinco vars.
Sugerencia: ampliar ThemePayload para exponer más niveles (backgroundElevated, backgroundMuted, etc.) y mapear cada variable a su nivel real; o, si es intencional aplanar la paleta en VS Code, dejar un comentario explicándolo.
| @@ -1,21 +1,22 @@ | |||
| import { isVSCodeEnv } from '@/core/vscode/env.helpers'; | |||
There was a problem hiding this comment.
🟡 Import order y comentario huérfano
Dos cosas en este reorder:
isVSCodeEnv(interno,@/core/vscode/...) queda antes queReact(externo). El resto del repo agrupa externos primero, luego internos con alias@/.- La línea 17 deja un comentario
// CanvasSettingButton,dentro del bloque de imports — ya estaba antes, pero este es buen momento para limpiarlo.
Sugerencia: mover import React arriba del todo y borrar el comentario huérfano.
| import { useVSCodeFileLoad } from './use-vscode-file-load.hook'; | ||
| import { useVSCodeTheme } from './use-vscode-theme.hook'; | ||
|
|
||
| /** |
There was a problem hiding this comment.
🔵 JSDoc multilínea para algo que el código ya transmite
El proyecto evita JSDoc multilínea cuando el nombre del símbolo es autoexplicativo. useVSCodeSync + el comportamiento de los hooks internos (cada uno hace su propio early-return en !isVSCodeEnv()) ya dicen lo mismo.
Sugerencia: borrar el bloque o reducirlo a una línea (// no-ops when not inside the VS Code webview).
| ? vscode.Uri.parse(openContext.backupId) | ||
| : uri; | ||
| const content = await readFile(source); | ||
| return { uri, content, dispose: () => {} }; |
There was a problem hiding this comment.
🔵 dispose: () => {} sin contexto
Es un stub para cumplir con vscode.CustomDocument. Está bien hoy, pero quien lea esto en seis meses se preguntará si se olvidó algo.
Sugerencia: comentario corto in-line // no resources to release; content is a plain string o, mejor, mover la construcción del objeto a una factory con nombre explícito.
| @@ -0,0 +1,38 @@ | |||
| import { basename } from 'node:path'; | |||
There was a problem hiding this comment.
🟡 Cobertura de tests inexistente para el nuevo módulo VS Code
Ninguno de los nuevos módulos lleva tests: hooks de auto-save / file-load / theme en apps/web/src/core/vscode/, helpers del bridge, provider del editor, ni este handler. La superficie es relevante: IO de archivos, mensajería entre procesos, CSP, ciclo de paneles.
Sugerencia mínima:
use-vscode-auto-save.hook— debounce y limpieza de timer.vscode-sync.helpers— round-trip de serialize/deserialize.handlers.ts— ramas WEBVIEW_READY (con y sin JSON válido) y SAVE.MongoModelerEditorProvider— ciclo de vida de paneles, revert.webview/theme.ts— cleanup del observer.
…n function and debouncing theme updates
…ntries from the panels map
…nd onMessage functions
Depends on #586
Close #587