Skip to content

Commit

Permalink
fmt: deno fmt - formats stdin and print to stdout (denoland#3920)
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinkassimo committed Feb 9, 2020
1 parent 1c0ffa1 commit 5066018
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 7 deletions.
17 changes: 16 additions & 1 deletion cli/flags.rs
Expand Up @@ -550,7 +550,10 @@ fn fmt_subcommand<'a, 'b>() -> App<'a, 'b> {
deno fmt myfile1.ts myfile2.ts
deno fmt --check",
deno fmt --check
# Format stdin and write to stdout
cat file.ts | deno fmt -",
)
.arg(
Arg::with_name("check")
Expand Down Expand Up @@ -1390,6 +1393,18 @@ mod tests {
..DenoFlags::default()
}
);

let r = flags_from_vec_safe(svec!["deno", "fmt"]);
assert_eq!(
r.unwrap(),
DenoFlags {
subcommand: DenoSubcommand::Format {
check: false,
files: None
},
..DenoFlags::default()
}
);
}

#[test]
Expand Down
63 changes: 62 additions & 1 deletion cli/fmt.rs
Expand Up @@ -7,10 +7,17 @@
//! the future it can be easily extended to provide
//! the same functions as ops available in JS runtime.

use crate::deno_error::DenoError;
use crate::deno_error::ErrorKind;
use deno_core::ErrBox;
use dprint_plugin_typescript as dprint;
use glob;
use regex::Regex;
use std::fs;
use std::io::stdin;
use std::io::stdout;
use std::io::Read;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
use std::time::Instant;
Expand Down Expand Up @@ -157,9 +164,29 @@ fn get_matching_files(glob_paths: Vec<String>) -> Vec<PathBuf> {
///
/// First argument supports globs, and if it is `None`
/// then the current directory is recursively walked.
pub fn format_files(maybe_files: Option<Vec<String>>, check: bool) {
pub fn format_files(
maybe_files: Option<Vec<String>>,
check: bool,
) -> Result<(), ErrBox> {
// TODO: improve glob to look for tsx?/jsx? files only
let glob_paths = maybe_files.unwrap_or_else(|| vec!["**/*".to_string()]);

for glob_path in glob_paths.iter() {
if glob_path == "-" {
// If the only given path is '-', format stdin.
if glob_paths.len() == 1 {
format_stdin(check);
} else {
// Otherwise it is an error
return Err(ErrBox::from(DenoError::new(
ErrorKind::Other,
"Ambiguous filename input. To format stdin, provide a single '-' instead.".to_owned()
)));
}
return Ok(());
}
}

let matching_files = get_matching_files(glob_paths);
let matching_files = get_supported_files(matching_files);
let config = get_config();
Expand All @@ -169,4 +196,38 @@ pub fn format_files(maybe_files: Option<Vec<String>>, check: bool) {
} else {
format_source_files(config, matching_files);
}

Ok(())
}

/// Format stdin and write result to stdout.
/// Treats input as TypeScript.
/// Compatible with `--check` flag.
fn format_stdin(check: bool) {
let mut source = String::new();
if stdin().read_to_string(&mut source).is_err() {
eprintln!("Failed to read from stdin");
}
let config = get_config();

match dprint::format_text("_stdin.ts", &source, &config) {
Ok(None) => {
// Should not happen.
unreachable!();
}
Ok(Some(formatted_text)) => {
if check {
if formatted_text != source {
println!("Not formatted stdin");
}
} else {
let _r = stdout().write_all(formatted_text.as_bytes());
// TODO(ry) Only ignore SIGPIPE. Currently ignoring all errors.
}
}
Err(e) => {
eprintln!("Error formatting from stdin");
eprintln!(" {}", e);
}
}
}
4 changes: 3 additions & 1 deletion cli/lib.rs
Expand Up @@ -405,7 +405,9 @@ async fn run_script(flags: DenoFlags, script: String) {
}

async fn fmt_command(files: Option<Vec<String>>, check: bool) {
fmt::format_files(files, check);
if let Err(err) = fmt::format_files(files, check) {
print_err_and_exit(err);
}
}

pub fn main() {
Expand Down
38 changes: 34 additions & 4 deletions cli/tests/integration_tests.rs
Expand Up @@ -603,6 +603,32 @@ itest!(bundle {
output: "bundle.test.out",
});

itest!(fmt_stdin {
args: "fmt -",
input: Some("const a = 1\n"),
output_str: Some("const a = 1;\n"),
});

itest!(fmt_stdin_ambiguous {
args: "fmt - file.ts",
input: Some("const a = 1\n"),
check_stderr: true,
exit_code: 1,
output_str: Some("Ambiguous filename input. To format stdin, provide a single '-' instead.\n"),
});

itest!(fmt_stdin_check_formatted {
args: "fmt --check -",
input: Some("const a = 1;\n"),
output_str: Some(""),
});

itest!(fmt_stdin_check_not_formatted {
args: "fmt --check -",
input: Some("const a = 1\n"),
output_str: Some("Not formatted stdin\n"),
});

itest!(circular1 {
args: "run --reload circular1.js",
output: "circular1.js.out",
Expand Down Expand Up @@ -917,6 +943,7 @@ mod util {
pub args: &'static str,
pub output: &'static str,
pub input: Option<&'static str>,
pub output_str: Option<&'static str>,
pub exit_code: i32,
pub check_stderr: bool,
pub http_server: bool,
Expand Down Expand Up @@ -982,10 +1009,13 @@ mod util {
);
}

let output_path = tests_dir.join(self.output);
println!("output path {}", output_path.display());
let expected =
std::fs::read_to_string(output_path).expect("cannot read output");
let expected = if let Some(s) = self.output_str {
s.to_owned()
} else {
let output_path = tests_dir.join(self.output);
println!("output path {}", output_path.display());
std::fs::read_to_string(output_path).expect("cannot read output")
};

if !wildcard_match(&expected, &actual) {
println!("OUTPUT\n{}\nOUTPUT", actual);
Expand Down

0 comments on commit 5066018

Please sign in to comment.