generateDefaultsProvider static method

String generateDefaultsProvider(
  1. Element element,
  2. bool createBaseClass
)

Implementation

static String generateDefaultsProvider(
    Element element, bool createBaseClass) {
  if (element is EnumElement) return '';
  final classElement = element.asClassElement();
  final superTypeElement = classElement.supertype!.element;

  final superTypeAnnotation = TypeChecker.fromRuntime(DefaultsProvider)
      .firstAnnotationOf(superTypeElement);

  final superClassConstructorFields = _getFieldDescriptors(superTypeElement,
      'Object' != superTypeElement.displayName);
  final superClassHasDefaultsProvider = superTypeAnnotation != null &&
      superClassConstructorFields.isNotEmpty;

  final className = classElement.name;

  final constructorFields = _getFieldDescriptors(classElement, true);
  final parameterFieldBuffer = StringBuffer();
  final constructorFieldBuffer = StringBuffer();

  // let's get all the constructors which cover all non-nullable final fields
  final missingFields = <String>{};
  final constructors = classElement.getConstructorsMatchingFields(
      fieldDescriptors: constructorFields,
      allowMissingFields: true,
      missingFields: missingFields);
  // let's just pick the first of the valid constructors
  final classConstructor = constructors.isEmpty
      ? throw InvalidGenerationSourceError(
          'Cannot generate defaults provider for class ${classElement.name} because '
          'it is missing a constructor that covers all final properties.\n'
          '\tMissing fields: $missingFields')
      : constructors.first;
  _buildConstructorBuffer(classConstructor, [...constructorFields],
      constructorFieldBuffer, createBaseClass);

  for (var field in constructorFields) {
    final fieldTypeName = field.fieldElementTypeName == 'dynamic'
        ? field.fieldElementTypeName
        : '${field.fieldElementTypeName}?';
    parameterFieldBuffer.writeln('$fieldTypeName ${field.displayName},');
  }

  final propertyFields = _getFieldDescriptors(classElement, false);
  final propertyFieldBuffer = StringBuffer();

  for (var field in constructorFields) {
    if (!superClassHasDefaultsProvider ||
        propertyFields
            .any((element) => element.displayName == field.displayName)) {
      var gen =
          FieldCodeGenerator.fromFieldDescriptor(field, createBaseClass);
      propertyFieldBuffer.writeln(
          '''${field.fieldElementTypeName} get ${field.displayName} ${createBaseClass && gen.defaultExpression == '' ? '' : ' => ${gen.defaultExpression}'};''');
    } else {
      propertyFieldBuffer.writeln(
          '''${field.fieldElementTypeName} get ${field.displayName} => _superDefaultsProvider.${field.displayName};''');
    }
  }

  final providerClassName =
      '\$${className}DefaultsProvider${createBaseClass ? 'Base' : ''}';

  final superDeclaration = superClassHasDefaultsProvider
      ? '''static const _superDefaultsProvider = \$${superTypeElement.name}DefaultsProvider();'''
      : '';

  final constructorName = classConstructor.name.isNotEmpty
      ? '$className.${classConstructor.name}'
      : className;

  final constructor = classElement.isAbstract
      ? ''
      : '''
      $className createWithDefaults( ${parameterFieldBuffer.isEmpty ? '' : '{ $parameterFieldBuffer }'} ) {
        return $constructorName(
          $constructorFieldBuffer
        );
      }
  ''';

  return '''

    ${createBaseClass ? 'abstract' : ''} class $providerClassName {
      const $providerClassName();

      $superDeclaration

      $constructor

      $propertyFieldBuffer

    }

  ''';
}