blob: 01efa09c8f5f39010d4806cede9552320379309f [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:path/path.dart' as p;
import 'package:pigeon/pigeon.dart';
enum GeneratorLanguages {
cpp,
java,
kotlin,
objc,
swift,
}
// A map of pigeons/ files to the languages that they can't yet be generated
// for due to limitations of that generator.
const Map<String, Set<GeneratorLanguages>> _unsupportedFiles =
<String, Set<GeneratorLanguages>>{
'enum_args': <GeneratorLanguages>{GeneratorLanguages.cpp},
};
String _snakeToPascalCase(String snake) {
final List<String> parts = snake.split('_');
return parts
.map((String part) =>
part.substring(0, 1).toUpperCase() + part.substring(1))
.join();
}
// Remaps some file names for Java output, since the filename on Java will be
// the name of the generated top-level class. In some cases this is necessary
// (e.g., "list", which collides with the Java List class in tests), and in
// others it is just preserving previous behavior from the earlier Bash version
// of the generation to minimize churn during the migration.
// TODO(stuartmorgan): Remove the need for this when addressing
// https://github.com/flutter/flutter/issues/115168.
String _javaFilenameForName(String inputName) {
const Map<String, String> specialCases = <String, String>{
'android_unittests': 'Pigeon',
'host2flutter': 'Host2Flutter',
'list': 'PigeonList',
'message': 'MessagePigeon',
'voidflutter': 'VoidFlutter',
'voidhost': 'VoidHost',
};
return specialCases[inputName] ?? _snakeToPascalCase(inputName);
}
Future<int> generatePigeons({required String baseDir}) async {
// TODO(stuartmorgan): Make this dynamic rather than hard-coded. Or eliminate
// it entirely; see https://github.com/flutter/flutter/issues/115169.
const List<String> inputs = <String>[
'android_unittests',
'async_handlers',
'background_platform_channels',
'core_tests',
'enum_args',
'enum',
'host2flutter',
'java_double_host_api',
'list',
'message',
'multiple_arity',
'non_null_fields',
'null_fields',
'nullable_returns',
'primitive',
'void_arg_flutter',
'void_arg_host',
'voidflutter',
'voidhost',
];
final String outputBase = p.join(baseDir, 'platform_tests', 'test_plugin');
final String alternateOutputBase =
p.join(baseDir, 'platform_tests', 'alternate_language_test_plugin');
final String sharedDartOutputBase =
p.join(baseDir, 'platform_tests', 'shared_test_plugin_code');
for (final String input in inputs) {
final String pascalCaseName = _snakeToPascalCase(input);
final Set<GeneratorLanguages> skipLanguages =
_unsupportedFiles[input] ?? <GeneratorLanguages>{};
// Generate the default language test plugin output.
int generateCode = await runPigeon(
input: './pigeons/$input.dart',
dartOut: '$sharedDartOutputBase/lib/src/generated/$input.gen.dart',
// Android
kotlinOut: skipLanguages.contains(GeneratorLanguages.kotlin)
? null
: '$outputBase/android/src/main/kotlin/com/example/test_plugin/$pascalCaseName.gen.kt',
kotlinPackage: 'com.example.test_plugin',
// iOS
swiftOut: skipLanguages.contains(GeneratorLanguages.swift)
? null
: '$outputBase/ios/Classes/$pascalCaseName.gen.swift',
// Windows
cppHeaderOut: skipLanguages.contains(GeneratorLanguages.cpp)
? null
: '$outputBase/windows/pigeon/$input.gen.h',
cppSourceOut: skipLanguages.contains(GeneratorLanguages.cpp)
? null
: '$outputBase/windows/pigeon/$input.gen.cpp',
cppNamespace: '${input}_pigeontest',
);
if (generateCode != 0) {
return generateCode;
}
// macOS has to be run as a separate generation, since currently Pigeon
// doesn't have a way to output separate macOS and iOS Swift output in a
// single invocation.
generateCode = await runPigeon(
input: './pigeons/$input.dart',
swiftOut: skipLanguages.contains(GeneratorLanguages.swift)
? null
: '$outputBase/macos/Classes/$pascalCaseName.gen.swift',
);
if (generateCode != 0) {
return generateCode;
}
// Generate the alternate language test plugin output.
generateCode = await runPigeon(
input: './pigeons/$input.dart',
// Android
// This doesn't use the '.gen' suffix since Java has strict file naming
// rules.
javaOut: skipLanguages.contains(GeneratorLanguages.java)
? null
: '$alternateOutputBase/android/src/main/java/com/example/'
'alternate_language_test_plugin/${_javaFilenameForName(input)}.java',
javaPackage: 'com.example.alternate_language_test_plugin',
// iOS
objcHeaderOut: skipLanguages.contains(GeneratorLanguages.objc)
? null
: '$alternateOutputBase/ios/Classes/$pascalCaseName.gen.h',
objcSourceOut: skipLanguages.contains(GeneratorLanguages.objc)
? null
: '$alternateOutputBase/ios/Classes/$pascalCaseName.gen.m',
);
if (generateCode != 0) {
return generateCode;
}
}
return 0;
}
Future<int> runPigeon({
required String input,
String? kotlinOut,
String? kotlinPackage,
String? swiftOut,
String? cppHeaderOut,
String? cppSourceOut,
String? cppNamespace,
String? dartOut,
String? dartTestOut,
String? javaOut,
String? javaPackage,
String? objcHeaderOut,
String? objcSourceOut,
}) async {
return Pigeon.runWithOptions(PigeonOptions(
input: input,
copyrightHeader: './copyright_header.txt',
dartOut: dartOut,
dartTestOut: dartTestOut,
dartOptions: const DartOptions(),
cppHeaderOut: cppHeaderOut,
cppSourceOut: cppSourceOut,
cppOptions: CppOptions(namespace: cppNamespace),
javaOut: javaOut,
javaOptions: JavaOptions(package: javaPackage),
kotlinOut: kotlinOut,
kotlinOptions: KotlinOptions(package: kotlinPackage),
objcHeaderOut: objcHeaderOut,
objcSourceOut: objcSourceOut,
objcOptions: const ObjcOptions(),
swiftOut: swiftOut,
swiftOptions: const SwiftOptions(),
));
}