0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-03-03 09:31:22 -05:00

feat: add option flags to 'deno fmt' (#12060)

This commit is contained in:
Bartek Iwańczuk 2021-09-13 22:06:45 +02:00 committed by GitHub
parent 0dbeb774ba
commit cba1e7b5a3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 215 additions and 22 deletions

View file

@ -13,6 +13,8 @@ use deno_runtime::permissions::PermissionsOptions;
use log::debug;
use log::Level;
use std::net::SocketAddr;
use std::num::NonZeroU32;
use std::num::NonZeroU8;
use std::num::NonZeroUsize;
use std::path::PathBuf;
use std::str::FromStr;
@ -86,6 +88,11 @@ pub struct FmtFlags {
pub files: Vec<PathBuf>,
pub ignore: Vec<PathBuf>,
pub ext: String,
pub use_tabs: Option<bool>,
pub line_width: Option<NonZeroU32>,
pub indent_width: Option<NonZeroU8>,
pub single_quote: Option<bool>,
pub prose_wrap: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
@ -845,6 +852,47 @@ Ignore formatting a file by adding an ignore comment at the top of the file:
.required(false),
)
.arg(watch_arg())
.arg(
Arg::with_name("options-use-tabs")
.long("options-use-tabs")
.help("Use tabs instead of spaces for indentation. Defaults to false."),
)
.arg(
Arg::with_name("options-line-width")
.long("options-line-width")
.help("Define maximum line width. Defaults to 80.")
.takes_value(true)
.validator(|val: String| match val.parse::<NonZeroUsize>() {
Ok(_) => Ok(()),
Err(_) => {
Err("options-line-width should be a non zero integer".to_string())
}
}),
)
.arg(
Arg::with_name("options-indent-width")
.long("options-indent-width")
.help("Define indentation width. Defaults to 2.")
.takes_value(true)
.validator(|val: String| match val.parse::<NonZeroUsize>() {
Ok(_) => Ok(()),
Err(_) => {
Err("options-indent-width should be a non zero integer".to_string())
}
}),
)
.arg(
Arg::with_name("options-single-quote")
.long("options-single-quote")
.help("Use single quotes. Defaults to false."),
)
.arg(
Arg::with_name("options-prose-wrap")
.long("options-prose-wrap")
.takes_value(true)
.possible_values(&["always", "never", "preserve"])
.help("Define how prose should be wrapped. Defaults to always."),
)
}
fn info_subcommand<'a, 'b>() -> App<'a, 'b> {
@ -1745,11 +1793,54 @@ fn fmt_parse(flags: &mut Flags, matches: &clap::ArgMatches) {
};
let ext = matches.value_of("ext").unwrap().to_string();
let use_tabs = if matches.is_present("options-use-tabs") {
Some(true)
} else {
None
};
let line_width = if matches.is_present("options-line-width") {
Some(
matches
.value_of("options-line-width")
.unwrap()
.parse()
.unwrap(),
)
} else {
None
};
let indent_width = if matches.is_present("options-indent-width") {
Some(
matches
.value_of("options-indent-width")
.unwrap()
.parse()
.unwrap(),
)
} else {
None
};
let single_quote = if matches.is_present("options-single-quote") {
Some(true)
} else {
None
};
let prose_wrap = if matches.is_present("options-prose-wrap") {
Some(matches.value_of("options-prose-wrap").unwrap().to_string())
} else {
None
};
flags.subcommand = DenoSubcommand::Fmt(FmtFlags {
check: matches.is_present("check"),
ext,
files,
ignore,
use_tabs,
line_width,
indent_width,
single_quote,
prose_wrap,
});
}
@ -2466,7 +2557,12 @@ mod tests {
PathBuf::from("script_1.ts"),
PathBuf::from("script_2.ts")
],
ext: "ts".to_string()
ext: "ts".to_string(),
use_tabs: None,
line_width: None,
indent_width: None,
single_quote: None,
prose_wrap: None,
}),
..Flags::default()
}
@ -2481,6 +2577,11 @@ mod tests {
check: true,
files: vec![],
ext: "ts".to_string(),
use_tabs: None,
line_width: None,
indent_width: None,
single_quote: None,
prose_wrap: None,
}),
..Flags::default()
}
@ -2495,6 +2596,11 @@ mod tests {
check: false,
files: vec![],
ext: "ts".to_string(),
use_tabs: None,
line_width: None,
indent_width: None,
single_quote: None,
prose_wrap: None,
}),
..Flags::default()
}
@ -2509,6 +2615,11 @@ mod tests {
check: false,
files: vec![],
ext: "ts".to_string(),
use_tabs: None,
line_width: None,
indent_width: None,
single_quote: None,
prose_wrap: None,
}),
watch: true,
..Flags::default()
@ -2531,6 +2642,11 @@ mod tests {
check: true,
files: vec![PathBuf::from("foo.ts")],
ext: "ts".to_string(),
use_tabs: None,
line_width: None,
indent_width: None,
single_quote: None,
prose_wrap: None,
}),
watch: true,
..Flags::default()
@ -2545,7 +2661,12 @@ mod tests {
ignore: vec![],
check: false,
files: vec![],
ext: "ts".to_string()
ext: "ts".to_string(),
use_tabs: None,
line_width: None,
indent_width: None,
single_quote: None,
prose_wrap: None,
}),
config_path: Some("deno.jsonc".to_string()),
..Flags::default()
@ -2567,13 +2688,48 @@ mod tests {
ignore: vec![],
check: false,
files: vec![PathBuf::from("foo.ts")],
ext: "ts".to_string()
ext: "ts".to_string(),
use_tabs: None,
line_width: None,
indent_width: None,
single_quote: None,
prose_wrap: None,
}),
config_path: Some("deno.jsonc".to_string()),
watch: true,
..Flags::default()
}
);
let r = flags_from_vec(svec![
"deno",
"fmt",
"--options-use-tabs",
"--options-line-width",
"60",
"--options-indent-width",
"4",
"--options-single-quote",
"--options-prose-wrap",
"never"
]);
assert_eq!(
r.unwrap(),
Flags {
subcommand: DenoSubcommand::Fmt(FmtFlags {
ignore: vec![],
check: false,
files: vec![],
ext: "ts".to_string(),
use_tabs: Some(true),
line_width: Some(NonZeroU32::new(60).unwrap()),
indent_width: Some(NonZeroU8::new(4).unwrap()),
single_quote: Some(true),
prose_wrap: Some("never".to_string()),
}),
..Flags::default()
}
);
}
#[test]

