Files
koi_swagger_parser/tool/verify_generated_package.dart
mr.koi 454e6c51d7 Release 0.2.0
Complete OpenAPI 3.0/3.1 generation, diagnostics, lifecycle safety, enum and naming mappings, bilingual documentation, examples, and pub.dev release validation.
2026-07-31 16:47:39 +08:00

178 lines
5.2 KiB
Dart

import 'dart:io';
import 'package:koi_swagger_parser/koi_swagger_parser.dart';
import 'package:path/path.dart' as p;
Future<void> main(List<String> arguments) async {
final keep = arguments.contains('--keep');
final root = Directory.current.path;
final fixture = p.join(root, 'test', 'fixtures', 'e2e_openapi.json');
final tempDirectory = await Directory.systemTemp.createTemp(
'koi_swagger_parser_generated_package_',
);
try {
await _writePackageFiles(tempDirectory, fixture);
await _run(Platform.resolvedExecutable, const <String>[
'pub',
'get',
], workingDirectory: tempDirectory.path);
final configPath = p.join(tempDirectory.path, 'koi_swagger_parser.yaml');
final result = await const KoiSwaggerParser().generate(
configPath: configPath,
);
stdout.writeln(
'Generated ${result.generatedFiles.length} files '
'(${result.modelsCount} models, ${result.operationsCount} operations).',
);
await _run(Platform.resolvedExecutable, const <String>[
'analyze',
], workingDirectory: tempDirectory.path);
await _run(Platform.resolvedExecutable, const <String>[
'test',
], workingDirectory: tempDirectory.path);
stdout.writeln('Generated package verification passed.');
} finally {
if (keep) {
stdout.writeln('Kept generated package at ${tempDirectory.path}');
} else if (tempDirectory.existsSync()) {
await tempDirectory.delete(recursive: true);
}
}
}
Future<void> _writePackageFiles(Directory directory, String fixture) async {
await File(p.join(directory.path, 'pubspec.yaml')).writeAsString(r'''
name: koi_generated_e2e
publish_to: none
environment:
sdk: ^3.11.0
dependencies:
dio: ^5.9.0
freezed_annotation: ^3.1.0
json_annotation: ^4.12.0
retrofit: ^4.9.0
dev_dependencies:
build_runner: ^2.10.0
freezed: ^3.2.0
json_serializable: ^6.11.0
retrofit_generator: ^10.2.0
test: ^1.26.0
''');
final output = p.join(directory.path, 'lib', 'src');
await File(p.join(directory.path, 'koi_swagger_parser.yaml')).writeAsString(
'''
input:
swagger_urls:
- url: $fixture
output:
base_dir: $output
api_dir: ${p.join(output, 'api')}
models_dir: ${p.join(output, 'models')}
generation:
api:
response_mode: http_response
binary_response_mode: bytes
cancel_token_support: true
response_wrapper:
mode: passthrough
models:
class_prefix: Koi
enum_unknown_fallback: true
formatting:
run_dart_format: true
run_build_runner: true
build_runner_mode: build
delete_conflicting_outputs: true
''',
);
final testDirectory = Directory(p.join(directory.path, 'test'));
await testDirectory.create(recursive: true);
await File(
p.join(testDirectory.path, 'generated_smoke_test.dart'),
).writeAsString(r'''
import 'package:koi_generated_e2e/src/api/v1/accounts_api.dart';
import 'package:koi_generated_e2e/src/models/request/account_request.dart';
import 'package:koi_generated_e2e/src/models/result/account_response.dart';
import 'package:koi_generated_e2e/src/models/result/search_criteria.dart';
import 'package:koi_generated_e2e/src/models/result/string_or_integer.dart';
import 'package:koi_generated_e2e/src/models/shared/flexible_settings.dart';
import 'package:test/test.dart';
void main() {
test('additional properties round-trip at the object root', () {
const settings = KoiFlexibleSettings(
theme: 'dark',
additionalProperties: <String, int>{'retries': 3},
);
expect(settings.toJson(), <String, dynamic>{
'theme': 'dark',
'retries': 3,
});
final decoded = KoiFlexibleSettings.fromJson(<String, dynamic>{
'theme': 'light',
'retries': 5,
});
expect(decoded.theme, 'light');
expect(decoded.additionalProperties, <String, int>{'retries': 5});
});
test('directional and generic union models are usable', () {
const request = KoiAccountRequest(
secret: 'long-secret',
displayName: null,
settings: KoiFlexibleSettings(theme: 'dark'),
);
expect(request.secret, 'long-secret');
const response = KoiAccountResponse(
id: 1,
displayName: null,
settings: KoiFlexibleSettings(theme: 'dark'),
);
expect(response.id, 1);
final primitive = KoiStringOrInteger.fromJson('text');
expect(primitive, isA<KoiStringOrIntegerString1>());
final criteria = KoiSearchCriteria.fromJson(<String, dynamic>{
'name': 'Koi',
'id': 7,
});
expect(criteria, isA<KoiSearchCriteriaAnyOf>());
expect((criteria as KoiSearchCriteriaAnyOf).matches, hasLength(2));
});
test('Retrofit transport adapter has a concrete generated implementation', () {
expect(AccountsApi, isNotNull);
});
}
''');
}
Future<void> _run(
String executable,
List<String> arguments, {
required String workingDirectory,
}) async {
stdout.writeln('> $executable ${arguments.join(' ')}');
final process = await Process.start(
executable,
arguments,
workingDirectory: workingDirectory,
mode: ProcessStartMode.inheritStdio,
);
final exitCode = await process.exitCode;
if (exitCode != 0) {
throw ProcessException(
executable,
arguments,
'Command failed with exit code $exitCode.',
exitCode,
);
}
}