blob: d4ac85f6e34aacfd5b26fba08ac4f3e699b21834 [file] [log] [blame] [edit]
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. 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:code_builder/code_builder.dart';
import '../generation_options.dart';
import '../parameterized_message.dart';
import 'generation.dart';
class MethodGeneration {
final GenerationOptions options;
final String? context;
final List<ParameterizedMessage> messages;
final Map<String, String> emptyFiles;
MethodGeneration(this.options, this.context, this.messages, this.emptyFiles);
Method? generateMessageCall(int index, ParameterizedMessage message) {
if (!message.nameIsDartConform) {
return null;
}
final arguments =
message.placeholders.map((placeholder) => placeholder.name).join(', ');
final indexStr = options.indexType == IndexType.enumerate
? '${enumName(context)}.${message.name}.index'
: index.toString();
final body =
'_currentMessages.generateStringAtIndex($indexStr, [$arguments])';
final methodType = message.placeholders.isEmpty ? MethodType.getter : null;
return Method(
(mb) => mb
..type = methodType
..name = message.name
..lambda = true
..returns = const Reference('String')
..requiredParameters.addAll(
message.placeholders.map(
(placeholder) => Parameter(
(pb) => pb
..type = Reference(placeholder.type ?? 'String')
..name = placeholder.name,
),
),
)
..body = Code(body),
);
}
List<Method> generate() {
Iterable<Method> messageCalls;
if (options.messageCalls) {
messageCalls = List.generate(
messages.length,
(i) => generateMessageCall(i, messages[i]),
).whereType<Method>();
} else {
messageCalls = [];
}
final loadLocale = Method(
(mb) {
final loading = switch (options.deserialization) {
DeserializationType.web => '''
final data = await _assetLoader(dataFile);
final messageList = MessageListJson.fromString(data, _pluralSelector);''',
};
final loadLibraries = emptyFiles.entries
.map(
(e) => '''
if (locale == '${e.key}') {
await ${e.value}.loadLibrary();
}
''',
)
.join(' else ');
mb
..name = 'loadLocale'
..requiredParameters.add(Parameter(
(p0) => p0
..name = 'locale'
..type = const Reference('String'),
))
..modifier = MethodModifier.async
..body = Code('''
if (!_messages.containsKey(locale)) {
final info = _dataFiles[locale];
final dataFile = info?.\$1;
if (dataFile == null) {
throw ArgumentError('Locale \$locale is not in \$knownLocales');
}
$loadLibraries
$loading
if (messageList.preamble.hash != info?.\$2) {
throw ArgumentError(\'\'\'
Messages file for locale \$locale has different hash "\${messageList.preamble.hash}" than generated code "\${info?.\$2}".\'\'\');
}
_messages[locale] = messageList;
}
_currentLocale = locale;
''')
..returns = const Reference('Future<void>');
},
);
final loadAllLocales = Method(
(mb) {
mb
..name = 'loadAllLocales'
..returns = const Reference('Future<void>')
..modifier = MethodModifier.async
..body = const Code('''
for (final locale in knownLocales) {
await loadLocale(locale);
}
''');
},
);
final getKnownLocales = Method(
(mb) => mb
..name = 'knownLocales'
..type = MethodType.getter
..lambda = true
..static = true
..body = const Code('_dataFiles.keys')
..returns = const Reference('Iterable<String>'),
);
final getCurrentMessages = Method(
(mb) => mb
..name = '_currentMessages'
..type = MethodType.getter
..lambda = true
..body = const Code('_messages[currentLocale]!')
..returns = const Reference('MessageList'),
);
final getCurrentLocale = Method(
(mb) => mb
..name = 'currentLocale'
..type = MethodType.getter
..lambda = true
..body = const Code('_currentLocale')
..returns = const Reference('String'),
);
final getMessagebyId = Method((mb) => mb
..name = 'getById'
..requiredParameters.addAll([
Parameter(
(pb) => pb
..name = 'id'
..type = const Reference('String'),
)
])
..optionalParameters.add(Parameter(
(pb) => pb
..name = 'args'
..type = const Reference('List<dynamic>')
..defaultTo = const Code('const []'),
))
..body =
const Code('return _currentMessages.generateStringAtId(id, args);')
..returns = const Reference('String'));
final findByEnum = Method((mb) => mb
..name = 'getByEnum'
..annotations
.add(const CodeExpression(Code("pragma('dart2js:noInline')")))
..requiredParameters.add(Parameter(
(pb) => pb
..name = 'val'
..type = Reference(enumName(context)),
))
..optionalParameters.add(Parameter(
(pb) => pb
..name = 'args'
..type = const Reference('List<dynamic>')
..defaultTo = const Code('const []'),
))
..body =
const Code('_currentMessages.generateStringAtIndex(val.index, args)')
..lambda = true
..returns = const Reference('String'));
return [
getCurrentLocale,
getCurrentMessages,
if (options.findById) getMessagebyId,
if (options.indexType == IndexType.enumerate) findByEnum,
getKnownLocales,
loadLocale,
loadAllLocales,
...messageCalls,
];
}
}