View file

@ -815,20 +815,12 @@ async fn format_command(
if fmt_flags.files.len() == 1 && fmt_flags.files[0].to_string_lossy() == "-" {
return tools::fmt::format_stdin(
fmt_flags.check,
fmt_flags.ext,
fmt_flags,
maybe_fmt_config.map(|c| c.options).unwrap_or_default(),
);
}
tools::fmt::format(
fmt_flags.files,
fmt_flags.ignore,
fmt_flags.check,
flags.watch,
maybe_fmt_config,
)
.await?;
tools::fmt::format(fmt_flags, flags.watch, maybe_fmt_config).await?;
Ok(())
}

View file

@ -14,6 +14,7 @@ use crate::config_file::ProseWrap;
use crate::diff::diff;
use crate::file_watcher;
use crate::file_watcher::ResolutionResult;
use crate::flags::FmtFlags;
use crate::fs_util::{collect_files, get_extension, is_supported_ext_fmt};
use crate::text_encoding;
use deno_ast::ParsedSource;
@ -34,17 +35,22 @@ use std::sync::{Arc, Mutex};
/// Format JavaScript/TypeScript files.
pub async fn format(
args: Vec<PathBuf>,
ignore: Vec<PathBuf>,
check: bool,
fmt_flags: FmtFlags,
watch: bool,
maybe_fmt_config: Option<FmtConfig>,
) -> Result<(), AnyError> {
let FmtFlags {
files,
ignore,
check,
..
} = fmt_flags.clone();
// 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 include_files = files.clone();
let mut exclude_files = ignore;
if let Some(fmt_config) = maybe_fmt_config.as_ref() {
@ -67,7 +73,11 @@ pub async fn format(
}
}
let fmt_options = maybe_fmt_config.map(|c| c.options).unwrap_or_default();
// Now do the same for options
let fmt_options = resolve_fmt_options(
&fmt_flags,
maybe_fmt_config.map(|c| c.options).unwrap_or_default(),
);
let resolver = |changed: Option<Vec<PathBuf>>| {
let files_changed = changed.is_some();
@ -345,19 +355,19 @@ async fn format_source_files(
/// Treats input as TypeScript or as set by `--ext` flag.
/// Compatible with `--check` flag.
pub fn format_stdin(
check: bool,
ext: String,
fmt_flags: FmtFlags,
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));
let file_path = PathBuf::from(format!("_stdin.{}", fmt_flags.ext));
let fmt_options = resolve_fmt_options(&fmt_flags, fmt_options);
match format_file(&file_path, &source, fmt_options) {
Ok(formatted_text) => {
if check {
if fmt_flags.check {
if formatted_text != source {
println!("Not formatted stdin");
}
@ -380,6 +390,41 @@ fn files_str(len: usize) -> &'static str {
}
}
fn resolve_fmt_options(
fmt_flags: &FmtFlags,
options: FmtOptionsConfig,
) -> FmtOptionsConfig {
let mut options = options;
if let Some(use_tabs) = fmt_flags.use_tabs {
options.use_tabs = Some(use_tabs);
}
if let Some(line_width) = fmt_flags.line_width {
options.line_width = Some(line_width.get());
}
if let Some(indent_width) = fmt_flags.indent_width {
options.indent_width = Some(indent_width.get());
}
if let Some(single_quote) = fmt_flags.single_quote {
options.single_quote = Some(single_quote);
}
if let Some(prose_wrap) = &fmt_flags.prose_wrap {
options.prose_wrap = Some(match prose_wrap.as_str() {
"always" => ProseWrap::Always,
"never" => ProseWrap::Never,
"preserve" => ProseWrap::Preserve,
// validators in `flags.rs` makes other values unreachable
_ => unreachable!(),
});
}
options
}
fn get_resolved_typescript_config(
options: &FmtOptionsConfig,
) -> dprint_plugin_typescript::configuration::Configuration {