v0-json-schema

This commit is contained in:
gongwenxin
2025-05-16 15:18:02 +08:00
parent 32676a314f
commit 6d0b70fe11
260 changed files with 280278 additions and 0 deletions
@@ -0,0 +1 @@
@@ -0,0 +1,355 @@
"""Input Parser Module"""
import json
import os
from typing import Any, Dict, Optional, List, Union
from pydantic import BaseModel # For defining the structure of parsed inputs
from dataclasses import dataclass, field
import logging
logger = logging.getLogger("InputParser")
class ParsedOpenAPISpec(BaseModel):
# Placeholder for OpenAPI spec details relevant to the compliance suite
spec: Dict[str, Any]
info: Dict[str, Any] # Swagger 'info' object with title, version, etc.
paths: Dict[str, Dict[str, Any]] # API paths and their operations
tags: Optional[List[Dict[str, str]]] = None # API tags
basePath: Optional[str] = None # Base path for all APIs
swagger_version: str # Swagger specification version
@dataclass
class YAPIEndpoint:
"""YAPI API端点信息"""
path: str
method: str
title: str = ""
description: str = ""
category_name: str = ""
req_params: List[Dict[str, Any]] = field(default_factory=list)
req_query: List[Dict[str, Any]] = field(default_factory=list)
req_headers: List[Dict[str, Any]] = field(default_factory=list)
req_body_type: str = ""
req_body_other: str = ""
res_body_type: str = ""
res_body: str = ""
@dataclass
class ParsedYAPISpec:
"""解析后的YAPI规范"""
endpoints: List[YAPIEndpoint]
categories: List[Dict[str, Any]]
total_count: int
@dataclass
class SwaggerEndpoint:
"""Swagger API端点信息"""
path: str
method: str
summary: str = ""
description: str = ""
operation_id: str = ""
tags: List[str] = field(default_factory=list)
parameters: List[Dict[str, Any]] = field(default_factory=list)
responses: Dict[str, Any] = field(default_factory=dict)
consumes: List[str] = field(default_factory=list)
produces: List[str] = field(default_factory=list)
request_body: Dict[str, Any] = field(default_factory=dict)
@dataclass
class ParsedSwaggerSpec:
"""解析后的Swagger规范"""
endpoints: List[SwaggerEndpoint]
info: Dict[str, Any]
swagger_version: str
host: str = ""
base_path: str = ""
schemes: List[str] = field(default_factory=list)
tags: List[Dict[str, Any]] = field(default_factory=list)
categories: List[Dict[str, Any]] = field(default_factory=list)
class ParsedBusinessLogic(BaseModel):
# Placeholder for parsed business logic flow
name: str
steps: list # List of steps, each could be another Pydantic model
class InputParser:
"""
Responsible for parsing DDMS supplier's input materials like API specs, etc.
"""
def __init__(self):
pass
def parse_openapi_spec(self, spec_path: str) -> Optional[ParsedOpenAPISpec]:
"""
Parses an OpenAPI specification from a file path.
Args:
spec_path: The file path of the OpenAPI specification.
Returns:
A ParsedOpenAPISpec object containing the parsed specification,
or None if parsing fails.
"""
try:
# Check if file exists
if not os.path.exists(spec_path):
print(f"Error: File not found: {spec_path}")
return None
# Read and parse JSON file
with open(spec_path, 'r', encoding='utf-8') as f:
swagger_data = json.load(f)
# Extract basic information
swagger_version = swagger_data.get('swagger', swagger_data.get('openapi', 'Unknown'))
info = swagger_data.get('info', {})
paths = swagger_data.get('paths', {})
tags = swagger_data.get('tags', [])
base_path = swagger_data.get('basePath', '')
# Create and return ParsedOpenAPISpec
return ParsedOpenAPISpec(
spec=swagger_data,
info=info,
paths=paths,
tags=tags,
basePath=base_path,
swagger_version=swagger_version
)
except FileNotFoundError:
print(f"File not found: {spec_path}")
return None
except json.JSONDecodeError as e:
print(f"Error parsing JSON from {spec_path}: {e}")
return None
except Exception as e:
print(f"Error parsing OpenAPI spec from {spec_path}: {e}")
return None
def parse_yapi_spec(self, file_path: str) -> Optional[ParsedYAPISpec]:
"""
解析YAPI规范文件
Args:
file_path: YAPI JSON文件路径
Returns:
Optional[ParsedYAPISpec]: 解析后的YAPI规范,如果解析失败则返回None
"""
if not os.path.isfile(file_path):
logger.error(f"文件不存在: {file_path}")
return None
try:
with open(file_path, 'r', encoding='utf-8') as f:
yapi_data = json.load(f)
if not isinstance(yapi_data, list):
logger.error(f"无效的YAPI文件格式: 顶层元素应该是数组")
return None
endpoints = []
categories = []
# 处理分类
for category_data in yapi_data:
if not isinstance(category_data, dict):
logger.warning(f"YAPI 分类条目格式不正确,应为字典类型,已跳过: {category_data}")
continue
category_name = category_data.get('name', '')
category_desc = category_data.get('desc', '')
# 添加到分类列表
categories.append({
'name': category_name,
'desc': category_desc
})
# 处理API接口
api_list = category_data.get('list', [])
if not isinstance(api_list, list):
logger.warning(f"分类 '{category_name}' 中的 API列表 (list) 格式不正确,应为数组类型,已跳过。")
continue
for api_item in api_list:
if not isinstance(api_item, dict):
logger.warning(f"分类 '{category_name}' 中的 API条目格式不正确,应为字典类型,已跳过: {api_item}")
continue
# 提取API信息
path = api_item.get('path', '')
if not path:
logger.info(f"分类 '{category_name}' 中的 API条目缺少 'path',使用空字符串。 API: {api_item.get('title', '未命名')}")
method = api_item.get('method', 'GET')
if api_item.get('method') is None: # 仅当原始数据中完全没有 method 字段时记录
logger.info(f"分类 '{category_name}' 中的 API条目 '{path}' 缺少 'method',使用默认值 'GET'")
title = api_item.get('title', '')
if not title:
logger.info(f"分类 '{category_name}' 中的 API条目 '{path}' ({method}) 缺少 'title',使用空字符串。")
description = api_item.get('desc', '')
# 提取请求参数
req_params = api_item.get('req_params', [])
req_query = api_item.get('req_query', [])
req_headers = api_item.get('req_headers', [])
# 提取请求体信息
req_body_type = api_item.get('req_body_type', '')
req_body_other = api_item.get('req_body_other', '')
# 提取响应体信息
res_body_type = api_item.get('res_body_type', '')
res_body = api_item.get('res_body', '')
# 创建端点对象
endpoint = YAPIEndpoint(
path=path,
method=method,
title=title,
description=description,
category_name=category_name,
req_params=req_params,
req_query=req_query,
req_headers=req_headers,
req_body_type=req_body_type,
req_body_other=req_body_other,
res_body_type=res_body_type,
res_body=res_body
)
endpoints.append(endpoint)
return ParsedYAPISpec(
endpoints=endpoints,
categories=categories,
total_count=len(endpoints)
)
except Exception as e:
logger.error(f"解析YAPI文件时出错: {str(e)}")
return None
def parse_swagger_spec(self, file_path: str) -> Optional[ParsedSwaggerSpec]:
"""
解析Swagger规范文件
Args:
file_path: Swagger JSON文件路径
Returns:
Optional[ParsedSwaggerSpec]: 解析后的Swagger规范,如果解析失败则返回None
"""
if not os.path.isfile(file_path):
logger.error(f"文件不存在: {file_path}")
return None
try:
with open(file_path, 'r', encoding='utf-8') as f:
swagger_data = json.load(f)
if not isinstance(swagger_data, dict):
logger.error(f"无效的Swagger文件格式: 顶层元素应该是对象")
return None
# 提取基本信息
swagger_version = swagger_data.get('swagger', swagger_data.get('openapi', ''))
info = swagger_data.get('info', {})
host = swagger_data.get('host', '')
base_path = swagger_data.get('basePath', '')
schemes = swagger_data.get('schemes', [])
tags = swagger_data.get('tags', [])
# 创建分类列表
categories = []
for tag in tags:
categories.append({
'name': tag.get('name', ''),
'desc': tag.get('description', '')
})
# 处理API路径
paths = swagger_data.get('paths', {})
endpoints = []
for path, path_item in paths.items():
if not isinstance(path_item, dict):
continue
# 处理每个HTTP方法 (GET, POST, PUT, DELETE等)
for method, operation in path_item.items():
if method in ['get', 'post', 'put', 'delete', 'patch', 'options', 'head', 'trace']:
if not isinstance(operation, dict):
continue
# 提取操作信息
summary = operation.get('summary', '')
description = operation.get('description', '')
operation_id = operation.get('operationId', '')
operation_tags = operation.get('tags', [])
# 提取参数信息
parameters = operation.get('parameters', [])
# 提取响应信息
responses = operation.get('responses', {})
# 提取请求和响应的内容类型
consumes = operation.get('consumes', swagger_data.get('consumes', []))
produces = operation.get('produces', swagger_data.get('produces', []))
# 提取请求体信息 (OpenAPI 3.0 格式)
request_body = operation.get('requestBody', {})
# 创建端点对象
endpoint = SwaggerEndpoint(
path=path,
method=method.upper(),
summary=summary,
description=description,
operation_id=operation_id,
tags=operation_tags,
parameters=parameters,
responses=responses,
consumes=consumes,
produces=produces,
request_body=request_body
)
endpoints.append(endpoint)
# 创建返回对象
return ParsedSwaggerSpec(
endpoints=endpoints,
info=info,
swagger_version=swagger_version,
host=host,
base_path=base_path,
schemes=schemes,
tags=tags,
categories=categories
)
except Exception as e:
logger.error(f"解析Swagger文件时出错: {str(e)}")
return None
def parse_business_logic_flow(self, flow_description: str) -> Optional[ParsedBusinessLogic]:
"""
Parses a business logic flow description.
The format of this description is TBD and this parser would need to be built accordingly.
Args:
flow_description: The string content describing the business logic flow.
Returns:
A ParsedBusinessLogic object or None if parsing fails.
"""
print(f"[InputParser] Placeholder: Parsing business logic flow. Content: {flow_description[:100]}...")
# Placeholder: Actual parsing logic will depend on the defined format.
return ParsedBusinessLogic(name="Example Flow", steps=["Step 1 API call", "Step 2 Validate Response"])
# Add other parsers as needed (e.g., for data object definitions)