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 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 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 get indexAnnotations { return _indexChecker.annotationsOfExact(nonSynthetic).map((DartObject ann) { final rawComposite = ann.getField('composite')!.toListValue(); final composite = []; 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); }