summaryrefslogtreecommitdiff
path: root/cli/tools/fmt.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/tools/fmt.rs')
-rw-r--r--cli/tools/fmt.rs223
1 files changed, 173 insertions, 50 deletions
diff --git a/cli/tools/fmt.rs b/cli/tools/fmt.rs
index b3dfc86e8..5f1507d19 100644
--- a/cli/tools/fmt.rs
+++ b/cli/tools/fmt.rs
@@ -8,6 +8,9 @@
//! the same functions as ops available in JS runtime.
use crate::colors;
+use crate::config_file::FmtConfig;
+use crate::config_file::FmtOptionsConfig;
+use crate::config_file::ProseWrap;
use crate::diff::diff;
use crate::file_watcher;
use crate::file_watcher::ResolutionResult;
@@ -35,24 +38,57 @@ pub async fn format(
ignore: Vec<PathBuf>,
check: bool,
watch: bool,
+ maybe_fmt_config: Option<FmtConfig>,
) -> Result<(), AnyError> {
+ // First, prepare final configuration.
+ // Collect included and ignored files. CLI flags take precendence
+ // over config file, ie. if there's `files.ignore` in config file
+ // and `--ignore` CLI flag, only the flag value is taken into account.
+ let mut include_files = args.clone();
+ let mut exclude_files = ignore;
+
+ if let Some(fmt_config) = maybe_fmt_config.as_ref() {
+ if include_files.is_empty() {
+ include_files = fmt_config
+ .files
+ .include
+ .iter()
+ .map(PathBuf::from)
+ .collect::<Vec<PathBuf>>();
+ }
+
+ if exclude_files.is_empty() {
+ exclude_files = fmt_config
+ .files
+ .exclude
+ .iter()
+ .map(PathBuf::from)
+ .collect::<Vec<PathBuf>>();
+ }
+ }
+
+ let fmt_options = maybe_fmt_config.map(|c| c.options).unwrap_or_default();
+
let resolver = |changed: Option<Vec<PathBuf>>| {
let files_changed = changed.is_some();
let result =
- collect_files(&args, &ignore, is_supported_ext_fmt).map(|files| {
- if let Some(paths) = changed {
- files
- .into_iter()
- .filter(|path| paths.contains(path))
- .collect::<Vec<_>>()
- } else {
- files
- }
- });
- let paths_to_watch = args.clone();
+ collect_files(&include_files, &exclude_files, is_supported_ext_fmt).map(
+ |files| {
+ let collected_files = if let Some(paths) = changed {
+ files
+ .into_iter()
+ .filter(|path| paths.contains(path))
+ .collect::<Vec<_>>()
+ } else {
+ files
+ };
+ (collected_files, fmt_options.clone())
+ },
+ );
+ let paths_to_watch = include_files.clone();
async move {
if (files_changed || !watch)
- && matches!(result, Ok(ref files) if files.is_empty())
+ && matches!(result, Ok((ref files, _)) if files.is_empty())
{
ResolutionResult::Ignore
} else {
@@ -63,11 +99,11 @@ pub async fn format(
}
}
};
- let operation = |paths: Vec<PathBuf>| async move {
+ let operation = |(paths, fmt_options): (Vec<PathBuf>, FmtOptionsConfig)| async move {
if check {
- check_source_files(paths).await?;
+ check_source_files(paths, fmt_options).await?;
} else {
- format_source_files(paths).await?;
+ format_source_files(paths, fmt_options).await?;
}
Ok(())
};
@@ -75,13 +111,13 @@ pub async fn format(
if watch {
file_watcher::watch_func(resolver, operation, "Fmt").await?;
} else {
- let files =
+ let (files, fmt_options) =
if let ResolutionResult::Restart { result, .. } = resolver(None).await {
result?
} else {
return Err(generic_error("No target files found."));
};
- operation(files).await?;
+ operation((files, fmt_options)).await?;
}
Ok(())
@@ -89,10 +125,14 @@ pub async fn format(
/// Formats markdown (using <https://github.com/dprint/dprint-plugin-markdown>) and its code blocks
/// (ts/tsx, js/jsx).
-fn format_markdown(file_text: &str) -> Result<String, String> {
+fn format_markdown(
+ file_text: &str,
+ fmt_options: &FmtOptionsConfig,
+) -> Result<String, String> {
+ let markdown_config = get_resolved_markdown_config(fmt_options);
dprint_plugin_markdown::format_text(
file_text,
- &MARKDOWN_CONFIG,
+ &markdown_config,
move |tag, text, line_width| {
let tag = tag.to_lowercase();
if matches!(
@@ -115,13 +155,14 @@ fn format_markdown(file_text: &str) -> Result<String, String> {
};
if matches!(extension, "json" | "jsonc") {
- let mut json_config = JSON_CONFIG.clone();
+ let mut json_config = get_resolved_json_config(fmt_options);
json_config.line_width = line_width;
dprint_plugin_json::format_text(text, &json_config)
} else {
let fake_filename =
PathBuf::from(format!("deno_fmt_stdin.{}", extension));
- let mut codeblock_config = TYPESCRIPT_CONFIG.clone();
+ let mut codeblock_config =
+ get_resolved_typescript_config(fmt_options);
codeblock_config.line_width = line_width;
dprint_plugin_typescript::format_text(
&fake_filename,
@@ -140,32 +181,36 @@ fn format_markdown(file_text: &str) -> Result<String, String> {
/// Formats JSON and JSONC using the rules provided by .deno()
/// of configuration builder of <https://github.com/dprint/dprint-plugin-json>.
/// See <https://git.io/Jt4ht> for configuration.
-fn format_json(file_text: &str) -> Result<String, String> {
- dprint_plugin_json::format_text(file_text, &JSON_CONFIG)
- .map_err(|e| e.to_string())
+fn format_json(
+ file_text: &str,
+ fmt_options: &FmtOptionsConfig,
+) -> Result<String, String> {
+ let config = get_resolved_json_config(fmt_options);
+ dprint_plugin_json::format_text(file_text, &config).map_err(|e| e.to_string())
}
/// Formats a single TS, TSX, JS, JSX, JSONC, JSON, or MD file.
pub fn format_file(
file_path: &Path,
file_text: &str,
+ fmt_options: FmtOptionsConfig,
) -> Result<String, String> {
let ext = get_extension(file_path).unwrap_or_else(String::new);
if ext == "md" {
- format_markdown(file_text)
+ format_markdown(file_text, &fmt_options)
} else if matches!(ext.as_str(), "json" | "jsonc") {
- format_json(file_text)
+ format_json(file_text, &fmt_options)
} else {
- dprint_plugin_typescript::format_text(
- file_path,
- file_text,
- &TYPESCRIPT_CONFIG,
- )
- .map_err(|e| e.to_string())
+ let config = get_resolved_typescript_config(&fmt_options);
+ dprint_plugin_typescript::format_text(file_path, file_text, &config)
+ .map_err(|e| e.to_string())
}
}
-pub fn format_parsed_module(parsed_source: &ParsedSource) -> String {
+pub fn format_parsed_module(
+ parsed_source: &ParsedSource,
+ fmt_options: FmtOptionsConfig,
+) -> String {
dprint_plugin_typescript::format_parsed_file(
&dprint_plugin_typescript::SourceFileInfo {
is_jsx: matches!(
@@ -178,11 +223,14 @@ pub fn format_parsed_module(parsed_source: &ParsedSource) -> String {
module: parsed_source.module(),
tokens: parsed_source.tokens(),
},
- &TYPESCRIPT_CONFIG,
+ &get_resolved_typescript_config(&fmt_options),
)
}
-async fn check_source_files(paths: Vec<PathBuf>) -> Result<(), AnyError> {
+async fn check_source_files(
+ paths: Vec<PathBuf>,
+ fmt_options: FmtOptionsConfig,
+) -> Result<(), AnyError> {
let not_formatted_files_count = Arc::new(AtomicUsize::new(0));
let checked_files_count = Arc::new(AtomicUsize::new(0));
@@ -196,7 +244,7 @@ async fn check_source_files(paths: Vec<PathBuf>) -> Result<(), AnyError> {
checked_files_count.fetch_add(1, Ordering::Relaxed);
let file_text = read_file_contents(&file_path)?.text;
- match format_file(&file_path, &file_text) {
+ match format_file(&file_path, &file_text, fmt_options.clone()) {
Ok(formatted_text) => {
if formatted_text != file_text {
not_formatted_files_count.fetch_add(1, Ordering::Relaxed);
@@ -235,7 +283,10 @@ async fn check_source_files(paths: Vec<PathBuf>) -> Result<(), AnyError> {
}
}
-async fn format_source_files(paths: Vec<PathBuf>) -> Result<(), AnyError> {
+async fn format_source_files(
+ paths: Vec<PathBuf>,
+ fmt_options: FmtOptionsConfig,
+) -> Result<(), AnyError> {
let formatted_files_count = Arc::new(AtomicUsize::new(0));
let checked_files_count = Arc::new(AtomicUsize::new(0));
let output_lock = Arc::new(Mutex::new(0)); // prevent threads outputting at the same time
@@ -247,7 +298,7 @@ async fn format_source_files(paths: Vec<PathBuf>) -> Result<(), AnyError> {
checked_files_count.fetch_add(1, Ordering::Relaxed);
let file_contents = read_file_contents(&file_path)?;
- match format_file(&file_path, &file_contents.text) {
+ match format_file(&file_path, &file_contents.text, fmt_options.clone()) {
Ok(formatted_text) => {
if formatted_text != file_contents.text {
write_file_contents(
@@ -293,14 +344,18 @@ async fn format_source_files(paths: Vec<PathBuf>) -> Result<(), AnyError> {
/// Format stdin and write result to stdout.
/// Treats input as TypeScript or as set by `--ext` flag.
/// Compatible with `--check` flag.
-pub fn format_stdin(check: bool, ext: String) -> Result<(), AnyError> {
+pub fn format_stdin(
+ check: bool,
+ ext: String,
+ fmt_options: FmtOptionsConfig,
+) -> Result<(), AnyError> {
let mut source = String::new();
if stdin().read_to_string(&mut source).is_err() {
return Err(generic_error("Failed to read from stdin"));
}
let file_path = PathBuf::from(format!("_stdin.{}", ext));
- match format_file(&file_path, &source) {
+ match format_file(&file_path, &source, fmt_options) {
Ok(formatted_text) => {
if check {
if formatted_text != source {
@@ -325,18 +380,86 @@ fn files_str(len: usize) -> &'static str {
}
}
-lazy_static::lazy_static! {
- static ref TYPESCRIPT_CONFIG: dprint_plugin_typescript::configuration::Configuration = dprint_plugin_typescript::configuration::ConfigurationBuilder::new()
- .deno()
- .build();
+fn get_resolved_typescript_config(
+ options: &FmtOptionsConfig,
+) -> dprint_plugin_typescript::configuration::Configuration {
+ let mut builder =
+ dprint_plugin_typescript::configuration::ConfigurationBuilder::new();
+ builder.deno();
+
+ if let Some(use_tabs) = options.use_tabs {
+ builder.use_tabs(use_tabs);
+ }
- static ref MARKDOWN_CONFIG: dprint_plugin_markdown::configuration::Configuration = dprint_plugin_markdown::configuration::ConfigurationBuilder::new()
- .deno()
- .build();
+ if let Some(line_width) = options.line_width {
+ builder.line_width(line_width);
+ }
+
+ if let Some(indent_width) = options.indent_width {
+ builder.indent_width(indent_width);
+ }
+
+ if let Some(single_quote) = options.single_quote {
+ if single_quote {
+ builder.quote_style(
+ dprint_plugin_typescript::configuration::QuoteStyle::AlwaysSingle,
+ );
+ }
+ }
+
+ builder.build()
+}
+
+fn get_resolved_markdown_config(
+ options: &FmtOptionsConfig,
+) -> dprint_plugin_markdown::configuration::Configuration {
+ let mut builder =
+ dprint_plugin_markdown::configuration::ConfigurationBuilder::new();
+
+ builder.deno();
+
+ if let Some(line_width) = options.line_width {
+ builder.line_width(line_width);
+ }
+
+ if let Some(prose_wrap) = options.prose_wrap {
+ builder.text_wrap(match prose_wrap {
+ ProseWrap::Always => {
+ dprint_plugin_markdown::configuration::TextWrap::Always
+ }
+ ProseWrap::Never => {
+ dprint_plugin_markdown::configuration::TextWrap::Never
+ }
+ ProseWrap::Preserve => {
+ dprint_plugin_markdown::configuration::TextWrap::Maintain
+ }
+ });
+ }
+
+ builder.build()
+}
+
+fn get_resolved_json_config(
+ options: &FmtOptionsConfig,
+) -> dprint_plugin_json::configuration::Configuration {
+ let mut builder =
+ dprint_plugin_json::configuration::ConfigurationBuilder::new();
+
+ builder.deno();
+
+ if let Some(use_tabs) = options.use_tabs {
+ builder.use_tabs(use_tabs);
+ }
+
+ if let Some(line_width) = options.line_width {
+ builder.line_width(line_width);
+ }
+
+ if let Some(indent_width) = options.indent_width {
+ builder.indent_width(indent_width);
+ }
- static ref JSON_CONFIG: dprint_plugin_json::configuration::Configuration = dprint_plugin_json::configuration::ConfigurationBuilder::new()
- .deno()
- .build();
+ builder.build()
}
struct FileContents {