From d8447cff363f099ef9f0bda9d3fb3b0474a48d6f Mon Sep 17 00:00:00 2001 From: crowlKats <13135287+crowlKats@users.noreply.github.com> Date: Fri, 16 Apr 2021 15:28:41 +0200 Subject: refactor(cli/flags): reorganize declarations (#10204) --- cli/flags.rs | 2180 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 1090 insertions(+), 1090 deletions(-) (limited to 'cli') diff --git a/cli/flags.rs b/cli/flags.rs index 900214701..82f582d41 100644 --- a/cli/flags.rs +++ b/cli/flags.rs @@ -417,430 +417,294 @@ If the flag is set, restrict these messages to errors.", .after_help(ENV_VARIABLES_HELP) } -fn types_parse(flags: &mut Flags, _matches: &clap::ArgMatches) { - flags.subcommand = DenoSubcommand::Types; +fn bundle_subcommand<'a, 'b>() -> App<'a, 'b> { + compile_args(SubCommand::with_name("bundle")) + .arg( + Arg::with_name("source_file") + .takes_value(true) + .required(true), + ) + .arg(Arg::with_name("out_file").takes_value(true).required(false)) + .arg(watch_arg()) + .about("Bundle module and dependencies into single file") + .long_about( + "Output a single JavaScript file with all dependencies. + deno bundle https://deno.land/std/examples/colors.ts colors.bundle.js + +If no output file is given, the output is written to standard output: + deno bundle https://deno.land/std/examples/colors.ts", + ) } -fn fmt_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - flags.watch = matches.is_present("watch"); - let files = match matches.values_of("files") { - Some(f) => f.map(PathBuf::from).collect(), - None => vec![], - }; - let ignore = match matches.values_of("ignore") { - Some(f) => f.map(PathBuf::from).collect(), - None => vec![], - }; - let ext = matches.value_of("ext").unwrap().to_string(); +fn cache_subcommand<'a, 'b>() -> App<'a, 'b> { + compile_args(SubCommand::with_name("cache")) + .arg( + Arg::with_name("file") + .takes_value(true) + .required(true) + .min_values(1), + ) + .about("Cache the dependencies") + .long_about( + "Cache and compile remote dependencies recursively. - flags.subcommand = DenoSubcommand::Fmt { - check: matches.is_present("check"), - ext, - files, - ignore, - } +Download and compile a module with all of its static dependencies and save them +in the local cache, without running any code: + deno cache https://deno.land/std/http/file_server.ts + +Future runs of this module will trigger no downloads or compilation unless +--reload is specified.", + ) } -fn install_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - runtime_args_parse(flags, matches, true, true); +fn compile_subcommand<'a, 'b>() -> App<'a, 'b> { + runtime_args(SubCommand::with_name("compile"), true, false) + .setting(AppSettings::TrailingVarArg) + .arg( + script_arg().required(true), + ) + .arg( + Arg::with_name("output") + .long("output") + .short("o") + .help("Output file (defaults to $PWD/)") + .takes_value(true) + ) + .arg( + Arg::with_name("target") + .long("target") + .help("Target OS architecture") + .takes_value(true) + .possible_values(&["x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc", "x86_64-apple-darwin", "aarch64-apple-darwin"]) + ) + .arg( + Arg::with_name("lite") + .long("lite") + .help("Use lite runtime") + ) + .about("Compile the script into a self contained executable") + .long_about( + "Compiles the given script into a self contained executable. + deno compile --unstable -A https://deno.land/std/http/file_server.ts + deno compile --unstable --output /usr/local/bin/color_util https://deno.land/std/examples/colors.ts + deno compile --unstable --lite --target x86_64-unknown-linux-gnu -A https://deno.land/std/http/file_server.ts - let root = if matches.is_present("root") { - let install_root = matches.value_of("root").unwrap(); - Some(PathBuf::from(install_root)) - } else { - None - }; +Any flags passed which affect runtime behavior, such as '--unstable', +'--allow-*', '--v8-flags', etc. are encoded into the output executable and used +at runtime as if they were passed to a similar 'deno run' command. - let force = matches.is_present("force"); - let name = matches.value_of("name").map(|s| s.to_string()); - let cmd_values = matches.values_of("cmd").unwrap(); - let mut cmd = vec![]; - for value in cmd_values { - cmd.push(value.to_string()); - } +The executable name is inferred by default: + - Attempt to take the file stem of the URL path. The above example would + become 'file_server'. + - If the file stem is something generic like 'main', 'mod', 'index' or 'cli', + and the path has no parent, take the file name of the parent path. Otherwise + settle with the generic name. + - If the resulting name has an '@...' suffix, strip it. - let module_url = cmd[0].to_string(); - let args = cmd[1..].to_vec(); +This commands supports cross-compiling to different target architectures using `--target` flag. +On the first invocation with deno will download proper binary and cache it in $DENO_DIR. The +aarch64-apple-darwin target is not supported in canary. - flags.subcommand = DenoSubcommand::Install { - name, - module_url, - args, - root, - force, - }; +It is possible to use \"lite\" binaries when compiling by passing `--lite` flag; these are stripped down versions +of the deno binary that do not contain built-in tooling (eg. formatter, linter). This feature is experimental. +", + ) } -fn compile_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - runtime_args_parse(flags, matches, true, false); - - let mut script: Vec = matches - .values_of("script_arg") - .unwrap() - .map(String::from) - .collect(); - assert!(!script.is_empty()); - let args = script.split_off(1); - let source_file = script[0].to_string(); - let output = matches.value_of("output").map(PathBuf::from); - let lite = matches.is_present("lite"); - let target = matches.value_of("target").map(String::from); - - flags.subcommand = DenoSubcommand::Compile { - source_file, - output, - args, - lite, - target, - }; +fn completions_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("completions") + .setting(AppSettings::DisableHelpSubcommand) + .arg( + Arg::with_name("shell") + .possible_values(&clap::Shell::variants()) + .required(true), + ) + .about("Generate shell completions") + .long_about( + "Output shell completion script to standard output. + deno completions bash > /usr/local/etc/bash_completion.d/deno.bash + source /usr/local/etc/bash_completion.d/deno.bash", + ) } -fn bundle_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - compile_args_parse(flags, matches); +fn coverage_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("coverage") + .about("Print coverage reports") + .long_about( + "Print coverage reports from coverage profiles. - let source_file = matches.value_of("source_file").unwrap().to_string(); +Collect a coverage profile with deno test: + deno test --coverage=cov_profile - let out_file = if let Some(out_file) = matches.value_of("out_file") { - flags.allow_write = Some(vec![]); - Some(PathBuf::from(out_file)) - } else { - None - }; +Print a report to stdout: + deno coverage cov_profile - flags.watch = matches.is_present("watch"); +Include urls that start with the file schema: + deno coverage --include=\"^file:\" cov_profile - flags.subcommand = DenoSubcommand::Bundle { - source_file, - out_file, - }; -} +Exclude urls ending with test.ts and test.js: + deno coverage --exclude=\"test\\.(ts|js)\" cov_profile -fn completions_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - let shell: &str = matches.value_of("shell").unwrap(); - let mut buf: Vec = vec![]; - clap_root(&*crate::version::deno()).gen_completions_to( - "deno", - clap::Shell::from_str(shell).unwrap(), - &mut buf, - ); +Include urls that start with the file schema and exclude files ending with test.ts and test.js, for +an url to match it must match the include pattern and not match the exclude pattern: + deno coverage --include=\"^file:\" --exclude=\"test\\.(ts|js)\" cov_profile - flags.subcommand = DenoSubcommand::Completions { - buf: buf.into_boxed_slice(), - }; +Write a report using the lcov format: + deno coverage --lcov cov_profile > cov.lcov + +Generate html reports from lcov: + genhtml -o html_cov cov.lcov +", + ) + .arg( + Arg::with_name("ignore") + .long("ignore") + .takes_value(true) + .use_delimiter(true) + .require_equals(true) + .help("Ignore coverage files"), + ) + .arg( + Arg::with_name("include") + .long("include") + .takes_value(true) + .value_name("regex") + .multiple(true) + .require_equals(true) + .default_value(r"^file:") + .help("Include source files in the report"), + ) + .arg( + Arg::with_name("exclude") + .long("exclude") + .takes_value(true) + .value_name("regex") + .multiple(true) + .require_equals(true) + .default_value(r"test\.(js|mjs|ts|jsx|tsx)$") + .help("Exclude source files from the report"), + ) + .arg( + Arg::with_name("lcov") + .long("lcov") + .help("Output coverage report in lcov format") + .takes_value(false), + ) + .arg( + Arg::with_name("files") + .takes_value(true) + .multiple(true) + .required(true), + ) } -fn repl_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - runtime_args_parse(flags, matches, false, true); - flags.repl = true; - flags.subcommand = DenoSubcommand::Repl; - flags.allow_net = Some(vec![]); - flags.allow_env = Some(vec![]); - flags.allow_run = Some(vec![]); - flags.allow_read = Some(vec![]); - flags.allow_write = Some(vec![]); - flags.allow_plugin = true; - flags.allow_hrtime = true; -} - -fn eval_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - runtime_args_parse(flags, matches, false, true); - flags.allow_net = Some(vec![]); - flags.allow_env = Some(vec![]); - flags.allow_run = Some(vec![]); - flags.allow_read = Some(vec![]); - flags.allow_write = Some(vec![]); - flags.allow_plugin = true; - flags.allow_hrtime = true; - // TODO(@satyarohith): remove this flag in 2.0. - let as_typescript = matches.is_present("ts"); - let ext = if as_typescript { - "ts".to_string() - } else { - matches.value_of("ext").unwrap().to_string() - }; - - let print = matches.is_present("print"); - let mut code: Vec = matches - .values_of("code_arg") - .unwrap() - .map(String::from) - .collect(); - assert!(!code.is_empty()); - let code_args = code.split_off(1); - let code = code[0].to_string(); - for v in code_args { - flags.argv.push(v); - } - flags.subcommand = DenoSubcommand::Eval { print, code, ext }; -} +fn doc_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("doc") + .about("Show documentation for a module") + .long_about( + "Show documentation for a module. -fn info_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - reload_arg_parse(flags, matches); - import_map_arg_parse(flags, matches); - ca_file_arg_parse(flags, matches); - let json = matches.is_present("json"); - flags.subcommand = DenoSubcommand::Info { - file: matches.value_of("file").map(|f| f.to_string()), - json, - }; -} +Output documentation to standard output: + deno doc ./path/to/module.ts -fn cache_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - compile_args_parse(flags, matches); - let files = matches - .values_of("file") - .unwrap() - .map(String::from) - .collect(); - flags.subcommand = DenoSubcommand::Cache { files }; -} +Output private documentation to standard output: + deno doc --private ./path/to/module.ts -fn coverage_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - let files = match matches.values_of("files") { - Some(f) => f.map(PathBuf::from).collect(), - None => vec![], - }; - let ignore = match matches.values_of("ignore") { - Some(f) => f.map(PathBuf::from).collect(), - None => vec![], - }; - let include = match matches.values_of("include") { - Some(f) => f.map(String::from).collect(), - None => vec![], - }; - let exclude = match matches.values_of("exclude") { - Some(f) => f.map(String::from).collect(), - None => vec![], - }; - let lcov = matches.is_present("lcov"); - flags.subcommand = DenoSubcommand::Coverage { - files, - ignore, - include, - exclude, - lcov, - }; -} +Output documentation in JSON format: + deno doc --json ./path/to/module.ts -fn lock_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - if matches.is_present("lock") { - let lockfile = matches.value_of("lock").unwrap(); - flags.lock = Some(PathBuf::from(lockfile)); - } - if matches.is_present("lock-write") { - flags.lock_write = true; - } -} +Target a specific symbol: + deno doc ./path/to/module.ts MyClass.someField -fn compile_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { - app +Show documentation for runtime built-ins: + deno doc + deno doc --builtin Deno.Listener", + ) .arg(import_map_arg()) - .arg(no_remote_arg()) - .arg(config_arg()) - .arg(no_check_arg()) .arg(reload_arg()) - .arg(lock_arg()) - .arg(lock_write_arg()) - .arg(ca_file_arg()) + .arg( + Arg::with_name("json") + .long("json") + .help("Output documentation in JSON format") + .takes_value(false), + ) + .arg( + Arg::with_name("private") + .long("private") + .help("Output private documentation") + .takes_value(false), + ) + // TODO(nayeemrmn): Make `--builtin` a proper option. Blocked by + // https://github.com/clap-rs/clap/issues/1794. Currently `--builtin` is + // just a possible value of `source_file` so leading hyphens must be + // enabled. + .setting(clap::AppSettings::AllowLeadingHyphen) + .arg(Arg::with_name("source_file").takes_value(true)) + .arg( + Arg::with_name("filter") + .help("Dot separated path to symbol") + .takes_value(true) + .required(false) + .conflicts_with("json") + .conflicts_with("pretty"), + ) } -fn compile_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - import_map_arg_parse(flags, matches); - no_remote_arg_parse(flags, matches); - config_arg_parse(flags, matches); - no_check_arg_parse(flags, matches); - reload_arg_parse(flags, matches); - lock_args_parse(flags, matches); - ca_file_arg_parse(flags, matches); -} +fn eval_subcommand<'a, 'b>() -> App<'a, 'b> { + runtime_args(SubCommand::with_name("eval"), false, true) + .about("Eval script") + .long_about( + "Evaluate JavaScript from the command line. + deno eval \"console.log('hello world')\" -fn runtime_args<'a, 'b>( - app: App<'a, 'b>, - include_perms: bool, - include_inspector: bool, -) -> App<'a, 'b> { - let app = compile_args(app); - let app = if include_perms { - permission_args(app) - } else { - app - }; - let app = if include_inspector { - inspect_args(app) - } else { - app - }; - app - .arg(cached_only_arg()) - .arg(location_arg()) - .arg(v8_flags_arg()) - .arg(seed_arg()) -} +To evaluate as TypeScript: + deno eval --ext=ts \"const v: string = 'hello'; console.log(v)\" -fn runtime_args_parse( - flags: &mut Flags, - matches: &clap::ArgMatches, - include_perms: bool, - include_inspector: bool, -) { - compile_args_parse(flags, matches); - cached_only_arg_parse(flags, matches); - if include_perms { - permission_args_parse(flags, matches); - } - if include_inspector { - inspect_arg_parse(flags, matches); - } - location_arg_parse(flags, matches); - v8_flags_arg_parse(flags, matches); - seed_arg_parse(flags, matches); - inspect_arg_parse(flags, matches); +This command has implicit access to all permissions (--allow-all).", + ) + .arg( + // TODO(@satyarohith): remove this argument in 2.0. + Arg::with_name("ts") + .long("ts") + .short("T") + .help("Treat eval input as TypeScript") + .takes_value(false) + .multiple(false) + .hidden(true), + ) + .arg( + Arg::with_name("ext") + .long("ext") + .help("Set standard input (stdin) content type") + .takes_value(true) + .default_value("js") + .possible_values(&["ts", "tsx", "js", "jsx"]), + ) + .arg( + Arg::with_name("print") + .long("print") + .short("p") + .help("print result to stdout") + .takes_value(false) + .multiple(false), + ) + .arg( + Arg::with_name("code_arg") + .multiple(true) + .help("Code arg") + .value_name("CODE_ARG") + .required(true), + ) } -fn run_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - runtime_args_parse(flags, matches, true, true); - - let mut script: Vec = matches - .values_of("script_arg") - .unwrap() - .map(String::from) - .collect(); - assert!(!script.is_empty()); - let script_args = script.split_off(1); - let script = script[0].to_string(); - for v in script_args { - flags.argv.push(v); - } - - flags.watch = matches.is_present("watch"); - flags.subcommand = DenoSubcommand::Run { script }; -} - -fn test_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - runtime_args_parse(flags, matches, true, true); - - let no_run = matches.is_present("no-run"); - let fail_fast = matches.is_present("fail-fast"); - let allow_none = matches.is_present("allow-none"); - let quiet = matches.is_present("quiet"); - let filter = matches.value_of("filter").map(String::from); - - if matches.is_present("script_arg") { - let script_arg: Vec = matches - .values_of("script_arg") - .unwrap() - .map(String::from) - .collect(); - - for v in script_arg { - flags.argv.push(v); - } - } - - let include = if matches.is_present("files") { - let files: Vec = matches - .values_of("files") - .unwrap() - .map(String::from) - .collect(); - Some(files) - } else { - None - }; - - flags.coverage_dir = matches.value_of("coverage").map(String::from); - flags.subcommand = DenoSubcommand::Test { - no_run, - fail_fast, - quiet, - include, - filter, - allow_none, - }; -} - -fn upgrade_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - ca_file_arg_parse(flags, matches); - - let dry_run = matches.is_present("dry-run"); - let force = matches.is_present("force"); - let canary = matches.is_present("canary"); - let version = matches.value_of("version").map(|s| s.to_string()); - let output = if matches.is_present("output") { - let install_root = matches.value_of("output").unwrap(); - Some(PathBuf::from(install_root)) - } else { - None - }; - let ca_file = matches.value_of("cert").map(|s| s.to_string()); - flags.subcommand = DenoSubcommand::Upgrade { - dry_run, - force, - canary, - version, - output, - ca_file, - }; -} - -fn doc_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - import_map_arg_parse(flags, matches); - reload_arg_parse(flags, matches); - - let source_file = matches.value_of("source_file").map(String::from); - let private = matches.is_present("private"); - let json = matches.is_present("json"); - let filter = matches.value_of("filter").map(String::from); - flags.subcommand = DenoSubcommand::Doc { - source_file, - json, - filter, - private, - }; -} - -fn lsp_parse(flags: &mut Flags, _matches: &clap::ArgMatches) { - flags.subcommand = DenoSubcommand::Lsp; -} - -fn lint_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - let files = match matches.values_of("files") { - Some(f) => f.map(PathBuf::from).collect(), - None => vec![], - }; - let ignore = match matches.values_of("ignore") { - Some(f) => f.map(PathBuf::from).collect(), - None => vec![], - }; - let rules = matches.is_present("rules"); - let json = matches.is_present("json"); - flags.subcommand = DenoSubcommand::Lint { - files, - rules, - ignore, - json, - }; -} - -fn types_subcommand<'a, 'b>() -> App<'a, 'b> { - SubCommand::with_name("types") - .about("Print runtime TypeScript declarations") - .long_about( - "Print runtime TypeScript declarations. - deno types > lib.deno.d.ts - -The declaration file could be saved and used for typing information.", - ) -} - -fn fmt_subcommand<'a, 'b>() -> App<'a, 'b> { - SubCommand::with_name("fmt") - .about("Format source files") - .long_about( - "Auto-format JavaScript, TypeScript, Markdown, and JSON files. - deno fmt - deno fmt myfile1.ts myfile2.ts - deno fmt --check +fn fmt_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("fmt") + .about("Format source files") + .long_about( + "Auto-format JavaScript, TypeScript, Markdown, and JSON files. + deno fmt + deno fmt myfile1.ts myfile2.ts + deno fmt --check Format stdin and write to stdout: cat file.ts | deno fmt - @@ -882,41 +746,73 @@ Ignore formatting a file by adding an ignore comment at the top of the file: .arg(watch_arg()) } -fn repl_subcommand<'a, 'b>() -> App<'a, 'b> { - runtime_args(SubCommand::with_name("repl"), false, true) - .about("Read Eval Print Loop") +fn info_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("info") + .about("Show info about cache or info related to source file") + .long_about( + "Information about a module or the cache directories. + +Get information about a module: + deno info https://deno.land/std/http/file_server.ts + +The following information is shown: + +local: Local path of the file. +type: JavaScript, TypeScript, or JSON. +compiled: Local path of compiled source code. (TypeScript only.) +map: Local path of source map. (TypeScript only.) +deps: Dependency tree of the source file. + +Without any additional arguments, 'deno info' shows: + +DENO_DIR: Directory containing Deno-managed files. +Remote modules cache: Subdirectory containing downloaded remote modules. +TypeScript compiler cache: Subdirectory containing TS compiler output.", + ) + .arg(Arg::with_name("file").takes_value(true).required(false)) + .arg(reload_arg().requires("file")) + .arg(ca_file_arg()) + // TODO(lucacasonato): remove for 2.0 + .arg(no_check_arg().hidden(true)) + .arg(import_map_arg()) + .arg( + Arg::with_name("json") + .long("json") + .help("Outputs the information in JSON format") + .takes_value(false), + ) } fn install_subcommand<'a, 'b>() -> App<'a, 'b> { runtime_args(SubCommand::with_name("install"), true, true) - .setting(AppSettings::TrailingVarArg) - .arg( - Arg::with_name("cmd") - .required(true) - .multiple(true) - .allow_hyphen_values(true)) - .arg( - Arg::with_name("name") - .long("name") - .short("n") - .help("Executable file name") - .takes_value(true) - .required(false)) - .arg( - Arg::with_name("root") - .long("root") - .help("Installation root") - .takes_value(true) - .multiple(false)) - .arg( - Arg::with_name("force") - .long("force") - .short("f") - .help("Forcefully overwrite existing installation") - .takes_value(false)) - .about("Install script as an executable") - .long_about( -"Installs a script as an executable in the installation root's bin directory. + .setting(AppSettings::TrailingVarArg) + .arg( + Arg::with_name("cmd") + .required(true) + .multiple(true) + .allow_hyphen_values(true)) + .arg( + Arg::with_name("name") + .long("name") + .short("n") + .help("Executable file name") + .takes_value(true) + .required(false)) + .arg( + Arg::with_name("root") + .long("root") + .help("Installation root") + .takes_value(true) + .multiple(false)) + .arg( + Arg::with_name("force") + .long("force") + .short("f") + .help("Forcefully overwrite existing installation") + .takes_value(false)) + .about("Install script as an executable") + .long_about( + "Installs a script as an executable in the installation root's bin directory. deno install --allow-net --allow-read https://deno.land/std/http/file_server.ts deno install https://deno.land/std/examples/colors.ts @@ -942,285 +838,202 @@ The installation root is determined, in order of precedence: These must be added to the path manually if required.") } -fn compile_subcommand<'a, 'b>() -> App<'a, 'b> { - runtime_args(SubCommand::with_name("compile"), true, false) - .setting(AppSettings::TrailingVarArg) - .arg( - script_arg().required(true), +fn lsp_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("lsp") + .about("Start the language server") + .long_about( + "The 'deno lsp' subcommand provides a way for code editors and IDEs to +interact with Deno using the Language Server Protocol. Usually humans do not +use this subcommand directly. For example, 'deno lsp' can provide IDEs with +go-to-definition support and automatic code formatting. + +How to connect various editors and IDEs to 'deno lsp': +https://deno.land/manual/getting_started/setup_your_environment#editors-and-ides") +} + +fn lint_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("lint") + .about("Lint source files") + .long_about( + "Lint JavaScript/TypeScript source code. + deno lint --unstable + deno lint --unstable myfile1.ts myfile2.js + +Print result as JSON: + deno lint --unstable --json + +Read from stdin: + cat file.ts | deno lint --unstable - + cat file.ts | deno lint --unstable --json - + +List available rules: + deno lint --unstable --rules + +Ignore diagnostics on the next line by preceding it with an ignore comment and +rule name: + // deno-lint-ignore no-explicit-any + + // deno-lint-ignore require-await no-empty + +Names of rules to ignore must be specified after ignore comment. + +Ignore linting a file by adding an ignore comment at the top of the file: + // deno-lint-ignore-file +", ) .arg( - Arg::with_name("output") - .long("output") - .short("o") - .help("Output file (defaults to $PWD/)") - .takes_value(true) + Arg::with_name("rules") + .long("rules") + .help("List available rules"), ) .arg( - Arg::with_name("target") - .long("target") - .help("Target OS architecture") + Arg::with_name("ignore") + .long("ignore") + .requires("unstable") .takes_value(true) - .possible_values(&["x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc", "x86_64-apple-darwin", "aarch64-apple-darwin"]) + .use_delimiter(true) + .require_equals(true) + .help("Ignore linting particular source files"), ) .arg( - Arg::with_name("lite") - .long("lite") - .help("Use lite runtime") + Arg::with_name("json") + .long("json") + .help("Output lint result in JSON format") + .takes_value(false), ) - .about("Compile the script into a self contained executable") - .long_about( - "Compiles the given script into a self contained executable. - deno compile --unstable -A https://deno.land/std/http/file_server.ts - deno compile --unstable --output /usr/local/bin/color_util https://deno.land/std/examples/colors.ts - deno compile --unstable --lite --target x86_64-unknown-linux-gnu -A https://deno.land/std/http/file_server.ts - -Any flags passed which affect runtime behavior, such as '--unstable', -'--allow-*', '--v8-flags', etc. are encoded into the output executable and used -at runtime as if they were passed to a similar 'deno run' command. - -The executable name is inferred by default: - - Attempt to take the file stem of the URL path. The above example would - become 'file_server'. - - If the file stem is something generic like 'main', 'mod', 'index' or 'cli', - and the path has no parent, take the file name of the parent path. Otherwise - settle with the generic name. - - If the resulting name has an '@...' suffix, strip it. - -This commands supports cross-compiling to different target architectures using `--target` flag. -On the first invocation with deno will download proper binary and cache it in $DENO_DIR. The -aarch64-apple-darwin target is not supported in canary. - -It is possible to use \"lite\" binaries when compiling by passing `--lite` flag; these are stripped down versions -of the deno binary that do not contain built-in tooling (eg. formatter, linter). This feature is experimental. -", - ) -} - -fn bundle_subcommand<'a, 'b>() -> App<'a, 'b> { - compile_args(SubCommand::with_name("bundle")) .arg( - Arg::with_name("source_file") + Arg::with_name("files") .takes_value(true) - .required(true), + .multiple(true) + .required(false), ) - .arg(Arg::with_name("out_file").takes_value(true).required(false)) - .arg(watch_arg()) - .about("Bundle module and dependencies into single file") - .long_about( - "Output a single JavaScript file with all dependencies. - deno bundle https://deno.land/std/examples/colors.ts colors.bundle.js +} -If no output file is given, the output is written to standard output: - deno bundle https://deno.land/std/examples/colors.ts", - ) +fn repl_subcommand<'a, 'b>() -> App<'a, 'b> { + runtime_args(SubCommand::with_name("repl"), false, true) + .about("Read Eval Print Loop") } -fn completions_subcommand<'a, 'b>() -> App<'a, 'b> { - SubCommand::with_name("completions") - .setting(AppSettings::DisableHelpSubcommand) +fn run_subcommand<'a, 'b>() -> App<'a, 'b> { + runtime_args(SubCommand::with_name("run"), true, true) .arg( - Arg::with_name("shell") - .possible_values(&clap::Shell::variants()) - .required(true), + watch_arg() + .conflicts_with("inspect") + .conflicts_with("inspect-brk") ) - .about("Generate shell completions") - .long_about( - "Output shell completion script to standard output. - deno completions bash > /usr/local/etc/bash_completion.d/deno.bash - source /usr/local/etc/bash_completion.d/deno.bash", + .setting(AppSettings::TrailingVarArg) + .arg( + script_arg() + .required(true) ) -} - -fn eval_subcommand<'a, 'b>() -> App<'a, 'b> { - runtime_args(SubCommand::with_name("eval"), false, true) - .about("Eval script") + .about("Run a program given a filename or url to the module. Use '-' as a filename to read from stdin.") .long_about( - "Evaluate JavaScript from the command line. - deno eval \"console.log('hello world')\" + "Run a program given a filename or url to the module. -To evaluate as TypeScript: - deno eval --ext=ts \"const v: string = 'hello'; console.log(v)\" +By default all programs are run in sandbox without access to disk, network or +ability to spawn subprocesses. + deno run https://deno.land/std/examples/welcome.ts -This command has implicit access to all permissions (--allow-all).", +Grant all permissions: + deno run -A https://deno.land/std/http/file_server.ts + +Grant permission to read from disk and listen to network: + deno run --allow-read --allow-net https://deno.land/std/http/file_server.ts + +Grant permission to read allow-listed files from disk: + deno run --allow-read=/etc https://deno.land/std/http/file_server.ts + +Deno allows specifying the filename '-' to read the file from stdin. + curl https://deno.land/std/examples/welcome.ts | target/debug/deno run -", ) +} + +fn test_subcommand<'a, 'b>() -> App<'a, 'b> { + runtime_args(SubCommand::with_name("test"), true, true) + .setting(AppSettings::TrailingVarArg) .arg( - // TODO(@satyarohith): remove this argument in 2.0. - Arg::with_name("ts") - .long("ts") - .short("T") - .help("Treat eval input as TypeScript") + Arg::with_name("no-run") + .long("no-run") + .help("Cache test modules, but don't run tests") .takes_value(false) - .multiple(false) - .hidden(true), + .requires("unstable"), ) .arg( - Arg::with_name("ext") - .long("ext") - .help("Set standard input (stdin) content type") - .takes_value(true) - .default_value("js") - .possible_values(&["ts", "tsx", "js", "jsx"]), + Arg::with_name("fail-fast") + .long("fail-fast") + .alias("failfast") + .help("Stop on first error") + .takes_value(false), ) .arg( - Arg::with_name("print") - .long("print") - .short("p") - .help("print result to stdout") - .takes_value(false) - .multiple(false), + Arg::with_name("allow-none") + .long("allow-none") + .help("Don't return error code if no test files are found") + .takes_value(false), ) .arg( - Arg::with_name("code_arg") - .multiple(true) - .help("Code arg") - .value_name("CODE_ARG") - .required(true), - ) -} - -fn info_subcommand<'a, 'b>() -> App<'a, 'b> { - SubCommand::with_name("info") - .about("Show info about cache or info related to source file") - .long_about( - "Information about a module or the cache directories. - -Get information about a module: - deno info https://deno.land/std/http/file_server.ts - -The following information is shown: - -local: Local path of the file. -type: JavaScript, TypeScript, or JSON. -compiled: Local path of compiled source code. (TypeScript only.) -map: Local path of source map. (TypeScript only.) -deps: Dependency tree of the source file. - -Without any additional arguments, 'deno info' shows: - -DENO_DIR: Directory containing Deno-managed files. -Remote modules cache: Subdirectory containing downloaded remote modules. -TypeScript compiler cache: Subdirectory containing TS compiler output.", + Arg::with_name("filter") + .set(ArgSettings::AllowLeadingHyphen) + .long("filter") + .takes_value(true) + .help("Run tests with this string or pattern in the test name"), ) - .arg(Arg::with_name("file").takes_value(true).required(false)) - .arg(reload_arg().requires("file")) - .arg(ca_file_arg()) - // TODO(lucacasonato): remove for 2.0 - .arg(no_check_arg().hidden(true)) - .arg(import_map_arg()) .arg( - Arg::with_name("json") - .long("json") - .help("Outputs the information in JSON format") - .takes_value(false), + Arg::with_name("coverage") + .long("coverage") + .require_equals(true) + .takes_value(true) + .requires("unstable") + .conflicts_with("inspect") + .conflicts_with("inspect-brk") + .help("Collect coverage profile data"), ) -} - -fn cache_subcommand<'a, 'b>() -> App<'a, 'b> { - compile_args(SubCommand::with_name("cache")) .arg( - Arg::with_name("file") + Arg::with_name("files") + .help("List of file names to run") .takes_value(true) - .required(true) - .min_values(1), + .multiple(true), ) - .about("Cache the dependencies") + .arg(script_arg().last(true)) + .about("Run tests") .long_about( - "Cache and compile remote dependencies recursively. + "Run tests using Deno's built-in test runner. -Download and compile a module with all of its static dependencies and save them -in the local cache, without running any code: - deno cache https://deno.land/std/http/file_server.ts +Evaluate the given modules, run all tests declared with 'Deno.test()' and +report results to standard output: + deno test src/fetch_test.ts src/signal_test.ts -Future runs of this module will trigger no downloads or compilation unless ---reload is specified.", +Directory arguments are expanded to all contained files matching the glob +{*_,*.,}test.{js,mjs,ts,jsx,tsx}: + deno test src/", ) } -fn coverage_subcommand<'a, 'b>() -> App<'a, 'b> { - SubCommand::with_name("coverage") - .about("Print coverage reports") +fn types_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("types") + .about("Print runtime TypeScript declarations") .long_about( - "Print coverage reports from coverage profiles. - -Collect a coverage profile with deno test: - deno test --coverage=cov_profile - -Print a report to stdout: - deno coverage cov_profile - -Include urls that start with the file schema: - deno coverage --include=\"^file:\" cov_profile + "Print runtime TypeScript declarations. + deno types > lib.deno.d.ts -Exclude urls ending with test.ts and test.js: - deno coverage --exclude=\"test\\.(ts|js)\" cov_profile +The declaration file could be saved and used for typing information.", + ) +} -Include urls that start with the file schema and exclude files ending with test.ts and test.js, for -an url to match it must match the include pattern and not match the exclude pattern: - deno coverage --include=\"^file:\" --exclude=\"test\\.(ts|js)\" cov_profile +fn upgrade_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("upgrade") + .about("Upgrade deno executable to given version") + .long_about( + "Upgrade deno executable to the given version. +Defaults to latest. -Write a report using the lcov format: - deno coverage --lcov cov_profile > cov.lcov +The version is downloaded from +https://github.com/denoland/deno/releases +and is used to replace the current executable. -Generate html reports from lcov: - genhtml -o html_cov cov.lcov -", - ) - .arg( - Arg::with_name("ignore") - .long("ignore") - .takes_value(true) - .use_delimiter(true) - .require_equals(true) - .help("Ignore coverage files"), - ) - .arg( - Arg::with_name("include") - .long("include") - .takes_value(true) - .value_name("regex") - .multiple(true) - .require_equals(true) - .default_value(r"^file:") - .help("Include source files in the report"), - ) - .arg( - Arg::with_name("exclude") - .long("exclude") - .takes_value(true) - .value_name("regex") - .multiple(true) - .require_equals(true) - .default_value(r"test\.(js|mjs|ts|jsx|tsx)$") - .help("Exclude source files from the report"), - ) - .arg( - Arg::with_name("lcov") - .long("lcov") - .help("Output coverage report in lcov format") - .takes_value(false), - ) - .arg( - Arg::with_name("files") - .takes_value(true) - .multiple(true) - .required(true), - ) -} - -fn upgrade_subcommand<'a, 'b>() -> App<'a, 'b> { - SubCommand::with_name("upgrade") - .about("Upgrade deno executable to given version") - .long_about( - "Upgrade deno executable to the given version. -Defaults to latest. - -The version is downloaded from -https://github.com/denoland/deno/releases -and is used to replace the current executable. - -If you want to not replace the current Deno executable but instead download an -update to a different location, use the --output flag - deno upgrade --output $HOME/my_deno", +If you want to not replace the current Deno executable but instead download an +update to a different location, use the --output flag + deno upgrade --output $HOME/my_deno", ) .arg( Arg::with_name("version") @@ -1253,127 +1066,16 @@ update to a different location, use the --output flag .arg(ca_file_arg()) } -fn doc_subcommand<'a, 'b>() -> App<'a, 'b> { - SubCommand::with_name("doc") - .about("Show documentation for a module") - .long_about( - "Show documentation for a module. - -Output documentation to standard output: - deno doc ./path/to/module.ts - -Output private documentation to standard output: - deno doc --private ./path/to/module.ts - -Output documentation in JSON format: - deno doc --json ./path/to/module.ts - -Target a specific symbol: - deno doc ./path/to/module.ts MyClass.someField - -Show documentation for runtime built-ins: - deno doc - deno doc --builtin Deno.Listener", - ) +fn compile_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { + app .arg(import_map_arg()) + .arg(no_remote_arg()) + .arg(config_arg()) + .arg(no_check_arg()) .arg(reload_arg()) - .arg( - Arg::with_name("json") - .long("json") - .help("Output documentation in JSON format") - .takes_value(false), - ) - .arg( - Arg::with_name("private") - .long("private") - .help("Output private documentation") - .takes_value(false), - ) - // TODO(nayeemrmn): Make `--builtin` a proper option. Blocked by - // https://github.com/clap-rs/clap/issues/1794. Currently `--builtin` is - // just a possible value of `source_file` so leading hyphens must be - // enabled. - .setting(clap::AppSettings::AllowLeadingHyphen) - .arg(Arg::with_name("source_file").takes_value(true)) - .arg( - Arg::with_name("filter") - .help("Dot separated path to symbol") - .takes_value(true) - .required(false) - .conflicts_with("json") - .conflicts_with("pretty"), - ) -} - -fn lsp_subcommand<'a, 'b>() -> App<'a, 'b> { - SubCommand::with_name("lsp") - .about("Start the language server") - .long_about( - "The 'deno lsp' subcommand provides a way for code editors and IDEs to -interact with Deno using the Language Server Protocol. Usually humans do not -use this subcommand directly. For example, 'deno lsp' can provide IDEs with -go-to-definition support and automatic code formatting. - -How to connect various editors and IDEs to 'deno lsp': -https://deno.land/manual/getting_started/setup_your_environment#editors-and-ides") -} - -fn lint_subcommand<'a, 'b>() -> App<'a, 'b> { - SubCommand::with_name("lint") - .about("Lint source files") - .long_about( - "Lint JavaScript/TypeScript source code. - deno lint --unstable - deno lint --unstable myfile1.ts myfile2.js - -Print result as JSON: - deno lint --unstable --json - -Read from stdin: - cat file.ts | deno lint --unstable - - cat file.ts | deno lint --unstable --json - - -List available rules: - deno lint --unstable --rules - -Ignore diagnostics on the next line by preceding it with an ignore comment and -rule name: - // deno-lint-ignore no-explicit-any - - // deno-lint-ignore require-await no-empty - -Names of rules to ignore must be specified after ignore comment. - -Ignore linting a file by adding an ignore comment at the top of the file: - // deno-lint-ignore-file -", - ) - .arg( - Arg::with_name("rules") - .long("rules") - .help("List available rules"), - ) - .arg( - Arg::with_name("ignore") - .long("ignore") - .requires("unstable") - .takes_value(true) - .use_delimiter(true) - .require_equals(true) - .help("Ignore linting particular source files"), - ) - .arg( - Arg::with_name("json") - .long("json") - .help("Output lint result in JSON format") - .takes_value(false), - ) - .arg( - Arg::with_name("files") - .takes_value(true) - .multiple(true) - .required(false), - ) + .arg(lock_arg()) + .arg(lock_write_arg()) + .arg(ca_file_arg()) } fn permission_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { @@ -1455,215 +1157,627 @@ fn permission_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { ) } -fn run_subcommand<'a, 'b>() -> App<'a, 'b> { - runtime_args(SubCommand::with_name("run"), true, true) +fn runtime_args<'a, 'b>( + app: App<'a, 'b>, + include_perms: bool, + include_inspector: bool, +) -> App<'a, 'b> { + let app = compile_args(app); + let app = if include_perms { + permission_args(app) + } else { + app + }; + let app = if include_inspector { + inspect_args(app) + } else { + app + }; + app + .arg(cached_only_arg()) + .arg(location_arg()) + .arg(v8_flags_arg()) + .arg(seed_arg()) +} + +fn inspect_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { + app .arg( - watch_arg() - .conflicts_with("inspect") - .conflicts_with("inspect-brk") + Arg::with_name("inspect") + .long("inspect") + .value_name("HOST:PORT") + .help("Activate inspector on host:port (default: 127.0.0.1:9229)") + .min_values(0) + .max_values(1) + .require_equals(true) + .takes_value(true) + .validator(inspect_arg_validate), ) - .setting(AppSettings::TrailingVarArg) .arg( - script_arg() - .required(true) - ) - .about("Run a program given a filename or url to the module. Use '-' as a filename to read from stdin.") - .long_about( - "Run a program given a filename or url to the module. - -By default all programs are run in sandbox without access to disk, network or -ability to spawn subprocesses. - deno run https://deno.land/std/examples/welcome.ts - -Grant all permissions: - deno run -A https://deno.land/std/http/file_server.ts - -Grant permission to read from disk and listen to network: - deno run --allow-read --allow-net https://deno.land/std/http/file_server.ts - -Grant permission to read allow-listed files from disk: - deno run --allow-read=/etc https://deno.land/std/http/file_server.ts - -Deno allows specifying the filename '-' to read the file from stdin. - curl https://deno.land/std/examples/welcome.ts | target/debug/deno run -", + Arg::with_name("inspect-brk") + .long("inspect-brk") + .value_name("HOST:PORT") + .help( + "Activate inspector on host:port and break at start of user script", + ) + .min_values(0) + .max_values(1) + .require_equals(true) + .takes_value(true) + .validator(inspect_arg_validate), ) } -fn test_subcommand<'a, 'b>() -> App<'a, 'b> { - runtime_args(SubCommand::with_name("test"), true, true) - .setting(AppSettings::TrailingVarArg) - .arg( - Arg::with_name("no-run") - .long("no-run") - .help("Cache test modules, but don't run tests") - .takes_value(false) - .requires("unstable"), - ) - .arg( - Arg::with_name("fail-fast") - .long("fail-fast") - .alias("failfast") - .help("Stop on first error") - .takes_value(false), - ) - .arg( - Arg::with_name("allow-none") - .long("allow-none") - .help("Don't return error code if no test files are found") - .takes_value(false), - ) - .arg( - Arg::with_name("filter") - .set(ArgSettings::AllowLeadingHyphen) - .long("filter") - .takes_value(true) - .help("Run tests with this string or pattern in the test name"), +fn import_map_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("import-map") + .long("import-map") + .alias("importmap") + .value_name("FILE") + .help("Load import map file") + .long_help( + "Load import map file from local file or remote URL. +Docs: https://deno.land/manual/linking_to_external_code/import_maps +Specification: https://wicg.github.io/import-maps/ +Examples: https://github.com/WICG/import-maps#the-import-map", ) - .arg( - Arg::with_name("coverage") - .long("coverage") - .require_equals(true) - .takes_value(true) - .requires("unstable") - .conflicts_with("inspect") - .conflicts_with("inspect-brk") - .help("Collect coverage profile data"), + .takes_value(true) +} + +fn reload_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("reload") + .short("r") + .min_values(0) + .takes_value(true) + .use_delimiter(true) + .require_equals(true) + .long("reload") + .help("Reload source code cache (recompile TypeScript)") + .value_name("CACHE_BLOCKLIST") + .long_help( + "Reload source code cache (recompile TypeScript) +--reload + Reload everything +--reload=https://deno.land/std + Reload only standard modules +--reload=https://deno.land/std/fs/utils.ts,https://deno.land/std/fmt/colors.ts + Reloads specific modules", ) - .arg( - Arg::with_name("files") - .help("List of file names to run") - .takes_value(true) - .multiple(true), +} + +fn ca_file_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("cert") + .long("cert") + .value_name("FILE") + .help("Load certificate authority from PEM encoded file") + .takes_value(true) +} + +fn cached_only_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("cached-only") + .long("cached-only") + .help("Require that remote dependencies are already cached") +} + +fn location_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("location") + .long("location") + .takes_value(true) + .value_name("HREF") + .validator(|href| { + let url = Url::parse(&href); + if url.is_err() { + return Err("Failed to parse URL".to_string()); + } + let mut url = url.unwrap(); + if !["http", "https"].contains(&url.scheme()) { + return Err("Expected protocol \"http\" or \"https\"".to_string()); + } + url.set_username("").unwrap(); + url.set_password(None).unwrap(); + Ok(()) + }) + .help("Value of 'globalThis.location' used by some web APIs") +} + +fn v8_flags_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("v8-flags") + .long("v8-flags") + .takes_value(true) + .use_delimiter(true) + .require_equals(true) + .help("Set V8 command line options (for help: --v8-flags=--help)") +} + +fn seed_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("seed") + .long("seed") + .value_name("NUMBER") + .help("Seed Math.random()") + .takes_value(true) + .validator(|val: String| match val.parse::() { + Ok(_) => Ok(()), + Err(_) => Err("Seed should be a number".to_string()), + }) +} + +fn watch_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("watch") + .requires("unstable") + .long("watch") + .help("Watch for file changes and restart process automatically") + .long_help( + "Watch for file changes and restart process automatically. +Only local files from entry point module graph are watched.", ) - .arg(script_arg().last(true)) - .about("Run tests") - .long_about( - "Run tests using Deno's built-in test runner. +} + +fn no_check_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("no-check") + .long("no-check") + .help("Skip type checking modules") +} + +fn script_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("script_arg") + .multiple(true) + // NOTE: these defaults are provided + // so `deno run --v8-flags=--help` works + // without specifying file to run. + .default_value_ifs(&[ + ("v8-flags", Some("--help"), "_"), + ("v8-flags", Some("-help"), "_"), + ]) + .help("Script arg") + .value_name("SCRIPT_ARG") +} + +fn lock_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("lock") + .long("lock") + .value_name("FILE") + .help("Check the specified lock file") + .takes_value(true) +} + +fn lock_write_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("lock-write") + .long("lock-write") + .requires("lock") + .help("Write lock file (use with --lock)") +} + +fn config_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("config") + .short("c") + .long("config") + .value_name("FILE") + .help("Load tsconfig.json configuration file") + .takes_value(true) +} + +fn no_remote_arg<'a, 'b>() -> Arg<'a, 'b> { + Arg::with_name("no-remote") + .long("no-remote") + .help("Do not resolve remote modules") +} + +fn bundle_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + compile_args_parse(flags, matches); + + let source_file = matches.value_of("source_file").unwrap().to_string(); + + let out_file = if let Some(out_file) = matches.value_of("out_file") { + flags.allow_write = Some(vec![]); + Some(PathBuf::from(out_file)) + } else { + None + }; + + flags.watch = matches.is_present("watch"); + + flags.subcommand = DenoSubcommand::Bundle { + source_file, + out_file, + }; +} + +fn cache_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + compile_args_parse(flags, matches); + let files = matches + .values_of("file") + .unwrap() + .map(String::from) + .collect(); + flags.subcommand = DenoSubcommand::Cache { files }; +} + +fn compile_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + runtime_args_parse(flags, matches, true, false); + + let mut script: Vec = matches + .values_of("script_arg") + .unwrap() + .map(String::from) + .collect(); + assert!(!script.is_empty()); + let args = script.split_off(1); + let source_file = script[0].to_string(); + let output = matches.value_of("output").map(PathBuf::from); + let lite = matches.is_present("lite"); + let target = matches.value_of("target").map(String::from); + + flags.subcommand = DenoSubcommand::Compile { + source_file, + output, + args, + lite, + target, + }; +} + +fn completions_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + let shell: &str = matches.value_of("shell").unwrap(); + let mut buf: Vec = vec![]; + clap_root(&*crate::version::deno()).gen_completions_to( + "deno", + clap::Shell::from_str(shell).unwrap(), + &mut buf, + ); + + flags.subcommand = DenoSubcommand::Completions { + buf: buf.into_boxed_slice(), + }; +} + +fn coverage_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + let files = match matches.values_of("files") { + Some(f) => f.map(PathBuf::from).collect(), + None => vec![], + }; + let ignore = match matches.values_of("ignore") { + Some(f) => f.map(PathBuf::from).collect(), + None => vec![], + }; + let include = match matches.values_of("include") { + Some(f) => f.map(String::from).collect(), + None => vec![], + }; + let exclude = match matches.values_of("exclude") { + Some(f) => f.map(String::from).collect(), + None => vec![], + }; + let lcov = matches.is_present("lcov"); + flags.subcommand = DenoSubcommand::Coverage { + files, + ignore, + include, + exclude, + lcov, + }; +} + +fn doc_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + import_map_arg_parse(flags, matches); + reload_arg_parse(flags, matches); + + let source_file = matches.value_of("source_file").map(String::from); + let private = matches.is_present("private"); + let json = matches.is_present("json"); + let filter = matches.value_of("filter").map(String::from); + flags.subcommand = DenoSubcommand::Doc { + source_file, + json, + filter, + private, + }; +} + +fn eval_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + runtime_args_parse(flags, matches, false, true); + flags.allow_net = Some(vec![]); + flags.allow_env = Some(vec![]); + flags.allow_run = Some(vec![]); + flags.allow_read = Some(vec![]); + flags.allow_write = Some(vec![]); + flags.allow_plugin = true; + flags.allow_hrtime = true; + // TODO(@satyarohith): remove this flag in 2.0. + let as_typescript = matches.is_present("ts"); + let ext = if as_typescript { + "ts".to_string() + } else { + matches.value_of("ext").unwrap().to_string() + }; + + let print = matches.is_present("print"); + let mut code: Vec = matches + .values_of("code_arg") + .unwrap() + .map(String::from) + .collect(); + assert!(!code.is_empty()); + let code_args = code.split_off(1); + let code = code[0].to_string(); + for v in code_args { + flags.argv.push(v); + } + flags.subcommand = DenoSubcommand::Eval { print, code, ext }; +} + +fn fmt_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + flags.watch = matches.is_present("watch"); + let files = match matches.values_of("files") { + Some(f) => f.map(PathBuf::from).collect(), + None => vec![], + }; + let ignore = match matches.values_of("ignore") { + Some(f) => f.map(PathBuf::from).collect(), + None => vec![], + }; + let ext = matches.value_of("ext").unwrap().to_string(); -Evaluate the given modules, run all tests declared with 'Deno.test()' and -report results to standard output: - deno test src/fetch_test.ts src/signal_test.ts + flags.subcommand = DenoSubcommand::Fmt { + check: matches.is_present("check"), + ext, + files, + ignore, + } +} -Directory arguments are expanded to all contained files matching the glob -{*_,*.,}test.{js,mjs,ts,jsx,tsx}: - deno test src/", - ) +fn info_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + reload_arg_parse(flags, matches); + import_map_arg_parse(flags, matches); + ca_file_arg_parse(flags, matches); + let json = matches.is_present("json"); + flags.subcommand = DenoSubcommand::Info { + file: matches.value_of("file").map(|f| f.to_string()), + json, + }; } -fn script_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("script_arg") - .multiple(true) - // NOTE: these defaults are provided - // so `deno run --v8-flags=--help` works - // without specifying file to run. - .default_value_ifs(&[ - ("v8-flags", Some("--help"), "_"), - ("v8-flags", Some("-help"), "_"), - ]) - .help("Script arg") - .value_name("SCRIPT_ARG") +fn install_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + runtime_args_parse(flags, matches, true, true); + + let root = if matches.is_present("root") { + let install_root = matches.value_of("root").unwrap(); + Some(PathBuf::from(install_root)) + } else { + None + }; + + let force = matches.is_present("force"); + let name = matches.value_of("name").map(|s| s.to_string()); + let cmd_values = matches.values_of("cmd").unwrap(); + let mut cmd = vec![]; + for value in cmd_values { + cmd.push(value.to_string()); + } + + let module_url = cmd[0].to_string(); + let args = cmd[1..].to_vec(); + + flags.subcommand = DenoSubcommand::Install { + name, + module_url, + args, + root, + force, + }; } -fn lock_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("lock") - .long("lock") - .value_name("FILE") - .help("Check the specified lock file") - .takes_value(true) +fn lsp_parse(flags: &mut Flags, _matches: &clap::ArgMatches) { + flags.subcommand = DenoSubcommand::Lsp; } -fn lock_write_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("lock-write") - .long("lock-write") - .requires("lock") - .help("Write lock file (use with --lock)") +fn lint_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + let files = match matches.values_of("files") { + Some(f) => f.map(PathBuf::from).collect(), + None => vec![], + }; + let ignore = match matches.values_of("ignore") { + Some(f) => f.map(PathBuf::from).collect(), + None => vec![], + }; + let rules = matches.is_present("rules"); + let json = matches.is_present("json"); + flags.subcommand = DenoSubcommand::Lint { + files, + rules, + ignore, + json, + }; } -fn config_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("config") - .short("c") - .long("config") - .value_name("FILE") - .help("Load tsconfig.json configuration file") - .takes_value(true) +fn repl_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + runtime_args_parse(flags, matches, false, true); + flags.repl = true; + flags.subcommand = DenoSubcommand::Repl; + flags.allow_net = Some(vec![]); + flags.allow_env = Some(vec![]); + flags.allow_run = Some(vec![]); + flags.allow_read = Some(vec![]); + flags.allow_write = Some(vec![]); + flags.allow_plugin = true; + flags.allow_hrtime = true; } -fn config_arg_parse(flags: &mut Flags, matches: &ArgMatches) { - flags.config_path = matches.value_of("config").map(ToOwned::to_owned); +fn run_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + runtime_args_parse(flags, matches, true, true); + + let mut script: Vec = matches + .values_of("script_arg") + .unwrap() + .map(String::from) + .collect(); + assert!(!script.is_empty()); + let script_args = script.split_off(1); + let script = script[0].to_string(); + for v in script_args { + flags.argv.push(v); + } + + flags.watch = matches.is_present("watch"); + flags.subcommand = DenoSubcommand::Run { script }; } -fn ca_file_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("cert") - .long("cert") - .value_name("FILE") - .help("Load certificate authority from PEM encoded file") - .takes_value(true) +fn test_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + runtime_args_parse(flags, matches, true, true); + + let no_run = matches.is_present("no-run"); + let fail_fast = matches.is_present("fail-fast"); + let allow_none = matches.is_present("allow-none"); + let quiet = matches.is_present("quiet"); + let filter = matches.value_of("filter").map(String::from); + + if matches.is_present("script_arg") { + let script_arg: Vec = matches + .values_of("script_arg") + .unwrap() + .map(String::from) + .collect(); + + for v in script_arg { + flags.argv.push(v); + } + } + + let include = if matches.is_present("files") { + let files: Vec = matches + .values_of("files") + .unwrap() + .map(String::from) + .collect(); + Some(files) + } else { + None + }; + + flags.coverage_dir = matches.value_of("coverage").map(String::from); + flags.subcommand = DenoSubcommand::Test { + no_run, + fail_fast, + quiet, + include, + filter, + allow_none, + }; } -fn ca_file_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - flags.ca_file = matches.value_of("cert").map(ToOwned::to_owned); +fn types_parse(flags: &mut Flags, _matches: &clap::ArgMatches) { + flags.subcommand = DenoSubcommand::Types; } -fn location_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - flags.location = matches - .value_of("location") - .map(|href| Url::parse(href).unwrap()); +fn upgrade_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + ca_file_arg_parse(flags, matches); + + let dry_run = matches.is_present("dry-run"); + let force = matches.is_present("force"); + let canary = matches.is_present("canary"); + let version = matches.value_of("version").map(|s| s.to_string()); + let output = if matches.is_present("output") { + let install_root = matches.value_of("output").unwrap(); + Some(PathBuf::from(install_root)) + } else { + None + }; + let ca_file = matches.value_of("cert").map(|s| s.to_string()); + flags.subcommand = DenoSubcommand::Upgrade { + dry_run, + force, + canary, + version, + output, + ca_file, + }; } -fn location_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("location") - .long("location") - .takes_value(true) - .value_name("HREF") - .validator(|href| { - let url = Url::parse(&href); - if url.is_err() { - return Err("Failed to parse URL".to_string()); - } - let mut url = url.unwrap(); - if !["http", "https"].contains(&url.scheme()) { - return Err("Expected protocol \"http\" or \"https\"".to_string()); - } - url.set_username("").unwrap(); - url.set_password(None).unwrap(); - Ok(()) - }) - .help("Value of 'globalThis.location' used by some web APIs") +fn compile_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + import_map_arg_parse(flags, matches); + no_remote_arg_parse(flags, matches); + config_arg_parse(flags, matches); + no_check_arg_parse(flags, matches); + reload_arg_parse(flags, matches); + lock_args_parse(flags, matches); + ca_file_arg_parse(flags, matches); } -fn inspect_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { - app - .arg( - Arg::with_name("inspect") - .long("inspect") - .value_name("HOST:PORT") - .help("Activate inspector on host:port (default: 127.0.0.1:9229)") - .min_values(0) - .max_values(1) - .require_equals(true) - .takes_value(true) - .validator(inspect_arg_validate), - ) - .arg( - Arg::with_name("inspect-brk") - .long("inspect-brk") - .value_name("HOST:PORT") - .help( - "Activate inspector on host:port and break at start of user script", - ) - .min_values(0) - .max_values(1) - .require_equals(true) - .takes_value(true) - .validator(inspect_arg_validate), - ) +fn permission_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + if let Some(read_wl) = matches.values_of("allow-read") { + let read_allowlist: Vec = read_wl.map(PathBuf::from).collect(); + flags.allow_read = Some(read_allowlist); + } + + if let Some(write_wl) = matches.values_of("allow-write") { + let write_allowlist: Vec = write_wl.map(PathBuf::from).collect(); + flags.allow_write = Some(write_allowlist); + } + + if let Some(net_wl) = matches.values_of("allow-net") { + let net_allowlist: Vec = + crate::flags_allow_net::parse(net_wl.map(ToString::to_string).collect()) + .unwrap(); + flags.allow_net = Some(net_allowlist); + debug!("net allowlist: {:#?}", &flags.allow_net); + } + + if let Some(env_wl) = matches.values_of("allow-env") { + let env_allowlist: Vec = env_wl + .map(|env: &str| { + if cfg!(windows) { + env.to_uppercase() + } else { + env.to_string() + } + }) + .collect(); + flags.allow_env = Some(env_allowlist); + debug!("env allowlist: {:#?}", &flags.allow_env); + } + + if let Some(run_wl) = matches.values_of("allow-run") { + let run_allowlist: Vec = run_wl.map(ToString::to_string).collect(); + flags.allow_run = Some(run_allowlist); + debug!("run allowlist: {:#?}", &flags.allow_run); + } + + if matches.is_present("allow-plugin") { + flags.allow_plugin = true; + } + if matches.is_present("allow-hrtime") { + flags.allow_hrtime = true; + } + if matches.is_present("allow-all") { + flags.allow_read = Some(vec![]); + flags.allow_env = Some(vec![]); + flags.allow_net = Some(vec![]); + flags.allow_run = Some(vec![]); + flags.allow_write = Some(vec![]); + flags.allow_plugin = true; + flags.allow_hrtime = true; + } + if matches.is_present("prompt") { + flags.prompt = true; + } } -fn inspect_arg_validate(val: String) -> Result<(), String> { - match val.parse::() { - Ok(_) => Ok(()), - Err(e) => Err(e.to_string()), +fn runtime_args_parse( + flags: &mut Flags, + matches: &clap::ArgMatches, + include_perms: bool, + include_inspector: bool, +) { + compile_args_parse(flags, matches); + cached_only_arg_parse(flags, matches); + if include_perms { + permission_args_parse(flags, matches); + } + if include_inspector { + inspect_arg_parse(flags, matches); } + location_arg_parse(flags, matches); + v8_flags_arg_parse(flags, matches); + seed_arg_parse(flags, matches); + inspect_arg_parse(flags, matches); } fn inspect_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { @@ -1688,25 +1802,8 @@ fn inspect_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { }; } -fn reload_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("reload") - .short("r") - .min_values(0) - .takes_value(true) - .use_delimiter(true) - .require_equals(true) - .long("reload") - .help("Reload source code cache (recompile TypeScript)") - .value_name("CACHE_BLOCKLIST") - .long_help( - "Reload source code cache (recompile TypeScript) ---reload - Reload everything ---reload=https://deno.land/std - Reload only standard modules ---reload=https://deno.land/std/fs/utils.ts,https://deno.land/std/fmt/colors.ts - Reloads specific modules", - ) +fn import_map_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + flags.import_map_path = matches.value_of("import-map").map(ToOwned::to_owned); } fn reload_arg_parse(flags: &mut Flags, matches: &ArgMatches) { @@ -1723,32 +1820,20 @@ fn reload_arg_parse(flags: &mut Flags, matches: &ArgMatches) { } } -fn import_map_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("import-map") - .long("import-map") - .alias("importmap") - .value_name("FILE") - .help("Load import map file") - .long_help( - "Load import map file from local file or remote URL. -Docs: https://deno.land/manual/linking_to_external_code/import_maps -Specification: https://wicg.github.io/import-maps/ -Examples: https://github.com/WICG/import-maps#the-import-map", - ) - .takes_value(true) +fn ca_file_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + flags.ca_file = matches.value_of("cert").map(ToOwned::to_owned); } -fn import_map_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - flags.import_map_path = matches.value_of("import-map").map(ToOwned::to_owned); +fn cached_only_arg_parse(flags: &mut Flags, matches: &ArgMatches) { + if matches.is_present("cached-only") { + flags.cached_only = true; + } } -fn v8_flags_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("v8-flags") - .long("v8-flags") - .takes_value(true) - .use_delimiter(true) - .require_equals(true) - .help("Set V8 command line options (for help: --v8-flags=--help)") +fn location_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + flags.location = matches + .value_of("location") + .map(|href| Url::parse(href).unwrap()); } fn v8_flags_arg_parse(flags: &mut Flags, matches: &ArgMatches) { @@ -1757,29 +1842,6 @@ fn v8_flags_arg_parse(flags: &mut Flags, matches: &ArgMatches) { } } -fn watch_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("watch") - .requires("unstable") - .long("watch") - .help("Watch for file changes and restart process automatically") - .long_help( - "Watch for file changes and restart process automatically. -Only local files from entry point module graph are watched.", - ) -} - -fn seed_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("seed") - .long("seed") - .value_name("NUMBER") - .help("Seed Math.random()") - .takes_value(true) - .validator(|val: String| match val.parse::() { - Ok(_) => Ok(()), - Err(_) => Err("Seed should be a number".to_string()), - }) -} - fn seed_arg_parse(flags: &mut Flags, matches: &ArgMatches) { if matches.is_present("seed") { let seed_string = matches.value_of("seed").unwrap(); @@ -1790,34 +1852,24 @@ fn seed_arg_parse(flags: &mut Flags, matches: &ArgMatches) { } } -fn cached_only_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("cached-only") - .long("cached-only") - .help("Require that remote dependencies are already cached") -} - -fn cached_only_arg_parse(flags: &mut Flags, matches: &ArgMatches) { - if matches.is_present("cached-only") { - flags.cached_only = true; - } -} - -fn no_check_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("no-check") - .long("no-check") - .help("Skip type checking modules") -} - fn no_check_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { if matches.is_present("no-check") { flags.no_check = true; } } -fn no_remote_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("no-remote") - .long("no-remote") - .help("Do not resolve remote modules") +fn lock_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + if matches.is_present("lock") { + let lockfile = matches.value_of("lock").unwrap(); + flags.lock = Some(PathBuf::from(lockfile)); + } + if matches.is_present("lock-write") { + flags.lock_write = true; + } +} + +fn config_arg_parse(flags: &mut Flags, matches: &ArgMatches) { + flags.config_path = matches.value_of("config").map(ToOwned::to_owned); } fn no_remote_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { @@ -1826,62 +1878,10 @@ fn no_remote_arg_parse(flags: &mut Flags, matches: &clap::ArgMatches) { } } -fn permission_args_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - if let Some(read_wl) = matches.values_of("allow-read") { - let read_allowlist: Vec = read_wl.map(PathBuf::from).collect(); - flags.allow_read = Some(read_allowlist); - } - - if let Some(write_wl) = matches.values_of("allow-write") { - let write_allowlist: Vec = write_wl.map(PathBuf::from).collect(); - flags.allow_write = Some(write_allowlist); - } - - if let Some(net_wl) = matches.values_of("allow-net") { - let net_allowlist: Vec = - crate::flags_allow_net::parse(net_wl.map(ToString::to_string).collect()) - .unwrap(); - flags.allow_net = Some(net_allowlist); - debug!("net allowlist: {:#?}", &flags.allow_net); - } - - if let Some(env_wl) = matches.values_of("allow-env") { - let env_allowlist: Vec = env_wl - .map(|env: &str| { - if cfg!(windows) { - env.to_uppercase() - } else { - env.to_string() - } - }) - .collect(); - flags.allow_env = Some(env_allowlist); - debug!("env allowlist: {:#?}", &flags.allow_env); - } - - if let Some(run_wl) = matches.values_of("allow-run") { - let run_allowlist: Vec = run_wl.map(ToString::to_string).collect(); - flags.allow_run = Some(run_allowlist); - debug!("run allowlist: {:#?}", &flags.allow_run); - } - - if matches.is_present("allow-plugin") { - flags.allow_plugin = true; - } - if matches.is_present("allow-hrtime") { - flags.allow_hrtime = true; - } - if matches.is_present("allow-all") { - flags.allow_read = Some(vec![]); - flags.allow_env = Some(vec![]); - flags.allow_net = Some(vec![]); - flags.allow_run = Some(vec![]); - flags.allow_write = Some(vec![]); - flags.allow_plugin = true; - flags.allow_hrtime = true; - } - if matches.is_present("prompt") { - flags.prompt = true; +fn inspect_arg_validate(val: String) -> Result<(), String> { + match val.parse::() { + Ok(_) => Ok(()), + Err(e) => Err(e.to_string()), } } -- cgit v1.2.3