1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-22 15:06:54 -05:00

fix(lsp): handle ts debug errors better (#8914)

Fixes #8864
This commit is contained in:
Kitson Kelly 2020-12-30 12:46:58 +11:00 committed by GitHub
parent 268e47c0d8
commit e8a81724bb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 109 additions and 74 deletions

View file

@ -244,20 +244,10 @@ pub async fn generate_ts_diagnostics(
let version = doc_data.version; let version = doc_data.version;
let current_version = diagnostic_collection.get_version(&file_id); let current_version = diagnostic_collection.get_version(&file_id);
if version != current_version { if version != current_version {
// TODO(@kitsonk): consider refactoring to get all diagnostics in one shot let req = tsc::RequestMethod::GetDiagnostics(specifier.clone());
// for a file. let ts_diagnostics = ts_json_to_diagnostics(
let req = tsc::RequestMethod::GetSemanticDiagnostics(specifier.clone());
let mut ts_diagnostics = ts_json_to_diagnostics(
ts_server.request(state_snapshot.clone(), req).await?, ts_server.request(state_snapshot.clone(), req).await?,
)?; )?;
let req = tsc::RequestMethod::GetSuggestionDiagnostics(specifier.clone());
ts_diagnostics.append(&mut ts_json_to_diagnostics(
ts_server.request(state_snapshot.clone(), req).await?,
)?);
let req = tsc::RequestMethod::GetSyntacticDiagnostics(specifier.clone());
ts_diagnostics.append(&mut ts_json_to_diagnostics(
ts_server.request(state_snapshot.clone(), req).await?,
)?);
diagnostics.push((file_id, version, ts_diagnostics)); diagnostics.push((file_id, version, ts_diagnostics));
} }
} }

View file

