in doc-architect/doc-architect-core/src/main/java/com/docarchitect/core/scanner/impl/dotnet/AspNetCoreApiScanner.java [705:768]
private String buildRequestSchemaFromAst(List<DotNetAst.Parameter> parameters, String fullPath) {
if (parameters == null || parameters.isEmpty()) {
return null;
}
List<String> routeParams = new ArrayList<>();
List<String> queryParams = new ArrayList<>();
List<String> bodyParams = new ArrayList<>();
// Extract path parameters from route
Matcher routeMatcher = ROUTE_PARAM_PATTERN.matcher(fullPath);
while (routeMatcher.find()) {
routeParams.add(routeMatcher.group(1));
}
// Process method parameters from AST
for (DotNetAst.Parameter parameter : parameters) {
String type = parameter.type();
String name = parameter.name();
// Check for From* attributes
String source = null;
for (DotNetAst.Attribute attribute : parameter.attributes()) {
if (attribute.name().startsWith("From")) {
source = attribute.name().substring(4); // FromBody -> Body
break;
}
}
if (source != null) {
switch (source) {
case PARAM_SOURCE_ROUTE -> routeParams.add(name + TYPE_SEPARATOR + type);
case PARAM_SOURCE_QUERY -> queryParams.add(name + TYPE_SEPARATOR + type);
case PARAM_SOURCE_BODY -> bodyParams.add(name + TYPE_SEPARATOR + type);
}
} else {
// No From* attribute - infer from type and route
if (routeParams.contains(name)) {
continue; // Already in route
}
// Complex types are body parameters
if (!isPrimitiveType(type)) {
bodyParams.add(name + TYPE_SEPARATOR + type);
} else {
// Simple types default to query parameters
queryParams.add(name + TYPE_SEPARATOR + type);
}
}
}
List<String> allParams = new ArrayList<>();
if (!routeParams.isEmpty()) {
allParams.add(SCHEMA_LABEL_ROUTE + String.join(PARAM_SEPARATOR, routeParams));
}
if (!queryParams.isEmpty()) {
allParams.add(SCHEMA_LABEL_QUERY + String.join(PARAM_SEPARATOR, queryParams));
}
if (!bodyParams.isEmpty()) {
allParams.add(SCHEMA_LABEL_BODY + String.join(PARAM_SEPARATOR, bodyParams));
}
return allParams.isEmpty() ? null : String.join(SCHEMA_SEPARATOR, allParams);
}