Fix diagnostic fighting between wasm and typescript (closes #2755) (#2799)

* start to gut and seperate the kcl lint from execute

* fix type signature

* re-add old codepath when not wasm

* also lint in the mock

* fix syntax

* fix message
This commit is contained in:
Paul Tagliamonte
2024-06-26 00:04:52 -04:00
committed by GitHub
parent 289ed291c4
commit 53db421d97
7 changed files with 79 additions and 10 deletions

View File

@ -786,7 +786,7 @@ test('if you write invalid kcl you get inlined errors', async ({ page }) => {
// error text on hover
await page.hover('.cm-lint-marker-error')
await expect(page.getByText('syntax: Unexpected token')).toBeVisible()
await expect(page.getByText('Unexpected token')).toBeVisible()
// select the line that's causing the error and delete it
await page.getByText('$ error').click()

View File

@ -1,4 +1,4 @@
import { executeAst } from 'useStore'
import { executeAst, lintAst } from 'useStore'
import { Selections } from 'lib/selections'
import { KCLError, kclErrorsToDiagnostics } from './errors'
import { uuidv4 } from 'lib/utils'
@ -211,6 +211,9 @@ export class KclManager {
ast,
engineCommandManager: this.engineCommandManager,
})
editorManager.addDiagnostics(await lintAst({ ast: ast }))
sceneInfra.modelingSend({ type: 'code edit during sketch' })
defaultSelectionFilter(programMemory, this.engineCommandManager)
@ -261,7 +264,10 @@ export class KclManager {
return
}
const newAst = this.safeParse(newCode)
if (!newAst) return
if (!newAst) {
this.clearAst()
return
}
codeManager.updateCodeEditor(newCode)
// Write the file to disk.
await codeManager.writeToFile()
@ -278,6 +284,9 @@ export class KclManager {
engineCommandManager: this.engineCommandManager,
useFakeExecutor: true,
})
editorManager.addDiagnostics(await lintAst({ ast: ast }))
this._logs = logs
this._kclErrors = errors
this._programMemory = programMemory

View File

@ -2,6 +2,7 @@ import init, {
parse_wasm,
recast_wasm,
execute_wasm,
kcl_lint,
lexer_wasm,
modify_ast_for_sketch_wasm,
is_points_ccw,
@ -20,6 +21,7 @@ import { KCLError } from './errors'
import { KclError as RustKclError } from '../wasm-lib/kcl/bindings/KclError'
import { EngineCommandManager } from './std/engineConnection'
import { ProgramReturn } from '../wasm-lib/kcl/bindings/ProgramReturn'
import { Discovered } from '../wasm-lib/kcl/bindings/Discovered'
import { MemoryItem } from '../wasm-lib/kcl/bindings/MemoryItem'
import type { Program } from '../wasm-lib/kcl/bindings/Program'
import type { Token } from '../wasm-lib/kcl/bindings/Token'
@ -205,6 +207,17 @@ export const _executor = async (
}
}
export const kclLint = async (ast: Program): Promise<Array<Discovered>> => {
try {
const discovered_findings: Array<Discovered> = await kcl_lint(
JSON.stringify(ast)
)
return discovered_findings
} catch (e: any) {
return Promise.reject(e)
}
}
export const recast = (ast: Program): string | Error => {
return recast_wasm(JSON.stringify(ast))
}

View File

@ -5,11 +5,13 @@ import {
_executor,
ProgramMemory,
programMemoryInit,
kclLint,
} from './lang/wasm'
import { enginelessExecutor } from './lib/testHelpers'
import { EngineCommandManager } from './lang/std/engineConnection'
import { KCLError } from './lang/errors'
import { SidebarType } from 'components/ModelingSidebar/ModelingPanes'
import { Diagnostic } from '@codemirror/lint'
export type ToolTip =
| 'lineTo'
@ -187,3 +189,24 @@ export async function executeAst({
}
}
}
export async function lintAst({
ast,
}: {
ast: Program
}): Promise<Array<Diagnostic>> {
try {
const discovered_findings = await kclLint(ast)
return discovered_findings.map((lint) => {
return {
message: lint.finding.title,
severity: 'info',
from: lint.pos[0],
to: lint.pos[1],
}
})
} catch (e: any) {
console.log(e)
return []
}
}

