| // 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, | |
| ]; | |
| } | |
| } |