visitClassDeclaration method
void
visitClassDeclaration(
- ClassDeclaration node
)
override
Implementation
@override
void visitClassDeclaration(ClassDeclaration node) {
final classBody = node.body;
if (classBody is! BlockClassBody) {
super.visitClassDeclaration(node);
return;
}
bool isMobXStore = false;
// Also check for abstract classes ending in '_Store' or with 'Store' mixin
// but the most reliable way is checking for annotations.
for (final member in classBody.members) {
if (member is FieldDeclaration) {
for (final metadata in member.metadata) {
final name = metadata.name.toSource();
if (name == 'observable' || name == 'computed') {
isMobXStore = true;
break;
}
}
}
if (isMobXStore) break;
}
if (isMobXStore) {
final className = node.namePart.typeName.lexeme;
final stateFields = <FieldInfo>[];
final methods = <MethodInfo>[];
bool isFamilyCandidate = false;
for (final member in classBody.members) {
if (member is FieldDeclaration) {
bool hasObservable = false;
bool hasComputed = false;
for (final metadata in member.metadata) {
final name = metadata.name.toSource();
if (name == 'observable') hasObservable = true;
if (name == 'computed') hasComputed = true;
}
if (hasObservable || hasComputed) {
for (final variable in member.fields.variables) {
// @computed fields are getters in MobX but stored as late fields;
// mark them with a `// computed` initializer hint so the
// transformer can emit a derived Provider instead of a state field.
stateFields.add(
FieldInfo(
rawName: variable.name.lexeme,
type: member.fields.type?.toSource() ?? 'dynamic',
initializer: hasComputed
? (variable.initializer?.toSource() ?? '/* computed */')
: variable.initializer?.toSource(),
),
);
}
}
} else if (member is ConstructorDeclaration) {
for (final param in member.parameters.parameters) {
final paramName = param.name?.lexeme ?? '';
if (paramName != 'key') {
isFamilyCandidate = true;
break;
}
}
} else if (member is MethodDeclaration) {
bool isAction = false;
for (final metadata in member.metadata) {
if (metadata.name.toSource() == 'action') {
isAction = true;
break;
}
}
// We capture all methods, but mark if they are actions (callsNotifyListeners equivalent)
methods.add(buildMethodInfo(member, callsNotifyListeners: isAction));
}
}
nodes.add(
LogicUnitNode(
name: className,
stateFields: stateFields,
methods: methods,
isNotifier: true,
notifierType: detectNotifierType(methods),
isFamilyCandidate: isFamilyCandidate,
filePath: filePath,
offset: node.offset,
length: node.length,
),
);
}
super.visitClassDeclaration(node);
}