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 {
  final Element enviedEl = element;
  if (enviedEl is! ClassElement) {
    throw InvalidGenerationSourceError(
      '`@Envied` can only be used on classes.',
      element: enviedEl,
    );
  }

  final Envied config = Envied(
    path: _buildOptions.override == true &&
            _buildOptions.path?.isNotEmpty == true
        ? _buildOptions.path
        : annotation.read('path').literalValue as String?,
    requireEnvFile:
        annotation.read('requireEnvFile').literalValue as bool? ?? false,
    name: annotation.read('name').literalValue as String?,
    obfuscate: annotation.read('obfuscate').literalValue as bool,
    allowOptionalFields:
        annotation.read('allowOptionalFields').literalValue as bool? ?? false,
    useConstantCase:
        annotation.read('useConstantCase').literalValue as bool? ?? false,
    interpolate: annotation.read('interpolate').literalValue as bool? ?? true,
    rawStrings: annotation.read('rawStrings').literalValue as bool? ?? false,
  );

  final Map<String, EnvVal> envs =
      await loadEnvs(config.path, (String error) {
    if (config.requireEnvFile) {
      throw InvalidGenerationSourceError(
        error,
        element: enviedEl,
      );
    }
  });

  final DartEmitter emitter = DartEmitter(useNullSafetySyntax: true);

  final Class cls = Class(
    (ClassBuilder classBuilder) => classBuilder
      ..modifier = ClassModifier.final$
      ..name = '_${config.name ?? enviedEl.name}'
      ..fields.addAll([
        for (FieldElement field in enviedEl.fields)
          if (_typeChecker(EnviedField).hasAnnotationOf(field))
            ..._generateFields(
              field: field,
              config: config,
              envs: envs,
            ),
      ]),
  );

  const String ignore = '// coverage:ignore-file\n'
      '// ignore_for_file: type=lint';

  return DartFormatter().format('$ignore\n${cls.accept(emitter)}');
}