Skip to content
This repository has been archived by the owner on Aug 31, 2023. It is now read-only.

Commit

Permalink
feat(rome_json_formatter): Enable JSON formatting for debug builds (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaReiser committed Nov 30, 2022
1 parent 62406bf commit 519df0b
Show file tree
Hide file tree
Showing 10 changed files with 188 additions and 37 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions crates/rome_cli/src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,15 @@ impl Execution {
}
}

pub(crate) fn is_ci(&self) -> bool {
pub(crate) const fn is_ci(&self) -> bool {
matches!(self.traversal_mode, TraversalMode::CI { .. })
}

pub(crate) fn is_check(&self) -> bool {
pub(crate) const fn is_check(&self) -> bool {
matches!(self.traversal_mode, TraversalMode::Check { .. })
}

pub(crate) fn is_format(&self) -> bool {
pub(crate) const fn is_format(&self) -> bool {
matches!(self.traversal_mode, TraversalMode::Format { .. })
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ statement();
# Emitted Messages

```block
Formatted 1 file(s) in <TIME>
Formatted 2 file(s) in <TIME>
```


2 changes: 2 additions & 0 deletions crates/rome_json_formatter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ where
N: AstNode<Language = JsonLanguage>,
{
fn fmt(&self, node: &N, f: &mut JsonFormatter) -> FormatResult<()> {
f.comments().mark_suppression_checked(node.syntax());

self.fmt_fields(node, f)
}

Expand Down
1 change: 0 additions & 1 deletion crates/rome_json_parser/src/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,6 @@ fn parse_rest(p: &mut JsonParser, value: ParsedSyntax) {
let range = match parse_value(p) {
Present(value) => value.range(p),
Absent => ParseRecovery::new(JSON_BOGUS_VALUE, VALUE_START)
.enable_recovery_on_line_break()
.recover(p)
.expect("Expect recovery to succeed because parser isn't at EOF nor at a value.")
.range(p),
Expand Down
1 change: 1 addition & 0 deletions crates/rome_service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ rome_js_formatter = { path = "../rome_js_formatter", features = ["serde"] }
rome_js_semantic = { path = "../rome_js_semantic" }
rome_json_parser = { path = "../rome_json_parser" }
rome_json_syntax = { path = "../rome_json_syntax" }
rome_json_formatter = { path = "../rome_json_formatter" }
rome_rowan = { path = "../rome_rowan", features = ["serde"] }
rome_text_edit = { path = "../rome_text_edit" }
indexmap = { workspace = true, features = ["serde"] }
Expand Down
2 changes: 1 addition & 1 deletion crates/rome_service/src/file_handlers/javascript.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ pub struct JsLinterSettings {

impl Language for JsLanguage {
type FormatterSettings = JsFormatterSettings;
type FormatOptions = JsFormatOptions;
type LinterSettings = JsLinterSettings;
type FormatOptions = JsFormatOptions;

fn lookup_settings(languages: &LanguagesSettings) -> &LanguageSettings<Self> {
&languages.javascript
Expand Down
138 changes: 134 additions & 4 deletions crates/rome_service/src/file_handlers/json.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,43 @@
use super::{ExtensionHandler, Mime};
use crate::file_handlers::{Capabilities, ParserCapabilities};
use crate::file_handlers::{Capabilities, FormatterCapabilities, ParserCapabilities};
use crate::file_handlers::{DebugCapabilities, Language as LanguageId};
use crate::settings::{
FormatSettings, Language, LanguageSettings, LanguagesSettings, SettingsHandle,
};
use crate::workspace::server::AnyParse;
use crate::workspace::GetSyntaxTreeResult;
use crate::RomeError;
#[cfg(debug_assertions)]
use rome_formatter::FormatError;
use rome_formatter::Printed;
use rome_fs::RomePath;
use rome_json_formatter::context::JsonFormatOptions;
use rome_json_formatter::format_node;
use rome_json_parser::JsonParse;
use rome_json_syntax::{JsonRoot, JsonSyntaxNode};
use rome_json_syntax::{JsonLanguage, JsonRoot, JsonSyntaxNode};
#[cfg(debug_assertions)]
use rome_rowan::{TextRange, TextSize, TokenAtOffset};
use tracing::debug;

impl Language for JsonLanguage {
type FormatterSettings = ();
type LinterSettings = ();
type FormatOptions = JsonFormatOptions;

fn lookup_settings(language: &LanguagesSettings) -> &LanguageSettings<Self> {
&language.json
}

fn resolve_format_options(
global: &FormatSettings,
_language: &Self::FormatterSettings,
_path: &RomePath,
) -> Self::FormatOptions {
JsonFormatOptions::default()
.with_indent_style(global.indent_style.unwrap_or_default())
.with_line_width(global.line_width.unwrap_or_default())
}
}

#[derive(Debug, Default, PartialEq, Eq)]
pub(crate) struct JsonFileHandler;
Expand All @@ -29,14 +61,28 @@ impl ExtensionHandler for JsonFileHandler {
debug: DebugCapabilities {
debug_syntax_tree: Some(debug_syntax_tree),
debug_control_flow: None,
debug_formatter_ir: None,
debug_formatter_ir: Some(debug_formatter_ir),
},
analyzer: Default::default(),
formatter: Default::default(),
formatter: formatter_capabilities(),
}
}
}

#[cfg(debug_assertions)]
fn formatter_capabilities() -> FormatterCapabilities {
FormatterCapabilities {
format: Some(format),
format_range: Some(format_range),
format_on_type: Some(format_on_type),
}
}

#[cfg(not(debug_assertions))]
fn formatter_capabilities() -> FormatterCapabilities {
FormatterCapabilities::default()
}

fn parse(rome_path: &RomePath, _: LanguageId, text: &str) -> AnyParse {
let file_id = rome_path.file_id();

Expand All @@ -53,6 +99,90 @@ fn debug_syntax_tree(_rome_path: &RomePath, parse: AnyParse) -> GetSyntaxTreeRes
}
}

fn debug_formatter_ir(
rome_path: &RomePath,
parse: AnyParse,
settings: SettingsHandle,
) -> Result<String, RomeError> {
let options = settings.format_options::<JsonLanguage>(rome_path);

let tree = parse.syntax();
let formatted = format_node(options, &tree)?;

let root_element = formatted.into_document();
Ok(root_element.to_string())
}

#[tracing::instrument(level = "debug", skip(parse))]
fn format(
rome_path: &RomePath,
parse: AnyParse,
settings: SettingsHandle,
) -> Result<Printed, RomeError> {
let options = settings.format_options::<JsonLanguage>(rome_path);

debug!("Format with the following options: \n{}", options);

let tree = parse.syntax();
let formatted = format_node(options, &tree)?;

match formatted.print() {
Ok(printed) => Ok(printed),
Err(error) => Err(RomeError::FormatError(error.into())),
}
}

#[cfg(debug_assertions)]
fn format_range(
rome_path: &RomePath,
parse: AnyParse,
settings: SettingsHandle,
range: TextRange,
) -> Result<Printed, RomeError> {
let options = settings.format_options::<JsonLanguage>(rome_path);

let tree = parse.syntax();
let printed = rome_json_formatter::format_range(options, &tree, range)?;
Ok(printed)
}

#[cfg(debug_assertions)]
fn format_on_type(
rome_path: &RomePath,
parse: AnyParse,
settings: SettingsHandle,
offset: TextSize,
) -> Result<Printed, RomeError> {
let options = settings.format_options::<JsonLanguage>(rome_path);

let tree = parse.syntax();

let range = tree.text_range();
if offset < range.start() || offset > range.end() {
return Err(RomeError::FormatError(FormatError::RangeError {
input: TextRange::at(offset, TextSize::from(0)),
tree: range,
}));
}

let token = match tree.token_at_offset(offset) {
// File is empty, do nothing
TokenAtOffset::None => panic!("empty file"),
TokenAtOffset::Single(token) => token,
// The cursor should be right after the closing character that was just typed,
// select the previous token as the correct one
TokenAtOffset::Between(token, _) => token,
};

let root_node = match token.parent() {
Some(node) => node,
None => panic!("found a token with no parent"),
};

let printed = rome_json_formatter::format_sub_tree(options, &root_node)?;
Ok(printed)
}

impl From<JsonParse> for AnyParse {
fn from(parse: JsonParse) -> Self {
let root = parse.syntax();
Expand Down
2 changes: 2 additions & 0 deletions crates/rome_service/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use rome_diagnostics::Category;
use rome_formatter::{IndentStyle, LineWidth};
use rome_fs::RomePath;
use rome_js_syntax::JsLanguage;
use rome_json_syntax::JsonLanguage;
use std::{
num::NonZeroU64,
sync::{RwLock, RwLockReadGuard},
Expand Down Expand Up @@ -152,6 +153,7 @@ impl Default for LinterSettings {
#[derive(Debug, Default)]
pub struct LanguagesSettings {
pub javascript: LanguageSettings<JsLanguage>,
pub json: LanguageSettings<JsonLanguage>,
}

pub trait Language: rome_rowan::Language {
Expand Down
70 changes: 43 additions & 27 deletions crates/rome_service/src/workspace/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::{
use dashmap::{mapref::entry::Entry, DashMap};
use indexmap::IndexSet;
use rome_analyze::{AnalysisFilter, RuleFilter};
use rome_diagnostics::{serde::Diagnostic, DiagnosticExt};
use rome_diagnostics::{serde::Diagnostic as SerdeDiagnostic, Diagnostic, DiagnosticExt, Severity};
use rome_formatter::Printed;
use rome_fs::RomePath;
use rome_parser::diagnostic::ParseDiagnostic;
Expand Down Expand Up @@ -84,8 +84,11 @@ impl AnyParse {
}

/// This function transforms diagnostics coming from the parser into serializable diagnostics
pub(crate) fn into_diagnostics(self) -> Vec<Diagnostic> {
self.diagnostics.into_iter().map(Diagnostic::new).collect()
pub(crate) fn into_diagnostics(self) -> Vec<SerdeDiagnostic> {
self.diagnostics
.into_iter()
.map(SerdeDiagnostic::new)
.collect()
}

fn has_errors(&self) -> bool {
Expand Down Expand Up @@ -372,44 +375,57 @@ impl Workspace for WorkspaceServer {
&self,
params: PullDiagnosticsParams,
) -> Result<PullDiagnosticsResult, RomeError> {
let capabilities = self.get_capabilities(&params.path);
let lint = capabilities
.analyzer
.lint
.ok_or_else(self.build_capability_error(&params.path))?;

let settings = self.settings.read().unwrap();
let feature = if params.categories.is_syntax() {
FeatureName::Format
} else {
FeatureName::Lint
};

let parse = self.get_parse(params.path.clone(), Some(feature))?;
let rules = settings.linter().rules.as_ref();
let rule_filter_list = self.build_rule_filter_list(rules);
let mut filter = AnalysisFilter::from_enabled_rules(Some(rule_filter_list.as_slice()));
filter.categories = params.categories;
let settings = self.settings.read().unwrap();

let results = lint(LintParams {
rome_path: &params.path,
parse,
filter,
rules,
settings: self.settings(),
max_diagnostics: params.max_diagnostics,
});
let (diagnostics, errors, skipped_diagnostics) = if let Some(lint) =
self.get_capabilities(&params.path).analyzer.lint
{
let rules = settings.linter().rules.as_ref();
let rule_filter_list = self.build_rule_filter_list(rules);
let mut filter = AnalysisFilter::from_enabled_rules(Some(rule_filter_list.as_slice()));
filter.categories = params.categories;

let results = lint(LintParams {
rome_path: &params.path,
parse,
filter,
rules,
settings: self.settings(),
max_diagnostics: params.max_diagnostics,
});

(
results.diagnostics,
results.errors,
results.skipped_diagnostics,
)
} else {
let parse_diagnostics = parse.into_diagnostics();
let errors = parse_diagnostics
.iter()
.filter(|diag| diag.severity() <= Severity::Error)
.count();

(parse_diagnostics, errors, 0)
};

Ok(PullDiagnosticsResult {
diagnostics: results
.diagnostics
diagnostics: diagnostics
.into_iter()
.map(|diag| {
let diag = diag.with_file_path(params.path.as_path().display().to_string());
Diagnostic::new(diag)
SerdeDiagnostic::new(diag)
})
.collect(),
errors: results.errors,
skipped_diagnostics: results.skipped_diagnostics,
errors,
skipped_diagnostics,
})
}

Expand Down

0 comments on commit 519df0b

Please sign in to comment.