generateForAnnotatedElement method

  1. @override
FutureOr<String> generateForAnnotatedElement(
  1. Element element,
  2. ConstantReader annotation,
  3. 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
FutureOr<String> generateForAnnotatedElement(
    Element element, ConstantReader annotation, BuildStep _) {
  if (!(element is ClassElement)) {
    throw Exception('Only annotate mixins with `@SumType()`.');
  }
  try {
    final clazz = ClassModel(element, annotation);
    if (clazz.fields.isEmpty) {
      throw CodegenException('no alternatives defined for ${clazz.mixinName}');
    }
    const tyArg = r'__T$';
    final otherwise = clazz.fieldNames.contains('otherwise') ? r'otherwise__$' : 'otherwise';
    final toStringMethod = '''
      @override
      String toString() {
        final __x\$ = iswitch(${clazz.toStringSwitch});
        return '${clazz.mixinName}.\${__x\$}';
      }
    ''';
    final code = '''
      /// This data class has been generated from ${clazz.mixinName}
      abstract class ${clazz.factoryName} {
        ${clazz.factoryMethods}
      }
      abstract class ${clazz.baseClassName}${clazz.typeArgsWithParens} {
        const ${clazz.baseClassName}();
        ${clazz.getterDecls}
        $tyArg iswitch<$tyArg>({
          ${clazz.switchParams(tyArg, SwitchMode.Required)}
        });
        $tyArg iswitcho<$tyArg>({
          ${clazz.switchParams(tyArg, SwitchMode.Optional)},
          ${clazz.config.nnbd ? 'required' : '@required'} $tyArg Function() $otherwise,
        });
      }

      @immutable
      class ${clazz.className}${clazz.typeArgsWithParens}
          extends ${clazz.baseClassName}${clazz.typeArgsWithParens}
          with ${clazz.mixinName}${clazz.typeArgsWithParens}
      {
        ${clazz.fieldDecls}

        ${clazz.getterImpls}

        const ${clazz.className}({
          ${clazz.constructorParams}
        }) : ${clazz.constructorInitializers};

        @override
        $tyArg iswitch<$tyArg>({
          ${clazz.switchParams(tyArg, SwitchMode.Required)},
        }) {
          ${clazz.iswitchBody}
        }

        @override
        $tyArg iswitcho<$tyArg>({
          ${clazz.switchParams(tyArg, SwitchMode.Optional)},
          ${clazz.config.nnbd ? 'required' : '@required'} $tyArg Function() $otherwise,
        }) {
          return iswitch(
            ${clazz.iswitchArgsFromOtherwise(otherwise)}
          );
        }

        ${clazz.config.genEqHashCode ? eqImpl(clazz.className, clazz.internalFieldNames) : ''}

        ${clazz.config.genEqHashCode ? hashCodeImpl(clazz.internalFieldNames) : ''}

        ${clazz.config.genToString ? toStringMethod : ''}
      }
      ''';
    //print(code);
    return code;
  } on CodegenException catch (e) {
    e.generatorName = 'SumType';
    rethrow;
  }
}