Skip to content

Commit f0944d4

Browse files
committed
feat(deno-lint): upgrade to [email protected]
1 parent f7c9a01 commit f0944d4

File tree

2 files changed

+61
-155
lines changed

2 files changed

+61
-155
lines changed

packages/deno-lint/Cargo.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ version = "0.1.0"
88
crate-type = ["cdylib"]
99

1010
[dependencies]
11-
deno_lint = "=0.12.0"
11+
annotate-snippets = {version = "0.9", features = ["color"]}
12+
ast_view = {version = "0.33.1", package = "dprint-swc-ecma-ast-view"}
13+
deno_lint = "=0.14.0"
1214
ignore = "0.4"
1315
napi = {version = "1", features = ["serde-json"]}
1416
napi-derive = "1"
1517
serde = "1"
1618
serde_json = "1"
17-
swc_ecmascript = {version = "=0.55.1", features = ["parser", "transforms", "utils", "visit"]}
18-
termcolor = "1.1"
19+
swc_ecmascript = {version = "=0.60.0", features = ["parser", "transforms", "utils", "visit"]}
1920

2021
[target.'cfg(all(target_arch = "x86_64", not(target_env = "musl")))'.dependencies]
2122
mimalloc = {version = "0.1"}

packages/deno-lint/src/lib.rs

Lines changed: 57 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,20 @@
55
extern crate napi_derive;
66

77
use std::env;
8-
use std::fmt;
98
use std::fs;
10-
use std::io::Write;
119
use std::str;
1210

11+
use annotate_snippets::{display_list, snippet};
12+
use ast_view::{SourceFile, SourceFileTextInfo};
1313
use deno_lint::ast_parser::get_default_ts_config;
14-
use deno_lint::diagnostic::LintDiagnostic;
14+
use deno_lint::diagnostic::{LintDiagnostic, Range};
1515
use deno_lint::linter::LinterBuilder;
1616
use deno_lint::rules::{get_all_rules, get_recommended_rules};
1717
use ignore::types::TypesBuilder;
1818
use ignore::WalkBuilder;
1919
use napi::{CallContext, Error, JsBoolean, JsBuffer, JsObject, JsString, Result, Status};
2020
use swc_ecmascript::parser::Syntax;
2121
use swc_ecmascript::parser::TsConfig;
22-
use termcolor::Color::{Ansi256, Red};
23-
use termcolor::{Ansi, ColorSpec, WriteColor};
24-
25-
#[cfg(windows)]
26-
use termcolor::{BufferWriter, ColorChoice};
2722

2823
#[cfg(all(
2924
target_arch = "x86_64",
@@ -33,150 +28,60 @@ use termcolor::{BufferWriter, ColorChoice};
3328
#[global_allocator]
3429
static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;
3530

36-
#[allow(unused)]
37-
#[cfg(windows)]
38-
fn enable_ansi() {
39-
BufferWriter::stdout(ColorChoice::AlwaysAnsi);
40-
}
41-
42-
fn gray(s: String) -> impl fmt::Display {
43-
let mut style_spec = ColorSpec::new();
44-
style_spec.set_fg(Some(Ansi256(8)));
45-
style(&s, style_spec)
46-
}
47-
48-
fn red(s: String) -> impl fmt::Display {
49-
let mut style_spec = ColorSpec::new();
50-
style_spec.set_fg(Some(Red));
51-
style(&s, style_spec)
52-
}
53-
54-
fn cyan(s: String) -> impl fmt::Display {
55-
let mut style_spec = ColorSpec::new();
56-
style_spec.set_fg(Some(Ansi256(14)));
57-
style(&s, style_spec)
58-
}
59-
60-
fn bold(s: String) -> impl fmt::Display {
61-
let mut style_spec = ColorSpec::new();
62-
style_spec.set_bold(true);
63-
style(&s, style_spec)
64-
}
65-
66-
fn style(s: &str, colorspec: ColorSpec) -> impl fmt::Display {
67-
let mut v = Vec::new();
68-
let mut ansi_writer = Ansi::new(&mut v);
69-
ansi_writer.set_color(&colorspec).unwrap();
70-
ansi_writer.write_all(s.as_bytes()).unwrap();
71-
ansi_writer.reset().unwrap();
72-
String::from_utf8_lossy(&v).into_owned()
31+
// Return slice of source code covered by diagnostic
32+
// and adjusted range of diagnostic (ie. original range - start line
33+
// of sliced source code).
34+
fn get_slice_source_and_range<'a>(
35+
source_file: &'a SourceFileTextInfo,
36+
range: &Range,
37+
) -> (&'a str, (usize, usize)) {
38+
let first_line_start = source_file.line_start(range.start.line_index).0 as usize;
39+
let last_line_end = source_file.line_end(range.end.line_index).0 as usize;
40+
let adjusted_start = range.start.byte_pos - first_line_start;
41+
let adjusted_end = range.end.byte_pos - first_line_start;
42+
let adjusted_range = (adjusted_start, adjusted_end);
43+
let slice_str = &source_file.text()[first_line_start..last_line_end];
44+
(slice_str, adjusted_range)
7345
}
7446

