import 'dart:io'; import 'package:koi_swagger_parser/koi_swagger_parser.dart'; import 'package:path/path.dart' as p; Future main(List 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 [ '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 [ 'analyze', ], workingDirectory: tempDirectory.path); await _run(Platform.resolvedExecutable, const [ '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 _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: {'retries': 3}, ); expect(settings.toJson(), { 'theme': 'dark', 'retries': 3, }); final decoded = KoiFlexibleSettings.fromJson({ 'theme': 'light', 'retries': 5, }); expect(decoded.theme, 'light'); expect(decoded.additionalProperties, {'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()); final criteria = KoiSearchCriteria.fromJson({ 'name': 'Koi', 'id': 7, }); expect(criteria, isA()); expect((criteria as KoiSearchCriteriaAnyOf).matches, hasLength(2)); }); test('Retrofit transport adapter has a concrete generated implementation', () { expect(AccountsApi, isNotNull); }); } '''); } Future _run( String executable, List 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, ); } }