use crate::args::{CliArgs, OutputTypeArg};
use httpgenerator_core::redact_authorization_headers;
use serde_json::{Map, Value};
use std::ffi::OsString;
const REDACTED: &str = "[REDACTED]";
pub(crate) fn feature_usage_names(args: &CliArgs) -> Vec<String> {
let mut features = Vec::new();
if args.skip_validation {
features.push("skip-validation".to_string());
}
if args.authorization_header.is_some() {
features.push("authorization-header".to_string());
}
if args.authorization_header_from_environment_variable {
features.push("load-authorization-header-from-environment".to_string());
}
features.push("authorization-header-variable-name".to_string());
features.push("content-type".to_string());
if args.base_url.is_some() {
features.push("base-url".to_string());
}
features.push("output-type".to_string());
if args.azure_scope.is_some() {
features.push("azure-scope".to_string());
}
if args.azure_tenant_id.is_some() {
features.push("azure-tenant-id".to_string());
}
features.push("timeout".to_string());
if args.generate_intellij_tests {
features.push("generate-intellij-tests".to_string());
}
if !args.custom_headers.is_empty() {
features.push("custom-header".to_string());
}
if args.skip_headers {
features.push("skip-headers".to_string());
}
features
}
pub(crate) fn redacted_command_line(raw_args: &[OsString]) -> String {
let mut arguments = raw_args
.iter()
.map(|value| value.to_string_lossy().into_owned())
.collect::<Vec<_>>();
if let Some(program_name) = arguments.first_mut() {
*program_name = "httpgenerator".to_string();
}
redact_authorization_headers(&arguments.join(" "))
}
pub(crate) fn redacted_settings(args: &CliArgs) -> Map<String, Value> {
let mut settings = Map::new();
settings.insert(
"openApiPath".to_string(),
option_string_value(args.open_api_path.as_deref()),
);
settings.insert(
"outputFolder".to_string(),
Value::String(args.output_folder.clone()),
);
settings.insert("noLogging".to_string(), Value::Bool(args.no_logging));
settings.insert(
"skipValidation".to_string(),
Value::Bool(args.skip_validation),
);
settings.insert(
"authorizationHeader".to_string(),
redacted_authorization_value(args.authorization_header.as_deref()),
);
settings.insert(
"authorizationHeaderFromEnvironmentVariable".to_string(),
Value::Bool(args.authorization_header_from_environment_variable),
);
settings.insert(
"authorizationHeaderVariableName".to_string(),
Value::String(args.authorization_header_variable_name.clone()),
);
settings.insert(
"contentType".to_string(),
Value::String(args.content_type.clone()),
);
settings.insert(
"baseUrl".to_string(),
option_string_value(args.base_url.as_deref()),
);
settings.insert(
"outputType".to_string(),
Value::from(output_type_ordinal(args.output_type)),
);
settings.insert(
"azureScope".to_string(),
option_string_value(args.azure_scope.as_deref()),
);
settings.insert(
"azureTenantId".to_string(),
option_string_value(args.azure_tenant_id.as_deref()),
);
settings.insert("timeout".to_string(), Value::from(args.timeout));
settings.insert(
"generateIntellijTests".to_string(),
Value::Bool(args.generate_intellij_tests),
);
settings.insert(
"customHeaders".to_string(),
Value::Array(
args.custom_headers
.iter()
.map(|value| Value::String(redact_custom_header(value)))
.collect(),
),
);
settings.insert("skipHeaders".to_string(), Value::Bool(args.skip_headers));
settings
}
fn option_string_value(value: Option<&str>) -> Value {
value
.map(|value| Value::String(value.to_string()))
.unwrap_or(Value::Null)
}
fn redacted_authorization_value(value: Option<&str>) -> Value {
value
.map(|_| Value::String(REDACTED.to_string()))
.unwrap_or(Value::Null)
}
fn output_type_ordinal(output_type: OutputTypeArg) -> u8 {
match output_type {
OutputTypeArg::OneRequestPerFile => 0,
OutputTypeArg::OneFile => 1,
OutputTypeArg::OneFilePerTag => 2,
}
}
fn redact_custom_header(value: &str) -> String {
let Some((name, _)) = value.split_once(':') else {
return value.to_string();
};
if name.trim().eq_ignore_ascii_case("authorization") {
format!("{}: {REDACTED}", name.trim())
} else {
value.to_string()
}
}