Establish the Koi Swagger parser release
Prepare the OpenAPI parser and Dart generator as a publishable Koi package with CLI entrypoint, docs, examples, tests, and pub.dev release metadata. Constraint: Initial GitHub import follows koi_blueprint_flutter identity mr.koi <i@mrkoi.is>. Rejected: Keep local runtime state in the initial repository | .dart_tool, .omx, and pubspec.lock are ignored for a reusable package source tree. Confidence: high Scope-risk: moderate Directive: Keep generated-output behavior covered by parser and generator tests before changing rendering rules. Tested: dart analyze; dart test; PUB_HOSTED_URL=https://pub.dev dart pub publish --dry-run Not-tested: End-to-end downstream build_runner compilation of generated Retrofit/Freezed output.
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:koi_swagger_parser/koi_swagger_parser.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group('KoiSwaggerConfigLoader', () {
|
||||
test('兼容旧版 generator_config.yaml 字段', () async {
|
||||
final tempDir = await Directory.systemTemp.createTemp(
|
||||
'koi_swagger_parser_config_',
|
||||
);
|
||||
addTearDown(() => tempDir.delete(recursive: true));
|
||||
|
||||
final configFile = File(p.join(tempDir.path, 'generator_config.yaml'));
|
||||
await configFile.writeAsString('''
|
||||
input:
|
||||
swagger_urls:
|
||||
- url: ./openapi.json
|
||||
enabled: true
|
||||
|
||||
output:
|
||||
base_dir: ./lib/src
|
||||
api_dir: ./lib/src/api
|
||||
models_dir: ./lib/src/api_models
|
||||
included_tags:
|
||||
- stores
|
||||
|
||||
generation:
|
||||
api:
|
||||
enabled: true
|
||||
use_retrofit: true
|
||||
cancel_token_support: true
|
||||
base_result_import: package:dba_network/dba_network.dart
|
||||
client:
|
||||
class_name: DbaApiClient
|
||||
file_name: dba_api_client
|
||||
models:
|
||||
enabled: true
|
||||
class_prefix: Koi
|
||||
default_non_nullable_list_to_empty: true
|
||||
json_serializable:
|
||||
checked: true
|
||||
explicit_to_json: true
|
||||
include_if_null: false
|
||||
formatting:
|
||||
run_dart_format: false
|
||||
''');
|
||||
|
||||
final config = await KoiSwaggerConfig.load(
|
||||
workingDirectory: tempDir.path,
|
||||
);
|
||||
|
||||
expect(config.input.swaggerUrls, <String>[
|
||||
p.join(tempDir.path, 'openapi.json'),
|
||||
]);
|
||||
expect(config.output.includedTags, <String>['stores']);
|
||||
expect(
|
||||
config.generation.api.responseWrapper.mode,
|
||||
ResponseWrapperMode.externalGeneric,
|
||||
);
|
||||
expect(
|
||||
config.generation.api.responseWrapper.externalImport,
|
||||
'package:dba_network/dba_network.dart',
|
||||
);
|
||||
expect(
|
||||
config.generation.api.responseWrapper.externalClassName,
|
||||
'BaseResult',
|
||||
);
|
||||
expect(config.generation.api.cancelTokenSupport, isTrue);
|
||||
expect(config.generation.preset.name, 'koi_flutter');
|
||||
expect(config.generation.models.classPrefix, 'Koi');
|
||||
expect(config.generation.formatting.runDartFormat, isFalse);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:koi_swagger_parser/koi_swagger_parser.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group('default values and optional parameters', () {
|
||||
test('枚举默认值与 query 默认值生成合法 Dart 代码', () async {
|
||||
final tempDir = await Directory.systemTemp.createTemp(
|
||||
'koi_swagger_parser_defaults_',
|
||||
);
|
||||
addTearDown(() => tempDir.delete(recursive: true));
|
||||
|
||||
final specFile = File(p.join(tempDir.path, 'openapi.json'));
|
||||
await specFile.writeAsString(r'''
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "Defaults Sample",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"paths": {
|
||||
"/api/v1/samples": {
|
||||
"get": {
|
||||
"tags": ["samples"],
|
||||
"operationId": "list_samples_api_v1_samples_get",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "page_no",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"schema": {"type": "integer", "default": 1}
|
||||
},
|
||||
{
|
||||
"name": "tag",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"schema": {"type": "string"}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "ok",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {"$ref": "#/components/schemas/SampleResponse"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"SampleResponse": {
|
||||
"type": "object",
|
||||
"required": ["id"],
|
||||
"properties": {
|
||||
"id": {"type": "integer"},
|
||||
"conflict_policy": {
|
||||
"type": "string",
|
||||
"enum": ["exclusive", "mix"],
|
||||
"default": "exclusive"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
''');
|
||||
|
||||
final outputDir = p.join(tempDir.path, 'lib', 'src');
|
||||
final configFile = File(p.join(tempDir.path, 'koi_swagger_parser.yaml'));
|
||||
await configFile.writeAsString('''
|
||||
input:
|
||||
swagger_urls:
|
||||
- url: ${specFile.path}
|
||||
enabled: true
|
||||
|
||||
output:
|
||||
base_dir: $outputDir
|
||||
api_dir: ${p.join(outputDir, 'api')}
|
||||
models_dir: ${p.join(outputDir, 'api_models')}
|
||||
included_tags:
|
||||
- samples
|
||||
split_by_tags: true
|
||||
|
||||
generation:
|
||||
preset:
|
||||
name: koi_flutter
|
||||
api:
|
||||
enabled: true
|
||||
use_retrofit: true
|
||||
cancel_token_support: false
|
||||
client:
|
||||
class_name: SampleApiClient
|
||||
file_name: sample_api_client
|
||||
response_wrapper:
|
||||
mode: passthrough
|
||||
detect_standard_envelope: false
|
||||
success_data_field: data
|
||||
models:
|
||||
enabled: true
|
||||
class_prefix: Koi
|
||||
default_non_nullable_list_to_empty: true
|
||||
json_serializable:
|
||||
checked: true
|
||||
explicit_to_json: true
|
||||
include_if_null: false
|
||||
formatting:
|
||||
run_dart_format: false
|
||||
''');
|
||||
|
||||
await const KoiSwaggerParser().generate(configPath: configFile.path);
|
||||
|
||||
final apiFile = File(
|
||||
p.join(outputDir, 'api', 'v1', 'samples_api.dart'),
|
||||
).readAsStringSync();
|
||||
expect(apiFile, contains("@Query('page_no') int pageNo = 1"));
|
||||
expect(apiFile, contains("@Query('tag') String? tag"));
|
||||
|
||||
final resultFile = File(
|
||||
p.join(outputDir, 'api_models', 'result', 'sample_response.dart'),
|
||||
).readAsStringSync();
|
||||
expect(
|
||||
resultFile,
|
||||
contains('@Default(KoiSampleResponseConflictPolicy.exclusive)'),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
Vendored
+6803
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,109 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:koi_swagger_parser/koi_swagger_parser.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group('DBA fixture generation', () {
|
||||
test('正确生成 Koi 风格 API 与模型文件', () async {
|
||||
final tempDir = await Directory.systemTemp.createTemp(
|
||||
'koi_swagger_parser_dba_',
|
||||
);
|
||||
addTearDown(() => tempDir.delete(recursive: true));
|
||||
|
||||
final outputDir = p.join(tempDir.path, 'lib', 'src');
|
||||
final fixturePath = p.normalize(
|
||||
p.join(Directory.current.path, 'test', 'fixtures', 'dba_openapi.json'),
|
||||
);
|
||||
|
||||
final configFile = File(p.join(tempDir.path, 'koi_swagger_parser.yaml'));
|
||||
await configFile.writeAsString('''
|
||||
input:
|
||||
swagger_urls:
|
||||
- url: $fixturePath
|
||||
enabled: true
|
||||
|
||||
output:
|
||||
base_dir: $outputDir
|
||||
api_dir: ${p.join(outputDir, 'api')}
|
||||
models_dir: ${p.join(outputDir, 'api_models')}
|
||||
included_tags:
|
||||
- stores
|
||||
- materials
|
||||
split_by_tags: true
|
||||
|
||||
generation:
|
||||
api:
|
||||
enabled: true
|
||||
use_retrofit: true
|
||||
cancel_token_support: true
|
||||
client:
|
||||
class_name: DbaApiClient
|
||||
file_name: dba_api_client
|
||||
response_wrapper:
|
||||
mode: external_generic
|
||||
detect_standard_envelope: true
|
||||
success_data_field: data
|
||||
external_generic:
|
||||
import: package:dba_network/dba_network.dart
|
||||
class_name: BaseResult
|
||||
models:
|
||||
enabled: true
|
||||
class_prefix: Koi
|
||||
default_non_nullable_list_to_empty: true
|
||||
json_serializable:
|
||||
checked: true
|
||||
explicit_to_json: true
|
||||
include_if_null: false
|
||||
formatting:
|
||||
run_dart_format: false
|
||||
''');
|
||||
|
||||
final result = await const KoiSwaggerParser().generate(
|
||||
configPath: configFile.path,
|
||||
);
|
||||
|
||||
expect(result.operationsCount, greaterThan(0));
|
||||
expect(result.modelsCount, greaterThan(0));
|
||||
|
||||
final materialsApi = File(
|
||||
p.join(outputDir, 'api', 'v1', 'materials_api.dart'),
|
||||
).readAsStringSync();
|
||||
expect(
|
||||
materialsApi,
|
||||
contains('Future<BaseResult<KoiMaterialListResponse>> listMaterials'),
|
||||
);
|
||||
expect(materialsApi, contains("@Query('store_id') int? storeId"));
|
||||
expect(materialsApi, contains("@Query('tag') String? tag"));
|
||||
|
||||
final storesApi = File(
|
||||
p.join(outputDir, 'api', 'v1', 'stores_api.dart'),
|
||||
).readAsStringSync();
|
||||
expect(
|
||||
storesApi,
|
||||
contains('Future<BaseResult<List<KoiStoreResponse>>> listStores'),
|
||||
);
|
||||
expect(
|
||||
storesApi,
|
||||
contains('Future<BaseResult<Map<String, bool>>> deleteStore'),
|
||||
);
|
||||
|
||||
final storeWrite = File(
|
||||
p.join(outputDir, 'api_models', 'request', 'store_write.dart'),
|
||||
).readAsStringSync();
|
||||
expect(storeWrite, contains('String? address'));
|
||||
|
||||
final materialResponse = File(
|
||||
p.join(outputDir, 'api_models', 'result', 'material_response.dart'),
|
||||
).readAsStringSync();
|
||||
expect(materialResponse, contains("@JsonKey(name: 'store_id')"));
|
||||
expect(materialResponse, contains('required int storeId'));
|
||||
|
||||
final sharedError = File(
|
||||
p.join(outputDir, 'api_models', 'shared', 'http_validation_error.dart'),
|
||||
);
|
||||
expect(sharedError.existsSync(), isTrue);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:koi_swagger_parser/koi_swagger_parser.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group('multipart generation', () {
|
||||
test('按 preset 生成 Retrofit multipart 参数', () async {
|
||||
final tempDir = await Directory.systemTemp.createTemp(
|
||||
'koi_swagger_parser_multipart_',
|
||||
);
|
||||
addTearDown(() => tempDir.delete(recursive: true));
|
||||
|
||||
final specFile = File(p.join(tempDir.path, 'openapi.json'));
|
||||
await specFile.writeAsString(r'''
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "Multipart Sample",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"paths": {
|
||||
"/api/v1/uploads": {
|
||||
"post": {
|
||||
"tags": ["uploads"],
|
||||
"operationId": "create_upload_api_v1_uploads_post",
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"multipart/form-data": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": ["file", "meta"],
|
||||
"properties": {
|
||||
"file": {"type": "string", "format": "binary"},
|
||||
"files": {
|
||||
"type": "array",
|
||||
"items": {"type": "string", "format": "binary"}
|
||||
},
|
||||
"meta": {"$ref": "#/components/schemas/UploadMeta"},
|
||||
"note": {"type": "string"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "ok",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {"$ref": "#/components/schemas/UploadResponse"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"UploadMeta": {
|
||||
"type": "object",
|
||||
"required": ["album_id"],
|
||||
"properties": {
|
||||
"album_id": {"type": "integer"},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"}
|
||||
}
|
||||
}
|
||||
},
|
||||
"UploadResponse": {
|
||||
"type": "object",
|
||||
"required": ["id"],
|
||||
"properties": {
|
||||
"id": {"type": "integer"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
''');
|
||||
|
||||
final outputDir = p.join(tempDir.path, 'lib', 'src');
|
||||
final configFile = File(p.join(tempDir.path, 'koi_swagger_parser.yaml'));
|
||||
await configFile.writeAsString('''
|
||||
input:
|
||||
swagger_urls:
|
||||
- url: ${specFile.path}
|
||||
enabled: true
|
||||
|
||||
output:
|
||||
base_dir: $outputDir
|
||||
api_dir: ${p.join(outputDir, 'api')}
|
||||
models_dir: ${p.join(outputDir, 'api_models')}
|
||||
split_by_tags: true
|
||||
|
||||
generation:
|
||||
preset:
|
||||
name: koi_flutter
|
||||
api:
|
||||
enabled: true
|
||||
use_retrofit: true
|
||||
cancel_token_support: false
|
||||
client:
|
||||
class_name: SampleApiClient
|
||||
file_name: sample_api_client
|
||||
response_wrapper:
|
||||
mode: passthrough
|
||||
detect_standard_envelope: false
|
||||
success_data_field: data
|
||||
models:
|
||||
enabled: true
|
||||
class_prefix: Koi
|
||||
default_non_nullable_list_to_empty: true
|
||||
json_serializable:
|
||||
checked: true
|
||||
explicit_to_json: true
|
||||
include_if_null: false
|
||||
formatting:
|
||||
run_dart_format: false
|
||||
''');
|
||||
|
||||
await const KoiSwaggerParser().generate(configPath: configFile.path);
|
||||
|
||||
final apiFile = File(
|
||||
p.join(outputDir, 'api', 'v1', 'uploads_api.dart'),
|
||||
).readAsStringSync();
|
||||
expect(apiFile, contains('@MultiPart()'));
|
||||
expect(
|
||||
apiFile,
|
||||
contains("@Part(name: 'file') required MultipartFile file"),
|
||||
);
|
||||
expect(
|
||||
apiFile,
|
||||
contains("@Part(name: 'files') List<MultipartFile>? files"),
|
||||
);
|
||||
expect(
|
||||
apiFile,
|
||||
contains(
|
||||
"@Part(name: 'meta', contentType: 'application/json') required KoiUploadMeta meta",
|
||||
),
|
||||
);
|
||||
expect(apiFile, contains("@Part(name: 'note') String? note"));
|
||||
|
||||
final metaFile = File(
|
||||
p.join(outputDir, 'api_models', 'request', 'upload_meta.dart'),
|
||||
).readAsStringSync();
|
||||
expect(metaFile, contains('class KoiUploadMeta'));
|
||||
expect(metaFile, contains("@JsonKey(name: 'album_id')"));
|
||||
});
|
||||
});
|
||||
|
||||
group('discriminator union generation', () {
|
||||
test('生成 sealed wrapper 并在结果模型中引用', () async {
|
||||
final tempDir = await Directory.systemTemp.createTemp(
|
||||
'koi_swagger_parser_union_',
|
||||
);
|
||||
addTearDown(() => tempDir.delete(recursive: true));
|
||||
|
||||
final specFile = File(p.join(tempDir.path, 'openapi.json'));
|
||||
await specFile.writeAsString(r'''
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "Union Sample",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"paths": {
|
||||
"/api/v1/pets/{pet_id}": {
|
||||
"get": {
|
||||
"tags": ["pets"],
|
||||
"operationId": "get_pet_api_v1_pets__pet_id__get",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "pet_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {"type": "integer"}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "ok",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {"$ref": "#/components/schemas/PetResponse"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"PetResponse": {
|
||||
"type": "object",
|
||||
"required": ["pet"],
|
||||
"properties": {
|
||||
"pet": {"$ref": "#/components/schemas/Pet"}
|
||||
}
|
||||
},
|
||||
"Pet": {
|
||||
"oneOf": [
|
||||
{"$ref": "#/components/schemas/Cat"},
|
||||
{"$ref": "#/components/schemas/Dog"}
|
||||
],
|
||||
"discriminator": {
|
||||
"propertyName": "pet_type",
|
||||
"mapping": {
|
||||
"cat": "#/components/schemas/Cat",
|
||||
"dog": "#/components/schemas/Dog"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Cat": {
|
||||
"type": "object",
|
||||
"required": ["pet_type", "lives"],
|
||||
"properties": {
|
||||
"pet_type": {"type": "string", "enum": ["cat"]},
|
||||
"lives": {"type": "integer"}
|
||||
}
|
||||
},
|
||||
"Dog": {
|
||||
"type": "object",
|
||||
"required": ["pet_type", "breed"],
|
||||
"properties": {
|
||||
"pet_type": {"type": "string", "enum": ["dog"]},
|
||||
"breed": {"type": "string"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
''');
|
||||
|
||||
final outputDir = p.join(tempDir.path, 'lib', 'src');
|
||||
final configFile = File(p.join(tempDir.path, 'koi_swagger_parser.yaml'));
|
||||
await configFile.writeAsString('''
|
||||
input:
|
||||
swagger_urls:
|
||||
- url: ${specFile.path}
|
||||
enabled: true
|
||||
|
||||
output:
|
||||
base_dir: $outputDir
|
||||
api_dir: ${p.join(outputDir, 'api')}
|
||||
models_dir: ${p.join(outputDir, 'api_models')}
|
||||
split_by_tags: true
|
||||
|
||||
generation:
|
||||
api:
|
||||
enabled: true
|
||||
use_retrofit: true
|
||||
cancel_token_support: false
|
||||
client:
|
||||
class_name: SampleApiClient
|
||||
file_name: sample_api_client
|
||||
response_wrapper:
|
||||
mode: passthrough
|
||||
detect_standard_envelope: false
|
||||
success_data_field: data
|
||||
models:
|
||||
enabled: true
|
||||
class_prefix: Koi
|
||||
default_non_nullable_list_to_empty: true
|
||||
json_serializable:
|
||||
checked: true
|
||||
explicit_to_json: true
|
||||
include_if_null: false
|
||||
formatting:
|
||||
run_dart_format: false
|
||||
''');
|
||||
|
||||
await const KoiSwaggerParser().generate(configPath: configFile.path);
|
||||
|
||||
final unionFile = File(
|
||||
p.join(outputDir, 'api_models', 'result', 'pet.dart'),
|
||||
).readAsStringSync();
|
||||
expect(unionFile, contains('sealed class KoiPet'));
|
||||
expect(
|
||||
unionFile,
|
||||
contains('factory KoiPet.fromJson(Map<String, dynamic> json)'),
|
||||
);
|
||||
expect(unionFile, contains("case 'cat':"));
|
||||
expect(unionFile, contains('return KoiPetCat(KoiCat.fromJson(json));'));
|
||||
expect(unionFile, contains('final class KoiPetDog extends KoiPet'));
|
||||
|
||||
final responseFile = File(
|
||||
p.join(outputDir, 'api_models', 'result', 'pet_response.dart'),
|
||||
).readAsStringSync();
|
||||
expect(responseFile, contains('required KoiPet pet'));
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:koi_swagger_parser/koi_swagger_parser.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group('passthrough wrapper', () {
|
||||
test('保留 envelope 模型并生成 enum', () async {
|
||||
final tempDir = await Directory.systemTemp.createTemp(
|
||||
'koi_swagger_parser_passthrough_',
|
||||
);
|
||||
addTearDown(() => tempDir.delete(recursive: true));
|
||||
|
||||
final specFile = File(p.join(tempDir.path, 'openapi.json'));
|
||||
await specFile.writeAsString('''
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "Sample",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"paths": {
|
||||
"/api/v1/orders": {
|
||||
"get": {
|
||||
"tags": ["orders"],
|
||||
"operationId": "list_orders_api_v1_orders_get",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "ok",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"\$ref": "#/components/schemas/ApiResponse_OrderStatusResponse_"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"ApiResponse_OrderStatusResponse_": {
|
||||
"type": "object",
|
||||
"required": ["data"],
|
||||
"properties": {
|
||||
"code": {"type": "integer"},
|
||||
"message": {"type": "string"},
|
||||
"data": {"\$ref": "#/components/schemas/OrderStatusResponse"}
|
||||
}
|
||||
},
|
||||
"OrderStatusResponse": {
|
||||
"type": "object",
|
||||
"required": ["status"],
|
||||
"properties": {
|
||||
"status": {"\$ref": "#/components/schemas/OrderStatus"}
|
||||
}
|
||||
},
|
||||
"OrderStatus": {
|
||||
"type": "string",
|
||||
"enum": ["pending", "done"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
''');
|
||||
|
||||
final outputDir = p.join(tempDir.path, 'lib', 'src');
|
||||
final configFile = File(p.join(tempDir.path, 'koi_swagger_parser.yaml'));
|
||||
await configFile.writeAsString('''
|
||||
input:
|
||||
swagger_urls:
|
||||
- url: ${specFile.path}
|
||||
enabled: true
|
||||
|
||||
output:
|
||||
base_dir: $outputDir
|
||||
api_dir: ${p.join(outputDir, 'api')}
|
||||
models_dir: ${p.join(outputDir, 'api_models')}
|
||||
split_by_tags: true
|
||||
|
||||
generation:
|
||||
api:
|
||||
enabled: true
|
||||
use_retrofit: true
|
||||
cancel_token_support: false
|
||||
client:
|
||||
class_name: SampleApiClient
|
||||
file_name: sample_api_client
|
||||
response_wrapper:
|
||||
mode: passthrough
|
||||
detect_standard_envelope: true
|
||||
success_data_field: data
|
||||
models:
|
||||
enabled: true
|
||||
class_prefix: Koi
|
||||
default_non_nullable_list_to_empty: true
|
||||
json_serializable:
|
||||
checked: true
|
||||
explicit_to_json: true
|
||||
include_if_null: false
|
||||
formatting:
|
||||
run_dart_format: false
|
||||
''');
|
||||
|
||||
await const KoiSwaggerParser().generate(configPath: configFile.path);
|
||||
|
||||
final apiFile = File(
|
||||
p.join(outputDir, 'api', 'v1', 'orders_api.dart'),
|
||||
).readAsStringSync();
|
||||
expect(
|
||||
apiFile,
|
||||
contains('Future<KoiApiResponseOrderStatusResponse> listOrders'),
|
||||
);
|
||||
expect(apiFile, isNot(contains('BaseResult')));
|
||||
|
||||
final envelopeModel = File(
|
||||
p.join(
|
||||
outputDir,
|
||||
'api_models',
|
||||
'result',
|
||||
'api_response_order_status_response.dart',
|
||||
),
|
||||
).readAsStringSync();
|
||||
expect(
|
||||
envelopeModel,
|
||||
contains('class KoiApiResponseOrderStatusResponse'),
|
||||
);
|
||||
|
||||
final enumFile = File(
|
||||
p.join(outputDir, 'api_models', 'enums', 'order_status.dart'),
|
||||
).readAsStringSync();
|
||||
expect(enumFile, contains('enum KoiOrderStatus'));
|
||||
expect(enumFile, contains("@JsonValue('pending')"));
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import 'package:koi_swagger_parser/src/util/utils.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group('toSnakeCase', () {
|
||||
test('保持常见缩写合并后的文件名可读性', () {
|
||||
expect(toSnakeCase('IoTDeviceResponse'), 'iot_device_response');
|
||||
expect(
|
||||
toSnakeCase('ApiResponse_IoTDeviceListResponse_'),
|
||||
'api_response_iot_device_list_response',
|
||||
);
|
||||
expect(toSnakeCase('HTTPValidationError'), 'http_validation_error');
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user