getClassFields function

List<({bool isCollection, bool isNamed, bool isNullable, String name, String type})> getClassFields(
  1. ClassDeclaration node, {
  2. bool constructorOnly = false,
})

Gets the fields of a class as a list of records containing name, type, isNamed, and isNullable. If constructorOnly is true, only fields present in the best constructor are returned.

Implementation

List<
  ({String name, String type, bool isNamed, bool isNullable, bool isCollection})
>
getClassFields(ClassDeclaration node, {bool constructorOnly = false}) {
  final constructor = getBestConstructorForCopyWith(node);

  // Build parameter map from constructor (if exists)
  final parameterMap = <String, bool>{};
  if (constructor != null) {
    for (final param in constructor.parameters.parameters) {
      final name = param.declaredFragment?.name ?? param.name!.lexeme;
      parameterMap[name] = param.isNamed;
    }
  }

  // If constructorOnly is true, we need a suitable constructor
  if (constructorOnly) {
    if (constructor == null) {
      return [];
    }

    if (!isConstructorSuitableForCopyWith(constructor)) {
      return [];
    }
  }

  final allFields = node.members
      .whereType<FieldDeclaration>()
      .where((f) => !f.isStatic)
      .expand(
        (fieldDecl) => fieldDecl.fields.variables.map((v) {
          final name = v.declaredFragment?.name ?? v.name.lexeme;
          final declaredElement = v.declaredFragment?.element;
          final type = declaredElement?.type.getDisplayString() ?? 'dynamic';
          final isNullable =
              declaredElement?.type.nullabilitySuffix ==
              NullabilitySuffix.question;
          final isCollection =
              declaredElement?.type.isDartCoreList == true ||
              declaredElement?.type.isDartCoreIterable == true ||
              declaredElement?.type.isDartCoreSet == true ||
              declaredElement?.type.isDartCoreMap == true;
          final isNamed = parameterMap[name] ?? false;

          return (
            name: name,
            type: type,
            isNamed: isNamed,
            isNullable: isNullable,
            isCollection: isCollection,
          );
        }),
      )
      .toList();

  // If constructorOnly is true, filter to only include constructor parameters
  if (constructorOnly) {
    return allFields
        .where((field) => parameterMap.containsKey(field.name))
        .toList();
  }

  return allFields;
}