Skip to content

Commit

Permalink
feat: Add Deno.formatDiagnostics (denoland#4032)
Browse files Browse the repository at this point in the history
  • Loading branch information
kitsonk committed Feb 24, 2020
1 parent 5da7c7d commit 2b7e28b
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 7 deletions.
17 changes: 10 additions & 7 deletions cli/diagnostics.rs
@@ -1,6 +1,10 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
//! This module encodes TypeScript errors (diagnostics) into Rust structs and
//! contains code for printing them to the console.

// TODO(ry) This module does a lot of JSON parsing manually. It should use
// serde_json.

use crate::colors;
use crate::fmt_errors::format_maybe_source_line;
use crate::fmt_errors::format_maybe_source_name;
Expand Down Expand Up @@ -29,7 +33,7 @@ impl Diagnostic {
let items_values = items_v.as_array().unwrap();

for item_v in items_values {
items.push(DiagnosticItem::from_json_value(item_v));
items.push(DiagnosticItem::from_json_value(item_v)?);
}
}

Expand Down Expand Up @@ -114,14 +118,13 @@ pub struct DiagnosticItem {
}

impl DiagnosticItem {
pub fn from_json_value(v: &serde_json::Value) -> Self {
pub fn from_json_value(v: &serde_json::Value) -> Option<Self> {
let obj = v.as_object().unwrap();

// required attributes
let message = obj
.get("message")
.and_then(|v| v.as_str().map(String::from))
.unwrap();
.and_then(|v| v.as_str().map(String::from))?;
let category = DiagnosticCategory::from(
obj.get("category").and_then(Value::as_i64).unwrap(),
);
Expand Down Expand Up @@ -154,15 +157,15 @@ impl DiagnosticItem {

for related_info_v in related_info_values {
related_information
.push(DiagnosticItem::from_json_value(related_info_v));
.push(DiagnosticItem::from_json_value(related_info_v)?);
}

Some(related_information)
}
_ => None,
};

Self {
Some(Self {
message,
message_chain,
related_information,
Expand All @@ -175,7 +178,7 @@ impl DiagnosticItem {
category,
start_column,
end_column,
}
})
}
}

Expand Down
1 change: 1 addition & 0 deletions cli/js/deno.ts
Expand Up @@ -43,6 +43,7 @@ export {
OpenOptions,
OpenMode
} from "./files.ts";
export { formatDiagnostics } from "./format_error.ts";
export { FsEvent, fsEvents } from "./fs_events.ts";
export {
EOF,
Expand Down
1 change: 1 addition & 0 deletions cli/js/dispatch.ts
Expand Up @@ -17,6 +17,7 @@ export let OP_GET_DIR: number;
export let OP_START: number;
export let OP_APPLY_SOURCE_MAP: number;
export let OP_FORMAT_ERROR: number;
export let OP_FORMAT_DIAGNOSTIC: number;
export let OP_CACHE: number;
export let OP_RESOLVE_MODULES: number;
export let OP_FETCH_ASSET: number;
Expand Down
9 changes: 9 additions & 0 deletions cli/js/format_error.ts
@@ -1,4 +1,5 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { DiagnosticItem } from "./diagnostics.ts";
import * as dispatch from "./dispatch.ts";
import { sendSync } from "./dispatch_json.ts";

Expand All @@ -7,3 +8,11 @@ export function formatError(errString: string): string {
const res = sendSync(dispatch.OP_FORMAT_ERROR, { error: errString });
return res.error;
}

/**
* Format an array of diagnostic items and return them as a single string.
* @param items An array of diagnostic items to format
*/
export function formatDiagnostics(items: DiagnosticItem[]): string {
return sendSync(dispatch.OP_FORMAT_DIAGNOSTIC, { items });
}
37 changes: 37 additions & 0 deletions cli/js/format_error_test.ts
@@ -0,0 +1,37 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { assert, test } from "./test_util.ts";

test(function formatDiagnosticBasic() {
const fixture: Deno.DiagnosticItem[] = [
{
message: "Example error",
category: Deno.DiagnosticCategory.Error,
sourceLine: "abcdefghijklmnopqrstuv",
lineNumber: 1000,
scriptResourceName: "foo.ts",
startColumn: 1,
endColumn: 2,
code: 4000
}
];
const out = Deno.formatDiagnostics(fixture);
assert(out.includes("Example error"));
assert(out.includes("foo.ts"));
});

test(function formatDiagnosticError() {
let thrown = false;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const bad = ([{ hello: 123 }] as any) as Deno.DiagnosticItem[];
try {
Deno.formatDiagnostics(bad);
} catch (e) {
assert(e instanceof TypeError);
thrown = true;
}
assert(thrown);
});

if (import.meta.main) {
Deno.runTests();
}
7 changes: 7 additions & 0 deletions cli/js/lib.deno.ns.d.ts
Expand Up @@ -1901,6 +1901,13 @@ declare namespace Deno {
items: DiagnosticItem[];
}

/** UNSTABLE: new API, yet to be vetted.
*
* Format an array of diagnostic items and return them as a single string.
* @param items An array of diagnostic items to format
*/
export function formatDiagnostics(items: DiagnosticItem[]): string;

/** UNSTABLE: new API, yet to be vetted.
*
* A specific subset TypeScript compiler options that can be supported by
Expand Down
1 change: 1 addition & 0 deletions cli/js/unit_tests.ts
Expand Up @@ -23,6 +23,7 @@ import "./fetch_test.ts";
import "./file_test.ts";
import "./files_test.ts";
import "./form_data_test.ts";
import "./format_error_test.ts";
import "./fs_events_test.ts";
import "./get_random_values_test.ts";
import "./globals_test.ts";
Expand Down
17 changes: 17 additions & 0 deletions cli/ops/errors.rs
@@ -1,5 +1,6 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use super::dispatch_json::{Deserialize, JsonOp, Value};
use crate::diagnostics::Diagnostic;
use crate::fmt_errors::JSError;
use crate::op_error::OpError;
use crate::ops::json_op;
Expand All @@ -18,6 +19,10 @@ pub fn init(i: &mut Isolate, s: &State) {
"format_error",
s.core_op(json_op(s.stateful_op(op_format_error))),
);
i.register_op(
"format_diagnostic",
s.core_op(json_op(s.stateful_op(op_format_diagnostic))),
);
}

#[derive(Deserialize)]
Expand Down Expand Up @@ -68,3 +73,15 @@ fn op_apply_source_map(
"column": orig_column as u32,
})))
}

fn op_format_diagnostic(
_state: &State,
args: Value,
_zero_copy: Option<ZeroCopyBuf>,
) -> Result<JsonOp, OpError> {
if let Some(diagnostic) = Diagnostic::from_json_value(&args) {
Ok(JsonOp::Sync(json!(diagnostic.to_string())))
} else {
Err(OpError::type_error("bad diagnostic".to_string()))
}
}

0 comments on commit 2b7e28b

Please sign in to comment.