use deno_core::op2;
#[derive(Debug, thiserror::Error, deno_error::JsError)]
#[class(generic)]
pub enum CliParserError {
#[error(
"Failed to parse Node.js CLI arguments: {message}. If you believe this is a valid Node.js flag, please report it at https://github.com/denoland/deno/issues"
)]
ParseError { message: String },
}
pub use node_shim::DebugOptions;
pub use node_shim::EnvironmentOptions;
pub use node_shim::HostPort;
pub use node_shim::InspectPublishUid;
pub use node_shim::OptionEnvvarSettings;
pub use node_shim::OptionType;
pub use node_shim::OptionsParser;
pub use node_shim::ParseResult;
pub use node_shim::PerIsolateOptions;
pub use node_shim::PerProcessOptions;
pub use node_shim::TranslateOptions;
pub use node_shim::TranslatedArgs as NodeShimTranslatedArgs;
pub use node_shim::parse_args;
pub use node_shim::parse_node_options_env_var;
pub use node_shim::translate_to_deno_args as translate_to_deno_args_impl;
pub use node_shim::wrap_eval_code;
use serde::Serialize;
#[derive(Debug, Clone, Serialize)]
pub struct TranslatedArgs {
pub deno_args: Vec<String>,
pub node_options: Vec<String>,
pub needs_npm_process_state: bool,
}
fn translate_to_deno_args(
parsed_args: ParseResult,
script_in_npm_package: bool,
wrap_eval: bool,
) -> TranslatedArgs {
let options = if wrap_eval {
TranslateOptions::for_child_process()
} else {
TranslateOptions::for_shell_command()
};
let result = translate_to_deno_args_impl(parsed_args, &options);
TranslatedArgs {
deno_args: result.deno_args,
node_options: result.node_options,
needs_npm_process_state: script_in_npm_package,
}
}
#[op2]
#[serde]
pub fn op_node_translate_cli_args(
#[serde] args: Vec<String>,
script_in_npm_package: bool,
wrap_eval: bool,
) -> Result<TranslatedArgs, CliParserError> {
if args.is_empty() {
return Ok(TranslatedArgs {
deno_args: vec!["run".to_string(), "-A".to_string(), "-".to_string()],
node_options: vec![],
needs_npm_process_state: script_in_npm_package,
});
}
match parse_args(args.clone()) {
Ok(parsed) => Ok(translate_to_deno_args(
parsed,
script_in_npm_package,
wrap_eval,
)),
Err(unknown_flags) => Err(CliParserError::ParseError {
message: unknown_flags.join(", "),
}),
}
}
#[cfg(test)]
mod tests {
use super::*;
macro_rules! svec {
($($x:expr),* $(,)?) => {
vec![$($x.to_string()),*]
};
}
#[test]
fn test_basic_parsing() {
let result = parse_args(svec!["--version"]).unwrap();
assert!(result.options.print_version);
}
#[test]
fn test_help_parsing() {
let result = parse_args(svec!["--help"]).unwrap();
assert!(result.options.print_help);
}
#[test]
fn test_debug_options() {
let result = parse_args(svec!["--inspect"]).unwrap();
assert!(
result
.options
.per_isolate
.per_env
.debug_options
.inspector_enabled
);
}
#[test]
fn test_string_option() {
let result = parse_args(svec!["--title", "myapp"]).unwrap();
assert_eq!(result.options.title, "myapp");
}
#[test]
fn test_boolean_negation() {
let result = parse_args(svec!["--no-warnings"]).unwrap();
assert!(!result.options.per_isolate.per_env.warnings);
}
#[test]
fn test_alias_expansion() {
let result = parse_args(svec!["-v"]).unwrap();
assert!(result.options.print_version);
}
#[test]
fn test_node_options_parsing() {
let env_args =
parse_node_options_env_var("--inspect --title \"my app\"").unwrap();
assert_eq!(env_args, vec!["--inspect", "--title", "my app"]);
}
#[test]
fn test_host_port_parsing() {
let result = parse_args(svec!["--inspect-port", "127.0.0.1:9229"]).unwrap();
assert_eq!(
result
.options
.per_isolate
.per_env
.debug_options
.host_port
.host,
"127.0.0.1"
);
assert_eq!(
result
.options
.per_isolate
.per_env
.debug_options
.host_port
.port,
9229
);
}
#[test]
fn test_translate_basic_script() {
let parsed = parse_args(svec!["script.js"]).unwrap();
let result = translate_to_deno_args(parsed, false, true);
assert_eq!(
result.deno_args,
svec![
"run",
"-A",
"--unstable-node-globals",
"--unstable-bare-node-builtins",
"--unstable-detect-cjs",
"script.js"
]
);
assert!(result.node_options.is_empty());
assert!(!result.needs_npm_process_state);
}
#[test]
fn test_translate_version() {
let parsed = parse_args(svec!["--version"]).unwrap();
let result = translate_to_deno_args(parsed, false, true);
assert_eq!(result.deno_args, svec!["--version"]);
}
#[test]
fn test_translate_help() {
let parsed = parse_args(svec!["--help"]).unwrap();
let result = translate_to_deno_args(parsed, false, true);
assert_eq!(result.deno_args, svec!["--help"]);
}
#[test]
fn test_translate_eval() {
let parsed = parse_args(svec!["--eval", "console.log(42)"]).unwrap();
let result = translate_to_deno_args(parsed, false, true);
assert!(result.deno_args.contains(&"eval".to_string()));
assert!(result.deno_args.iter().any(|a| {
a.contains(r#"process.getBuiltinModule("vm").runInThisContext"#)
}));
}
#[test]
fn test_translate_inspect() {
let parsed = parse_args(svec!["--inspect", "script.js"]).unwrap();
let result = translate_to_deno_args(parsed, false, true);
assert!(
result
.deno_args
.contains(&"--inspect=127.0.0.1:9229".to_string())
);
assert!(result.deno_args.contains(&"script.js".to_string()));
}
#[test]
fn test_translate_inspect_brk() {
let parsed = parse_args(svec!["--inspect-brk", "script.js"]).unwrap();
let result = translate_to_deno_args(parsed, false, true);
assert!(
result
.deno_args
.contains(&"--inspect-brk=127.0.0.1:9229".to_string())
);
}
#[test]
fn test_translate_watch() {
let parsed = parse_args(svec!["--watch", "script.js"]).unwrap();
let result = translate_to_deno_args(parsed, false, true);
assert!(result.deno_args.contains(&"--watch".to_string()));
}
#[test]
fn test_translate_no_warnings() {
let parsed = parse_args(svec!["--no-warnings", "script.js"]).unwrap();
let result = translate_to_deno_args(parsed, false, true);
assert!(result.deno_args.contains(&"--quiet".to_string()));
assert!(result.node_options.contains(&"--no-warnings".to_string()));
}
#[test]
fn test_translate_conditions() {
let parsed =
parse_args(svec!["--conditions", "development", "script.js"]).unwrap();
let result = translate_to_deno_args(parsed, false, true);
assert!(
result
.deno_args
.contains(&"--conditions=development".to_string())
);
}
#[test]
fn test_translate_conditions_equals_format() {
let parsed = parse_args(svec!["--conditions=custom", "script.js"]).unwrap();
let result = translate_to_deno_args(parsed, false, true);
assert!(
result
.deno_args
.contains(&"--conditions=custom".to_string()),
);
}
#[test]
fn test_translate_conditions_short_alias() {
let parsed = parse_args(svec!["-C", "custom", "script.js"]).unwrap();
let result = translate_to_deno_args(parsed, false, true);
assert!(
result
.deno_args
.contains(&"--conditions=custom".to_string()),
);
}
#[test]
fn test_translate_v8_flags() {
let parsed =
parse_args(svec!["--max-old-space-size=4096", "script.js"]).unwrap();
let result = translate_to_deno_args(parsed, false, true);
assert!(result.deno_args.iter().any(|a| a.contains("--v8-flags=")));
}
#[test]
fn test_translate_repl() {
let parsed = parse_args(svec![]).unwrap();
let result = translate_to_deno_args(parsed, false, true);
assert!(result.deno_args.is_empty());
}
#[test]
fn test_translate_npm_package() {
let parsed = parse_args(svec!["script.js"]).unwrap();
let result = translate_to_deno_args(parsed, true, true);
assert!(result.needs_npm_process_state);
}
#[test]
fn test_translate_run_script() {
let parsed = parse_args(svec!["--run", "build"]).unwrap();
let result = translate_to_deno_args(parsed, false, true);
assert_eq!(result.deno_args, svec!["task", "build"]);
}
#[test]
fn test_translate_test_runner() {
let parsed = parse_args(svec!["--test", "test.js"]).unwrap();
let result = translate_to_deno_args(parsed, false, true);
assert!(result.deno_args.contains(&"test".to_string()));
assert!(result.deno_args.contains(&"-A".to_string()));
assert!(result.deno_args.contains(&"test.js".to_string()));
}
#[test]
fn test_translate_test_with_watch() {
let parsed = parse_args(svec!["--test", "--watch", "test.js"]).unwrap();
let result = translate_to_deno_args(parsed, false, true);
assert!(result.deno_args.contains(&"test".to_string()));
assert!(result.deno_args.contains(&"--watch".to_string()));
}
#[test]
fn test_wrap_eval_code() {
let wrapped = wrap_eval_code("console.log(42)");
assert!(
wrapped.contains(r#"process.getBuiltinModule("vm").runInThisContext"#)
);
assert!(wrapped.contains("process.getBuiltinModule"));
assert!(wrapped.contains("\"console.log(42)\""));
}
}