185 lines
5.7 KiB
Dart
185 lines
5.7 KiB
Dart
import 'package:analyzer/dart/constant/value.dart';
|
|
import 'package:analyzer/dart/element/element.dart';
|
|
import 'package:analyzer/dart/element/type.dart';
|
|
import 'package:dartx/dartx.dart';
|
|
import 'package:isar/isar.dart';
|
|
import 'package:source_gen/source_gen.dart';
|
|
|
|
const TypeChecker _collectionChecker = TypeChecker.fromRuntime(Collection);
|
|
const TypeChecker _enumeratedChecker = TypeChecker.fromRuntime(Enumerated);
|
|
const TypeChecker _embeddedChecker = TypeChecker.fromRuntime(Embedded);
|
|
const TypeChecker _ignoreChecker = TypeChecker.fromRuntime(Ignore);
|
|
const TypeChecker _nameChecker = TypeChecker.fromRuntime(Name);
|
|
const TypeChecker _indexChecker = TypeChecker.fromRuntime(Index);
|
|
const TypeChecker _backlinkChecker = TypeChecker.fromRuntime(Backlink);
|
|
|
|
extension ClassElementX on ClassElement {
|
|
bool get hasZeroArgsConstructor {
|
|
return constructors.any(
|
|
(ConstructorElement c) =>
|
|
c.isPublic &&
|
|
!c.parameters.any((ParameterElement p) => !p.isOptional),
|
|
);
|
|
}
|
|
|
|
List<PropertyInducingElement> get allAccessors {
|
|
final ignoreFields =
|
|
collectionAnnotation?.ignore ?? embeddedAnnotation!.ignore;
|
|
return [
|
|
...accessors.mapNotNull((e) => e.variable),
|
|
if (collectionAnnotation?.inheritance ?? embeddedAnnotation!.inheritance)
|
|
for (InterfaceType supertype in allSupertypes) ...[
|
|
if (!supertype.isDartCoreObject)
|
|
...supertype.accessors.mapNotNull((e) => e.variable)
|
|
]
|
|
]
|
|
.where(
|
|
(PropertyInducingElement e) =>
|
|
e.isPublic &&
|
|
!e.isStatic &&
|
|
!_ignoreChecker.hasAnnotationOf(e.nonSynthetic) &&
|
|
!ignoreFields.contains(e.name),
|
|
)
|
|
.distinctBy((e) => e.name)
|
|
.toList();
|
|
}
|
|
|
|
List<String> get enumConsts {
|
|
return fields.where((e) => e.isEnumConstant).map((e) => e.name).toList();
|
|
}
|
|
}
|
|
|
|
extension PropertyElementX on PropertyInducingElement {
|
|
bool get isLink => type.element2!.name == 'IsarLink';
|
|
|
|
bool get isLinks => type.element2!.name == 'IsarLinks';
|
|
|
|
Enumerated? get enumeratedAnnotation {
|
|
final ann = _enumeratedChecker.firstAnnotationOfExact(nonSynthetic);
|
|
if (ann == null) {
|
|
return null;
|
|
}
|
|
final typeIndex = ann.getField('type')!.getField('index')!.toIntValue()!;
|
|
return Enumerated(
|
|
EnumType.values[typeIndex],
|
|
ann.getField('property')?.toStringValue(),
|
|
);
|
|
}
|
|
|
|
Backlink? get backlinkAnnotation {
|
|
final ann = _backlinkChecker.firstAnnotationOfExact(nonSynthetic);
|
|
if (ann == null) {
|
|
return null;
|
|
}
|
|
return Backlink(to: ann.getField('to')!.toStringValue()!);
|
|
}
|
|
|
|
List<Index> get indexAnnotations {
|
|
return _indexChecker.annotationsOfExact(nonSynthetic).map((DartObject ann) {
|
|
final rawComposite = ann.getField('composite')!.toListValue();
|
|
final composite = <CompositeIndex>[];
|
|
if (rawComposite != null) {
|
|
for (final c in rawComposite) {
|
|
final indexTypeField = c.getField('type')!;
|
|
IndexType? indexType;
|
|
if (!indexTypeField.isNull) {
|
|
final indexTypeIndex =
|
|
indexTypeField.getField('index')!.toIntValue()!;
|
|
indexType = IndexType.values[indexTypeIndex];
|
|
}
|
|
composite.add(
|
|
CompositeIndex(
|
|
c.getField('property')!.toStringValue()!,
|
|
type: indexType,
|
|
caseSensitive: c.getField('caseSensitive')!.toBoolValue(),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
final indexTypeField = ann.getField('type')!;
|
|
IndexType? indexType;
|
|
if (!indexTypeField.isNull) {
|
|
final indexTypeIndex = indexTypeField.getField('index')!.toIntValue()!;
|
|
indexType = IndexType.values[indexTypeIndex];
|
|
}
|
|
return Index(
|
|
name: ann.getField('name')!.toStringValue(),
|
|
composite: composite,
|
|
unique: ann.getField('unique')!.toBoolValue()!,
|
|
replace: ann.getField('replace')!.toBoolValue()!,
|
|
type: indexType,
|
|
caseSensitive: ann.getField('caseSensitive')!.toBoolValue(),
|
|
);
|
|
}).toList();
|
|
}
|
|
}
|
|
|
|
extension ElementX on Element {
|
|
String get isarName {
|
|
final ann = _nameChecker.firstAnnotationOfExact(nonSynthetic);
|
|
late String name;
|
|
if (ann == null) {
|
|
name = displayName;
|
|
} else {
|
|
name = ann.getField('name')!.toStringValue()!;
|
|
}
|
|
checkIsarName(name, this);
|
|
return name;
|
|
}
|
|
|
|
Collection? get collectionAnnotation {
|
|
final ann = _collectionChecker.firstAnnotationOfExact(nonSynthetic);
|
|
if (ann == null) {
|
|
return null;
|
|
}
|
|
return Collection(
|
|
inheritance: ann.getField('inheritance')!.toBoolValue()!,
|
|
accessor: ann.getField('accessor')!.toStringValue(),
|
|
ignore: ann
|
|
.getField('ignore')!
|
|
.toSetValue()!
|
|
.map((e) => e.toStringValue()!)
|
|
.toSet(),
|
|
);
|
|
}
|
|
|
|
String get collectionAccessor {
|
|
var accessor = collectionAnnotation?.accessor;
|
|
if (accessor != null) {
|
|
return accessor;
|
|
}
|
|
|
|
accessor = displayName.decapitalize();
|
|
if (!accessor.endsWith('s')) {
|
|
accessor += 's';
|
|
}
|
|
|
|
return accessor;
|
|
}
|
|
|
|
Embedded? get embeddedAnnotation {
|
|
final ann = _embeddedChecker.firstAnnotationOfExact(nonSynthetic);
|
|
if (ann == null) {
|
|
return null;
|
|
}
|
|
return Embedded(
|
|
inheritance: ann.getField('inheritance')!.toBoolValue()!,
|
|
ignore: ann
|
|
.getField('ignore')!
|
|
.toSetValue()!
|
|
.map((e) => e.toStringValue()!)
|
|
.toSet(),
|
|
);
|
|
}
|
|
}
|
|
|
|
void checkIsarName(String name, Element element) {
|
|
if (name.isBlank || name.startsWith('_')) {
|
|
err('Names must not be blank or start with "_".', element);
|
|
}
|
|
}
|
|
|
|
Never err(String msg, [Element? element]) {
|
|
throw InvalidGenerationSourceError(msg, element: element);
|
|
}
|