generateForAnnotatedElement method

  1. @override
Future<String> generateForAnnotatedElement(
  1. Element element,
  2. ConstantReader annotation,
  3. BuildStep buildStep
)

Implement to return source code to generate for element.

This method is invoked based on finding elements annotated with an instance of T. The annotation is provided as a ConstantReader.

Supported return values include a single String or multiple String instances within an Iterable or Stream. It is also valid to return a Future of String, Iterable, or Stream.

Implementations should return null when no content is generated. Empty or whitespace-only String instances are also ignored.

Implementation

@override
Future<String> generateForAnnotatedElement(
  Element element,
  ConstantReader annotation,
  BuildStep buildStep,
) async {
  if (element.isPrivate) {
    throw InvalidGenerationSourceError(
      'Widgetbook annotations cannot be applied to private elements',
      element: element,
    );
  }

  final locales = <String>[];

  final node = await buildStep.resolver.astNodeFor(element);
  if (node != null) {
    final entities = node.childEntities.toList();
    if (entities[0] is SimpleIdentifier &&
        entities[1] is Token &&
        entities[2] is ListLiteral) {
      final listLiteral = entities[2] as ListLiteral;

      // TODO this is likely the most flaky code that has ever been written
      // check the following cases
      // - Locale('en')
      // - const Locale('en')
      // - Locale('en', 'US')
      // - const Locale('en', 'US')
      // - additional methods, e.g. Locale.fromString('...') and similar stuff
      // Maybe it's best to just use a regex
      final localeDefinitions = listLiteral.elements.toList();
      for (final localeDefinition in localeDefinitions) {
        // If expression starts WITHOUT const e.g. Local('en'), this will
        // be called
        if (localeDefinition is MethodInvocation) {
          final stringLiteral =
              localeDefinition.argumentList.arguments.first as StringLiteral;
          final value = stringLiteral.stringValue!;
          locales.add(value);
        }
        // If expression starts WITH const e.g. const Local('en'), this will
        // be called
        if (localeDefinition is InstanceCreationExpression) {
          final stringLiteral =
              localeDefinition.argumentList.arguments.first as StringLiteral;
          final value = stringLiteral.stringValue!;
          locales.add(value);
        }
      }
    }
  }

  final data = WidgetbookLocalesData(
    name: element.name!,
    importStatement: element.importStatement,
    dependencies: [],
    locales: locales,
  );

  return [data].toJson();
}