View File

@ -1,4 +1,6 @@
use anyhow::Result;
use schemars::JsonSchema;
use serde::Serialize;
use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity};
use crate::{executor::SourceRange, lint::Node, lsp::IntoDiagnostic};
@ -22,8 +24,10 @@ where
}
/// Specific discovered lint rule Violation of a particular Finding.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, ts_rs::TS, Serialize, JsonSchema)]
#[ts(export)]
#[cfg_attr(feature = "pyo3", pyo3::pyclass)]
#[serde(rename_all = "camelCase")]
pub struct Discovered {
/// Zoo Lint Finding information.
pub finding: Finding,
@ -83,8 +87,10 @@ impl IntoDiagnostic for Discovered {
}
/// Abstract lint problem type.
#[derive(Clone, Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq, ts_rs::TS, Serialize, JsonSchema)]
#[ts(export)]
#[cfg_attr(feature = "pyo3", pyo3::pyclass)]
#[serde(rename_all = "camelCase")]
pub struct Finding {
/// Unique identifier for this particular issue.
pub code: &'static str,

View File

@ -37,11 +37,13 @@ use super::backend::{InnerHandle, UpdateHandle};
use crate::{
ast::types::VariableKind,
executor::SourceRange,
lint::checks,
lsp::{backend::Backend as _, safemap::SafeMap, util::IntoDiagnostic},
parser::PIPE_OPERATOR,
};
#[cfg(not(target_arch = "wasm32"))]
use crate::lint::checks;
/// A subcommand for running the server.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "cli", derive(Parser))]
@ -256,12 +258,14 @@ impl crate::lsp::backend::Backend for Backend {
// This function automatically executes if we should & updates the diagnostics if we got
// errors.
if self.execute(&params, ast.clone()).await.is_err() {
// if there was an issue, let's bail and avoid trying to lint.
return;
}
for discovered_finding in ast.lint(checks::lint_variables).into_iter().flatten() {
self.add_to_diagnostics(&params, discovered_finding).await;
#[cfg(not(target_arch = "wasm32"))]
{
for discovered_finding in ast.lint(checks::lint_variables).into_iter().flatten() {
self.add_to_diagnostics(&params, discovered_finding).await;
}
}
}
}

View File

@ -7,7 +7,7 @@ use std::{
use futures::stream::TryStreamExt;
use gloo_utils::format::JsValueSerdeExt;
use kcl_lib::{coredump::CoreDump, engine::EngineManager, executor::ExecutorSettings};
use kcl_lib::{coredump::CoreDump, engine::EngineManager, executor::ExecutorSettings, lint::checks};
use tower_lsp::{LspService, Server};
use wasm_bindgen::prelude::*;
@ -59,6 +59,20 @@ pub async fn execute_wasm(
JsValue::from_serde(&memory).map_err(|e| e.to_string())
}
// wasm_bindgen wrapper for execute
#[wasm_bindgen]
pub async fn kcl_lint(program_str: &str) -> Result<JsValue, String> {
console_error_panic_hook::set_once();
let program: kcl_lib::ast::types::Program = serde_json::from_str(program_str).map_err(|e| e.to_string())?;
let mut findings = vec![];
for discovered_finding in program.lint(checks::lint_variables).into_iter().flatten() {
findings.push(discovered_finding);
}
Ok(JsValue::from_serde(&findings).map_err(|e| e.to_string())?)
}
// wasm_bindgen wrapper for creating default planes
#[wasm_bindgen]
pub async fn make_default_planes(