CLI: list --sort by method/tag, show merges path-level parameters
list: new --sort flag accepts path (default), method, or tag. All sort modes maintain alias-first grouping for cross-alias queries. method sort orders GET/POST/PUT/PATCH/DELETE/etc. tag sort uses first tag as primary key with path and method as tiebreakers. show: merge path-item-level parameters into operation parameters per OpenAPI 3.x spec. Path-level params apply to all operations unless overridden by an operation-level param with the same (name, in) pair. Uses the operation_ptr to derive the parent path-item pointer and resolve_json_pointer to access the raw spec.
This commit is contained in:
@@ -388,13 +388,37 @@ async fn execute_all_aliases(args: &Args, robot_mode: bool) -> Result<(), Swagge
|
|||||||
|
|
||||||
let filtered_count = all_entries.len();
|
let filtered_count = all_entries.len();
|
||||||
|
|
||||||
// Sort: alias ASC, path ASC, method_rank ASC
|
// Sort: alias first for grouping, then apply user's --sort preference
|
||||||
all_entries.sort_by(|a, b| {
|
match args.sort.as_str() {
|
||||||
a.alias
|
"method" => {
|
||||||
.cmp(&b.alias)
|
all_entries.sort_by(|a, b| {
|
||||||
.then_with(|| a.path.cmp(&b.path))
|
a.alias
|
||||||
.then_with(|| method_rank(&a.method).cmp(&method_rank(&b.method)))
|
.cmp(&b.alias)
|
||||||
});
|
.then_with(|| method_rank(&a.method).cmp(&method_rank(&b.method)))
|
||||||
|
.then_with(|| a.path.cmp(&b.path))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
"tag" => {
|
||||||
|
all_entries.sort_by(|a, b| {
|
||||||
|
let tag_a = a.tags.first().map(String::as_str).unwrap_or("");
|
||||||
|
let tag_b = b.tags.first().map(String::as_str).unwrap_or("");
|
||||||
|
a.alias
|
||||||
|
.cmp(&b.alias)
|
||||||
|
.then_with(|| tag_a.cmp(tag_b))
|
||||||
|
.then_with(|| a.path.cmp(&b.path))
|
||||||
|
.then_with(|| method_rank(&a.method).cmp(&method_rank(&b.method)))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// "path" or default
|
||||||
|
_ => {
|
||||||
|
all_entries.sort_by(|a, b| {
|
||||||
|
a.alias
|
||||||
|
.cmp(&b.alias)
|
||||||
|
.then_with(|| a.path.cmp(&b.path))
|
||||||
|
.then_with(|| method_rank(&a.method).cmp(&method_rank(&b.method)))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ---- Limit ----
|
// ---- Limit ----
|
||||||
if !args.all {
|
if !args.all {
|
||||||
|
|||||||
@@ -112,10 +112,53 @@ pub async fn execute(args: &Args, robot: bool) -> Result<(), SwaggerCliError> {
|
|||||||
expand_refs(&mut operation, &raw, args.max_depth);
|
expand_refs(&mut operation, &raw, args.max_depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
let parameters = operation
|
// Merge path-level parameters into operation parameters.
|
||||||
.get("parameters")
|
// Per OpenAPI 3.x, parameters defined at the path-item level apply to all
|
||||||
.cloned()
|
// operations unless overridden (same name + location) at the operation level.
|
||||||
.unwrap_or(Value::Array(vec![]));
|
let parameters = {
|
||||||
|
let op_params = operation
|
||||||
|
.get("parameters")
|
||||||
|
.and_then(Value::as_array)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
// Derive path-item pointer by stripping the last segment (method) from operation_ptr
|
||||||
|
let path_item_ptr = endpoint
|
||||||
|
.operation_ptr
|
||||||
|
.rfind('/')
|
||||||
|
.map(|i| &endpoint.operation_ptr[..i]);
|
||||||
|
|
||||||
|
let mut merged = op_params.clone();
|
||||||
|
|
||||||
|
if let Some(ptr) = path_item_ptr
|
||||||
|
&& let Some(path_item) = resolve_json_pointer(&raw, ptr)
|
||||||
|
&& let Some(path_params) = path_item.get("parameters").and_then(Value::as_array)
|
||||||
|
{
|
||||||
|
// Collect (name, in) pairs from operation-level params for override detection
|
||||||
|
let op_keys: std::collections::HashSet<(String, String)> = op_params
|
||||||
|
.iter()
|
||||||
|
.filter_map(|p| {
|
||||||
|
let name = p.get("name")?.as_str()?.to_string();
|
||||||
|
let loc = p.get("in")?.as_str()?.to_string();
|
||||||
|
Some((name, loc))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for pp in path_params {
|
||||||
|
let key = pp
|
||||||
|
.get("name")
|
||||||
|
.and_then(Value::as_str)
|
||||||
|
.zip(pp.get("in").and_then(Value::as_str));
|
||||||
|
if let Some((name, loc)) = key
|
||||||
|
&& !op_keys.contains(&(name.to_string(), loc.to_string()))
|
||||||
|
{
|
||||||
|
merged.push(pp.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Value::Array(merged)
|
||||||
|
};
|
||||||
|
|
||||||
let request_body = operation.get("requestBody").cloned();
|
let request_body = operation.get("requestBody").cloned();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user