Signature.parseMethodSignature constructor

Signature.parseMethodSignature(
  1. String signature
)

Parses a Dart method signature string and returns a Signature instance.

The signature string should follow the standard Dart method signature syntax, including return type, method name, and parameter list enclosed in parentheses. This parser attempts to correctly identify positional, optional positional, required named, and optional named parameters, extracting only their names. It handles basic type annotations and default values but might not cover all edge cases of complex Dart type syntax.

Example:

final signatureString = '''String greet(String name,
[String? greeting = "Hello"])''';
final signature = Signature.parseMethodSignature(signatureString);
print(signature.positionalParameters); // Output: [name]
print(signature.positionalOptionalParameters); // Output: [greeting]
print(signature.namedParameters); // Output: []
print(signature.namedOptionalParameters); // Output: []

Throws a FormatException if the provided signature string does not match the expected basic method signature format.

Implementation

factory Signature.parseMethodSignature(String signature) {
  var firstParensIndex = signature.indexOf('(');
  int? lastParensIndex = signature.lastIndexOf(')');
  if (firstParensIndex == -1 || lastParensIndex == -1) {
    throw const FormatException('Invalid signature format');
  }
  final parameterString = signature
      .substring(firstParensIndex + 1, lastParensIndex)
      .split('\n')
      .map((line) => line.trim())
      .whereNot((line) => line.startsWith('//'))
      .join('\n');

  final positionalParams = <String>[];
  final positionalOptionalParams = <String>[];
  final namedParams = <String>[];
  final namedOptionalParams = <String>[];

  if (parameterString.isNotEmpty) {
    var inOptionalPositional = false;
    var inNamed = false;

    var i = 0;
    while (i < parameterString.length) {
      var start = i;
      var bracketCounter = 0;
      for (; i < parameterString.length; i++) {
        if (parameterString[i] == '<') {
          bracketCounter++;
        } else if (parameterString[i] == '>') {
          bracketCounter--;
        } else if (parameterString[i] == ',' && bracketCounter == 0) {
          break;
        }
      }
      var param = parameterString.substring(start, i);
      i++;

      param = param.trim();
      if (param.isEmpty) {
        continue;
      }

      if (param.startsWith('[')) {
        inOptionalPositional = true;
        param = param.substring(1).trim();
      } else if (param.startsWith('{')) {
        inNamed = true;
        param = param.substring(1).trim();
      }
      if (param.endsWith(']')) {
        param = param.substring(0, param.length - 1).trim();
      } else if (param.endsWith('}')) {
        param = param.substring(0, param.length - 1).trim();
      }

      if (inOptionalPositional) {
        positionalOptionalParams.add(_extractParameterName(param));
      } else if (inNamed) {
        var req = 'required ';
        if (param.startsWith(req)) {
          namedParams.add(_extractParameterName(param.substring(req.length)));
        } else {
          namedOptionalParams.add(_extractParameterName(param));
        }
      } else {
        positionalParams.add(_extractParameterName(param));
      }
    }
  }

  // Extract only the name for positional parameters
  final positionalNames =
      positionalParams.map(_extractParameterName).toList();
  final positionalOptionalNames =
      positionalOptionalParams.map(_extractParameterName).toList();

  return Signature(
    positionalParameters: positionalNames,
    positionalOptionalParameters: positionalOptionalNames,
    namedParameters: namedParams,
    namedOptionalParameters: namedOptionalParams,
  );
}