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:
parent
0dbeb774ba
commit
cba1e7b5a3
3 changed files with 215 additions and 22 deletions
162
cli/flags.rs
162
cli/flags.rs
|
@ -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]
|
||||
|
|
12
cli/main.rs
12
cli/main.rs
|
@ -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(())
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Reference in a new issue