@ -154,12 +154,19 @@ impl LanguageServer {
if enabled { if enabled {
let diagnostics = { let diagnostics = {
let diagnostic_collection = self.diagnostics.read().unwrap().clone(); let diagnostic_collection = self.diagnostics.read().unwrap().clone();
diagnostics::generate_ts_diagnostics( match diagnostics::generate_ts_diagnostics(
&self.ts_server, &self.ts_server,
&diagnostic_collection, &diagnostic_collection,
self.snapshot(), self.snapshot(),
) )
.await? .await
{
Ok(diagnostics) => diagnostics,
Err(err) => {
error!("Error processing TypeScript diagnostics:\n{}", err);
vec![]
}
}
}; };
{ {
let mut diagnostics_collection = self.diagnostics.write().unwrap(); let mut diagnostics_collection = self.diagnostics.write().unwrap();

View file

@ -1123,12 +1123,8 @@ pub enum RequestMethod {
Configure(TsConfig), Configure(TsConfig),
/// Retrieve the text of an assets that exists in memory in the isolate. /// Retrieve the text of an assets that exists in memory in the isolate.
GetAsset(ModuleSpecifier), GetAsset(ModuleSpecifier),
/// Return semantic diagnostics for given file. /// Return diagnostics for given file.
GetSemanticDiagnostics(ModuleSpecifier), GetDiagnostics(ModuleSpecifier),
/// Returns suggestion diagnostics for given file.
GetSuggestionDiagnostics(ModuleSpecifier),
/// Return syntactic diagnostics for a given file.
GetSyntacticDiagnostics(ModuleSpecifier),
/// Return quick info at position (hover information). /// Return quick info at position (hover information).
GetQuickInfo((ModuleSpecifier, u32)), GetQuickInfo((ModuleSpecifier, u32)),
/// Return document highlights at position. /// Return document highlights at position.
@ -1156,19 +1152,9 @@ impl RequestMethod {
"method": "getAsset", "method": "getAsset",
"specifier": specifier, "specifier": specifier,
}), }),
RequestMethod::GetSemanticDiagnostics(specifier) => json!({ RequestMethod::GetDiagnostics(specifier) => json!({
"id": id, "id": id,
"method": "getSemanticDiagnostics", "method": "getDiagnostics",
"specifier": specifier,
}),
RequestMethod::GetSuggestionDiagnostics(specifier) => json!({
"id": id,
"method": "getSuggestionDiagnostics",
"specifier": specifier,
}),
RequestMethod::GetSyntacticDiagnostics(specifier) => json!({
"id": id,
"method": "getSyntacticDiagnostics",
"specifier": specifier, "specifier": specifier,
}), }),
RequestMethod::GetQuickInfo((specifier, position)) => json!({ RequestMethod::GetQuickInfo((specifier, position)) => json!({
@ -1369,7 +1355,7 @@ mod tests {
} }
#[test] #[test]
fn test_get_semantic_diagnostics() { fn test_get_diagnostics() {
let (mut runtime, state_snapshot) = setup( let (mut runtime, state_snapshot) = setup(
false, false,
json!({ json!({
@ -1384,7 +1370,7 @@ mod tests {
let result = request( let result = request(
&mut runtime, &mut runtime,
state_snapshot, state_snapshot,
RequestMethod::GetSemanticDiagnostics(specifier), RequestMethod::GetDiagnostics(specifier),
); );
assert!(result.is_ok()); assert!(result.is_ok());
let response = result.unwrap(); let response = result.unwrap();
@ -1437,7 +1423,7 @@ mod tests {
let result = request( let result = request(
&mut runtime, &mut runtime,
state_snapshot, state_snapshot,
RequestMethod::GetSemanticDiagnostics(specifier), RequestMethod::GetDiagnostics(specifier),
); );
assert!(result.is_ok()); assert!(result.is_ok());
let response = result.unwrap(); let response = result.unwrap();
@ -1467,11 +1453,29 @@ mod tests {
let result = request( let result = request(
&mut runtime, &mut runtime,
state_snapshot, state_snapshot,
RequestMethod::GetSyntacticDiagnostics(specifier), RequestMethod::GetDiagnostics(specifier),
); );
assert!(result.is_ok()); assert!(result.is_ok());
let response = result.unwrap(); let response = result.unwrap();
assert_eq!(response, json!([])); assert_eq!(
response,
json!([{
"start": {
"line": 1,
"character": 8
},
"end": {
"line": 1,
"character": 30
},
"fileName": "file:///a.ts",
"messageText": "\'A\' is declared but its value is never read.",
"sourceLine": " import { A } from \".\";",
"category": 2,
"code": 6133,
"reportsUnnecessary": true,
}])
);
} }
#[test] #[test]
@ -1501,7 +1505,7 @@ mod tests {
let result = request( let result = request(
&mut runtime, &mut runtime,
state_snapshot, state_snapshot,
RequestMethod::GetSyntacticDiagnostics(specifier), RequestMethod::GetDiagnostics(specifier),
); );
assert!(result.is_ok()); assert!(result.is_ok());
let response = result.unwrap(); let response = result.unwrap();
@ -1538,13 +1542,28 @@ mod tests {
let result = request( let result = request(
&mut runtime, &mut runtime,
state_snapshot, state_snapshot,
RequestMethod::GetSyntacticDiagnostics(specifier), RequestMethod::GetDiagnostics(specifier),
); );
assert!(result.is_ok()); assert!(result.is_ok());
let response = result.unwrap(); let response = result.unwrap();
assert_eq!( assert_eq!(
response, response,
json!([{ json!([{
"start": {
"line": 1,
"character": 8
},
"end": {
"line": 6,
"character": 55,
},
"fileName": "file:///a.ts",
"messageText": "All imports in import declaration are unused.",
"sourceLine": " import {",
"category": 2,
"code": 6192,
"reportsUnnecessary": true
}, {
"start": { "start": {
"line": 8, "line": 8,
"character": 29 "character": 29
@ -1562,6 +1581,30 @@ mod tests {
); );
} }
#[test]
fn test_no_debug_failure() {
let (mut runtime, state_snapshot) = setup(
false,
json!({
"target": "esnext",
"module": "esnext",
"lib": ["deno.ns", "deno.window"],
"noEmit": true,
}),
vec![("file:///a.ts", r#"const url = new URL("b.js", import."#, 1)],
);
let specifier = ModuleSpecifier::resolve_url("file:///a.ts")
.expect("could not resolve url");
let result = request(
&mut runtime,
state_snapshot,
RequestMethod::GetDiagnostics(specifier),
);
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(response, json!([]));
}
#[test] #[test]
fn test_request_asset() { fn test_request_asset() {
let (mut runtime, state_snapshot) = setup( let (mut runtime, state_snapshot) = setup(

View file

@ -922,7 +922,7 @@ fn ts_reload() {
.output() .output()
.expect("failed to spawn script"); .expect("failed to spawn script");
// check the output of the the bundle program. // check the output of the the bundle program.
assert!(std::str::from_utf8(&output.stdout) assert!(std::str::from_utf8(&output.stderr)
.unwrap() .unwrap()
.trim() .trim()
.contains("host.writeFile(\"deno://002_hello.js\")")); .contains("host.writeFile(\"deno://002_hello.js\")"));

View file

@ -31,10 +31,22 @@ delete Object.prototype.__proto__;
const stringifiedArgs = args.map((arg) => const stringifiedArgs = args.map((arg) =>
typeof arg === "string" ? arg : JSON.stringify(arg) typeof arg === "string" ? arg : JSON.stringify(arg)
).join(" "); ).join(" ");
core.print(`DEBUG ${logSource} - ${stringifiedArgs}\n`); // adding a non-zero integer value to the end of the debug string causes
// the message to be printed to stderr instead of stdout, which is better
// aligned to the behaviour of debug messages
core.print(`DEBUG ${logSource} - ${stringifiedArgs}\n`, 1);
} }
} }
function error(...args) {
const stringifiedArgs = args.map((arg) =>
typeof arg === "string" || arg instanceof Error
? String(arg)
: JSON.stringify(arg)
).join(" ");
core.print(`ERROR ${logSource} = ${stringifiedArgs}\n`, 1);
}
class AssertionError extends Error { class AssertionError extends Error {
constructor(msg) { constructor(msg) {
super(msg); super(msg);
@ -497,23 +509,18 @@ delete Object.prototype.__proto__;
); );
return respond(id, sourceFile && sourceFile.text); return respond(id, sourceFile && sourceFile.text);
} }
case "getSemanticDiagnostics": { case "getDiagnostics": {
const diagnostics = languageService.getSemanticDiagnostics( try {
request.specifier, const diagnostics = [
).filter(({ code }) => !IGNORED_DIAGNOSTICS.includes(code)); ...languageService.getSemanticDiagnostics(request.specifier),
...languageService.getSuggestionDiagnostics(request.specifier),
...languageService.getSyntacticDiagnostics(request.specifier),
].filter(({ code }) => !IGNORED_DIAGNOSTICS.includes(code));
return respond(id, fromTypeScriptDiagnostic(diagnostics)); return respond(id, fromTypeScriptDiagnostic(diagnostics));
} catch (e) {
error(e);
return respond(id, []);
} }
case "getSuggestionDiagnostics": {
const diagnostics = languageService.getSuggestionDiagnostics(
request.specifier,
).filter(({ code }) => !IGNORED_DIAGNOSTICS.includes(code));
return respond(id, fromTypeScriptDiagnostic(diagnostics));
}
case "getSyntacticDiagnostics": {
const diagnostics = languageService.getSyntacticDiagnostics(
request.specifier,
).filter(({ code }) => !IGNORED_DIAGNOSTICS.includes(code));
return respond(id, fromTypeScriptDiagnostic(diagnostics));
} }
case "getQuickInfo": { case "getQuickInfo": {
return respond( return respond(

20
cli/tsc/compiler.d.ts vendored
View file

@ -36,16 +36,14 @@ declare global {
// deno-lint-ignore no-explicit-any // deno-lint-ignore no-explicit-any
jsonOpSync<T>(name: string, params: T): any; jsonOpSync<T>(name: string, params: T): any;
ops(): void; ops(): void;
print(msg: string): void; print(msg: string, code?: number): void;
registerErrorClass(name: string, Ctor: typeof Error): void; registerErrorClass(name: string, Ctor: typeof Error): void;
} }
type LanguageServerRequest = type LanguageServerRequest =
| ConfigureRequest | ConfigureRequest
| GetAsset | GetAsset
| GetSyntacticDiagnosticsRequest | GetDiagnosticsRequest
| GetSemanticDiagnosticsRequest
| GetSuggestionDiagnosticsRequest
| GetQuickInfoRequest | GetQuickInfoRequest
| GetDocumentHighlightsRequest | GetDocumentHighlightsRequest
| GetReferencesRequest | GetReferencesRequest
@ -69,18 +67,8 @@ declare global {
specifier: string; specifier: string;
} }
interface GetSyntacticDiagnosticsRequest extends BaseLanguageServerRequest { interface GetDiagnosticsRequest extends BaseLanguageServerRequest {
method: "getSyntacticDiagnostics"; method: "getDiagnostics";
specifier: string;
}
interface GetSemanticDiagnosticsRequest extends BaseLanguageServerRequest {
method: "getSemanticDiagnostics";
specifier: string;
}
interface GetSuggestionDiagnosticsRequest extends BaseLanguageServerRequest {
method: "getSuggestionDiagnostics";
specifier: string; specifier: string;
} }