Complete OpenAPI 3.0/3.1 generation, diagnostics, lifecycle safety, enum and naming mappings, bilingual documentation, examples, and pub.dev release validation.
178 lines
5.2 KiB
Dart
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,
|
|
);
|
|
}
|
|
}
|