75-
pub fn format_diagnostic(diagnostic: &LintDiagnostic, source: &str) -> String {
76-
let pretty_error = format!(
77-
"({}) {}",
78-
gray(diagnostic.code.to_string()),
79-
diagnostic.message
80-
);
81-
82-
let file_name = &diagnostic.filename;
83-
let location =
84-
if file_name.contains('/') || file_name.contains('\\') || file_name.starts_with("./") {
85-
file_name.to_string()
86-
} else {
87-
format!("./{}", file_name)
88-
};
89-
90-
let line_str_len = diagnostic.range.end.line.to_string().len();
91-
let pretty_location = cyan(format!(
92-
"{}--> {}:{}:{}",
93-
" ".repeat(line_str_len),
94-
location,
95-
diagnostic.range.start.line,
96-
diagnostic.range.start.col
97-
))
98-
.to_string();
99-
100-
let dummy = format!("{} |", " ".repeat(line_str_len));
101-
102-
if diagnostic.range.start.line == diagnostic.range.end.line {
103-
let snippet_length = diagnostic.range.end.col - diagnostic.range.start.col;
104-
let source_lines: Vec<&str> = source.split('\n').collect();
105-
let line = source_lines[diagnostic.range.start.line - 1];
106-
let pretty_line_src = format!("{} | {}", diagnostic.range.start.line, line);
107-
let red_glyphs = format!(
108-
"{} | {}{}",
109-
" ".repeat(line_str_len),
110-
" ".repeat(diagnostic.range.start.col),
111-
red("^".repeat(snippet_length))
112-
);
113-
114-
let lines = vec![
115-
pretty_error,
116-
pretty_location,
117-
dummy.clone(),
118-
pretty_line_src,
119-
red_glyphs,
120-
dummy,
121-
];
122-
123-
lines.join("\n")
47+
fn format_diagnostic(diagnostic: &LintDiagnostic, source_file: &SourceFileTextInfo) -> String {
48+
let (slice_source, range) = get_slice_source_and_range(source_file, &diagnostic.range);
49+
let footer = if let Some(hint) = &diagnostic.hint {
50+
vec![snippet::Annotation {
51+
label: Some(hint),
52+
id: None,
53+
annotation_type: snippet::AnnotationType::Help,
54+
}]
12455
} else {
125-
let mut lines = vec![pretty_error, pretty_location, dummy.clone()];
126-
let source_lines: Vec<&str> = source.split('\n').collect();
127-
128-
for i in diagnostic.range.start.line..(diagnostic.range.end.line + 1) {
129-
let line = source_lines[i - 1];
130-
let is_first = i == diagnostic.range.start.line;
131-
let is_last = i == diagnostic.range.end.line;
132-
133-
if is_first {
134-
let (rest, snippet) = line.split_at(diagnostic.range.start.col);
135-
lines.push(format!("{} | {}{}", i, rest, bold(snippet.to_string())));
136-
} else if is_last {
137-
let (snippet, rest) = line.split_at(diagnostic.range.end.col);
138-
lines.push(format!(
139-
"{} | {} {}{}",
140-
i,
141-
red("|".to_string()),
142-
bold(snippet.to_string()),
143-
rest
144-
));
145-
} else {
146-
lines.push(format!(
147-
"{} | {} {}",
148-
i,
149-
red("|".to_string()),
150-
bold(line.to_string())
151-
));
152-
}
153-
154-
// If this is the first line, render the ∨ symbols
155-
if is_first {
156-
lines.push(format!(
157-
"{} | {}{}",
158-
" ".repeat(line_str_len),
159-
red("_".repeat(diagnostic.range.start.col + 1)),
160-
red("^".to_string())
161-
));
162-
}
163-
164-
// If this is the last line, render the ∨ symbols
165-
if is_last {
166-
lines.push(format!(
167-
"{} | {}{}{}",
168-
" ".repeat(line_str_len),
169-
red("|".to_string()),
170-
red("_".repeat(diagnostic.range.end.col)),
171-
red("^".to_string())
172-
));
173-
}
174-
}
175-
176-
lines.push(dummy);
56+
vec![]
57+
};
17758

178-
lines.join("\n")
179-
}
59+
let snippet = snippet::Snippet {
60+
title: Some(snippet::Annotation {
61+
label: Some(&diagnostic.message),
62+
id: Some(&diagnostic.code),
63+
annotation_type: snippet::AnnotationType::Error,
64+
}),
65+
footer,
66+
slices: vec![snippet::Slice {
67+
source: slice_source,
68+
line_start: diagnostic.range.start.line_index + 1, // make 1-indexed
69+
origin: Some(&diagnostic.filename),
70+
fold: false,
71+
annotations: vec![snippet::SourceAnnotation {
72+
range,
73+
label: "",
74+
annotation_type: snippet::AnnotationType::Error,
75+
}],
76+
}],
77+
opt: display_list::FormatOptions {
78+
color: true,
79+
anonymized_line_numbers: false,
80+
margin: None,
81+
},
82+
};
83+
let display_list = display_list::DisplayList::from(snippet);
84+
format!("{}", display_list)
18085
}
18186

18287
#[module_exports]
@@ -208,7 +113,7 @@ fn lint(ctx: CallContext) -> Result<JsObject> {
208113

209114
let file_name_ref = file_name.as_str()?;
210115

211-
let (_, file_diagnostics) = linter
116+
let (s, file_diagnostics) = linter
212117
.lint(file_name_ref.to_owned(), source_string.to_owned())
213118
.map_err(|e| Error {
214119
status: Status::GenericFailure,
@@ -222,7 +127,7 @@ fn lint(ctx: CallContext) -> Result<JsObject> {
222127
index as _,
223128
ctx
224129
.env
225-
.create_string(format_diagnostic(diagnostic, source_string).as_str())?,
130+
.create_string(format_diagnostic(&diagnostic, &s).as_str())?,
226131
)?;
227132
}
228133

@@ -314,7 +219,7 @@ fn lint_command(ctx: CallContext) -> Result<JsBoolean> {
314219
})
315220
.syntax(syntax)
316221
.build();
317-
let (_, file_diagnostics) = linter
222+
let (s, file_diagnostics) = linter
318223
.lint(
319224
(&p.to_str())
320225
.ok_or(Error::from_reason(format!(
@@ -330,7 +235,7 @@ fn lint_command(ctx: CallContext) -> Result<JsBoolean> {
330235
})?;
331236
for diagnostic in file_diagnostics {
332237
has_error = true;
333-
println!("{}", format_diagnostic(&diagnostic, file_content.as_str()));
238+
println!("{}", format_diagnostic(&diagnostic, &s));
334239
}
335240
}
336241
}

0 commit comments

Comments
 (0)