getBestConstructorsFor method

List<ConstructorReflection<O>> getBestConstructorsFor({
  1. Iterable<String> requiredParameters = const <String>[],
  2. Iterable<String> optionalParameters = const <String>[],
  3. Iterable<String> nullableParameters = const <String>[],
  4. Iterable<String> presentParameters = const <String>[],
  5. bool allowEmptyConstructors = true,
  6. bool allowOptionalOnlyConstructors = true,
  7. bool jsonName = false,
})

Returns a List of the best ConstructorReflection for requiredParameters, optionalParameters, nullableParameters and presentParameters.

Implementation

List<ConstructorReflection<O>> getBestConstructorsFor({
  Iterable<String> requiredParameters = const <String>[],
  Iterable<String> optionalParameters = const <String>[],
  Iterable<String> nullableParameters = const <String>[],
  Iterable<String> presentParameters = const <String>[],
  bool allowEmptyConstructors = true,
  bool allowOptionalOnlyConstructors = true,
  bool jsonName = false,
}) {
  if (nullableParameters is! List && nullableParameters is! Set) {
    nullableParameters = nullableParameters.toList(growable: false);
  }

  var constructors = allConstructors().toList();
  if (constructors.isEmpty) return <ConstructorReflection<O>>[];

  if (!allowEmptyConstructors) {
    var emptyConstructors = constructors
        .where((c) => c.parametersLength == 0)
        .toList();

    if (emptyConstructors.isNotEmpty) {
      constructors = constructors
          .where((c) => !emptyConstructors.contains(c))
          .toList();
    }

    if (constructors.isEmpty) return <ConstructorReflection<O>>[];
  }

  if (!allowOptionalOnlyConstructors) {
    var optionalOnlyConstructors = constructors
        .where(
          (c) =>
              (c.normalParameters.isEmpty &&
              c.optionalParameters.none((c) => c.required) &&
              c.namedParameters.values.none((c) => c.required)),
        )
        .toList();

    if (optionalOnlyConstructors.isNotEmpty) {
      constructors = constructors
          .where((c) => !optionalOnlyConstructors.contains(c))
          .toList();
    }

    if (constructors.isEmpty) return <ConstructorReflection<O>>[];
  }

  var presentParametersResolved = presentParameters.toSet();

  String paramNameResolver(ParameterReflection p, String name) {
    var f = field(p.name);
    var alias = f?.jsonFieldAliasAnnotations.alias;
    return alias ?? name;
  }

  var paramNameResolverJson = jsonName ? paramNameResolver : null;

  var invalidConstructors = constructors.where((c) {
    var paramsRequired = c
        .parametersNamesWhere(
          (p) => p.required && !p.nullable,
          jsonName: jsonName,
          nameResolver: paramNameResolverJson,
        )
        .toList();
    return _elementsInCount(
          presentParameters,
          paramsRequired,
          _nameNormalizer,
        ) <
        paramsRequired.length;
  }).toList();

  if (invalidConstructors.isNotEmpty) {
    constructors = constructors
        .where((c) => !invalidConstructors.contains(c))
        .toList();

    if (constructors.isEmpty) return <ConstructorReflection<O>>[];
  }

  if (requiredParameters.isNotEmpty) {
    var constructorsWithRequired = constructors.where((c) {
      var paramsAll = c
          .parametersNamesWhere(
            (p) => true,
            jsonName: jsonName,
            nameResolver: paramNameResolverJson,
          )
          .toList();
      return _elementsInCount<String>(
            requiredParameters,
            paramsAll,
            _nameNormalizer,
          ) ==
          requiredParameters.length;
    }).toList();

    constructors = constructorsWithRequired;
    if (constructors.isEmpty) return <ConstructorReflection<O>>[];

    presentParametersResolved.addAll(requiredParameters);
  }

  if (nullableParameters.isNotEmpty) {
    var constructorsWithNullables = constructors.where((c) {
      var paramsNullable = c
          .parametersNamesWhere(
            (p) => p.nullable || !p.required,
            jsonName: jsonName,
            nameResolver: paramNameResolverJson,
          )
          .toList();
      return _elementsInCount(
            nullableParameters,
            paramsNullable,
            _nameNormalizer,
          ) ==
          nullableParameters.length;
    }).toList();

    constructors = constructorsWithNullables;
    if (constructors.isEmpty) return <ConstructorReflection<O>>[];

    presentParametersResolved.addAll(nullableParameters);
  }

  presentParametersResolved.addAll(optionalParameters);

  constructors = constructors.where((c) {
    var paramsRequired = c
        .parametersNamesWhere(
          (p) => p.required,
          jsonName: jsonName,
          nameResolver: paramNameResolverJson,
        )
        .toList();
    return _elementsInCount<String>(
          presentParametersResolved,
          paramsRequired,
          _nameNormalizer,
        ) ==
        paramsRequired.length;
  }).toList();

  if (constructors.length <= 1) {
    return constructors;
  }

  var constructorsInfo = Map.fromEntries(
    constructors.map((c) {
      var requiredCount = c
          .getParametersByNames(requiredParameters, jsonName: jsonName)
          .length;
      var optionalCount = c
          .getParametersByNames(optionalParameters, jsonName: jsonName)
          .length;
      return MapEntry(c, [requiredCount, optionalCount]);
    }),
  );

  constructors.sort((c1, c2) {
    var i1 = constructorsInfo[c1]!;
    var i2 = constructorsInfo[c2]!;

    var req1 = i1[0];
    var req2 = i2[0];

    var cmp = req2.compareTo(req1);
    if (cmp == 0) {
      var opt1 = i1[1];
      var opt2 = i2[1];
      cmp = opt2.compareTo(opt1);
    }
    return cmp;
  });

  return constructors;
}