blob: 57a75d0fc0db36eaf38217e9ec30dcc25af115df [file] [log] [blame] [edit]
abstract class CodegenError {
bool get hasErrors;
String get message;
}
class StoreClassCodegenErrors implements CodegenError {
StoreClassCodegenErrors(this.name);
final String name;
final NonAbstractStoreMixinDeclarations nonAbstractStoreMixinDeclarations =
NonAbstractStoreMixinDeclarations();
final PropertyErrors finalObservables = FinalObservableFields();
final PropertyErrors staticObservables = StaticObservableFields();
final PropertyErrors invalidObservableAnnotations =
InvalidObservableAnnotations();
final PropertyErrors invalidReadOnlyAnnotations =
InvalidReadOnlyAnnotations();
final PropertyErrors invalidComputedAnnotations =
InvalidComputedAnnotations();
final PropertyErrors invalidPublicSetterOnReadOnlyObservable =
InvalidSetterOnReadOnlyObservable();
final PropertyErrors staticMethods = InvalidStaticMethods();
final PropertyErrors asyncGeneratorActions = AsyncGeneratorActionMethods();
final PropertyErrors nonAsyncMethods = NonAsyncMethods();
final PropertyErrors invalidActionAnnotations = InvalidActionAnnotations();
List<CodegenError> get _errorCategories => [
nonAbstractStoreMixinDeclarations,
invalidComputedAnnotations,
invalidObservableAnnotations,
invalidReadOnlyAnnotations,
invalidActionAnnotations,
staticObservables,
invalidPublicSetterOnReadOnlyObservable,
staticMethods,
finalObservables,
asyncGeneratorActions,
nonAsyncMethods,
];
@override
String get message {
final errors = _errorCategories
.where((category) => category.hasErrors)
.toList(growable: false)
.asMap()
.map((i, category) => MapEntry(i, ' ${i + 1}. ${category.message}'))
.values
.join('\n');
return 'Could not make class "$name" observable. Changes needed:\n$errors';
}
@override
bool get hasErrors => _errorCategories.any((category) => category.hasErrors);
}
final _fieldPluralizer = Pluralize('the field', 'fields');
final _methodPluralizer = Pluralize('the method', 'methods');
final _memberPluralizer = Pluralize('the member', 'members');
abstract class _InvalidStoreDeclarations implements CodegenError {
final NameList _classNames = NameList();
// ignore: avoid_positional_boolean_parameters
bool addIf(bool condition, String className) {
if (condition) {
_classNames.add(className);
}
return condition;
}
@override
bool get hasErrors => _classNames.isNotEmpty;
}
class NonAbstractStoreMixinDeclarations extends _InvalidStoreDeclarations {
@override
String get message =>
'Classes that use the Store mixin must be marked abstract. Affected classes: $_classNames.';
}
abstract class PropertyErrors implements CodegenError {
final NameList _properties = NameList();
// ignore: avoid_positional_boolean_parameters
bool addIf(bool condition, String propertyName) {
if (condition) {
_properties.add(propertyName);
}
return condition;
}
String get propertyList => _properties.toString();
Pluralize propertyPlural = _fieldPluralizer;
String get property => propertyPlural(_properties.length);
@override
bool get hasErrors => _properties.isNotEmpty;
}
class FinalObservableFields extends PropertyErrors {
@override
String get message => 'Remove final modifier from $property $propertyList.';
}
class StaticObservableFields extends PropertyErrors {
@override
String get message => 'Remove static modifier from $property $propertyList.';
}
class AsyncGeneratorActionMethods extends PropertyErrors {
@override
// ignore: overridden_fields
Pluralize propertyPlural = _methodPluralizer;
@override
String get message =>
'Replace async* modifier with async from $property $propertyList.';
}
class NonAsyncMethods extends PropertyErrors {
@override
// ignore: overridden_fields
Pluralize propertyPlural = _methodPluralizer;
@override
String get message =>
'Return a Future or a Stream from $property $propertyList.';
}
class InvalidComputedAnnotations extends PropertyErrors {
@override
// ignore: overridden_fields
Pluralize propertyPlural = _memberPluralizer;
@override
String get message =>
'Remove @computed annotation for $property $propertyList. They only apply to property-getters.';
}
class InvalidObservableAnnotations extends PropertyErrors {
@override
// ignore: overridden_fields
Pluralize propertyPlural = _memberPluralizer;
@override
String get message =>
'Remove @observable annotation for $property $propertyList. They only apply to fields.';
}
class InvalidReadOnlyAnnotations extends PropertyErrors {
@override
// ignore: overridden_fields
Pluralize propertyPlural = _fieldPluralizer;
@override
String get message =>
'You should only use @readonly annotation with private properties. Please remove from $property $propertyList.';
}
class InvalidSetterOnReadOnlyObservable extends PropertyErrors {
@override
// ignore: overridden_fields
Pluralize propertyPlural = _memberPluralizer;
@override
String get message =>
'Must not define a public setter to a readonly field. Remove $property $propertyList.';
}
class InvalidActionAnnotations extends PropertyErrors {
@override
// ignore: overridden_fields
Pluralize propertyPlural = _memberPluralizer;
@override
String get message =>
'Remove @action annotation for $property $propertyList. They only apply to methods.';
}
class InvalidStaticMethods extends PropertyErrors {
@override
// ignore: overridden_fields
Pluralize propertyPlural = _methodPluralizer;
@override
String get message => 'Remove static modifier from $property $propertyList.';
}
class NameList {
final List<String> _names = [];
void add(String name) => _names.add(name);
int get length => _names.length;
bool get isNotEmpty => _names.isNotEmpty;
@override
String toString() {
if (_names.length == 1) {
return '"${_names[0]}"';
}
final buf = StringBuffer();
for (var i = 0; i < _names.length; i++) {
final name = _names[i];
buf.write('"$name"');
if (i < _names.length - 2) {
buf.write(', ');
} else if (i == _names.length - 2) {
buf.write(' and ');
}
}
return buf.toString();
}
}
class Pluralize {
Pluralize(this._single, this._multiple);
final String _single;
final String _multiple;
String call(int count) => count == 1 ? _single : _multiple;
}