generateForAnnotatedElement method

  1. @override
dynamic generateForAnnotatedElement(
  1. Element element,
  2. ConstantReader annotation,
  3. BuildStep buildStep
)
inherited

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
generateForAnnotatedElement(
    Element element, ConstantReader annotation, BuildStep buildStep) {
  if (element is ClassElement) {
    Set<PropertyInfo> propertySet = {};
    Set<ConvertInfo> convertSet = {};

    var className = element.name;
    var genMixin = '_${className}Mixin';

    String genClass = '';
    var superType = element.supertype;
    if (superType == null || superType.element.name == 'Object') {
      genClass = '_${className}Impl';
    }

    ///
    var annConverts = annotation.peek('converts');
    var converts = <String, String>{};
    if (annConverts != null) {
      var mapValues = annConverts.mapValue;
      for (var entry in mapValues.entries) {
        var key = entry.key;
        var value = entry.value;

        var propertyTypeObject = key!.toTypeValue()!;
        var typeElement =
            propertyTypeObject.getDisplayString(withNullability: false);
        var convertName = value!.toStringValue()!;
        converts[typeElement] = convertName;

        convertSet.add(ConvertInfo(
          type: propertyTypeObject,
          convert: convertName,
        ));
      }
    }

    /// property list
    String propertyString = '';
    String initString = '';
    String exportString = '';
    String validateString = '';
    String typesString = '';
    var properties = annotation.peek('properties');
    if (properties != null) {
      for (var item in properties.listValue) {
        /// property type
        late DartType propertyTypeObject;
        late String propertyType;
        var itemType = item.type;
        if (itemType is ParameterizedType) {
          if (itemType.typeArguments.isNotEmpty) {
            propertyTypeObject = itemType.typeArguments.first;
            propertyType =
                propertyTypeObject.getDisplayString(withNullability: true);
          }
        }

        /// property name
        var propertyName = item.getField('name')!.toStringValue()!;
        var propertyValue = "$modelRef['$propertyName']";

        var propertyInfo = PropertyInfo(
          propertyName: propertyName,
          propertyType: propertyTypeObject,
        );
        propertySet.add(propertyInfo);

        /// property default
        var defaultValue = item.getField('value');
        if (defaultValue != null && !defaultValue.isNull) {
          initString += '''
          if ($propertyValue == null) {
            $propertyValue = ${defaultValue.toStringValue()};
          }
          ''';
        }

        var setValue = propertyValue;
        if (propertyTypeObject.isDartCoreList) {
          /// castList
          propertyTypeObject as ParameterizedType;
          var listEleType = propertyTypeObject.typeArguments.first;
          if (listEleType is! DynamicType) {
            setValue = '''
            $setValue?.runtimeType.toString() == 'CastList<dynamic, $listEleType>'? $setValue: $setValue?.cast<$listEleType>()
            ''';
          }
        } else if (propertyTypeObject.isDartCoreMap) {
          /// castMap
          propertyTypeObject as ParameterizedType;
          var keyType = propertyTypeObject.typeArguments.first;
          var valueType = propertyTypeObject.typeArguments.last;
          if (keyType is! DynamicType || valueType is! DynamicType) {
            setValue = '''
            $setValue?.runtimeType.toString() == 'CastMap<dynamic, dynamic, $keyType, $valueType>'? $setValue: $setValue?.cast<$keyType, $valueType>()
            ''';
          }
        }

        var typeElement =
            propertyTypeObject.getDisplayString(withNullability: false);

        /// types
        typesString += '''
        map['$propertyName'] = $typeElement;
        ''';

        /// validate
        if (propertyTypeObject is! DynamicType) {
          var convertCode = "assert($propertyName is $propertyType, '$propertyName is not $propertyType');";

          var convert = converts[typeElement] ??
              defaultConvert(typeElement, propertyInfo);
          if (convert != null) {
            convertCode = "$propertyValue = $convert('$propertyName', $propertyName);";
          } else {
            var str = customConvert(propertyInfo);
            if (str != null) convertCode = '$propertyValue = $str;';
          }

          validateString += '''
            var $propertyName = $propertyValue;
            if ($propertyName != null) {
              $convertCode
            }
            ''';
        }

        propertyString += '''
          $propertyType get $propertyName => $setValue;

          set $propertyName($propertyType $propertyName) => $propertyValue = $propertyName;

        ''';
        exportString += "map['$propertyName'] = $propertyValue;";
      }
    }

    return '''
${genSupperClass(genClass, genMixin, propertySet, convertSet)}
mixin $genMixin on $superClass {

${propertyString}
$customCode


${genDefault(initCode, initString, propertySet, convertSet)}

${genValidate(validateString, propertySet, convertSet)}

${genTypes(typesString, propertySet, convertSet)}

${genExport(exportString, propertySet, convertSet)}
}

  ''';
  }
}