diff --git a/Cargo.lock b/Cargo.lock index ea3ea416b6..195f55069c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -167,9 +167,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" @@ -693,18 +693,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.13" +version = "4.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc" +checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.13" +version = "4.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99" +checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" dependencies = [ "anstream", "anstyle", @@ -715,9 +715,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.12" +version = "4.5.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8670053e87c316345e384ca1f3eba3006fc6355ed8b8a1140d104e109e3df34" +checksum = "6d7db6eca8c205649e8d3ccd05aa5042b1800a784e56bc7c43524fde8abbfa9b" dependencies = [ "clap", ] diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 9c62406ffe..a1d8f31dd0 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -91,8 +91,8 @@ bincode = "=1.3.3" bytes.workspace = true cache_control.workspace = true chrono = { workspace = true, features = ["now"] } -clap = { version = "=4.5.13", features = ["env", "string", "wrap_help"] } -clap_complete = "=4.5.12" +clap = { version = "=4.5.16", features = ["env", "string", "wrap_help", "error-context"] } +clap_complete = "=4.5.24" clap_complete_fig = "=4.5.2" color-print = "0.3.5" console_static_text.workspace = true diff --git a/cli/args/flags.rs b/cli/args/flags.rs index 2467de88f3..257bf81785 100644 --- a/cli/args/flags.rs +++ b/cli/args/flags.rs @@ -1,7 +1,10 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. +use crate::args::resolve_no_prompt; +use crate::util::fs::canonicalize_path; use clap::builder::styling::AnsiColor; use clap::builder::FalseyValueParser; +use clap::error::ErrorKind; use clap::value_parser; use clap::Arg; use clap::ArgAction; @@ -37,9 +40,6 @@ use std::path::Path; use std::path::PathBuf; use std::str::FromStr; -use crate::args::resolve_no_prompt; -use crate::util::fs::canonicalize_path; - use super::flags_net; #[derive(Clone, Debug, Default, Eq, PartialEq)] @@ -1118,6 +1118,7 @@ static DENO_HELP: &str = cstr!( deno bench bench.ts cache Cache the dependencies check Type-check the dependencies + clean Remove the cache directory compile Compile the script into a self contained executable deno compile main.ts | deno compile --target=x86_64-unknown-linux-gnu coverage Print coverage reports @@ -1145,7 +1146,32 @@ static DENO_HELP: &str = cstr!( /// Main entry point for parsing deno's command line flags. pub fn flags_from_vec(args: Vec) -> clap::error::Result { let mut app = clap_root(); - let mut matches = app.try_get_matches_from_mut(&args)?; + let mut matches = + app + .try_get_matches_from_mut(&args) + .map_err(|mut e| match e.kind() { + ErrorKind::MissingRequiredArgument => { + if let Some(clap::error::ContextValue::Strings(s)) = + e.get(clap::error::ContextKind::InvalidArg) + { + if s.len() == 1 + && s[0] == "--global" + && args.iter().any(|arg| arg == "install") + { + e.insert( + clap::error::ContextKind::Usage, + clap::error::ContextValue::StyledStr( + "Note: Permission flags can only be used in a global setting" + .into(), + ), + ); + } + } + + e + } + _ => e, + })?; let mut flags = Flags::default(); @@ -1463,7 +1489,7 @@ pub fn clap_root() -> Command { .subcommand(fmt_subcommand()) .subcommand(init_subcommand()) .subcommand(info_subcommand()) - .subcommand(future_install_subcommand()) + .subcommand(install_subcommand()) .subcommand(json_reference_subcommand()) .subcommand(jupyter_subcommand()) .subcommand(uninstall_subcommand()) @@ -1510,13 +1536,13 @@ fn help_subcommand(app: &Command) -> Command { fn add_subcommand() -> Command { command( "add", - "Add dependencies to the configuration file. - - deno add @std/path + cstr!( + "Add dependencies to your configuration file. + deno add @std/path You can add multiple dependencies at once: - deno add @std/path @std/assert -", + deno add @std/path @std/assert" + ), UnstableArgsConfig::None, ) .defer(|cmd| { @@ -1535,8 +1561,7 @@ fn remove_subcommand() -> Command { "remove", cstr!( "Remove dependencies from the configuration file. - - deno remove @std/path + deno remove @std/path You can remove multiple dependencies at once: deno remove @std/path @std/assert @@ -1558,15 +1583,15 @@ You can remove multiple dependencies at once: fn bench_subcommand() -> Command { command( "bench", - "Run benchmarks using Deno's built-in bench tool. + cstr!("Run benchmarks using Deno's built-in bench tool. -Evaluate the given modules, run all benches declared with 'Deno.bench()' -and report results to standard output: - deno bench src/fetch_bench.ts src/signal_bench.ts +Evaluate the given files, run all benches declared with 'Deno.bench()' and report results to standard output: + deno bench src/fetch_bench.ts src/signal_bench.ts -Directory arguments are expanded to all contained files matching the -glob {*_,*.,}bench.{js,mjs,ts,mts,jsx,tsx}: - deno bench src/", +If you specify a directory instead of a file, the path is expanded to all contained files matching the glob {*_,*.,}bench.{js,mjs,ts,mts,jsx,tsx}: + deno bench src/ + +Read more: https://docs.deno.com/go/cmd/bench"), UnstableArgsConfig::ResolutionAndRuntime, ) .defer(|cmd| { @@ -1624,14 +1649,14 @@ See the Deno 1.x to 2.x Migration Guide for migration instructions: https://docs fn cache_subcommand() -> Command { command( "cache", - "Cache and compile remote dependencies recursively. + cstr!("Cache and compile remote dependencies. -Download and compile a module with all of its static dependencies and save -them in the local cache, without running any code: - deno cache jsr:@std/http/file-server +Download and compile a module with all of its static dependencies and save them in the local cache, without running any code: + deno cache jsr:@std/http/file-server -Future runs of this module will trigger no downloads or compilation unless ---reload is specified.", +Future runs of this module will trigger no downloads or compilation unless --reload is specified + +Read more: https://docs.deno.com/go/cmd/cache"), UnstableArgsConfig::ResolutionOnly, ) .defer(|cmd| { @@ -1651,18 +1676,20 @@ Future runs of this module will trigger no downloads or compilation unless fn clean_subcommand() -> Command { command( "clean", - "Remove the cache directory ($DENO_DIR)", + cstr!("Remove the cache directory ($DENO_DIR)"), UnstableArgsConfig::None, ) } fn check_subcommand() -> Command { command("check", - "Download and type-check without execution. + cstr!("Download and type-check without execution. - deno check jsr:@std/http/file-server + deno check jsr:@std/http/file-server -Unless --reload is specified, this command will not re-download already cached dependencies.", +Unless --reload is specified, this command will not re-download already cached dependencies + +Read more: https://docs.deno.com/go/cmd/check"), UnstableArgsConfig::ResolutionAndRuntime ) .defer(|cmd| { @@ -1696,26 +1723,18 @@ Unless --reload is specified, this command will not re-download already cached d fn compile_subcommand() -> Command { command( "compile", - "Compiles the given script into a self contained executable. + cstr!("Compiles the given script into a self contained executable. - deno compile -A jsr:@std/http/file-server - deno compile --output file_server jsr:@std/http/file-server + deno compile -A jsr:@std/http/file-server + deno compile --output file_server jsr:@std/http/file-server -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. +Any flags specified which affect runtime behavior will be applied to the resulting binary. -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. +Cross-compiling to different target architectures is supported using the --target flag. +On the first invocation with deno will download the proper binary and cache it in $DENO_DIR. -Cross-compiling to different target architectures is supported using the -`--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. -", +Read more: https://docs.deno.com/go/cmd/compile +"), UnstableArgsConfig::ResolutionAndRuntime, ) .defer(|cmd| { @@ -1783,10 +1802,12 @@ supported in canary. fn completions_subcommand() -> Command { command( "completions", - "Output shell completion script to standard output. + cstr!( + "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", + deno completions bash > /usr/local/etc/bash_completion.d/deno.bash + source /usr/local/etc/bash_completion.d/deno.bash" + ), UnstableArgsConfig::None, ) .defer(|cmd| { @@ -1801,31 +1822,25 @@ fn completions_subcommand() -> Command { fn coverage_subcommand() -> Command { command( "coverage", - "Print coverage reports from coverage profiles. + cstr!("Print coverage reports from coverage profiles. Collect a coverage profile with deno test: - deno test --coverage=cov_profile + deno test --coverage=cov_profile Print a report to stdout: - deno coverage cov_profile + deno coverage cov_profile -Include urls that start with the file schema: - deno coverage --include=\"^file:\" cov_profile - -Exclude urls ending with test.ts and test.js: - deno coverage --exclude=\"test\\.(ts|js)\" cov_profile - -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 +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 Write a report using the lcov format: - deno coverage --lcov --output=cov.lcov cov_profile/ + deno coverage --lcov --output=cov.lcov cov_profile/ Generate html reports from lcov: - genhtml -o html_cov cov.lcov -", + genhtml -o html_cov cov.lcov + +Read more: https://docs.deno.com/go/cmd/coverage"), UnstableArgsConfig::None, ) .defer(|cmd| { @@ -1900,31 +1915,25 @@ Generate html reports from lcov: fn doc_subcommand() -> Command { command("doc", - "Show documentation for a module. + cstr!("Show documentation for a module. Output documentation to standard output: - deno doc ./path/to/module.ts + deno doc ./path/to/module.ts Output documentation in HTML format: - deno doc --html --name=\"My library\" ./path/to/module.ts - deno doc --html --name=\"My library\" ./main.ts ./dev.ts - deno doc --html --name=\"My library\" --output=./documentation/ ./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 + deno doc --html --name=\"My library\" ./path/to/module.ts Lint a module for documentation diagnostics: - deno doc --lint ./path/to/module.ts + deno doc --lint ./path/to/module.ts Target a specific symbol: - deno doc ./path/to/module.ts MyClass.someField + deno doc ./path/to/module.ts MyClass.someField Show documentation for runtime built-ins: - deno doc - deno doc --filter Deno.Listener", + deno doc + deno doc --filter Deno.Listener + +Read more: https://docs.deno.com/go/cmd/doc"), UnstableArgsConfig::ResolutionOnly ) .defer(|cmd| { @@ -2035,14 +2044,17 @@ Show documentation for runtime built-ins: fn eval_subcommand() -> Command { command( "eval", - "Evaluate JavaScript from the command line. - - deno eval \"console.log('hello world')\" + cstr!( + "Evaluate JavaScript from the command line. + deno eval \"console.log('hello world')\" To evaluate as TypeScript: - deno eval --ext=ts \"const v: string = 'hello'; console.log(v)\" + deno eval --ext=ts \"const v: string = 'hello'; console.log(v)\" -This command has implicit access to all permissions (--allow-all).", +This command has implicit access to all permissions. + +Read more: https://docs.deno.com/go/cmd/eval" + ), UnstableArgsConfig::ResolutionAndRuntime, ) .defer(|cmd| { @@ -2071,20 +2083,25 @@ This command has implicit access to all permissions (--allow-all).", fn fmt_subcommand() -> Command { command( "fmt", - "Auto-format JavaScript, TypeScript, Markdown, and JSON files. + cstr!("Auto-format various file types. + deno fmt myfile1.ts myfile2.ts - deno fmt - deno fmt myfile1.ts myfile2.ts - deno fmt --check +Supported file types are: + JavaScript, TypeScript, Markdown, JSON(C) and Jupyter Notebooks + +Supported file types which are behind corresponding unstable flags (see formatting options): + HTML, CSS, SCSS, SASS, LESS, YAML, Svelte, Vue, Astro and Angular Format stdin and write to stdout: - cat file.ts | deno fmt - + cat file.ts | deno fmt - Ignore formatting code by preceding it with an ignore comment: - // deno-fmt-ignore + // deno-fmt-ignore Ignore formatting a file by adding an ignore comment at the top of the file: - // deno-fmt-ignore-file", + // deno-fmt-ignore-file + +Read more: https://docs.deno.com/go/cmd/fmt"), UnstableArgsConfig::None, ) .defer(|cmd| { @@ -2104,6 +2121,7 @@ Ignore formatting a file by adding an ignore comment at the top of the file: .help("Set content type of the supplied file") // prefer using ts for formatting instead of js because ts works in more scenarios .default_value("ts") + .hide_default_value(true) .value_parser([ "ts", "tsx", "js", "jsx", "md", "json", "jsonc", "css", "scss", "sass", "less", "html", "svelte", "vue", "astro", "yml", "yaml", @@ -2250,23 +2268,18 @@ fn init_subcommand() -> Command { fn info_subcommand() -> Command { command("info", - "Information about a module or the cache directories. + cstr!("Show information about a module or the cache directories. Get information about a module: - deno info jsr:@std/http/file-server + deno info jsr:@std/http/file-server The following information is shown: + local: Local path of the file + type: JavaScript, TypeScript, or JSON + emit: Local path of compiled source code (TypeScript only) + dependencies: Dependency tree of the source file -local: Local path of the file. -type: JavaScript, TypeScript, or JSON. -emit: Local path of compiled source code. (TypeScript only.) -dependencies: 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.", +Read more: https://docs.deno.com/go/cmd/info"), UnstableArgsConfig::ResolutionOnly ) .defer(|cmd| cmd @@ -2297,89 +2310,83 @@ TypeScript compiler cache: Subdirectory containing TS compiler output.", )) } -fn install_args(cmd: Command) -> Command { - let cmd = cmd.arg( - Arg::new("cmd") - .required_if_eq("global", "true") - .num_args(1..) - .value_hint(ValueHint::FilePath), - ); - cmd - .arg( - Arg::new("name") - .long("name") - .short('n') - .help("Executable file name"), - ) - .arg( - Arg::new("root") - .long("root") - .help("Installation root") - .value_hint(ValueHint::DirPath), - ) - .arg( - Arg::new("force") - .long("force") - .short('f') - .help("Forcefully overwrite existing installation") - .action(ArgAction::SetTrue), - ) - .arg( - Arg::new("global") - .long("global") - .short('g') - .help("Install a package or script as a globally available executable") - .action(ArgAction::SetTrue), - ) - .arg(env_file_arg()) -} +fn install_subcommand() -> Command { + command("install", cstr!("Installs dependencies either in the local project or globally to a bin directory. -fn future_install_subcommand() -> Command { - command("install", "Installs dependencies either in the local project or globally to a bin directory. +Local installation -Local installation -------------------- -If the --global flag is not set, adds dependencies to the local project's configuration -(package.json / deno.json) and installs them in the package cache. If no dependency -is specified, installs all dependencies listed in package.json. +Add dependencies to the local project's configuration (deno.json / package.json) and installs them +in the package cache. If no dependency is specified, installs all dependencies listed in the config file. - deno install - deno install @std/bytes - deno install npm:chalk + deno install + deno install @std/bytes + deno install npm:chalk -Global installation -------------------- -If the --global flag is set, installs a script as an executable in the installation root's bin directory. +Global installation - deno install --global --allow-net --allow-read jsr:@std/http/file-server - deno install -g https://examples.deno.land/color-logging.ts +If the --global flag is set, installs a script as an executable in the installation root's bin directory. + + deno install --global --allow-net --allow-read jsr:@std/http/file-server + deno install -g https://examples.deno.land/color-logging.ts To change the executable name, use -n/--name: - - deno install -g --allow-net --allow-read -n serve jsr:@std/http/file-server + deno install -g --allow-net --allow-read -n serve jsr:@std/http/file-server 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', + 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. + - If the resulting name has an @... suffix, strip it. -To change the installation root, use --root: - - deno install -g --allow-net --allow-read --root /usr/local jsr:@std/http/file-server +To change the installation root, use --root: + deno install -g --allow-net --allow-read --root /usr/local jsr:@std/http/file-server The installation root is determined, in order of precedence: - - --root option - - DENO_INSTALL_ROOT environment variable - - $HOME/.deno + - --root option + - DENO_INSTALL_ROOT environment variable + - $HOME/.deno -These must be added to the path manually if required.", UnstableArgsConfig::ResolutionAndRuntime) +These must be added to the path manually if required."), UnstableArgsConfig::ResolutionAndRuntime) .visible_alias("i") .defer(|cmd| { - let cmd = runtime_args(cmd, true, true).arg(check_arg(true)).arg(allow_scripts_arg()); - install_args(cmd) + permission_args(runtime_args(cmd, false, true), Some("global")) + .arg(check_arg(true)) + .arg(allow_scripts_arg()) + .arg( + Arg::new("cmd") + .required_if_eq("global", "true") + .num_args(1..) + .value_hint(ValueHint::FilePath), + ) + .arg( + Arg::new("name") + .long("name") + .short('n') + .help("Executable file name"), + ) + .arg( + Arg::new("root") + .long("root") + .help("Installation root") + .value_hint(ValueHint::DirPath), + ) + .arg( + Arg::new("force") + .long("force") + .short('f') + .help("Forcefully overwrite existing installation") + .action(ArgAction::SetTrue), + ) + .arg( + Arg::new("global") + .long("global") + .short('g') + .help("Install a package or script as a globally available executable") + .action(ArgAction::SetTrue), + ) + .arg(env_file_arg()) }) } @@ -2417,17 +2424,16 @@ fn jupyter_subcommand() -> Command { fn uninstall_subcommand() -> Command { command( "uninstall", - "Uninstalls an executable script in the installation root's bin directory. + cstr!("Uninstalls an executable script in the installation root's bin directory. + deno uninstall serve - deno uninstall serve - -To change the installation root, use --root: - deno uninstall --root /usr/local serve +To change the installation root, use --root flag: + deno uninstall --root /usr/local serve The installation root is determined, in order of precedence: - - --root option - - DENO_INSTALL_ROOT environment variable - - $HOME/.deno", + - --root option + - DENO_INSTALL_ROOT environment variable + - $HOME/.deno"), UnstableArgsConfig::None, ) .defer(|cmd| { @@ -2451,44 +2457,41 @@ The installation root is determined, in order of precedence: fn lsp_subcommand() -> Command { Command::new("lsp").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. + "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://docs.deno.com/go/lsp", +How to connect various editors and IDEs to 'deno lsp': https://docs.deno.com/go/lsp", ) } fn lint_subcommand() -> Command { command( "lint", - "Lint JavaScript/TypeScript source code. + cstr!("Lint JavaScript/TypeScript source code. - deno lint - deno lint myfile1.ts myfile2.js + deno lint + deno lint myfile1.ts myfile2.js Print result as JSON: - deno lint --json + deno lint --json Read from stdin: - cat file.ts | deno lint - - cat file.ts | deno lint --json - + cat file.ts | deno lint - + cat file.ts | deno lint --json - List available rules: - deno lint --rules + deno lint --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 +To ignore specific diagnostics, you can write an ignore comment on the preceding line with a rule name (or multiple): + // deno-lint-ignore no-explicit-any + // deno-lint-ignore require-await no-empty -Names of rules to ignore must be specified after ignore comment. +To ignore linting on an entire file, you can add an ignore comment at the top of the file: + // deno-lint-ignore-file -Ignore linting a file by adding an ignore comment at the top of the file: - // deno-lint-ignore-file -", +Read more: https://docs.deno.com/go/cmd/lint +"), UnstableArgsConfig::ResolutionOnly, ) .defer(|cmd| { @@ -2645,7 +2648,9 @@ Grant all permissions: deno run -A jsr:@std/http/file-server Specifying the filename '-' to read the file from stdin. - curl https://examples.deno.land/hello-world.ts | deno run -"), UnstableArgsConfig::ResolutionAndRuntime), false) + curl https://examples.deno.land/hello-world.ts | deno run - + +Read more: https://docs.deno.com/go/cmd/run"), UnstableArgsConfig::ResolutionAndRuntime), false) } fn serve_host_validator(host: &str) -> Result { @@ -2657,7 +2662,19 @@ fn serve_host_validator(host: &str) -> Result { } fn serve_subcommand() -> Command { - runtime_args(command("serve", None, UnstableArgsConfig::ResolutionAndRuntime), true, true) + runtime_args(command("serve", cstr!("Run a server defined in a main module + +The serve command uses the default exports of the main module to determine which servers to start. + +See https://docs.deno.com/runtime/manual/tools/serve for more detailed information. + +Start a server defined in server.ts: + deno serve server.ts + +Start a server defined in server.ts, watching for changes and running on port 5050: + deno serve --watch --port 5050 server.ts + +Read more: https://docs.deno.com/go/cmd/serve"), UnstableArgsConfig::ResolutionAndRuntime), true, true) .arg( Arg::new("port") .long("port") @@ -2686,29 +2703,18 @@ fn serve_subcommand() -> Command { ) .arg(env_file_arg()) .arg(no_code_cache_arg()) - .about("Run a server defined in a main module - -The serve command uses the default exports of the main module to determine which -servers to start. - -See https://docs.deno.com/runtime/manual/tools/serve for -more detailed information. - -Start a server defined in server.ts: - - deno serve server.ts - -Start a server defined in server.ts, watching for changes and running on port 5050: - - deno serve --watch --port 5050 server.ts") } fn task_subcommand() -> Command { command( "task", - "Run a task defined in the configuration file - - deno task build", + cstr!( + "Run a task defined in the configuration file. + deno task build + +List all available tasks: + deno task" + ), UnstableArgsConfig::ResolutionAndRuntime, ) .defer(|cmd| { @@ -2728,15 +2734,16 @@ fn task_subcommand() -> Command { fn test_subcommand() -> Command { command("test", - "Run tests using Deno's built-in test runner. + cstr!("Run tests using Deno's built-in test runner. -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 +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 -Directory arguments are expanded to all contained files matching the glob -{*_,*.,}test.{js,mjs,ts,mts,jsx,tsx} or **/__tests__/**: - deno test src/", +Directory arguments are expanded to all contained files matching the glob {*_,*.,}test.{js,mjs,ts,mts,jsx,tsx} +or **/__tests__/**: + deno test src/ + +Read more: https://docs.deno.com/go/cmd/test"), UnstableArgsConfig::ResolutionAndRuntime ) .defer(|cmd| @@ -2882,7 +2889,7 @@ fn types_subcommand() -> Command { "types", "Print runtime TypeScript declarations. - deno types > lib.deno.d.ts + deno types > lib.deno.d.ts The declaration file could be saved and used for typing information.", UnstableArgsConfig::None, @@ -2892,31 +2899,28 @@ The declaration file could be saved and used for typing information.", fn upgrade_subcommand() -> Command { command( "upgrade", - color_print::cstr!("Upgrade deno executable to the given version. + cstr!("Upgrade deno executable to the given version. Latest - - deno upgrade + deno upgrade Specific version - - deno upgrade 1.45.0 - deno upgrade 1.46.0-rc.1 - deno upgrade 9bc2dd29ad6ba334fd57a20114e367d3c04763d4 + deno upgrade 1.45.0 + deno upgrade 1.46.0-rc.1 + deno upgrade 9bc2dd29ad6ba334fd57a20114e367d3c04763d4 Channel + deno upgrade stable + deno upgrade rc + deno upgrade canary - deno upgrade stable - deno upgrade rc - deno upgrade canary +The version is downloaded from https://dl.deno.land and is used to replace the current executable. -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"), +Read more: https://docs.deno.com/go/cmd/upgrade"), UnstableArgsConfig::None, ) .hide(cfg!(not(feature = "upgrade"))) @@ -2972,7 +2976,7 @@ update to a different location, use the --output flag: ) .arg( Arg::new("version-or-hash-or-channel") - .help(color_print::cstr!("Version (v1.46.0), channel (rc, canary) or commit hash (9bc2dd29ad6ba334fd57a20114e367d3c04763d4)")) + .help(cstr!("Version (v1.46.0), channel (rc, canary) or commit hash (9bc2dd29ad6ba334fd57a20114e367d3c04763d4)")) .value_name("VERSION") .action(ArgAction::Append) .trailing_var_arg(true), @@ -3057,7 +3061,7 @@ fn compile_args_without_check_args(app: Command) -> Command { .arg(unsafely_ignore_certificate_errors_arg()) } -fn permission_args(app: Command) -> Command { +fn permission_args(app: Command, requires: Option<&'static str>) -> Command { app .after_help(cstr!(r#"Permission options: Docs: https://docs.deno.com/go/permissions @@ -3095,216 +3099,342 @@ Docs: https://docs.deno.com/go/permissions --deny-ffi | --deny-ffi="./libfoo.so" "#)) .arg( - Arg::new("allow-all") - .short('A') - .long("allow-all") - .action(ArgAction::SetTrue) - .help("Allow all permissions") - .hide(true), + { + let mut arg = Arg::new("allow-all") + .short('A') + .long("allow-all") + .action(ArgAction::SetTrue) + .help("Allow all permissions") + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("allow-read") - .long("allow-read") - .short('R') - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("PATH") - .help("Allow file system read access. Optionally specify allowed paths") - .value_parser(value_parser!(String)) - .value_hint(ValueHint::AnyPath) - .hide(true), + { + let mut arg = Arg::new("allow-read") + .long("allow-read") + .short('R') + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("PATH") + .help("Allow file system read access. Optionally specify allowed paths") + .value_parser(value_parser!(String)) + .value_hint(ValueHint::AnyPath) + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("deny-read") - .long("deny-read") - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("PATH") - .help("Deny file system read access. Optionally specify denied paths") - .value_parser(value_parser!(String)) - .value_hint(ValueHint::AnyPath) - .hide(true), + { + let mut arg = Arg::new("deny-read") + .long("deny-read") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("PATH") + .help("Deny file system read access. Optionally specify denied paths") + .value_parser(value_parser!(String)) + .value_hint(ValueHint::AnyPath) + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("allow-write") - .long("allow-write") - .short('W') - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("PATH") - .help("Allow file system write access. Optionally specify allowed paths") - .value_parser(value_parser!(String)) - .value_hint(ValueHint::AnyPath) - .hide(true), + { + let mut arg = Arg::new("allow-write") + .long("allow-write") + .short('W') + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("PATH") + .help("Allow file system write access. Optionally specify allowed paths") + .value_parser(value_parser!(String)) + .value_hint(ValueHint::AnyPath) + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("deny-write") - .long("deny-write") - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("PATH") - .help("Deny file system write access. Optionally specify denied paths") - .value_parser(value_parser!(String)) - .value_hint(ValueHint::AnyPath) - .hide(true), + { + let mut arg = Arg::new("deny-write") + .long("deny-write") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("PATH") + .help("Deny file system write access. Optionally specify denied paths") + .value_parser(value_parser!(String)) + .value_hint(ValueHint::AnyPath) + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("allow-net") - .long("allow-net") - .short('N') - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("IP_OR_HOSTNAME") - .help("Allow network access. Optionally specify allowed IP addresses and host names, with ports as necessary") - .value_parser(flags_net::validator) - .hide(true), + { + let mut arg = Arg::new("allow-net") + .long("allow-net") + .short('N') + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("IP_OR_HOSTNAME") + .help("Allow network access. Optionally specify allowed IP addresses and host names, with ports as necessary") + .value_parser(flags_net::validator) + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("deny-net") - .long("deny-net") - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("IP_OR_HOSTNAME") - .help("Deny network access. Optionally specify denied IP addresses and host names, with ports as necessary") - .value_parser(flags_net::validator) - .hide(true), + { + let mut arg = Arg::new("deny-net") + .long("deny-net") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("IP_OR_HOSTNAME") + .help("Deny network access. Optionally specify denied IP addresses and host names, with ports as necessary") + .value_parser(flags_net::validator) + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("allow-env") - .long("allow-env") - .short('E') - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("VARIABLE_NAME") - .help("Allow access to system environment information. Optionally specify accessible environment variables") - .value_parser(|key: &str| { - if key.is_empty() || key.contains(&['=', '\0'] as &[char]) { - return Err(format!("invalid key \"{key}\"")); - } + { + let mut arg = Arg::new("allow-env") + .long("allow-env") + .short('E') + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("VARIABLE_NAME") + .help("Allow access to system environment information. Optionally specify accessible environment variables") + .value_parser(|key: &str| { + if key.is_empty() || key.contains(&['=', '\0'] as &[char]) { + return Err(format!("invalid key \"{key}\"")); + } - Ok(if cfg!(windows) { - key.to_uppercase() - } else { - key.to_string() + Ok(if cfg!(windows) { + key.to_uppercase() + } else { + key.to_string() + }) }) - }) - .hide(true), + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("deny-env") - .long("deny-env") - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("VARIABLE_NAME") - .help("Deny access to system environment information. Optionally specify accessible environment variables") - .value_parser(|key: &str| { - if key.is_empty() || key.contains(&['=', '\0'] as &[char]) { - return Err(format!("invalid key \"{key}\"")); - } + { + let mut arg = Arg::new("deny-env") + .long("deny-env") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("VARIABLE_NAME") + .help("Deny access to system environment information. Optionally specify accessible environment variables") + .value_parser(|key: &str| { + if key.is_empty() || key.contains(&['=', '\0'] as &[char]) { + return Err(format!("invalid key \"{key}\"")); + } - Ok(if cfg!(windows) { - key.to_uppercase() - } else { - key.to_string() + Ok(if cfg!(windows) { + key.to_uppercase() + } else { + key.to_string() + }) }) - }) - .hide(true), + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("allow-sys") - .long("allow-sys") - .short('S') - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("API_NAME") - .help("Allow access to OS information. Optionally allow specific APIs by function name") - .value_parser(|key: &str| parse_sys_kind(key).map(ToString::to_string)) - .hide(true), + { + let mut arg = Arg::new("allow-sys") + .long("allow-sys") + .short('S') + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("API_NAME") + .help("Allow access to OS information. Optionally allow specific APIs by function name") + .value_parser(|key: &str| parse_sys_kind(key).map(ToString::to_string)) + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("deny-sys") - .long("deny-sys") - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("API_NAME") - .help("Deny access to OS information. Optionally deny specific APIs by function name") - .value_parser(|key: &str| parse_sys_kind(key).map(ToString::to_string)) - .hide(true), + { + let mut arg = Arg::new("deny-sys") + .long("deny-sys") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("API_NAME") + .help("Deny access to OS information. Optionally deny specific APIs by function name") + .value_parser(|key: &str| parse_sys_kind(key).map(ToString::to_string)) + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("allow-run") - .long("allow-run") - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("PROGRAM_NAME") - .help("Allow running subprocesses. Optionally specify allowed runnable program names") - .hide(true), + { + let mut arg = Arg::new("allow-run") + .long("allow-run") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("PROGRAM_NAME") + .help("Allow running subprocesses. Optionally specify allowed runnable program names") + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("deny-run") - .long("deny-run") - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("PROGRAM_NAME") - .help("Deny running subprocesses. Optionally specify denied runnable program names") - .hide(true), + { + let mut arg = Arg::new("deny-run") + .long("deny-run") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("PROGRAM_NAME") + .help("Deny running subprocesses. Optionally specify denied runnable program names") + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + + } ) .arg( - Arg::new("allow-ffi") - .long("allow-ffi") - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("PATH") - .help("(Unstable) Allow loading dynamic libraries. Optionally specify allowed directories or files") - .value_parser(value_parser!(String)) - .value_hint(ValueHint::AnyPath) - .hide(true), + { + let mut arg = Arg::new("allow-ffi") + .long("allow-ffi") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("PATH") + .help("(Unstable) Allow loading dynamic libraries. Optionally specify allowed directories or files") + .value_parser(value_parser!(String)) + .value_hint(ValueHint::AnyPath) + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("deny-ffi") - .long("deny-ffi") - .num_args(0..) - .use_value_delimiter(true) - .require_equals(true) - .value_name("PATH") - .help("(Unstable) Deny loading dynamic libraries. Optionally specify denied directories or files") - .value_parser(value_parser!(String)) - .value_hint(ValueHint::AnyPath) - .hide(true), + { + let mut arg = Arg::new("deny-ffi") + .long("deny-ffi") + .num_args(0..) + .use_value_delimiter(true) + .require_equals(true) + .value_name("PATH") + .help("(Unstable) Deny loading dynamic libraries. Optionally specify denied directories or files") + .value_parser(value_parser!(String)) + .value_hint(ValueHint::AnyPath) + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("allow-hrtime") - .long("allow-hrtime") - .action(ArgAction::SetTrue) - .help("REMOVED in Deno 2.0") - .hide(true), + { + let mut arg = Arg::new("allow-hrtime") + .long("allow-hrtime") + .action(ArgAction::SetTrue) + .help("REMOVED in Deno 2.0") + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("deny-hrtime") - .long("deny-hrtime") - .action(ArgAction::SetTrue) - .help("REMOVED in Deno 2.0") - .hide(true), + { + let mut arg = Arg::new("deny-hrtime") + .long("deny-hrtime") + .action(ArgAction::SetTrue) + .help("REMOVED in Deno 2.0") + .hide(true) + ; + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) .arg( - Arg::new("no-prompt") - .long("no-prompt") - .action(ArgAction::SetTrue) - .hide(true) - .help("Always throw if required permission wasn't passed"), + { + let mut arg = Arg::new("no-prompt") + .long("no-prompt") + .action(ArgAction::SetTrue) + .hide(true) + .help("Always throw if required permission wasn't passed"); + if let Some(requires) = requires { + arg = arg.requires(requires) + } + arg + } ) } @@ -3315,7 +3445,7 @@ fn runtime_args( ) -> Command { let app = compile_args(app); let app = if include_perms { - permission_args(app) + permission_args(app, None) } else { app }; @@ -10295,4 +10425,15 @@ mod tests { assert_eq!(long_flag, subcommand, "{} subcommand", command.get_name()); } } + + #[test] + fn install_permissions_non_global() { + let r = + flags_from_vec(svec!["deno", "install", "--allow-net", "jsr:@std/fs"]); + + assert!(r + .unwrap_err() + .to_string() + .contains("Note: Permission flags can only be used in a global setting")); + } } diff --git a/tests/specs/npm/npmrc_not_next_to_package_json/__test__.jsonc b/tests/specs/npm/npmrc_not_next_to_package_json/__test__.jsonc index 68fa8fdf0d..1f4952ed9b 100644 --- a/tests/specs/npm/npmrc_not_next_to_package_json/__test__.jsonc +++ b/tests/specs/npm/npmrc_not_next_to_package_json/__test__.jsonc @@ -4,7 +4,7 @@ "HOME": "$DENO_DIR" }, "tempDir": true, - "args": "install -A -L debug", + "args": "install -L debug", "output": "main.out", "cwd": "subdir" }