diff options
Diffstat (limited to 'cli/tools')
-rw-r--r-- | cli/tools/doc.rs | 137 | ||||
-rw-r--r-- | cli/tools/lint.rs | 181 | ||||
-rw-r--r-- | cli/tools/registry/diagnostics.rs | 175 | ||||
-rw-r--r-- | cli/tools/registry/graph.rs | 25 | ||||
-rw-r--r-- | cli/tools/registry/mod.rs | 11 | ||||
-rw-r--r-- | cli/tools/registry/tar.rs | 2 | ||||
-rw-r--r-- | cli/tools/repl/session.rs | 15 | ||||
-rw-r--r-- | cli/tools/test/mod.rs | 2 | ||||
-rw-r--r-- | cli/tools/test/reporters/pretty.rs | 2 | ||||
-rw-r--r-- | cli/tools/vendor/analyze.rs | 3 |
10 files changed, 187 insertions, 366 deletions
diff --git a/cli/tools/doc.rs b/cli/tools/doc.rs index 729ee05fc..d2cd0c2a2 100644 --- a/cli/tools/doc.rs +++ b/cli/tools/doc.rs @@ -4,24 +4,14 @@ use crate::args::DocFlags; use crate::args::DocHtmlFlag; use crate::args::DocSourceFileFlag; use crate::args::Flags; -use crate::cache::LazyGraphSourceParser; use crate::colors; -use crate::diagnostics::Diagnostic; -use crate::diagnostics::DiagnosticLevel; -use crate::diagnostics::DiagnosticLocation; -use crate::diagnostics::DiagnosticSnippet; -use crate::diagnostics::DiagnosticSnippetHighlight; -use crate::diagnostics::DiagnosticSnippetHighlightStyle; -use crate::diagnostics::DiagnosticSnippetSource; -use crate::diagnostics::DiagnosticSourcePos; -use crate::diagnostics::DiagnosticSourceRange; -use crate::diagnostics::SourceTextParsedSourceStore; use crate::display::write_json_to_stdout; use crate::display::write_to_stdout_ignore_sigpipe; use crate::factory::CliFactory; use crate::graph_util::graph_lock_or_exit; use crate::tsc::get_types_declaration_file_text; use crate::util::fs::collect_specifiers; +use deno_ast::diagnostics::Diagnostic; use deno_config::glob::FilePatterns; use deno_config::glob::PathOrPatternSet; use deno_core::anyhow::bail; @@ -34,10 +24,7 @@ use deno_graph::ModuleAnalyzer; use deno_graph::ModuleParser; use deno_graph::ModuleSpecifier; use doc::DocDiagnostic; -use doc::DocDiagnosticKind; use indexmap::IndexMap; -use lsp_types::Url; -use std::borrow::Cow; use std::collections::BTreeMap; use std::rc::Rc; @@ -143,10 +130,7 @@ pub async fn doc(flags: Flags, doc_flags: DocFlags) -> Result<(), AnyError> { if doc_flags.lint { let diagnostics = doc_parser.take_diagnostics(); - check_diagnostics( - LazyGraphSourceParser::new(parsed_source_cache, &graph), - &diagnostics, - )?; + check_diagnostics(&diagnostics)?; } doc_nodes_by_url @@ -252,6 +236,7 @@ async fn generate_docs_directory( hide_module_doc_title: false, href_resolver: Rc::new(DocResolver { deno_ns }), sidebar_flatten_namespaces: false, + usage_composer: None, }; let files = deno_doc::html::generate(options, doc_nodes_by_url) @@ -308,118 +293,7 @@ fn print_docs_to_stdout( write_to_stdout_ignore_sigpipe(details.as_bytes()).map_err(AnyError::from) } -impl Diagnostic for DocDiagnostic { - fn level(&self) -> DiagnosticLevel { - DiagnosticLevel::Error - } - - fn code(&self) -> impl std::fmt::Display + '_ { - match self.kind { - DocDiagnosticKind::MissingJsDoc => "missing-jsdoc", - DocDiagnosticKind::MissingExplicitType => "missing-explicit-type", - DocDiagnosticKind::MissingReturnType => "missing-return-type", - DocDiagnosticKind::PrivateTypeRef { .. } => "private-type-ref", - } - } - - fn message(&self) -> impl std::fmt::Display + '_ { - match &self.kind { - DocDiagnosticKind::MissingJsDoc => { - Cow::Borrowed("exported symbol is missing JSDoc documentation") - } - DocDiagnosticKind::MissingExplicitType => { - Cow::Borrowed("exported symbol is missing an explicit type annotation") - } - DocDiagnosticKind::MissingReturnType => Cow::Borrowed( - "exported function is missing an explicit return type annotation", - ), - DocDiagnosticKind::PrivateTypeRef { - reference, name, .. - } => Cow::Owned(format!( - "public type '{name}' references private type '{reference}'", - )), - } - } - - fn location(&self) -> DiagnosticLocation { - let specifier = Url::parse(&self.location.filename).unwrap(); - DiagnosticLocation::ModulePosition { - specifier: Cow::Owned(specifier), - source_pos: DiagnosticSourcePos::ByteIndex(self.location.byte_index), - } - } - - fn snippet(&self) -> Option<DiagnosticSnippet<'_>> { - let specifier = Url::parse(&self.location.filename).unwrap(); - Some(DiagnosticSnippet { - source: DiagnosticSnippetSource::Specifier(Cow::Owned(specifier)), - highlight: DiagnosticSnippetHighlight { - style: DiagnosticSnippetHighlightStyle::Error, - range: DiagnosticSourceRange { - start: DiagnosticSourcePos::ByteIndex(self.location.byte_index), - end: DiagnosticSourcePos::ByteIndex(self.location.byte_index + 1), - }, - description: None, - }, - }) - } - - fn hint(&self) -> Option<impl std::fmt::Display + '_> { - match &self.kind { - DocDiagnosticKind::PrivateTypeRef { .. } => { - Some("make the referenced type public or remove the reference") - } - _ => None, - } - } - fn snippet_fixed(&self) -> Option<DiagnosticSnippet<'_>> { - match &self.kind { - DocDiagnosticKind::PrivateTypeRef { - reference_location, .. - } => { - let specifier = Url::parse(&reference_location.filename).unwrap(); - Some(DiagnosticSnippet { - source: DiagnosticSnippetSource::Specifier(Cow::Owned(specifier)), - highlight: DiagnosticSnippetHighlight { - style: DiagnosticSnippetHighlightStyle::Hint, - range: DiagnosticSourceRange { - start: DiagnosticSourcePos::ByteIndex( - reference_location.byte_index, - ), - end: DiagnosticSourcePos::ByteIndex( - reference_location.byte_index + 1, - ), - }, - description: Some(Cow::Borrowed("this is the referenced type")), - }, - }) - } - _ => None, - } - } - - fn info(&self) -> std::borrow::Cow<'_, [std::borrow::Cow<'_, str>]> { - match &self.kind { - DocDiagnosticKind::MissingJsDoc => Cow::Borrowed(&[]), - DocDiagnosticKind::MissingExplicitType => Cow::Borrowed(&[]), - DocDiagnosticKind::MissingReturnType => Cow::Borrowed(&[]), - DocDiagnosticKind::PrivateTypeRef { .. } => { - Cow::Borrowed(&[Cow::Borrowed( - "to ensure documentation is complete all types that are exposed in the public API must be public", - )]) - } - } - } - - fn docs_url(&self) -> Option<impl std::fmt::Display + '_> { - None::<&str> - } -} - -fn check_diagnostics( - source_parser: LazyGraphSourceParser, - diagnostics: &[DocDiagnostic], -) -> Result<(), AnyError> { +fn check_diagnostics(diagnostics: &[DocDiagnostic]) -> Result<(), AnyError> { if diagnostics.is_empty() { return Ok(()); } @@ -441,8 +315,7 @@ fn check_diagnostics( for (_, diagnostics_by_col) in diagnostics_by_lc { for (_, diagnostics) in diagnostics_by_col { for diagnostic in diagnostics { - let sources = SourceTextParsedSourceStore(source_parser); - log::error!("{}", diagnostic.display(&sources)); + log::error!("{}", diagnostic.display()); } } } diff --git a/cli/tools/lint.rs b/cli/tools/lint.rs index e9f84fd77..32b47e453 100644 --- a/cli/tools/lint.rs +++ b/cli/tools/lint.rs @@ -8,33 +8,22 @@ use crate::args::LintOptions; use crate::args::LintReporterKind; use crate::args::LintRulesConfig; use crate::colors; -use crate::diagnostics::Diagnostic; -use crate::diagnostics::DiagnosticLevel; -use crate::diagnostics::DiagnosticLocation; -use crate::diagnostics::DiagnosticSnippet; -use crate::diagnostics::DiagnosticSnippetHighlight; -use crate::diagnostics::DiagnosticSnippetHighlightStyle; -use crate::diagnostics::DiagnosticSnippetSource; -use crate::diagnostics::DiagnosticSourcePos; -use crate::diagnostics::DiagnosticSourceRange; -use crate::diagnostics::SourceTextStore; use crate::factory::CliFactory; use crate::tools::fmt::run_parallelized; use crate::util::file_watcher; use crate::util::fs::canonicalize_path; +use crate::util::fs::specifier_from_file_path; use crate::util::fs::FileCollector; use crate::util::path::is_script_ext; use crate::util::sync::AtomicFlag; +use deno_ast::diagnostics::Diagnostic; use deno_ast::MediaType; -use deno_ast::ModuleSpecifier; use deno_ast::ParsedSource; -use deno_ast::SourceTextInfo; use deno_config::glob::FilePatterns; use deno_core::anyhow::bail; use deno_core::error::generic_error; use deno_core::error::AnyError; use deno_core::serde_json; -use deno_core::url; use deno_lint::diagnostic::LintDiagnostic; use deno_lint::linter::LintFileOptions; use deno_lint::linter::Linter; @@ -44,7 +33,6 @@ use deno_lint::rules::LintRule; use log::debug; use log::info; use serde::Serialize; -use std::borrow::Cow; use std::fs; use std::io::stdin; use std::io::Read; @@ -124,9 +112,12 @@ pub async fn lint(flags: Flags, lint_flags: LintFlags) -> Result<(), AnyError> { let reporter_lock = Arc::new(Mutex::new(create_reporter(reporter_kind))); let lint_rules = get_config_rules_err_empty(lint_options.rules)?; let file_path = cli_options.initial_cwd().join(STDIN_FILE_NAME); - let file_path = file_path.to_string_lossy(); let r = lint_stdin(&file_path, lint_rules); - let success = handle_lint_result(&file_path, r, reporter_lock.clone()); + let success = handle_lint_result( + &file_path.to_string_lossy(), + r, + reporter_lock.clone(), + ); reporter_lock.lock().unwrap().close(1); success } else { @@ -278,13 +269,13 @@ fn lint_file( source_code: String, lint_rules: Vec<&'static dyn LintRule>, ) -> Result<(Vec<LintDiagnostic>, ParsedSource), AnyError> { - let filename = file_path.to_string_lossy().to_string(); - let media_type = MediaType::from_path(file_path); + let specifier = specifier_from_file_path(file_path)?; + let media_type = MediaType::from_specifier(&specifier); let linter = create_linter(lint_rules); let (source, file_diagnostics) = linter.lint_file(LintFileOptions { - filename, + specifier, media_type, source_code: source_code.clone(), })?; @@ -296,7 +287,7 @@ fn lint_file( /// Treats input as TypeScript. /// Compatible with `--json` flag. fn lint_stdin( - file_path: &str, + file_path: &Path, lint_rules: Vec<&'static dyn LintRule>, ) -> Result<(Vec<LintDiagnostic>, ParsedSource), AnyError> { let mut source_code = String::new(); @@ -307,7 +298,7 @@ fn lint_stdin( let linter = create_linter(lint_rules); let (source, file_diagnostics) = linter.lint_file(LintFileOptions { - filename: file_path.to_string(), + specifier: specifier_from_file_path(file_path)?, source_code: source_code.clone(), media_type: MediaType::TypeScript, })?; @@ -324,7 +315,10 @@ fn handle_lint_result( match result { Ok((mut file_diagnostics, source)) => { - sort_diagnostics(&mut file_diagnostics); + file_diagnostics.sort_by(|a, b| match a.specifier.cmp(&b.specifier) { + std::cmp::Ordering::Equal => a.range.start.cmp(&b.range.start), + file_order => file_order, + }); for d in file_diagnostics.iter() { reporter.visit_diagnostic(d, &source); } @@ -359,77 +353,11 @@ impl PrettyLintReporter { } } -impl Diagnostic for LintDiagnostic { - fn level(&self) -> DiagnosticLevel { - DiagnosticLevel::Error - } - - fn code(&self) -> impl std::fmt::Display + '_ { - &self.code - } - - fn message(&self) -> impl std::fmt::Display + '_ { - &self.message - } - - fn location(&self) -> DiagnosticLocation { - let specifier = url::Url::from_file_path(&self.filename).unwrap(); - DiagnosticLocation::ModulePosition { - specifier: Cow::Owned(specifier), - source_pos: DiagnosticSourcePos::ByteIndex(self.range.start.byte_index), - } - } - - fn snippet(&self) -> Option<DiagnosticSnippet<'_>> { - let specifier = url::Url::from_file_path(&self.filename).unwrap(); - let range = DiagnosticSourceRange { - start: DiagnosticSourcePos::ByteIndex(self.range.start.byte_index), - end: DiagnosticSourcePos::ByteIndex(self.range.end.byte_index), - }; - Some(DiagnosticSnippet { - source: DiagnosticSnippetSource::Specifier(Cow::Owned(specifier)), - highlight: DiagnosticSnippetHighlight { - range, - style: DiagnosticSnippetHighlightStyle::Error, - description: None, - }, - }) - } - - fn hint(&self) -> Option<impl std::fmt::Display + '_> { - self.hint.as_ref().map(|h| h as &dyn std::fmt::Display) - } - - fn snippet_fixed(&self) -> Option<DiagnosticSnippet<'_>> { - None // todo - } - - fn info(&self) -> Cow<'_, [std::borrow::Cow<'_, str>]> { - Cow::Borrowed(&[]) - } - - fn docs_url(&self) -> Option<impl std::fmt::Display + '_> { - Some(format!("https://lint.deno.land/#{}", &self.code)) - } -} - -struct OneSource<'a>(&'a ParsedSource); - -impl SourceTextStore for OneSource<'_> { - fn get_source_text<'a>( - &'a self, - _specifier: &ModuleSpecifier, - ) -> Option<Cow<'a, SourceTextInfo>> { - Some(Cow::Borrowed(self.0.text_info())) - } -} - impl LintReporter for PrettyLintReporter { - fn visit_diagnostic(&mut self, d: &LintDiagnostic, source: &ParsedSource) { + fn visit_diagnostic(&mut self, d: &LintDiagnostic, _source: &ParsedSource) { self.lint_count += 1; - let sources = OneSource(source); - eprintln!("{}", d.display(&sources)); + eprintln!("{}", d.display()); } fn visit_error(&mut self, file_path: &str, err: &AnyError) { @@ -466,11 +394,12 @@ impl LintReporter for CompactLintReporter { fn visit_diagnostic(&mut self, d: &LintDiagnostic, _source: &ParsedSource) { self.lint_count += 1; + let line_and_column = d.text_info.line_and_column_display(d.range.start); eprintln!( "{}: line {}, col {} - {} ({})", - d.filename, - d.range.start.line_index + 1, - d.range.start.column_index + 1, + d.specifier, + line_and_column.line_number, + line_and_column.column_number, d.message, d.code ) @@ -496,9 +425,47 @@ impl LintReporter for CompactLintReporter { } } +// WARNING: Ensure doesn't change because it's used in the JSON output +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct JsonDiagnosticLintPosition { + /// The 1-indexed line number. + pub line: usize, + /// The 0-indexed column index. + pub col: usize, + pub byte_pos: usize, +} + +impl JsonDiagnosticLintPosition { + pub fn new(byte_index: usize, loc: deno_ast::LineAndColumnIndex) -> Self { + JsonDiagnosticLintPosition { + line: loc.line_index + 1, + col: loc.column_index, + byte_pos: byte_index, + } + } +} + +// WARNING: Ensure doesn't change because it's used in the JSON output +#[derive(Debug, Clone, PartialEq, Eq, Serialize)] +struct JsonLintDiagnosticRange { + pub start: JsonDiagnosticLintPosition, + pub end: JsonDiagnosticLintPosition, +} + +// WARNING: Ensure doesn't change because it's used in the JSON output +#[derive(Clone, Serialize)] +struct JsonLintDiagnostic { + pub filename: String, + pub range: JsonLintDiagnosticRange, + pub message: String, + pub code: String, + pub hint: Option<String>, +} + #[derive(Serialize)] struct JsonLintReporter { - diagnostics: Vec<LintDiagnostic>, + diagnostics: Vec<JsonLintDiagnostic>, errors: Vec<LintError>, } @@ -513,7 +480,22 @@ impl JsonLintReporter { impl LintReporter for JsonLintReporter { fn visit_diagnostic(&mut self, d: &LintDiagnostic, _source: &ParsedSource) { - self.diagnostics.push(d.clone()); + self.diagnostics.push(JsonLintDiagnostic { + filename: d.specifier.to_string(), + range: JsonLintDiagnosticRange { + start: JsonDiagnosticLintPosition::new( + d.range.start.as_byte_index(d.text_info.range().start), + d.text_info.line_and_column_index(d.range.start), + ), + end: JsonDiagnosticLintPosition::new( + d.range.end.as_byte_index(d.text_info.range().start), + d.text_info.line_and_column_index(d.range.end), + ), + }, + message: d.message.clone(), + code: d.code.clone(), + hint: d.hint.clone(), + }); } fn visit_error(&mut self, file_path: &str, err: &AnyError) { @@ -530,19 +512,16 @@ impl LintReporter for JsonLintReporter { } } -fn sort_diagnostics(diagnostics: &mut [LintDiagnostic]) { +fn sort_diagnostics(diagnostics: &mut [JsonLintDiagnostic]) { // Sort so that we guarantee a deterministic output which is useful for tests diagnostics.sort_by(|a, b| { use std::cmp::Ordering; let file_order = a.filename.cmp(&b.filename); match file_order { Ordering::Equal => { - let line_order = - a.range.start.line_index.cmp(&b.range.start.line_index); + let line_order = a.range.start.line.cmp(&b.range.start.line); match line_order { - Ordering::Equal => { - a.range.start.column_index.cmp(&b.range.start.column_index) - } + Ordering::Equal => a.range.start.col.cmp(&b.range.start.col), _ => line_order, } } diff --git a/cli/tools/registry/diagnostics.rs b/cli/tools/registry/diagnostics.rs index e7f947303..aeb5d61e2 100644 --- a/cli/tools/registry/diagnostics.rs +++ b/cli/tools/registry/diagnostics.rs @@ -1,28 +1,25 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. use std::borrow::Cow; -use std::fmt::Display; use std::path::PathBuf; use std::sync::Arc; use std::sync::Mutex; +use deno_ast::diagnostics::Diagnostic; +use deno_ast::diagnostics::DiagnosticLevel; +use deno_ast::diagnostics::DiagnosticLocation; +use deno_ast::diagnostics::DiagnosticSnippet; +use deno_ast::diagnostics::DiagnosticSnippetHighlight; +use deno_ast::diagnostics::DiagnosticSnippetHighlightStyle; +use deno_ast::diagnostics::DiagnosticSourcePos; +use deno_ast::diagnostics::DiagnosticSourceRange; use deno_ast::swc::common::util::take::Take; +use deno_ast::SourceTextInfo; use deno_core::anyhow::anyhow; use deno_core::error::AnyError; use deno_graph::FastCheckDiagnostic; use lsp_types::Url; -use crate::cache::LazyGraphSourceParser; -use crate::diagnostics::Diagnostic; -use crate::diagnostics::DiagnosticLevel; -use crate::diagnostics::DiagnosticLocation; -use crate::diagnostics::DiagnosticSnippet; -use crate::diagnostics::DiagnosticSnippetHighlight; -use crate::diagnostics::DiagnosticSnippetHighlightStyle; -use crate::diagnostics::DiagnosticSnippetSource; -use crate::diagnostics::DiagnosticSourcePos; -use crate::diagnostics::DiagnosticSourceRange; -use crate::diagnostics::SourceTextParsedSourceStore; use crate::util::import_map::ImportMapUnfurlDiagnostic; #[derive(Clone, Default)] @@ -31,16 +28,12 @@ pub struct PublishDiagnosticsCollector { } impl PublishDiagnosticsCollector { - pub fn print_and_error( - &self, - sources: LazyGraphSourceParser, - ) -> Result<(), AnyError> { + pub fn print_and_error(&self) -> Result<(), AnyError> { let mut errors = 0; let mut has_zap_errors = false; let diagnostics = self.diagnostics.lock().unwrap().take(); - let sources = SourceTextParsedSourceStore(sources); for diagnostic in diagnostics { - eprint!("{}", diagnostic.display(&sources)); + eprint!("{}", diagnostic.display()); if matches!(diagnostic.level(), DiagnosticLevel::Error) { errors += 1; } @@ -90,6 +83,7 @@ pub enum PublishDiagnostic { InvalidExternalImport { kind: String, imported: Url, + text_info: SourceTextInfo, referrer: deno_graph::Range, }, } @@ -110,22 +104,22 @@ impl Diagnostic for PublishDiagnostic { } } - fn code(&self) -> impl Display + '_ { + fn code(&self) -> Cow<'_, str> { use PublishDiagnostic::*; match &self { FastCheck(diagnostic) => diagnostic.code(), - ImportMapUnfurl(diagnostic) => diagnostic.code(), - InvalidPath { .. } => "invalid-path", - DuplicatePath { .. } => "case-insensitive-duplicate-path", - UnsupportedFileType { .. } => "unsupported-file-type", - InvalidExternalImport { .. } => "invalid-external-import", + ImportMapUnfurl(diagnostic) => Cow::Borrowed(diagnostic.code()), + InvalidPath { .. } => Cow::Borrowed("invalid-path"), + DuplicatePath { .. } => Cow::Borrowed("case-insensitive-duplicate-path"), + UnsupportedFileType { .. } => Cow::Borrowed("unsupported-file-type"), + InvalidExternalImport { .. } => Cow::Borrowed("invalid-external-import"), } } - fn message(&self) -> impl Display + '_ { + fn message(&self) -> Cow<'_, str> { use PublishDiagnostic::*; match &self { - FastCheck(diagnostic) => Cow::Owned(diagnostic.to_string()) , + FastCheck(diagnostic) => diagnostic.message(), ImportMapUnfurl(diagnostic) => Cow::Borrowed(diagnostic.message()), InvalidPath { message, .. } => Cow::Borrowed(message.as_str()), DuplicatePath { .. } => { @@ -141,21 +135,15 @@ impl Diagnostic for PublishDiagnostic { fn location(&self) -> DiagnosticLocation { use PublishDiagnostic::*; match &self { - FastCheck(diagnostic) => match diagnostic.range() { - Some(range) => DiagnosticLocation::ModulePosition { - specifier: Cow::Borrowed(diagnostic.specifier()), - source_pos: DiagnosticSourcePos::SourcePos(range.range.start), - }, - None => DiagnosticLocation::Module { - specifier: Cow::Borrowed(diagnostic.specifier()), - }, - }, + FastCheck(diagnostic) => diagnostic.location(), ImportMapUnfurl(diagnostic) => match diagnostic { ImportMapUnfurlDiagnostic::UnanalyzableDynamicImport { specifier, + text_info, range, } => DiagnosticLocation::ModulePosition { specifier: Cow::Borrowed(specifier), + text_info: Cow::Borrowed(text_info), source_pos: DiagnosticSourcePos::SourcePos(range.start), }, }, @@ -168,41 +156,31 @@ impl Diagnostic for PublishDiagnostic { UnsupportedFileType { specifier, .. } => DiagnosticLocation::Module { specifier: Cow::Borrowed(specifier), }, - InvalidExternalImport { referrer, .. } => { - DiagnosticLocation::ModulePosition { - specifier: Cow::Borrowed(&referrer.specifier), - source_pos: DiagnosticSourcePos::LineAndCol { - line: referrer.start.line, - column: referrer.start.character, - }, - } - } + InvalidExternalImport { + referrer, + text_info, + .. + } => DiagnosticLocation::ModulePosition { + specifier: Cow::Borrowed(&referrer.specifier), + text_info: Cow::Borrowed(text_info), + source_pos: DiagnosticSourcePos::LineAndCol { + line: referrer.start.line, + column: referrer.start.character, + }, + }, } } fn snippet(&self) -> Option<DiagnosticSnippet<'_>> { match &self { - PublishDiagnostic::FastCheck(diagnostic) => { - diagnostic.range().map(|range| DiagnosticSnippet { - source: DiagnosticSnippetSource::Specifier(Cow::Borrowed( - diagnostic.specifier(), - )), - highlight: DiagnosticSnippetHighlight { - style: DiagnosticSnippetHighlightStyle::Error, - range: DiagnosticSourceRange { - start: DiagnosticSourcePos::SourcePos(range.range.start), - end: DiagnosticSourcePos::SourcePos(range.range.end), - }, - description: diagnostic.range_description().map(Cow::Borrowed), - }, - }) - } + PublishDiagnostic::FastCheck(diagnostic) => diagnostic.snippet(), PublishDiagnostic::ImportMapUnfurl(diagnostic) => match diagnostic { ImportMapUnfurlDiagnostic::UnanalyzableDynamicImport { - specifier, + text_info, range, + .. } => Some(DiagnosticSnippet { - source: DiagnosticSnippetSource::Specifier(Cow::Borrowed(specifier)), + source: Cow::Borrowed(text_info), highlight: DiagnosticSnippetHighlight { style: DiagnosticSnippetHighlightStyle::Warning, range: DiagnosticSourceRange { @@ -216,44 +194,44 @@ impl Diagnostic for PublishDiagnostic { PublishDiagnostic::InvalidPath { .. } => None, PublishDiagnostic::DuplicatePath { .. } => None, PublishDiagnostic::UnsupportedFileType { .. } => None, - PublishDiagnostic::InvalidExternalImport { referrer, .. } => { - Some(DiagnosticSnippet { - source: DiagnosticSnippetSource::Specifier(Cow::Borrowed( - &referrer.specifier, - )), - highlight: DiagnosticSnippetHighlight { - style: DiagnosticSnippetHighlightStyle::Error, - range: DiagnosticSourceRange { - start: DiagnosticSourcePos::LineAndCol { - line: referrer.start.line, - column: referrer.start.character, - }, - end: DiagnosticSourcePos::LineAndCol { - line: referrer.end.line, - column: referrer.end.character, - }, + PublishDiagnostic::InvalidExternalImport { + referrer, + text_info, + .. + } => Some(DiagnosticSnippet { + source: Cow::Borrowed(text_info), + highlight: DiagnosticSnippetHighlight { + style: DiagnosticSnippetHighlightStyle::Error, + range: DiagnosticSourceRange { + start: DiagnosticSourcePos::LineAndCol { + line: referrer.start.line, + column: referrer.start.character, + }, + end: DiagnosticSourcePos::LineAndCol { + line: referrer.end.line, + column: referrer.end.character, }, - description: Some("the specifier".into()), }, - }) - } + description: Some("the specifier".into()), + }, + }), } } - fn hint(&self) -> Option<impl Display + '_> { + fn hint(&self) -> Option<Cow<'_, str>> { match &self { - PublishDiagnostic::FastCheck(diagnostic) => Some(diagnostic.fix_hint()), + PublishDiagnostic::FastCheck(diagnostic) => diagnostic.hint(), PublishDiagnostic::ImportMapUnfurl(_) => None, PublishDiagnostic::InvalidPath { .. } => Some( - "rename or remove the file, or add it to 'publish.exclude' in the config file", + Cow::Borrowed("rename or remove the file, or add it to 'publish.exclude' in the config file"), ), PublishDiagnostic::DuplicatePath { .. } => Some( - "rename or remove the file", + Cow::Borrowed("rename or remove the file"), ), PublishDiagnostic::UnsupportedFileType { .. } => Some( - "remove the file, or add it to 'publish.exclude' in the config file", + Cow::Borrowed("remove the file, or add it to 'publish.exclude' in the config file"), ), - PublishDiagnostic::InvalidExternalImport { .. } => Some("replace this import with one from jsr or npm, or vendor the dependency into your package") + PublishDiagnostic::InvalidExternalImport { .. } => Some(Cow::Borrowed("replace this import with one from jsr or npm, or vendor the dependency into your package")) } } @@ -264,12 +242,7 @@ impl Diagnostic for PublishDiagnostic { fn info(&self) -> Cow<'_, [Cow<'_, str>]> { match &self { PublishDiagnostic::FastCheck(diagnostic) => { - let infos = diagnostic - .additional_info() - .iter() - .map(|s| Cow::Borrowed(*s)) - .collect(); - Cow::Owned(infos) + diagnostic.info() } PublishDiagnostic::ImportMapUnfurl(diagnostic) => match diagnostic { ImportMapUnfurlDiagnostic::UnanalyzableDynamicImport { .. } => Cow::Borrowed(&[ @@ -296,25 +269,23 @@ impl Diagnostic for PublishDiagnostic { } } - fn docs_url(&self) -> Option<impl Display + '_> { + fn docs_url(&self) -> Option<Cow<'_, str>> { match &self { - PublishDiagnostic::FastCheck(diagnostic) => { - Some(format!("https://jsr.io/go/{}", diagnostic.code())) - } + PublishDiagnostic::FastCheck(diagnostic) => diagnostic.docs_url(), PublishDiagnostic::ImportMapUnfurl(diagnostic) => match diagnostic { ImportMapUnfurlDiagnostic::UnanalyzableDynamicImport { .. } => None, }, PublishDiagnostic::InvalidPath { .. } => { - Some("https://jsr.io/go/invalid-path".to_owned()) - } - PublishDiagnostic::DuplicatePath { .. } => { - Some("https://jsr.io/go/case-insensitive-duplicate-path".to_owned()) + Some(Cow::Borrowed("https://jsr.io/go/invalid-path")) } + PublishDiagnostic::DuplicatePath { .. } => Some(Cow::Borrowed( + "https://jsr.io/go/case-insensitive-duplicate-path", + )), PublishDiagnostic::UnsupportedFileType { .. } => { - Some("https://jsr.io/go/unsupported-file-type".to_owned()) + Some(Cow::Borrowed("https://jsr.io/go/unsupported-file-type")) } PublishDiagnostic::InvalidExternalImport { .. } => { - Some("https://jsr.io/go/invalid-external-import".to_owned()) + Some(Cow::Borrowed("https://jsr.io/go/invalid-external-import")) } } } diff --git a/cli/tools/registry/graph.rs b/cli/tools/registry/graph.rs index d9fb665c4..3445d55e7 100644 --- a/cli/tools/registry/graph.rs +++ b/cli/tools/registry/graph.rs @@ -2,8 +2,10 @@ use std::collections::HashSet; use std::collections::VecDeque; +use std::sync::Arc; use deno_ast::ModuleSpecifier; +use deno_ast::SourceTextInfo; use deno_config::ConfigFile; use deno_config::WorkspaceConfig; use deno_core::anyhow::bail; @@ -76,7 +78,9 @@ pub fn collect_invalid_external_imports( let mut skip_specifiers: HashSet<Url> = HashSet::new(); let mut collect_if_invalid = - |skip_specifiers: &mut HashSet<Url>, resolution: &ResolutionResolved| { + |skip_specifiers: &mut HashSet<Url>, + text: &Arc<str>, + resolution: &ResolutionResolved| { if visited.insert(resolution.specifier.clone()) { match resolution.specifier.scheme() { "file" | "data" | "node" => {} @@ -88,6 +92,7 @@ pub fn collect_invalid_external_imports( diagnostics_collector.push( PublishDiagnostic::InvalidExternalImport { kind: format!("non-JSR '{}'", resolution.specifier.scheme()), + text_info: SourceTextInfo::new(text.clone()), imported: resolution.specifier.clone(), referrer: resolution.range.clone(), }, @@ -98,6 +103,7 @@ pub fn collect_invalid_external_imports( diagnostics_collector.push( PublishDiagnostic::InvalidExternalImport { kind: format!("'{}'", resolution.specifier.scheme()), + text_info: SourceTextInfo::new(text.clone()), imported: resolution.specifier.clone(), referrer: resolution.range.clone(), }, @@ -128,10 +134,10 @@ pub fn collect_invalid_external_imports( for (_, dep) in &module.dependencies { if let Some(resolved) = dep.maybe_code.ok() { - collect_if_invalid(&mut skip_specifiers, resolved); + collect_if_invalid(&mut skip_specifiers, &module.source, resolved); } if let Some(resolved) = dep.maybe_type.ok() { - collect_if_invalid(&mut skip_specifiers, resolved); + collect_if_invalid(&mut skip_specifiers, &module.source, resolved); } } } @@ -144,7 +150,7 @@ pub fn collect_fast_check_type_graph_diagnostics( packages: &[MemberRoots], diagnostics_collector: &PublishDiagnosticsCollector, ) -> bool { - let mut seen_diagnostics = HashSet::new(); + let mut had_diagnostic = false; let mut seen_modules = HashSet::with_capacity(graph.specifiers_count()); for package in packages { let mut pending = VecDeque::new(); @@ -161,12 +167,9 @@ pub fn collect_fast_check_type_graph_diagnostics( let Some(es_module) = module.js() else { continue; }; - if let Some(diagnostic) = es_module.fast_check_diagnostic() { - for diagnostic in diagnostic.flatten_multiple() { - if !seen_diagnostics.insert(diagnostic.message_with_range_for_test()) - { - continue; - } + if let Some(diagnostics) = es_module.fast_check_diagnostics() { + for diagnostic in diagnostics { + had_diagnostic = true; diagnostics_collector .push(PublishDiagnostic::FastCheck(diagnostic.clone())); if matches!( @@ -197,5 +200,5 @@ pub fn collect_fast_check_type_graph_diagnostics( } } - !seen_diagnostics.is_empty() + had_diagnostic } diff --git a/cli/tools/registry/mod.rs b/cli/tools/registry/mod.rs index 5f03fa6fd..cfdec04c5 100644 --- a/cli/tools/registry/mod.rs +++ b/cli/tools/registry/mod.rs @@ -643,7 +643,6 @@ async fn publish_package( struct PreparePackagesData { publish_order_graph: PublishOrderGraph, - graph: Arc<deno_graph::ModuleGraph>, package_by_name: HashMap<String, Rc<PreparedPublishPackage>>, } @@ -678,7 +677,7 @@ async fn prepare_packages_for_publishing( let package = prepare_publish( &deno_json, source_cache.clone(), - graph.clone(), + graph, import_map, diagnostics_collector, ) @@ -689,7 +688,6 @@ async fn prepare_packages_for_publishing( let package_by_name = HashMap::from([(package_name, package)]); return Ok(PreparePackagesData { publish_order_graph, - graph, package_by_name, }); }; @@ -743,7 +741,6 @@ async fn prepare_packages_for_publishing( } Ok(PreparePackagesData { publish_order_graph, - graph, package_by_name, }) } @@ -849,11 +846,7 @@ pub async fn publish( ) .await?; - let source_parser = LazyGraphSourceParser::new( - cli_factory.parsed_source_cache(), - &prepared_data.graph, - ); - diagnostics_collector.print_and_error(source_parser)?; + diagnostics_collector.print_and_error()?; if prepared_data.package_by_name.is_empty() { bail!("No packages to publish"); diff --git a/cli/tools/registry/tar.rs b/cli/tools/registry/tar.rs index e63a76516..6543fbf2e 100644 --- a/cli/tools/registry/tar.rs +++ b/cli/tools/registry/tar.rs @@ -206,7 +206,7 @@ fn resolve_content_maybe_unfurling( let text = String::from_utf8(data)?; deno_ast::parse_module(deno_ast::ParseParams { - specifier: specifier.to_string(), + specifier: specifier.clone(), text_info: deno_ast::SourceTextInfo::from_string(text), media_type, capture_tokens: false, diff --git a/cli/tools/repl/session.rs b/cli/tools/repl/session.rs index e98f4b430..a52eb095f 100644 --- a/cli/tools/repl/session.rs +++ b/cli/tools/repl/session.rs @@ -16,14 +16,15 @@ use crate::tools::test::worker_has_tests; use crate::tools::test::TestEvent; use crate::tools::test::TestEventSender; +use deno_ast::diagnostics::Diagnostic; use deno_ast::swc::ast as swc_ast; use deno_ast::swc::common::comments::CommentKind; use deno_ast::swc::visit::noop_visit_type; use deno_ast::swc::visit::Visit; use deno_ast::swc::visit::VisitWith; -use deno_ast::DiagnosticsError; use deno_ast::ImportsNotUsedAsValues; use deno_ast::ModuleSpecifier; +use deno_ast::ParseDiagnosticsError; use deno_ast::ParsedSource; use deno_ast::SourcePos; use deno_ast::SourceRangedForSpanned; @@ -324,7 +325,7 @@ impl ReplSession { &mut self, line: &str, ) -> EvaluationOutput { - fn format_diagnostic(diagnostic: &deno_ast::Diagnostic) -> String { + fn format_diagnostic(diagnostic: &deno_ast::ParseDiagnostic) -> String { let display_position = diagnostic.display_position(); format!( "{}: {} at {}:{}", @@ -377,11 +378,11 @@ impl ReplSession { } Err(err) => { // handle a parsing diagnostic - match err.downcast_ref::<deno_ast::Diagnostic>() { + match err.downcast_ref::<deno_ast::ParseDiagnostic>() { Some(diagnostic) => { Ok(EvaluationOutput::Error(format_diagnostic(diagnostic))) } - None => match err.downcast_ref::<DiagnosticsError>() { + None => match err.downcast_ref::<ParseDiagnosticsError>() { Some(diagnostics) => Ok(EvaluationOutput::Error( diagnostics .0 @@ -786,13 +787,13 @@ fn parse_source_as( media_type: deno_ast::MediaType, ) -> Result<deno_ast::ParsedSource, AnyError> { let specifier = if media_type == deno_ast::MediaType::Tsx { - "repl.tsx" + ModuleSpecifier::parse("file:///repl.tsx").unwrap() } else { - "repl.ts" + ModuleSpecifier::parse("file:///repl.ts").unwrap() }; let parsed = deno_ast::parse_module(deno_ast::ParseParams { - specifier: specifier.to_string(), + specifier, text_info: deno_ast::SourceTextInfo::from_string(source), media_type, capture_tokens: true, diff --git a/cli/tools/test/mod.rs b/cli/tools/test/mod.rs index 332bfa8c8..c138abec2 100644 --- a/cli/tools/test/mod.rs +++ b/cli/tools/test/mod.rs @@ -752,7 +752,7 @@ fn extract_files_from_source_comments( media_type: MediaType, ) -> Result<Vec<File>, AnyError> { let parsed_source = deno_ast::parse_module(deno_ast::ParseParams { - specifier: specifier.to_string(), + specifier: specifier.clone(), text_info: deno_ast::SourceTextInfo::new(source), media_type, capture_tokens: false, diff --git a/cli/tools/test/reporters/pretty.rs b/cli/tools/test/reporters/pretty.rs index c49081dd6..4e8a1f402 100644 --- a/cli/tools/test/reporters/pretty.rs +++ b/cli/tools/test/reporters/pretty.rs @@ -141,7 +141,7 @@ impl PrettyTestReporter { .child_results_buffer .entry(description.parent_id) .or_default() - .remove(&description.id); + .shift_remove(&description.id); } fn write_output_end(&mut self) { diff --git a/cli/tools/vendor/analyze.rs b/cli/tools/vendor/analyze.rs index c804fa1ce..2b00f6bf4 100644 --- a/cli/tools/vendor/analyze.rs +++ b/cli/tools/vendor/analyze.rs @@ -61,6 +61,7 @@ fn export_specifier_has_default(s: &ExportSpecifier) -> bool { #[cfg(test)] mod test { use deno_ast::MediaType; + use deno_ast::ModuleSpecifier; use deno_ast::ParseParams; use deno_ast::ParsedSource; use deno_ast::SourceTextInfo; @@ -101,7 +102,7 @@ mod test { fn parse_module(text: &str) -> ParsedSource { deno_ast::parse_module(ParseParams { - specifier: "file:///mod.ts".to_string(), + specifier: ModuleSpecifier::parse("file:///mod.ts").unwrap(), capture_tokens: false, maybe_syntax: None, media_type: MediaType::TypeScript, |