compareTo method
Compares this method with newMethod and returns a list of
ApiChanges that have been detected between the two methods.
Implementation
List<ApiChange> compareTo(
DocMethod newMethod, {
required DocComponent component,
}) {
final changes = <ApiChange>[];
_addChange(DocParameter parameter, ApiChangeOperation operation, {String? oldName, String? annotation}) {
changes.add(MethodParameterApiChange(
component: component,
method: this,
operation: operation,
parameter: parameter,
oldName: oldName,
annotation: annotation,
));
}
void _checkParamAnnotations(DocParameter oldP, DocParameter newP) {
for (final annotation in oldP.annotations) {
if (!newP.annotations.contains(annotation)) {
_addChange(oldP, ApiChangeOperation.annotationRemoved, annotation: annotation);
}
}
for (final annotation in newP.annotations) {
if (!oldP.annotations.contains(annotation)) {
_addChange(oldP, ApiChangeOperation.annotationAdded, annotation: annotation);
}
}
}
if (returnType != newMethod.returnType) {
changes.add(MethodApiChange(
component: component,
method: this,
operation: ApiChangeOperation.typeChanged,
newType: newMethod.returnType,
));
}
for (final annotation in annotations) {
if (!newMethod.annotations.contains(annotation)) {
changes.add(MethodApiChange(
component: component,
method: this,
operation: ApiChangeOperation.annotationRemoved,
annotation: annotation,
));
}
}
for (final annotation in newMethod.annotations) {
if (!annotations.contains(annotation)) {
changes.add(MethodApiChange(
component: component,
method: this,
operation: ApiChangeOperation.annotationAdded,
annotation: annotation,
));
}
}
final oldPositional = signature.where((p) => !p.named).toList();
final oldNamed = signature.where((p) => p.named).toList();
final newPositional = newMethod.signature.where((p) => !p.named).toList();
final newNamed = newMethod.signature.where((p) => p.named).toList();
final processedOld = <DocParameter>{};
final processedNew = <DocParameter>{};
// Check old named -> new positional
for (final oldP in oldNamed) {
final newP = newPositional.firstWhereOrNull((p) => p.name == oldP.name);
if (newP != null) {
_addChange(oldP, ApiChangeOperation.becamePositional);
if (oldP.type != newP.type) {
_addChange(oldP, ApiChangeOperation.typeChanged);
}
if (oldP.required != newP.required) {
_addChange(
oldP,
oldP.required ? ApiChangeOperation.becameOptional : ApiChangeOperation.becameRequired,
);
}
_checkParamAnnotations(oldP, newP);
processedOld.add(oldP);
processedNew.add(newP);
}
}
// Check old positional -> new named
for (final oldP in oldPositional) {
final newP = newNamed.firstWhereOrNull((p) => p.name == oldP.name);
if (newP != null) {
_addChange(oldP, ApiChangeOperation.becameNamed);
if (oldP.type != newP.type) {
_addChange(oldP, ApiChangeOperation.typeChanged);
}
if (oldP.required != newP.required) {
_addChange(
oldP,
oldP.required ? ApiChangeOperation.becameOptional : ApiChangeOperation.becameRequired,
);
}
_checkParamAnnotations(oldP, newP);
processedOld.add(oldP);
processedNew.add(newP);
}
}
// Compare remaining named parameters
for (final oldP in oldNamed) {
if (processedOld.contains(oldP)) continue;
final newP = newNamed.firstWhereOrNull((p) => p.name == oldP.name);
if (newP == null) {
_addChange(oldP, ApiChangeOperation.removed);
} else {
processedNew.add(newP);
if (oldP.type != newP.type) {
_addChange(oldP, ApiChangeOperation.typeChanged);
}
if (oldP.required != newP.required) {
_addChange(
oldP,
oldP.required ? ApiChangeOperation.becameOptional : ApiChangeOperation.becameRequired,
);
}
_checkParamAnnotations(oldP, newP);
}
}
for (final newP in newNamed) {
if (processedNew.contains(newP)) continue;
_addChange(newP, ApiChangeOperation.added);
}
// Compare remaining positional parameters by index
final remainingOldPositional = oldPositional.where((p) => !processedOld.contains(p)).toList();
final remainingNewPositional = newPositional.where((p) => !processedNew.contains(p)).toList();
final maxPos = remainingOldPositional.length > remainingNewPositional.length
? remainingOldPositional.length
: remainingNewPositional.length;
for (var i = 0; i < maxPos; i++) {
if (i < remainingOldPositional.length && i < remainingNewPositional.length) {
final oldP = remainingOldPositional[i];
final newP = remainingNewPositional[i];
if (oldP.name != newP.name) {
_addChange(newP, ApiChangeOperation.renamed, oldName: oldP.name);
}
if (oldP.type != newP.type) {
_addChange(oldP, ApiChangeOperation.typeChanged);
}
if (oldP.required != newP.required) {
_addChange(
oldP,
oldP.required ? ApiChangeOperation.becameOptional : ApiChangeOperation.becameRequired,
);
}
_checkParamAnnotations(oldP, newP);
} else if (i >= remainingOldPositional.length) {
_addChange(remainingNewPositional[i], ApiChangeOperation.added);
} else {
_addChange(remainingOldPositional[i], ApiChangeOperation.removed);
}
}
return changes;
}