/// Swagger数据模型定义 /// 提供类型安全的数据结构 library; /// HTTP方法枚举 /// 表示常见的 RESTful API 方法。 enum HttpMethod { /// GET 方法 get('GET'), /// POST 方法 post('POST'), /// PUT 方法 put('PUT'), /// DELETE 方法 delete('DELETE'), /// PATCH 方法 patch('PATCH'), /// HEAD 方法 head('HEAD'), /// OPTIONS 方法 options('OPTIONS'); /// 枚举值对应的字符串 const HttpMethod(this.value); final String value; /// 通过字符串获取 HttpMethod 枚举 static HttpMethod fromString(String value) { return HttpMethod.values.firstWhere( (method) => method.value == value.toUpperCase(), orElse: () => HttpMethod.get, ); } } /// 模型用途类型 /// 用于标识 API 模型在实际使用中的角色 enum ModelUsageType { /// 请求模型 - 用于 requestBody 或 parameters /// 此类模型不应添加 defaultValue,以确保数据的明确性 request, /// 响应模型 - 用于 response /// 此类模型应添加 defaultValue,以提高安全性和容错性 response, /// 通用模型 - 既用于请求又用于响应 /// 此类模型的处理策略可配置,默认添加 defaultValue common, /// 未知 - 未被任何 API 使用,或无法确定用途 /// 此类模型的处理策略可配置,默认添加 defaultValue unknown, } /// API服务器信息 (OpenAPI 3.0) class ApiServer { const ApiServer({ required this.url, this.description = '', this.variables = const {}, }); /// 从JSON创建ApiServer factory ApiServer.fromJson(Map json) { final variablesJson = json['variables']; final variables = {}; if (variablesJson != null && variablesJson is Map) { variablesJson.forEach((key, value) { if (value is Map) { variables[key.toString()] = ApiServerVariable.fromJson( Map.from(value), ); } }); } return ApiServer( url: json['url'] as String? ?? '', description: json['description'] as String? ?? '', variables: variables, ); } /// 服务器URL final String url; /// 服务器描述 final String description; /// 服务器变量 final Map variables; } /// API服务器变量 (OpenAPI 3.0) class ApiServerVariable { const ApiServerVariable({ required this.defaultValue, this.enumValues = const [], this.description = '', }); /// 从JSON创建ApiServerVariable factory ApiServerVariable.fromJson(Map json) { return ApiServerVariable( enumValues: (json['enum'] as List?)?.map((e) => e.toString()).toList() ?? [], defaultValue: json['default'] as String? ?? '', description: json['description'] as String? ?? '', ); } /// 变量的可选值 final List enumValues; /// 默认值 final String defaultValue; /// 变量描述 final String description; } /// 属性类型枚举 /// 用于描述 API 属性的数据类型。 enum PropertyType { /// 字符串类型 string('string'), /// 整数类型 integer('integer'), /// 浮点数类型 number('number'), /// 布尔类型 boolean('boolean'), /// 数组类型 array('array'), /// 对象类型 object('object'), /// 文件类型 file('file'), /// 日期类型 date('date'), /// 日期时间类型 dateTime('date-time'), /// 引用类型 reference('reference'), /// 枚举类型 enumType('enum'), /// 未知类型 unknown('unknown'); /// 枚举值对应的字符串 const PropertyType(this.value); final String value; /// 通过字符串获取 PropertyType 枚举 static PropertyType fromString(String value) { return PropertyType.values.firstWhere( (type) => type.value == value.toLowerCase(), orElse: () => PropertyType.unknown, ); } } /// 参数位置枚举 /// 用于描述 API 参数在请求中的位置。 enum ParameterLocation { /// 查询参数 query('query'), /// 路径参数 path('path'), /// 请求头参数 header('header'), /// 请求体参数 body('body'), /// 表单参数 form('formData'), /// Cookie 参数 cookie('cookie'); /// 枚举值对应的字符串 const ParameterLocation(this.value); final String value; /// 通过字符串获取 ParameterLocation 枚举 static ParameterLocation fromString(String value) { return ParameterLocation.values.firstWhere( (location) => location.value == value.toLowerCase(), orElse: () => ParameterLocation.query, ); } } /// OpenAPI 3.0 文档信息 /// 描述整个 API 的元数据和结构。 class SwaggerDocument { /// 构造函数 const SwaggerDocument({ required this.title, required this.version, required this.description, required this.paths, required this.models, required this.controllers, this.servers = const [], this.components = const ApiComponents(), this.security = const [], }); /// 从JSON创建SwaggerDocument factory SwaggerDocument.fromJson(Map json) { final info = json['info'] as Map? ?? {}; // 解析 servers (OpenAPI 3.0) final serversJson = json['servers'] as List? ?? []; final servers = serversJson .map((server) => ApiServer.fromJson(server as Map)) .toList(); // 如果没有 servers 配置,提供默认值 if (servers.isEmpty) { servers.add(const ApiServer(url: '/')); } // 解析 components (OpenAPI 3.0) final componentsJson = json['components']; final components = componentsJson != null && componentsJson is Map ? ApiComponents.fromJson( Map.from(componentsJson), ) : const ApiComponents(); // 解析全局安全要求 final securityJson = json['security'] as List? ?? []; final security = securityJson .whereType>() .map( (s) => ApiSecurityRequirement.fromJson( Map.from(s), ), ) .toList(); return SwaggerDocument( title: info['title'] as String? ?? 'API', version: info['version'] as String? ?? '1.0.0', description: info['description'] as String? ?? '', servers: servers, components: components, paths: _parsePaths(json['paths'] as Map? ?? {}), models: components.schemas, // 从 components 中提取 schemas controllers: {}, security: security, ); } /// 文档标题 final String title; /// 版本号 final String version; /// 文档描述 final String description; /// 服务器配置 (OpenAPI 3.0) final List servers; /// 可重用组件 (OpenAPI 3.0) final ApiComponents components; /// 路径定义 final Map paths; /// 数据模型定义 (从 components.schemas 提取) final Map models; /// 控制器定义 final Map controllers; /// 全局安全要求 final List security; /// 从JSON解析API路径 (静态辅助方法) static Map _parsePaths(Map pathsJson) { final paths = {}; final methodLookup = { for (final method in HttpMethod.values) method.name: method, }; for (final pathEntry in pathsJson.entries) { if (pathEntry.value is! Map) continue; final pathData = Map.from(pathEntry.value as Map); for (final methodEntry in pathData.entries) { final httpMethod = methodLookup[methodEntry.key]; if (httpMethod == null) { continue; } if (methodEntry.value is! Map) continue; // 简化解析用于测试;当路径包含多个方法时可能覆盖。 // SwaggerDataParser 中的主解析器会创建唯一键以避免覆盖。 paths[pathEntry.key] = ApiPath.fromJson( pathEntry.key, httpMethod, Map.from(methodEntry.value as Map), ); } } return paths; } } /// API路径信息 class ApiPath { const ApiPath({ required this.path, required this.method, required this.summary, required this.description, required this.operationId, required this.tags, required this.parameters, required this.responses, this.requestBody, this.deprecated = false, this.security = const [], }); /// 从JSON创建ApiPath factory ApiPath.fromJson( String path, HttpMethod method, Map json, ) { return ApiPath( path: path, method: method, summary: json['summary'] as String? ?? '', description: json['description'] as String? ?? '', operationId: json['operationId'] as String? ?? '', tags: (json['tags'] as List?)?.map((e) => e.toString()).toList() ?? [], parameters: (json['parameters'] as List?) ?.map((p) => ApiParameter.fromJson(p as Map)) .toList() ?? [], responses: (json['responses'] as Map?)?.map( (code, response) => MapEntry( code, ApiResponse.fromJson(code, response as Map), ), ) ?? {}, requestBody: json['requestBody'] != null ? ApiRequestBody.fromJson(json['requestBody'] as Map) : null, deprecated: json['deprecated'] as bool? ?? false, security: (json['security'] as List?) ?.map( (s) => ApiSecurityRequirement.fromJson(s as Map), ) .toList() ?? [], ); } final String path; final HttpMethod method; final String summary; final String description; final String operationId; final List tags; final List parameters; final Map responses; final ApiRequestBody? requestBody; final bool deprecated; /// 安全要求 final List security; } /// API参数信息 class ApiParameter { const ApiParameter({ required this.name, required this.location, required this.required, required this.type, required this.description, this.format, this.example, this.defaultValue, }); /// 从JSON创建ApiParameter factory ApiParameter.fromJson(Map json) { final schema = json['schema'] as Map?; final type = schema?['type'] as String? ?? json['type'] as String? ?? 'string'; return ApiParameter( name: json['name'] as String? ?? '', location: ParameterLocation.fromString(json['in'] as String? ?? 'query'), required: json['required'] as bool? ?? false, type: PropertyType.fromString(type), description: json['description'] as String? ?? '', format: schema?['format'] as String? ?? json['format'] as String?, example: json['example'], defaultValue: schema?['default'] ?? json['default'], ); } final String name; final ParameterLocation location; final bool required; final PropertyType type; final String description; final String? format; final dynamic example; final dynamic defaultValue; } /// API响应信息 (OpenAPI 3.0) class ApiResponse { const ApiResponse({ required this.code, required this.description, this.headers = const {}, this.content = const {}, this.links = const {}, this.schema, }); /// 从JSON创建ApiResponse factory ApiResponse.fromJson(String code, Map json) { // 解析 headers final headersJson = json['headers'] as Map? ?? {}; final headers = {}; headersJson.forEach((key, value) { if (value is Map) { headers[key] = ApiHeader.fromJson(value); } }); // 解析 content final contentJson = json['content'] as Map? ?? {}; final content = {}; contentJson.forEach((mediaType, mediaTypeData) { if (mediaTypeData is Map) { content[mediaType] = ApiMediaType.fromJson(mediaTypeData, mediaType); } }); // 解析 links final linksJson = json['links'] as Map? ?? {}; final links = {}; linksJson.forEach((key, value) { if (value is Map) { links[key] = ApiLink.fromJson(value); } }); return ApiResponse( code: code, description: json['description'] as String? ?? '', headers: headers, content: content, links: links, // 保留 schema 字段以兼容 Swagger 2.0 schema: json['schema'] as Map?, ); } /// 响应状态码 final String code; /// 响应描述 final String description; /// 响应头定义 final Map headers; /// 内容类型映射 (media type -> MediaTypeObject) final Map content; /// 响应链接 final Map links; /// Schema 定义 (Swagger 2.0 兼容字段,优先使用 content) final Map? schema; /// 获取支持的媒体类型列表 List get supportedMediaTypes => content.keys.toList(); /// 检查是否支持指定的媒体类型 bool supportsMediaType(String mediaType) => content.containsKey(mediaType); /// 获取指定媒体类型的 schema Map? getSchemaForMediaType(String mediaType) { return content[mediaType]?.schema; } /// 检查是否有响应头定义 bool get hasHeaders => headers.isNotEmpty; /// 检查是否有响应链接 bool get hasLinks => links.isNotEmpty; } /// API请求体信息 (OpenAPI 3.0) class ApiRequestBody { const ApiRequestBody({ this.description = '', this.required = false, this.content = const {}, }); /// 从JSON创建ApiRequestBody factory ApiRequestBody.fromJson(Map json) { final contentJson = json['content'] as Map? ?? {}; final content = {}; contentJson.forEach((mediaType, mediaTypeData) { if (mediaTypeData is Map) { content[mediaType] = ApiMediaType.fromJson(mediaTypeData, mediaType); } }); return ApiRequestBody( description: json['description'] as String? ?? '', required: json['required'] as bool? ?? false, content: content, ); } /// 请求体描述 final String description; /// 是否必需 final bool required; /// 内容类型映射 (media type -> MediaTypeObject) final Map content; /// 获取支持的媒体类型列表 List get supportedMediaTypes => content.keys.toList(); /// 检查是否支持指定的媒体类型 bool supportsMediaType(String mediaType) => content.containsKey(mediaType); /// 获取指定媒体类型的 schema Map? getSchemaForMediaType(String mediaType) { return content[mediaType]?.schema; } } /// 媒体类型枚举 enum MediaType { json, xml, formData, formUrlEncoded, multipartFormData, textPlain, textHtml, textCsv, applicationOctetStream, applicationPdf, imagePng, imageJpeg, imageGif, imageSvg, audioMp3, videoMp4, custom, } extension MediaTypeExtension on MediaType { String get value { switch (this) { case MediaType.json: return 'application/json'; case MediaType.xml: return 'application/xml'; case MediaType.formData: return 'multipart/form-data'; case MediaType.formUrlEncoded: return 'application/x-www-form-urlencoded'; case MediaType.multipartFormData: return 'multipart/form-data'; case MediaType.textPlain: return 'text/plain'; case MediaType.textHtml: return 'text/html'; case MediaType.textCsv: return 'text/csv'; case MediaType.applicationOctetStream: return 'application/octet-stream'; case MediaType.applicationPdf: return 'application/pdf'; case MediaType.imagePng: return 'image/png'; case MediaType.imageJpeg: return 'image/jpeg'; case MediaType.imageGif: return 'image/gif'; case MediaType.imageSvg: return 'image/svg+xml'; case MediaType.audioMp3: return 'audio/mpeg'; case MediaType.videoMp4: return 'video/mp4'; case MediaType.custom: return 'custom'; } } static MediaType fromString(String value) { final lowerValue = value.toLowerCase(); switch (lowerValue) { case 'application/json': return MediaType.json; case 'application/xml': case 'text/xml': return MediaType.xml; case 'multipart/form-data': return MediaType.multipartFormData; case 'application/x-www-form-urlencoded': return MediaType.formUrlEncoded; case 'text/plain': return MediaType.textPlain; case 'text/html': return MediaType.textHtml; case 'text/csv': return MediaType.textCsv; case 'application/octet-stream': return MediaType.applicationOctetStream; case 'application/pdf': return MediaType.applicationPdf; case 'image/png': return MediaType.imagePng; case 'image/jpeg': case 'image/jpg': return MediaType.imageJpeg; case 'image/gif': return MediaType.imageGif; case 'image/svg+xml': return MediaType.imageSvg; case 'audio/mpeg': case 'audio/mp3': return MediaType.audioMp3; case 'video/mp4': return MediaType.videoMp4; default: return MediaType.custom; } } /// 检查是否是文本类型 bool get isText { switch (this) { case MediaType.textPlain: case MediaType.textHtml: case MediaType.textCsv: case MediaType.json: case MediaType.xml: return true; case MediaType.formData: case MediaType.formUrlEncoded: case MediaType.multipartFormData: case MediaType.applicationOctetStream: case MediaType.applicationPdf: case MediaType.imagePng: case MediaType.imageJpeg: case MediaType.imageGif: case MediaType.imageSvg: case MediaType.audioMp3: case MediaType.videoMp4: case MediaType.custom: return false; } } /// 检查是否是二进制类型 bool get isBinary { switch (this) { case MediaType.applicationOctetStream: case MediaType.applicationPdf: case MediaType.imagePng: case MediaType.imageJpeg: case MediaType.imageGif: case MediaType.imageSvg: case MediaType.audioMp3: case MediaType.videoMp4: return true; case MediaType.json: case MediaType.xml: case MediaType.formData: case MediaType.formUrlEncoded: case MediaType.multipartFormData: case MediaType.textPlain: case MediaType.textHtml: case MediaType.textCsv: case MediaType.custom: return false; } } /// 检查是否是表单类型 bool get isForm { switch (this) { case MediaType.formData: case MediaType.formUrlEncoded: case MediaType.multipartFormData: return true; case MediaType.json: case MediaType.xml: case MediaType.textPlain: case MediaType.textHtml: case MediaType.textCsv: case MediaType.applicationOctetStream: case MediaType.applicationPdf: case MediaType.imagePng: case MediaType.imageJpeg: case MediaType.imageGif: case MediaType.imageSvg: case MediaType.audioMp3: case MediaType.videoMp4: case MediaType.custom: return false; } } /// 检查是否是图片类型 bool get isImage { switch (this) { case MediaType.imagePng: case MediaType.imageJpeg: case MediaType.imageGif: case MediaType.imageSvg: return true; case MediaType.json: case MediaType.xml: case MediaType.formData: case MediaType.formUrlEncoded: case MediaType.multipartFormData: case MediaType.textPlain: case MediaType.textHtml: case MediaType.textCsv: case MediaType.applicationOctetStream: case MediaType.applicationPdf: case MediaType.audioMp3: case MediaType.videoMp4: case MediaType.custom: return false; } } /// 检查是否是音频类型 bool get isAudio { switch (this) { case MediaType.audioMp3: return true; case MediaType.json: case MediaType.xml: case MediaType.formData: case MediaType.formUrlEncoded: case MediaType.multipartFormData: case MediaType.textPlain: case MediaType.textHtml: case MediaType.textCsv: case MediaType.applicationOctetStream: case MediaType.applicationPdf: case MediaType.imagePng: case MediaType.imageJpeg: case MediaType.imageGif: case MediaType.imageSvg: case MediaType.videoMp4: case MediaType.custom: return false; } } /// 检查是否是视频类型 bool get isVideo { switch (this) { case MediaType.videoMp4: return true; case MediaType.json: case MediaType.xml: case MediaType.formData: case MediaType.formUrlEncoded: case MediaType.multipartFormData: case MediaType.textPlain: case MediaType.textHtml: case MediaType.textCsv: case MediaType.applicationOctetStream: case MediaType.applicationPdf: case MediaType.imagePng: case MediaType.imageJpeg: case MediaType.imageGif: case MediaType.imageSvg: case MediaType.audioMp3: case MediaType.custom: return false; } } /// 获取适合的 Dart 类型 String get dartType { switch (this) { case MediaType.json: return 'Map'; case MediaType.xml: return 'String'; case MediaType.formData: case MediaType.formUrlEncoded: case MediaType.multipartFormData: return 'FormData'; case MediaType.textPlain: case MediaType.textHtml: case MediaType.textCsv: return 'String'; case MediaType.applicationOctetStream: case MediaType.applicationPdf: case MediaType.imagePng: case MediaType.imageJpeg: case MediaType.imageGif: case MediaType.audioMp3: case MediaType.videoMp4: return 'List'; case MediaType.imageSvg: return 'String'; case MediaType.custom: return 'dynamic'; } } } /// API媒体类型信息 (OpenAPI 3.0) class ApiMediaType { const ApiMediaType({ this.schema, this.example, this.examples = const {}, this.encoding = const {}, this.mediaType = MediaType.json, this.rawMediaType = 'application/json', }); /// 从JSON创建ApiMediaType factory ApiMediaType.fromJson( Map json, [ String? contentType, ]) { final examplesJson = json['examples'] as Map? ?? {}; final examples = {}; examplesJson.forEach((key, value) { if (value is Map) { examples[key] = ApiExample.fromJson(value); } }); final encodingJson = json['encoding'] as Map? ?? {}; final encoding = {}; encodingJson.forEach((key, value) { if (value is Map) { encoding[key] = ApiEncoding.fromJson(value); } }); // 确定媒体类型 final rawType = contentType ?? 'application/json'; final mediaType = MediaTypeExtension.fromString(rawType); return ApiMediaType( schema: json['schema'] as Map?, example: json['example'], examples: examples, encoding: encoding, mediaType: mediaType, rawMediaType: rawType, ); } /// Schema 定义 final Map? schema; /// 示例数据 final dynamic example; /// 多个示例数据 final Map examples; /// 编码信息 (用于 multipart 和 form data) final Map encoding; /// 媒体类型 final MediaType mediaType; /// 原始媒体类型字符串 final String rawMediaType; /// 检查是否是 JSON 类型 bool get isJson => mediaType == MediaType.json; /// 检查是否是 XML 类型 bool get isXml => mediaType == MediaType.xml; /// 检查是否是表单类型 bool get isForm => mediaType.isForm; /// 检查是否是文件上传类型 bool get isFileUpload => mediaType == MediaType.multipartFormData; /// 检查是否是二进制类型 bool get isBinary => mediaType.isBinary; /// 检查是否是文本类型 bool get isText => mediaType.isText; /// 检查是否是图片类型 bool get isImage => mediaType.isImage; /// 获取适合的 Dart 类型 String get dartType => mediaType.dartType; } /// API示例信息 (OpenAPI 3.0) class ApiExample { const ApiExample({ this.summary = '', this.description = '', this.value, this.externalValue, }); /// 从JSON创建ApiExample factory ApiExample.fromJson(Map json) { return ApiExample( summary: json['summary'] as String? ?? '', description: json['description'] as String? ?? '', value: json['value'], externalValue: json['externalValue'] as String?, ); } /// 示例摘要 final String summary; /// 示例描述 final String description; /// 示例值 final dynamic value; /// 外部示例URL final String? externalValue; } /// API编码信息 (OpenAPI 3.0) class ApiEncoding { const ApiEncoding({ this.contentType, this.headers = const {}, this.style, this.explode = false, this.allowReserved = false, }); /// 从JSON创建ApiEncoding factory ApiEncoding.fromJson(Map json) { final headersJson = json['headers'] as Map? ?? {}; final headers = {}; headersJson.forEach((key, value) { if (value is Map) { headers[key] = ApiHeader.fromJson(value); } }); return ApiEncoding( contentType: json['contentType'] as String?, headers: headers, style: json['style'] as String?, explode: json['explode'] as bool? ?? false, allowReserved: json['allowReserved'] as bool? ?? false, ); } /// 内容类型 final String? contentType; /// 头部信息 final Map headers; /// 样式 final String? style; /// 是否展开 final bool explode; /// 是否允许保留字符 final bool allowReserved; /// 检查是否是文件类型 bool get isFile { if (contentType == null) return false; final type = contentType!.toLowerCase(); return type.startsWith('image/') || type.startsWith('audio/') || type.startsWith('video/') || type == 'application/octet-stream' || type == 'application/pdf' || type.contains('binary'); } /// 检查是否是图片文件 bool get isImage { if (contentType == null) return false; return contentType!.toLowerCase().startsWith('image/'); } /// 检查是否是音频文件 bool get isAudio { if (contentType == null) return false; return contentType!.toLowerCase().startsWith('audio/'); } /// 检查是否是视频文件 bool get isVideo { if (contentType == null) return false; return contentType!.toLowerCase().startsWith('video/'); } /// 检查是否有自定义头部 bool get hasHeaders => headers.isNotEmpty; } /// API头部信息 (OpenAPI 3.0) class ApiHeader { const ApiHeader({ this.description = '', this.required = false, this.deprecated = false, this.schema, this.example, }); /// 从JSON创建ApiHeader factory ApiHeader.fromJson(Map json) { return ApiHeader( description: json['description'] as String? ?? '', required: json['required'] as bool? ?? false, deprecated: json['deprecated'] as bool? ?? false, schema: json['schema'] as Map?, example: json['example'], ); } /// 头部描述 final String description; /// 是否必需 final bool required; /// 是否已弃用 final bool deprecated; /// Schema 定义 final Map? schema; /// 示例值 final dynamic example; } /// API链接信息 (OpenAPI 3.0) class ApiLink { const ApiLink({ this.description = '', this.operationRef, this.operationId, this.parameters = const {}, this.requestBody, this.server, }); /// 从JSON创建ApiLink factory ApiLink.fromJson(Map json) { final serverJson = json['server'] as Map?; final server = serverJson != null ? ApiServer.fromJson(serverJson) : null; return ApiLink( description: json['description'] as String? ?? '', operationRef: json['operationRef'] as String?, operationId: json['operationId'] as String?, parameters: json['parameters'] as Map? ?? {}, requestBody: json['requestBody'], server: server, ); } /// 链接描述 final String description; /// 操作引用 final String? operationRef; /// 操作ID final String? operationId; /// 参数映射 final Map parameters; /// 请求体映射 final dynamic requestBody; /// 服务器信息 final ApiServer? server; } /// API组件信息 (OpenAPI 3.0) /// 包含可重用的组件定义 class ApiComponents { const ApiComponents({ this.schemas = const {}, this.responses = const {}, this.parameters = const {}, this.examples = const {}, this.requestBodies = const {}, this.headers = const {}, this.securitySchemes = const {}, this.links = const {}, this.callbacks = const {}, }); /// 从JSON创建ApiComponents factory ApiComponents.fromJson(Map json) { // 解析 schemas final schemasJson = json['schemas'] as Map? ?? {}; final schemas = {}; schemasJson.forEach((key, value) { if (value is Map) { schemas[key] = ApiModel.fromJson(key, value); } }); // 解析 responses final responsesJson = json['responses'] as Map? ?? {}; final responses = {}; responsesJson.forEach((key, value) { if (value is Map) { responses[key] = ApiResponse.fromJson(key, value); } }); // 解析 parameters final parametersJson = json['parameters'] as Map? ?? {}; final parameters = {}; parametersJson.forEach((key, value) { if (value is Map) { parameters[key] = ApiParameter.fromJson(value); } }); // 解析 examples final examplesJson = json['examples'] as Map? ?? {}; final examples = {}; examplesJson.forEach((key, value) { if (value is Map) { examples[key] = ApiExample.fromJson(value); } }); // 解析 requestBodies final requestBodiesJson = json['requestBodies'] as Map? ?? {}; final requestBodies = {}; requestBodiesJson.forEach((key, value) { if (value is Map) { requestBodies[key] = ApiRequestBody.fromJson(value); } }); // 解析 headers final headersJson = json['headers'] as Map? ?? {}; final headers = {}; headersJson.forEach((key, value) { if (value is Map) { headers[key] = ApiHeader.fromJson(value); } }); // 解析 securitySchemes final securitySchemesJson = json['securitySchemes'] as Map? ?? {}; final securitySchemes = {}; securitySchemesJson.forEach((key, value) { if (value is Map) { securitySchemes[key] = ApiSecurityScheme.fromJson(value); } }); // 解析 links final linksJson = json['links'] as Map? ?? {}; final links = {}; linksJson.forEach((key, value) { if (value is Map) { links[key] = ApiLink.fromJson(value); } }); // 解析 callbacks final callbacksJson = json['callbacks'] as Map? ?? {}; final callbacks = {}; callbacksJson.forEach((key, value) { if (value is Map) { callbacks[key] = ApiCallback.fromJson(value); } }); return ApiComponents( schemas: schemas, responses: responses, parameters: parameters, examples: examples, requestBodies: requestBodies, headers: headers, securitySchemes: securitySchemes, links: links, callbacks: callbacks, ); } /// Schema 定义 final Map schemas; /// 响应定义 final Map responses; /// 参数定义 final Map parameters; /// 示例定义 final Map examples; /// 请求体定义 final Map requestBodies; /// 头部定义 final Map headers; /// 安全方案定义 final Map securitySchemes; /// 链接定义 final Map links; /// 回调定义 final Map callbacks; } /// API安全方案信息 (OpenAPI 3.0) class ApiSecurityScheme { const ApiSecurityScheme({ required this.type, this.description = '', this.name, this.location, this.scheme, this.bearerFormat, this.flows, this.openIdConnectUrl, }); /// 从JSON创建ApiSecurityScheme factory ApiSecurityScheme.fromJson(Map json) { final type = SecuritySchemeTypeExtension.fromString( json['type'] as String? ?? 'apiKey', ); return ApiSecurityScheme( type: type, description: json['description'] as String? ?? '', name: json['name'] as String?, location: json['in'] != null ? ApiKeyLocationExtension.fromString(json['in'] as String) : null, scheme: json['scheme'] as String?, bearerFormat: json['bearerFormat'] as String?, flows: json['flows'] != null ? OAuth2Flows.fromJson(json['flows'] as Map) : null, openIdConnectUrl: json['openIdConnectUrl'] as String?, ); } /// 安全方案类型 final SecuritySchemeType type; /// 描述 final String description; /// 名称 (用于 apiKey) final String? name; /// 位置 (用于 apiKey) final ApiKeyLocation? location; /// 方案 (用于 http) final String? scheme; /// Bearer 格式 (用于 http bearer) final String? bearerFormat; /// OAuth2 流程信息 (用于 oauth2) final OAuth2Flows? flows; /// OpenID Connect URL (用于 openIdConnect) final String? openIdConnectUrl; /// 检查是否是 API Key 认证 bool get isApiKey => type == SecuritySchemeType.apiKey; /// 检查是否是 HTTP 认证 bool get isHttp => type == SecuritySchemeType.http; /// 检查是否是 OAuth2 认证 bool get isOAuth2 => type == SecuritySchemeType.oauth2; /// 检查是否是 OpenID Connect 认证 bool get isOpenIdConnect => type == SecuritySchemeType.openIdConnect; /// 检查是否是 Bearer 认证 bool get isBearer => isHttp && scheme?.toLowerCase() == 'bearer'; /// 检查是否是 Basic 认证 bool get isBasic => isHttp && scheme?.toLowerCase() == 'basic'; /// 检查是否有 OAuth2 流程 bool get hasOAuth2Flows => flows?.hasAnyFlow ?? false; /// 获取 API Key 的完整配置信息 String get apiKeyInfo { if (!isApiKey || name == null || location == null) return ''; return '${location!.value}:$name'; } /// 获取 HTTP 认证的完整配置信息 String get httpAuthInfo { if (!isHttp || scheme == null) return ''; if (bearerFormat != null) { return '$scheme ($bearerFormat)'; } return scheme!; } } /// API回调信息 (OpenAPI 3.0) class ApiCallback { const ApiCallback({ this.expressions = const {}, }); /// 从JSON创建ApiCallback factory ApiCallback.fromJson(Map json) { final expressions = {}; json.forEach((expression, pathItemData) { if (pathItemData is Map) { expressions[expression] = ApiPathItem.fromJson(pathItemData); } }); return ApiCallback( expressions: expressions, ); } /// 回调表达式映射 final Map expressions; } /// API路径项信息 (OpenAPI 3.0) class ApiPathItem { const ApiPathItem({ this.summary = '', this.description = '', this.operations = const {}, this.servers = const [], this.parameters = const [], }); /// 从JSON创建ApiPathItem factory ApiPathItem.fromJson(Map json) { final operations = {}; final httpMethods = [ 'get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace', ]; for (final method in httpMethods) { if (json[method] != null) { operations[method] = ApiOperation.fromJson(json[method] as Map); } } final serversJson = json['servers'] as List? ?? []; final servers = serversJson .map((server) => ApiServer.fromJson(server as Map)) .toList(); final parametersJson = json['parameters'] as List? ?? []; final parameters = parametersJson .map((param) => ApiParameter.fromJson(param as Map)) .toList(); return ApiPathItem( summary: json['summary'] as String? ?? '', description: json['description'] as String? ?? '', operations: operations, servers: servers, parameters: parameters, ); } /// 路径摘要 final String summary; /// 路径描述 final String description; /// 操作映射 (HTTP方法 -> 操作) final Map operations; /// 服务器信息 final List servers; /// 参数信息 final List parameters; } /// API操作信息 (OpenAPI 3.0) class ApiOperation { const ApiOperation({ this.summary = '', this.description = '', this.operationId, this.tags = const [], this.parameters = const [], this.requestBody, this.responses = const {}, this.security = const [], }); /// 从JSON创建ApiOperation factory ApiOperation.fromJson(Map json) { final parametersJson = json['parameters'] as List? ?? []; final parameters = parametersJson .map((param) => ApiParameter.fromJson(param as Map)) .toList(); final requestBodyJson = json['requestBody'] as Map?; final requestBody = requestBodyJson != null ? ApiRequestBody.fromJson(requestBodyJson) : null; final responsesJson = json['responses'] as Map? ?? {}; final responses = {}; responsesJson.forEach((code, responseData) { if (responseData is Map) { responses[code] = ApiResponse.fromJson(code, responseData); } }); final securityJson = json['security'] as List? ?? []; final security = securityJson .map((s) => ApiSecurityRequirement.fromJson(s as Map)) .toList(); return ApiOperation( summary: json['summary'] as String? ?? '', description: json['description'] as String? ?? '', operationId: json['operationId'] as String?, tags: (json['tags'] as List?)?.map((e) => e.toString()).toList() ?? [], parameters: parameters, requestBody: requestBody, responses: responses, security: security, ); } /// 操作摘要 final String summary; /// 操作描述 final String description; /// 操作ID final String? operationId; /// 标签 final List tags; /// 参数 final List parameters; /// 请求体 final ApiRequestBody? requestBody; /// 响应 final Map responses; /// 安全要求 final List security; } /// API 判别器信息 (OpenAPI 3.0) /// 用于多态类型的判别 class ApiDiscriminator { const ApiDiscriminator({ required this.propertyName, this.mapping = const {}, }); /// 从JSON创建ApiDiscriminator factory ApiDiscriminator.fromJson(Map json) { final mappingJson = json['mapping'] as Map? ?? {}; final mapping = {}; mappingJson.forEach((key, value) { if (value is String) { mapping[key] = value; } }); return ApiDiscriminator( propertyName: json['propertyName'] as String? ?? '', mapping: mapping, ); } /// 判别器属性名 final String propertyName; /// 映射表 (值 -> schema 引用) final Map mapping; /// 检查是否有映射表 bool get hasMapping => mapping.isNotEmpty; /// 根据值获取对应的 schema 引用 String? getSchemaForValue(String value) => mapping[value]; } /// API Schema 信息 (OpenAPI 3.0) /// 表示一个 JSON Schema 对象,支持组合模式 class ApiSchema { const ApiSchema({ this.type, this.format, this.description = '', this.properties = const {}, this.required = const [], this.items, this.reference, this.enumValues = const [], this.allOf = const [], this.oneOf = const [], this.anyOf = const [], this.not, this.discriminator, this.additionalProperties, this.patternProperties = const {}, this.propertyNames, this.dependencies = const {}, this.constValue, this.ifSchema, this.thenSchema, this.elseSchema, this.minimum, this.maximum, this.exclusiveMinimum, this.exclusiveMaximum, this.minLength, this.maxLength, this.pattern, this.minItems, this.maxItems, this.uniqueItems, this.nullable = false, this.example, this.defaultValue, }); /// 从JSON创建ApiSchema factory ApiSchema.fromJson(Map json) { // 解析 properties final propertiesJson = json['properties'] as Map? ?? {}; final properties = {}; final requiredFields = (json['required'] as List?) ?.map((e) => e.toString()) .toList() ?? []; propertiesJson.forEach((propName, propData) { if (propData is Map) { properties[propName] = ApiProperty.fromJson( propName, propData, requiredFields, ); } }); // 解析 items (用于数组类型) final itemsJson = json['items'] as Map?; final items = itemsJson != null ? ApiSchema.fromJson(itemsJson) : null; // 解析组合模式 final allOfJson = json['allOf'] as List? ?? []; final allOf = allOfJson .map((schema) => ApiSchema.fromJson(schema as Map)) .toList(); final oneOfJson = json['oneOf'] as List? ?? []; final oneOf = oneOfJson .map((schema) => ApiSchema.fromJson(schema as Map)) .toList(); final anyOfJson = json['anyOf'] as List? ?? []; final anyOf = anyOfJson .map((schema) => ApiSchema.fromJson(schema as Map)) .toList(); final notJson = json['not'] as Map?; final not = notJson != null ? ApiSchema.fromJson(notJson) : null; // 解析 discriminator final discriminatorJson = json['discriminator'] as Map?; final discriminator = discriminatorJson != null ? ApiDiscriminator.fromJson(discriminatorJson) : null; // 解析 patternProperties final patternPropertiesJson = json['patternProperties'] as Map? ?? {}; final patternProperties = {}; patternPropertiesJson.forEach((pattern, schemaData) { if (schemaData is Map) { patternProperties[pattern] = ApiSchema.fromJson(schemaData); } }); // 解析 propertyNames final propertyNamesJson = json['propertyNames'] as Map?; final propertyNames = propertyNamesJson != null ? ApiSchema.fromJson(propertyNamesJson) : null; // 解析 dependencies final dependencies = json['dependencies'] as Map? ?? {}; // 解析条件 Schema (if/then/else) final ifJson = json['if'] as Map?; final ifSchema = ifJson != null ? ApiSchema.fromJson(ifJson) : null; final thenJson = json['then'] as Map?; final thenSchema = thenJson != null ? ApiSchema.fromJson(thenJson) : null; final elseJson = json['else'] as Map?; final elseSchema = elseJson != null ? ApiSchema.fromJson(elseJson) : null; // 处理引用 String? reference; if (json[r'$ref'] != null) { final ref = json[r'$ref'] as String; reference = ref.split('/').last; } return ApiSchema( type: json['type'] as String?, format: json['format'] as String?, description: json['description'] as String? ?? '', properties: properties, required: requiredFields, items: items, reference: reference, enumValues: (json['enum'] as List?) ?? [], allOf: allOf, oneOf: oneOf, anyOf: anyOf, not: not, discriminator: discriminator, additionalProperties: json['additionalProperties'], patternProperties: patternProperties, propertyNames: propertyNames, dependencies: dependencies, constValue: json['const'], ifSchema: ifSchema, thenSchema: thenSchema, elseSchema: elseSchema, minimum: json['minimum'] as num?, maximum: json['maximum'] as num?, exclusiveMinimum: json['exclusiveMinimum'] as bool?, exclusiveMaximum: json['exclusiveMaximum'] as bool?, minLength: json['minLength'] as int?, maxLength: json['maxLength'] as int?, pattern: json['pattern'] as String?, minItems: json['minItems'] as int?, maxItems: json['maxItems'] as int?, uniqueItems: json['uniqueItems'] as bool?, nullable: json['nullable'] as bool? ?? false, example: json['example'], defaultValue: json['default'], ); } /// Schema 类型 final String? type; /// Schema 格式 final String? format; /// Schema 描述 final String description; /// 属性定义 (用于 object 类型) final Map properties; /// 必需字段 final List required; /// 数组项定义 (用于 array 类型) final ApiSchema? items; /// 引用 ($ref) final String? reference; /// 枚举值 final List enumValues; /// 组合模式 final List allOf; final List oneOf; final List anyOf; final ApiSchema? not; /// 多态类型判别器 (OpenAPI 3.0) final ApiDiscriminator? discriminator; /// 额外属性 (可以是 boolean 或 Schema) final dynamic additionalProperties; /// 模式属性 (patternProperties) final Map patternProperties; /// 属性名称约束 final ApiSchema? propertyNames; /// 属性依赖关系 final Map dependencies; /// 常量值 final dynamic constValue; /// 条件 Schema (if/then/else) final ApiSchema? ifSchema; final ApiSchema? thenSchema; final ApiSchema? elseSchema; /// 最小值/最大值 (用于数值类型) final num? minimum; final num? maximum; final bool? exclusiveMinimum; final bool? exclusiveMaximum; /// 字符串长度限制 final int? minLength; final int? maxLength; final String? pattern; /// 数组长度限制 final int? minItems; final int? maxItems; final bool? uniqueItems; /// 可空性 final bool nullable; /// 示例值 final dynamic example; /// 默认值 final dynamic defaultValue; /// 检查是否是组合模式 bool get isComposition => allOf.isNotEmpty || oneOf.isNotEmpty || anyOf.isNotEmpty; /// 检查是否是 allOf 组合 bool get isAllOf => allOf.isNotEmpty; /// 检查是否是 oneOf 组合 bool get isOneOf => oneOf.isNotEmpty; /// 检查是否是 anyOf 组合 bool get isAnyOf => anyOf.isNotEmpty; /// 检查是否有 not 约束 bool get hasNot => not != null; /// 检查是否有判别器 bool get hasDiscriminator => discriminator != null; /// 检查是否是引用类型 bool get isReference => reference != null; /// 检查是否是枚举类型 bool get isEnum => enumValues.isNotEmpty; /// 检查是否是数组类型 bool get isArray => type == 'array'; /// 检查是否是对象类型 bool get isObject => type == 'object' || properties.isNotEmpty; /// 检查是否有模式属性 bool get hasPatternProperties => patternProperties.isNotEmpty; /// 检查是否有属性名称约束 bool get hasPropertyNames => propertyNames != null; /// 检查是否有属性依赖 bool get hasDependencies => dependencies.isNotEmpty; /// 检查是否有常量值 bool get hasConstValue => constValue != null; /// 检查是否有条件 Schema bool get hasConditionalSchema => ifSchema != null || thenSchema != null || elseSchema != null; /// 检查是否允许额外属性 bool get allowsAdditionalProperties { if (additionalProperties == null) return true; // 默认允许 if (additionalProperties is bool) return additionalProperties as bool; return true; // 如果是 Schema 对象,表示允许但有约束 } /// 获取额外属性的 Schema(如果 additionalProperties 是 Schema 对象) ApiSchema? get additionalPropertiesSchema { final additionalProps = additionalProperties; if (additionalProps is Map) { return ApiSchema.fromJson(additionalProps); } return null; } } /// API模型信息 class ApiModel { const ApiModel({ required this.name, required this.description, required this.properties, required this.required, this.isEnum = false, this.enumValues = const [], this.enumType, this.allOf = const [], this.oneOf = const [], this.anyOf = const [], this.not, this.discriminator, this.usageType = ModelUsageType.unknown, }); /// 从JSON创建ApiModel factory ApiModel.fromJson( String name, Map json, { ModelUsageType usageType = ModelUsageType.unknown, }) { final isEnum = json['enum'] != null; final enumValues = isEnum ? (json['enum'] as List?) ?? [] : []; final properties = json['properties'] as Map? ?? {}; List required; if (json.containsKey('required')) { required = (json['required'] as List?) ?.map((e) => e.toString()) .toList() ?? []; } else { // 没有 required 字段时,凡 nullable != true 的都视为 required required = properties.entries .where((entry) { final value = entry.value; if (value is Map) { return !(value['nullable'] as bool? ?? false); } return true; }) .map((entry) => entry.key) .toList(); } // 解析组合模式 final allOfJson = json['allOf'] as List? ?? []; final allOf = allOfJson .map((schema) => ApiSchema.fromJson(schema as Map)) .toList(); final oneOfJson = json['oneOf'] as List? ?? []; final oneOf = oneOfJson .map((schema) => ApiSchema.fromJson(schema as Map)) .toList(); final anyOfJson = json['anyOf'] as List? ?? []; final anyOf = anyOfJson .map((schema) => ApiSchema.fromJson(schema as Map)) .toList(); final notJson = json['not'] as Map?; final not = notJson != null ? ApiSchema.fromJson(notJson) : null; // 解析 discriminator final discriminatorJson = json['discriminator'] as Map?; final discriminator = discriminatorJson != null ? ApiDiscriminator.fromJson(discriminatorJson) : null; return ApiModel( name: name, description: json['description'] as String? ?? '', required: required, isEnum: isEnum, enumValues: enumValues, enumType: isEnum ? PropertyType.fromString(json['type'] as String? ?? 'string') : null, allOf: allOf, oneOf: oneOf, anyOf: anyOf, not: not, discriminator: discriminator, usageType: usageType, properties: properties.map( (propName, propData) => MapEntry( propName, ApiProperty.fromJson( propName, propData as Map, required, ), ), ), ); } final String name; final String description; final Map properties; final List required; final bool isEnum; final List enumValues; final PropertyType? enumType; /// 组合模式支持 (OpenAPI 3.0) final List allOf; final List oneOf; final List anyOf; final ApiSchema? not; /// 多态类型判别器 (OpenAPI 3.0) final ApiDiscriminator? discriminator; /// 模型用途类型 /// 标识该模型在 API 中的实际用途(请求/响应/通用/未知) final ModelUsageType usageType; /// 检查是否使用了组合模式 bool get isComposition => allOf.isNotEmpty || oneOf.isNotEmpty || anyOf.isNotEmpty; /// 检查是否是 allOf 组合 bool get isAllOf => allOf.isNotEmpty; /// 检查是否是 oneOf 组合 bool get isOneOf => oneOf.isNotEmpty; /// 检查是否是 anyOf 组合 bool get isAnyOf => anyOf.isNotEmpty; /// 检查是否有 not 约束 bool get hasNot => not != null; /// 检查是否有判别器 bool get hasDiscriminator => discriminator != null; /// 创建副本并更新用途类型 /// 用于在分析 schema 使用情况后更新模型的用途类型 ApiModel copyWithUsageType(ModelUsageType newUsageType) { return ApiModel( name: name, description: description, properties: properties, required: required, isEnum: isEnum, enumValues: enumValues, enumType: enumType, allOf: allOf, oneOf: oneOf, anyOf: anyOf, not: not, discriminator: discriminator, usageType: newUsageType, ); } } /// API属性信息 class ApiProperty { const ApiProperty({ required this.name, required this.type, required this.description, required this.required, this.format, this.nullable = false, this.example, this.defaultValue, this.reference, this.items, this.nestedProperties = const {}, this.nestedRequired = const [], this.schema, }); /// 从JSON创建ApiProperty factory ApiProperty.fromJson( String name, Map json, List requiredFields, { int maxDepth = 10, int currentDepth = 0, }) { // 防止过深的嵌套 if (currentDepth >= maxDepth) { return ApiProperty( name: name, type: PropertyType.object, description: '达到最大嵌套深度的对象', required: requiredFields.contains(name), ); } final type = PropertyType.fromString(json['type'] as String? ?? 'string'); String? reference; ApiModel? items; final nestedProperties = {}; var nestedRequired = []; ApiSchema? schema; // 处理引用类型 if (json[r'$ref'] != null) { final ref = json[r'$ref'] as String; reference = ref.split('/').last; } // 处理复杂 schema(组合模式等) if (json['allOf'] != null || json['oneOf'] != null || json['anyOf'] != null) { schema = ApiSchema.fromJson(json); } // 处理嵌套对象类型 if (type == PropertyType.object && json['properties'] != null) { final propertiesJson = json['properties'] as Map; nestedRequired = (json['required'] as List?) ?.map((e) => e.toString()) .toList() ?? []; propertiesJson.forEach((propName, propData) { if (propData is Map) { try { final nestedProperty = ApiProperty.fromJson( propName, propData, nestedRequired, maxDepth: maxDepth, currentDepth: currentDepth + 1, ); nestedProperties[propName] = nestedProperty; } on Exception { // 如果解析嵌套属性失败,创建一个基本属性 nestedProperties[propName] = ApiProperty( name: propName, type: PropertyType.string, description: '解析失败的嵌套属性', required: nestedRequired.contains(propName), ); } } }); } // 处理数组类型的 items if (type == PropertyType.array && json['items'] != null) { final itemsJson = json['items'] as Map; // 如果 items 是引用类型 if (itemsJson[r'$ref'] != null) { final itemRef = itemsJson[r'$ref'] as String; final itemRefName = itemRef.split('/').last; items = ApiModel( name: itemRefName, description: '', properties: {}, required: [], ); } else if (itemsJson['type'] == 'object' && itemsJson['properties'] != null) { // 如果 items 是嵌套对象 final itemProperties = {}; final itemRequired = (itemsJson['required'] as List?) ?.map((e) => e.toString()) .toList() ?? []; final itemPropertiesJson = itemsJson['properties'] as Map; for (final entry in itemPropertiesJson.entries) { final propName = entry.key; final propData = entry.value; if (propData is Map) { ApiProperty itemProperty; try { itemProperty = ApiProperty.fromJson( propName, propData, itemRequired, maxDepth: maxDepth, currentDepth: currentDepth + 1, ); } on Exception { // 创建基本属性作为后备 itemProperty = ApiProperty( name: propName, type: PropertyType.string, description: '解析失败的数组项属性', required: itemRequired.contains(propName), ); } itemProperties[propName] = itemProperty; } } items = ApiModel( name: '${name}Item', description: itemsJson['description'] as String? ?? '', properties: itemProperties, required: itemRequired, ); } else { // 如果 items 是基本类型 final itemType = PropertyType.fromString(itemsJson['type'] as String? ?? 'string'); items = ApiModel( name: itemType.value, description: '', properties: {}, required: [], ); } } return ApiProperty( name: name, type: reference != null ? PropertyType.reference : type, format: json['format'] as String?, description: json['description'] as String? ?? '', required: requiredFields.contains(name), nullable: json['nullable'] as bool? ?? false, example: json['example'], defaultValue: json['default'], reference: reference, items: items, nestedProperties: nestedProperties, nestedRequired: nestedRequired, schema: schema, ); } final String name; final PropertyType type; final String? format; final String description; final bool required; final bool nullable; final dynamic example; final dynamic defaultValue; final String? reference; final ApiModel? items; // 用于数组类型 /// 嵌套对象属性 (用于 object 类型) final Map nestedProperties; /// 嵌套对象的必需字段 final List nestedRequired; /// Schema 定义 (用于复杂类型) final ApiSchema? schema; /// 检查是否有嵌套属性 bool get hasNestedProperties => nestedProperties.isNotEmpty; /// 检查是否有复杂 schema bool get hasComplexSchema => schema != null; } /// API控制器信息 class ApiController { const ApiController({ required this.name, required this.description, required this.paths, }); /// 从路径列表创建ApiController factory ApiController.fromPaths(String name, List paths) { return ApiController(name: name, description: name, paths: paths); } final String name; final String description; final List paths; } /// 安全方案类型 enum SecuritySchemeType { apiKey, http, oauth2, openIdConnect, } extension SecuritySchemeTypeExtension on SecuritySchemeType { String get value { switch (this) { case SecuritySchemeType.apiKey: return 'apiKey'; case SecuritySchemeType.http: return 'http'; case SecuritySchemeType.oauth2: return 'oauth2'; case SecuritySchemeType.openIdConnect: return 'openIdConnect'; } } static SecuritySchemeType fromString(String value) { switch (value.toLowerCase()) { case 'apikey': return SecuritySchemeType.apiKey; case 'http': return SecuritySchemeType.http; case 'oauth2': return SecuritySchemeType.oauth2; case 'openidconnect': return SecuritySchemeType.openIdConnect; default: return SecuritySchemeType.apiKey; } } } /// API Key 位置 enum ApiKeyLocation { query, header, cookie, } extension ApiKeyLocationExtension on ApiKeyLocation { String get value { switch (this) { case ApiKeyLocation.query: return 'query'; case ApiKeyLocation.header: return 'header'; case ApiKeyLocation.cookie: return 'cookie'; } } static ApiKeyLocation fromString(String value) { switch (value.toLowerCase()) { case 'query': return ApiKeyLocation.query; case 'header': return ApiKeyLocation.header; case 'cookie': return ApiKeyLocation.cookie; default: return ApiKeyLocation.header; } } } /// OAuth2 流程类型 enum OAuth2FlowType { authorizationCode, implicit, password, clientCredentials, } extension OAuth2FlowTypeExtension on OAuth2FlowType { String get value { switch (this) { case OAuth2FlowType.authorizationCode: return 'authorizationCode'; case OAuth2FlowType.implicit: return 'implicit'; case OAuth2FlowType.password: return 'password'; case OAuth2FlowType.clientCredentials: return 'clientCredentials'; } } static OAuth2FlowType fromString(String value) { switch (value.toLowerCase()) { case 'authorizationcode': return OAuth2FlowType.authorizationCode; case 'implicit': return OAuth2FlowType.implicit; case 'password': return OAuth2FlowType.password; case 'clientcredentials': return OAuth2FlowType.clientCredentials; default: return OAuth2FlowType.authorizationCode; } } } /// OAuth2 流程配置 class OAuth2Flow { const OAuth2Flow({ this.authorizationUrl, this.tokenUrl, this.refreshUrl, this.scopes = const {}, }); /// 从 JSON 创建 OAuth2Flow factory OAuth2Flow.fromJson(Map json) { final scopesData = json['scopes']; final Map scopes; if (scopesData is Map) { scopes = scopesData .map((key, value) => MapEntry(key.toString(), value.toString())); } else { scopes = {}; } return OAuth2Flow( authorizationUrl: json['authorizationUrl'] as String?, tokenUrl: json['tokenUrl'] as String?, refreshUrl: json['refreshUrl'] as String?, scopes: scopes, ); } /// 授权 URL (用于 authorizationCode 和 implicit 流程) final String? authorizationUrl; /// 令牌 URL (用于 authorizationCode, password 和 clientCredentials 流程) final String? tokenUrl; /// 刷新 URL (可选) final String? refreshUrl; /// 可用的作用域 final Map scopes; /// 检查是否有授权 URL bool get hasAuthorizationUrl => authorizationUrl != null && authorizationUrl!.isNotEmpty; /// 检查是否有令牌 URL bool get hasTokenUrl => tokenUrl != null && tokenUrl!.isNotEmpty; /// 检查是否有刷新 URL bool get hasRefreshUrl => refreshUrl != null && refreshUrl!.isNotEmpty; /// 检查是否有作用域 bool get hasScopes => scopes.isNotEmpty; } /// OAuth2 流程集合 class OAuth2Flows { const OAuth2Flows({ this.authorizationCode, this.implicit, this.password, this.clientCredentials, }); /// 从 JSON 创建 OAuth2Flows factory OAuth2Flows.fromJson(Map json) { return OAuth2Flows( authorizationCode: json['authorizationCode'] != null ? OAuth2Flow.fromJson( json['authorizationCode'] as Map, ) : null, implicit: json['implicit'] != null ? OAuth2Flow.fromJson(json['implicit'] as Map) : null, password: json['password'] != null ? OAuth2Flow.fromJson(json['password'] as Map) : null, clientCredentials: json['clientCredentials'] != null ? OAuth2Flow.fromJson( json['clientCredentials'] as Map, ) : null, ); } /// 授权码流程 final OAuth2Flow? authorizationCode; /// 隐式流程 final OAuth2Flow? implicit; /// 密码流程 final OAuth2Flow? password; /// 客户端凭证流程 final OAuth2Flow? clientCredentials; /// 获取所有可用的流程 List get availableFlows { final flows = []; if (authorizationCode != null) flows.add(OAuth2FlowType.authorizationCode); if (implicit != null) flows.add(OAuth2FlowType.implicit); if (password != null) flows.add(OAuth2FlowType.password); if (clientCredentials != null) flows.add(OAuth2FlowType.clientCredentials); return flows; } /// 检查是否有任何流程 bool get hasAnyFlow => availableFlows.isNotEmpty; /// 获取指定类型的流程 OAuth2Flow? getFlow(OAuth2FlowType type) { switch (type) { case OAuth2FlowType.authorizationCode: return authorizationCode; case OAuth2FlowType.implicit: return implicit; case OAuth2FlowType.password: return password; case OAuth2FlowType.clientCredentials: return clientCredentials; } } } /// 安全要求 (单个安全方案的要求) class ApiSecurityRequirement { const ApiSecurityRequirement({ this.requirements = const {}, }); /// 从 JSON 创建 ApiSecurityRequirement factory ApiSecurityRequirement.fromJson(Map json) { final requirements = >{}; json.forEach((schemeName, scopes) { if (scopes is List) { requirements[schemeName] = List.from(scopes); } else { requirements[schemeName] = []; } }); return ApiSecurityRequirement(requirements: requirements); } /// 安全方案名称到作用域列表的映射 final Map> requirements; /// 检查是否为空 bool get isEmpty => requirements.isEmpty; /// 检查是否非空 bool get isNotEmpty => requirements.isNotEmpty; /// 获取所有安全方案名称 List get schemeNames => requirements.keys.toList(); /// 获取指定方案的作用域 List getScopesForScheme(String schemeName) { return requirements[schemeName] ?? []; } /// 检查是否包含指定的安全方案 bool hasScheme(String schemeName) { return requirements.containsKey(schemeName); } }