adding packages

This commit is contained in:
2026-01-15 14:38:46 -08:00
parent ef86e3ab6a
commit 6869cf47e5
5253 changed files with 726695 additions and 34 deletions
+8
View File
@@ -0,0 +1,8 @@
import 'package:build/build.dart';
import 'package:source_gen/source_gen.dart';
import 'src/class_annotation_gen.dart';
Builder widgetGenerator(BuilderOptions options) {
return SharedPartBuilder([WidgetGenerator()], 'widget_generator');
}
@@ -0,0 +1,86 @@
import 'dart:async';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type_system.dart';
import 'package:build/build.dart';
import 'package:source_gen/source_gen.dart';
import 'store_class_visitor.dart';
import 'template/widget_class_gen.dart';
import 'template/store_file.dart';
import 'type_names.dart';
class WidgetGenerator extends Generator {
//GeneratorForAnnotation<WidgetClass> {
@override
FutureOr<String> generate(LibraryReader library, BuildStep buildStep) async {
if (library.allElements.isEmpty) {
return '';
}
final typeSystem = await library.allElements.first.session.typeSystem;
final file = StoreFileTemplate()
..storeSources = _generateCodeForLibrary(library, typeSystem).toSet();
return file.toString();
}
Iterable<String> _generateCodeForLibrary(
LibraryReader library,
TypeSystem typeSystem,
) sync* {
for (final classElement in library.classes) {
yield* _generateCodeForMixinStore(
library,
classElement,
typeSystem,
);
}
}
Iterable<String> _generateCodeForMixinStore(
LibraryReader library,
ClassElement baseClass,
TypeSystem typeSystem,
) sync* {
final typeNameFinder = LibraryScopedNameFinder(library.element);
String _base;
double width, height;
if (isWidgetClass(baseClass)) {
width = getPreferredWidth(baseClass);
height = getPreferredHeight(baseClass);
if (width != null || height != null) {
_base = 'WidgetPreferredSizedBase';
} else {
_base = 'WidgetBase';
}
}
if (isPropertyClass(baseClass)) {
_base = 'PropertyBase';
}
if (_base != null) {
final _template = MixinStoreTemplate(_base)
..width = width
..height = height;
yield _generateCodeFromTemplate(
baseClass.name,
baseClass,
_template,
typeNameFinder,
);
}
}
String _generateCodeFromTemplate(
String publicTypeName,
ClassElement userStoreClass,
StoreTemplate template,
LibraryScopedNameFinder typeNameFinder,
) {
final visitor = StoreClassVisitor(publicTypeName, userStoreClass, template);
userStoreClass
..accept(visitor)
..visitChildren(visitor);
return visitor.source;
}
}
+204
View File
@@ -0,0 +1,204 @@
abstract class CodegenError {
bool get hasErrors;
String get message;
}
class StoreClassCodegenErrors implements CodegenError {
StoreClassCodegenErrors(this.name) {
_errorCategories = [
// nonAbstractStoreMixinDeclarations,
// invalidComputedAnnotations,
// invalidObservableAnnotations,
invalidActionAnnotations,
// staticObservables,
// finalObservables,
];
}
final String name;
final NonAbstractStoreMixinDeclarations nonAbstractStoreMixinDeclarations =
NonAbstractStoreMixinDeclarations();
// final PropertyErrors finalObservables = FinalObservableFields();
final PropertyErrors staticObservables = StaticObservableFields();
final PropertyErrors invalidObservableAnnotations =
InvalidObservableAnnotations();
final PropertyErrors invalidComputedAnnotations =
InvalidComputedAnnotations();
final PropertyErrors invalidActionAnnotations = InvalidActionAnnotations();
List<CodegenError> _errorCategories;
@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 SettingsStore 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 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;
}
@@ -0,0 +1,365 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/dart/element/visitor.dart';
import 'package:build/build.dart';
import 'package:source_gen/source_gen.dart';
import '../widget_gen_annotations.dart';
import 'errors.dart';
import 'template/properties/base.dart';
import 'template/properties/color.dart';
import 'template/properties/edge_insets_geometry.dart';
import 'template/properties/enum.dart';
import 'template/properties/function.dart';
import 'template/properties/key.dart';
import 'template/properties/list_widget.dart';
import 'template/properties/matrix_4.dart';
import 'template/properties/offset.dart';
import 'template/properties/size.dart';
import 'template/properties/supported.dart';
import 'template/properties/widget.dart';
import 'template/util.dart';
import 'template/widget_class_gen.dart';
import 'type_names.dart';
class StoreClassVisitor extends SimpleElementVisitor {
StoreClassVisitor(
String publicTypeName,
ClassElement userClass,
StoreTemplate template,
) : _errors = StoreClassCodegenErrors(publicTypeName) {
_storeTemplate = template
..typeParams.templates.addAll(userClass.typeParameters
.map((type) => typeParamTemplate(type, typeNameFinder)))
..typeArgs.templates.addAll(userClass.typeParameters.map((t) => t.name))
..parentTypeName = userClass.name
..publicTypeName = publicTypeName
..widgetName = getClassName(userClass)
..isAnimated = getWidgetIsAnimated(userClass)
..allowTap = getAllowTap(userClass)
..animatedDurationMilliseconds = getAnimationDuration(userClass);
}
StoreTemplate _storeTemplate;
DartType className;
Map<String, DartType> fields = {};
Map<String, dynamic> metaData = {};
LibraryScopedNameFinder typeNameFinder;
final StoreClassCodegenErrors _errors;
String get source {
if (_errors.hasErrors) {
log.severe(_errors.message);
return '';
}
return _storeTemplate.toString();
}
@override
visitConstructorElement(ConstructorElement element) {
className = element.type.returnType;
return super.visitConstructorElement(element);
}
@override
void visitClassElement(ClassElement element) {
if (isWidgetClass(element) || isPropertyClass(element)) {
_errors.nonAbstractStoreMixinDeclarations
.addIf(!element.isAbstract, element.name);
}
// if the class is annotated to generate toString() method we add the information to the _storeTemplate
// _storeTemplate.generateToString = hasGeneratedToString(element);
}
@override
void visitFieldElement(FieldElement element) {
fields[element.name] = element.type;
metaData[element.name] = element.metadata;
if (_fieldIsNotValid(element)) {
return;
}
final _enumKey = const TypeChecker.fromRuntime(EnumKey);
if (_enumKey.hasAnnotationOfExact(element, throwOnUnresolved: false)) {
final annotation = _enumKey.firstAnnotationOfExact(element);
final template = EnumOptionTemplate()
..defaultValue = annotation.getField('defaultValue').toStringValue()
..key = annotation.getField('key').toStringValue()
..values = annotation
.getField('values')
.toListValue()
.map((e) => e.toStringValue())
.toList()
..isPrivate = element.isPrivate
..propertyType =
annotation?.getField('propertyType')?.toStringValue() ??
element.type.toString()
..name = element.name;
_storeTemplate.settings.add(template);
return;
}
if (element.type.toString() == 'Color') {
final template = ColorOptionTemplate();
final _colorKey = const TypeChecker.fromRuntime(ColorKey);
if (_colorKey.hasAnnotationOfExact(element, throwOnUnresolved: false)) {
final annotation = _colorKey.firstAnnotationOfExact(element);
template.defaultValue =
annotation.getField('defaultValue').toIntValue();
template.key = annotation.getField('key').toStringValue();
}
template.isPrivate = element.isPrivate;
template.propertyType = element.type.toString();
template.name = element.name;
_storeTemplate.settings.add(template);
return;
}
final _supportedKey = const TypeChecker.fromRuntime(SupportedKey);
if (_supportedKey.hasAnnotationOfExact(element, throwOnUnresolved: false)) {
final template = SupportedOptionTemplate();
final annotation = _supportedKey.firstAnnotationOfExact(element);
template.key = annotation.getField('key').toStringValue();
template.isPrivate = element.isPrivate;
template.propertyType = element.type.toString();
template.name = element.name;
_storeTemplate.settings.add(template);
return;
}
if (element.type.toString() == 'Widget') {
final template = WidgetOptionTemplate();
final _widgetKey = const TypeChecker.fromRuntime(WidgetKey);
if (_widgetKey.hasAnnotationOfExact(element, throwOnUnresolved: false)) {
final annotation = _widgetKey.firstAnnotationOfExact(element);
template.fallback = annotation.getField('defaultValue').toStringValue();
template.key = annotation.getField('key').toStringValue();
template.acceptType = annotation.getField('acceptType').toStringValue();
template.acceptWidth =
annotation.getField('acceptWidth').toDoubleValue();
template.acceptHeight =
annotation.getField('acceptHeight').toDoubleValue();
}
template.isPrivate = element.isPrivate;
template.propertyType = element.type.toString();
template.name = element.name;
_storeTemplate.settings.add(template);
return;
}
if (element.type.toString() == 'Matrix4') {
final template = Matrix4OptionTemplate();
final _widgetKey = const TypeChecker.fromRuntime(Matrix4Key);
if (_widgetKey.hasAnnotationOfExact(element, throwOnUnresolved: false)) {
final annotation = _widgetKey.firstAnnotationOfExact(element);
template.key = annotation.getField('key').toStringValue();
}
template.isPrivate = element.isPrivate;
template.propertyType = element.type.toString();
template.name = element.name;
_storeTemplate.settings.add(template);
return;
}
if (element.type.toString() == 'EdgeInsets') {
final template = EdgeInsetsOptionTemplate();
final _widgetKey = const TypeChecker.fromRuntime(EdgeInsetsKey);
if (_widgetKey.hasAnnotationOfExact(element, throwOnUnresolved: false)) {
final annotation = _widgetKey.firstAnnotationOfExact(element);
template.key = annotation.getField('key').toStringValue();
template.defaultValue =
annotation.getField('defaultValue').toDoubleValue();
}
template.isPrivate = element.isPrivate;
template.propertyType = element.type.toString();
template.name = element.name;
_storeTemplate.settings.add(template);
return;
}
if (element.type.toString() == 'Offset') {
final template = OffsetOptionTemplate();
final _widgetKey = const TypeChecker.fromRuntime(OffsetKey);
if (_widgetKey.hasAnnotationOfExact(element, throwOnUnresolved: false)) {
final annotation = _widgetKey.firstAnnotationOfExact(element);
template.key = annotation.getField('key').toStringValue();
}
template.isPrivate = element.isPrivate;
template.propertyType = element.type.toString();
template.name = element.name;
_storeTemplate.settings.add(template);
return;
}
if (element.type.toString() == 'Size') {
final template = SizeOptionTemplate();
final _widgetKey = const TypeChecker.fromRuntime(SizeKey);
if (_widgetKey.hasAnnotationOfExact(element, throwOnUnresolved: false)) {
final annotation = _widgetKey.firstAnnotationOfExact(element);
template.key = annotation.getField('key').toStringValue();
}
template.isPrivate = element.isPrivate;
template.propertyType = element.type.toString();
template.name = element.name;
_storeTemplate.settings.add(template);
return;
}
if (element.type.toString().contains('List')) {
final template = ListWidgetOptionTemplate();
final _widgetKey = const TypeChecker.fromRuntime(ListWidgetKey);
if (_widgetKey.hasAnnotationOfExact(element, throwOnUnresolved: false)) {
final annotation = _widgetKey.firstAnnotationOfExact(element);
template.fallback = annotation.getField('fallback').toStringValue();
template.key = annotation.getField('key').toStringValue();
template.empty = annotation.getField('empty').toBoolValue();
template.acceptType = annotation.getField('acceptType').toStringValue();
}
template.acceptType ??= 'WidgetBaseData';
template.empty ??= true;
template.isPrivate = element.isPrivate;
template.propertyType = element.type.toString();
template.name = element.name;
_storeTemplate.settings.add(template);
return;
}
if (element.type.toString() == 'Function') {
final template = FunctionOptionTemplate();
final _widgetKey = const TypeChecker.fromRuntime(FunctionKey);
if (_widgetKey.hasAnnotationOfExact(element, throwOnUnresolved: false)) {
final annotation = _widgetKey.firstAnnotationOfExact(element);
template.defaultValue = annotation.getField('fallback').toStringValue();
template.key = annotation.getField('key').toStringValue();
}
template.isPrivate = element.isPrivate;
template.propertyType = element.type.toString();
template.name = element.name;
_storeTemplate.settings.add(template);
return;
}
if (element.type.toString() == 'Key') {
final template = KeyOptionTemplate();
final _widgetKey = const TypeChecker.fromRuntime(TreeKey);
if (_widgetKey.hasAnnotationOfExact(element, throwOnUnresolved: false)) {
final annotation = _widgetKey.firstAnnotationOfExact(element);
template.defaultValue =
annotation.getField('defaultValue').toStringValue();
template.key = annotation.getField('key').toStringValue();
}
template.isPrivate = element.isPrivate;
template.propertyType = element.type.toString();
template.name = element.name;
_storeTemplate.settings.add(template);
return;
}
const _ignoreFields = [
'widgetData',
'widgetContext',
'widgetRender',
];
if (_ignoreFields.contains(element.name)) {
return;
}
const _allowedTypes = [
'double',
'int',
'num',
'String',
'bool',
'Object',
];
if (!_allowedTypes.contains(element.type.toString())) {
print('Not Implemented -> ${element.type}');
return;
}
final template = BaseOptionTemplate();
final _baseKey = const TypeChecker.fromRuntime(PropertyKey);
if (_baseKey.hasAnnotationOfExact(element, throwOnUnresolved: false)) {
final annotation = _baseKey.firstAnnotationOfExact(element);
template.defaultValue =
annotation.getField('defaultValue').toStringValue();
template.key = annotation.getField('key').toStringValue();
template.tryParse = annotation.getField('tryParse').toBoolValue();
} else {
template.tryParse = false;
}
template.isPrivate = element.isPrivate;
template.propertyType = element.type.toString();
template.name = element.name;
_storeTemplate.settings.add(template);
return;
}
bool _fieldIsNotValid(FieldElement element) => _any([
_errors.staticObservables.addIf(element.isStatic, element.name),
// _errors.finalObservables.addIf(element.isFinal, element.name)
]);
}
const _widgetChecker = TypeChecker.fromRuntime(WidgetClass);
const _propertyChecker = TypeChecker.fromRuntime(PropertyClass);
// Checks if the class as a toString annotation
bool isWidgetClass(ClassElement classElement) =>
_widgetChecker.hasAnnotationOfExact(classElement);
bool isPropertyClass(ClassElement classElement) =>
_propertyChecker.hasAnnotationOfExact(classElement);
String getClassName(ClassElement classElement) {
if (isWidgetClass(classElement)) {
final annotation = _widgetChecker.firstAnnotationOfExact(classElement);
return annotation.getField('name').toStringValue();
}
if (isPropertyClass(classElement)) {
final annotation = _propertyChecker.firstAnnotationOfExact(classElement);
return annotation.getField('name').toStringValue();
}
return null;
}
bool getWidgetIsAnimated(ClassElement classElement) {
if (isWidgetClass(classElement)) {
final annotation = _widgetChecker.firstAnnotationOfExact(classElement);
return annotation.getField('animated').toBoolValue();
}
return false;
}
int getAnimationDuration(ClassElement classElement) {
if (isWidgetClass(classElement)) {
final annotation = _widgetChecker.firstAnnotationOfExact(classElement);
return annotation.getField('durationMilliseconds').toIntValue();
}
return 250;
}
double getPreferredHeight(ClassElement classElement) {
if (isWidgetClass(classElement)) {
final annotation = _widgetChecker.firstAnnotationOfExact(classElement);
return annotation.getField('preferredHeight').toDoubleValue();
}
return null;
}
double getPreferredWidth(ClassElement classElement) {
if (isWidgetClass(classElement)) {
final annotation = _widgetChecker.firstAnnotationOfExact(classElement);
return annotation.getField('preferredWidth').toDoubleValue();
}
return null;
}
bool getAllowTap(ClassElement classElement) {
if (isWidgetClass(classElement)) {
final annotation = _widgetChecker.firstAnnotationOfExact(classElement);
return annotation.getField('allowTap').toBoolValue();
}
return false;
}
bool _any(List<bool> list) => list.any(_identity);
T _identity<T>(T value) => value;
@@ -0,0 +1,25 @@
import 'util.dart';
class CommaList<T> {
CommaList(this.templates) : assert(templates != null);
final List<T> templates;
@override
String toString() =>
templates.map((t) => t.toString()).where((s) => s.isNotEmpty).join(', ');
}
class SurroundedCommaList<T> {
SurroundedCommaList(this.prefix, this.suffix, this.templates)
: assert(prefix != null),
assert(suffix != null),
assert(templates != null);
final String prefix;
final String suffix;
final List<T> templates;
@override
String toString() => surroundNonEmpty(prefix, suffix, CommaList(templates));
}
@@ -0,0 +1,34 @@
class ParamTemplate {
String name;
String type;
String defaultValue;
bool hasRequiredAnnotation = false;
String get asArgument => name;
NamedArgTemplate get asNamedArgument => NamedArgTemplate()..name = name;
String get metadata => hasRequiredAnnotation ? '@required ' : '';
@override
String toString() => defaultValue == null
? '$metadata$type $name'
: '$type $name = $defaultValue';
}
class TypeParamTemplate {
String name;
String bound;
String get asArgument => name;
@override
String toString() => bound == null ? name : '$name extends $bound';
}
class NamedArgTemplate {
String name;
@override
String toString() => '$name: $name';
}
@@ -0,0 +1,50 @@
import 'impl.dart';
class BaseOptionTemplate extends SettingsImpl {
String defaultValue;
bool isPrivate;
bool tryParse;
@override
String name;
@override
String key;
@override
String propertyType;
@override
String access() {
final sb = StringBuffer();
sb.writeln('$propertyType get ${name}Val {');
sb.write("if (params[${name}Key] != null) ");
sb.writeln('{');
sb.write('return ');
if (tryParse) {
sb.write("$propertyType.tryParse(params[${name}Key].toString())");
if (defaultValue != null) {
sb.write(' ?? $defaultValue');
}
} else {
sb.write('params[${name}Key] as $propertyType');
}
sb.writeln(';');
sb.writeln('}');
if (defaultValue != null) {
if (propertyType == 'String') {
sb.writeln("return '$defaultValue';");
} else {
sb.writeln("return $defaultValue;");
}
} else {
sb.writeln("return null;");
}
sb.writeln('}');
sb.writeln('set ${name}Val($propertyType val) {');
sb.writeln('params[${name}Key] = val;');
sb.writeln('widgetContext.onUpdate(id, widgetData);');
sb.writeln('}');
return sb.toString();
}
}
@@ -0,0 +1,56 @@
import 'impl.dart';
class ColorOptionTemplate extends SettingsImpl {
int defaultValue;
bool isPrivate;
@override
String name;
@override
String key;
@override
String propertyType;
@override
String access() {
final sb = StringBuffer();
// Getter
sb.writeln('$propertyType get ${name}Val {');
sb.write("if (params[${name}Key] != null) ");
sb.writeln('{');
sb.writeln('int _value = $defaultValue;');
sb.write("""
String description = params[${name}Key].toString();
if (description.startsWith('#')) {
description = description.replaceAll('#$propertyType(', '').replaceAll(')', '');
_value = int.tryParse(description);
} else if (params[${name}Key] is Map) {
if (params[${name}Key]['name'] == '$propertyType'
&& params[${name}Key]['params'] != null
&& params[${name}Key]['params']['0'] != null) {
_value = int.tryParse(params[${name}Key]['params']['0']);
}
}
""");
sb.writeln('if (_value != null) {');
sb.write('return $propertyType(_value);');
sb.writeln('}');
sb.writeln('}');
if (defaultValue != null) {
sb.writeln("return $propertyType($defaultValue);");
} else {
sb.writeln("return null;");
}
sb.writeln('}');
// Setter
sb.writeln('set ${name}Val($propertyType val) {');
sb.write('params[${name}Key] = "');
sb.write('#$propertyType(\${val.value})');
sb.writeln('";');
sb.writeln('widgetContext.onUpdate(id, widgetData);');
sb.writeln('}');
return sb.toString();
}
}
@@ -0,0 +1,54 @@
import 'impl.dart';
class EdgeInsetsOptionTemplate extends SettingsImpl {
bool isPrivate;
double defaultValue;
@override
String name;
@override
String key;
@override
String propertyType;
@override
String access() {
final sb = StringBuffer();
sb.writeln('$propertyType get ${name}Val {');
sb.writeln("""
EdgeInsets _spacing = EdgeInsets.all(0.0);
if (params[${name}Key] != null) {
double top = 0;
double bottom = 0;
double left = 0;
double right = 0;
Map<String, dynamic> _spacingParams = params[${name}Key]['params'];
top = _spacingParams['top'] ?? 0;
bottom = _spacingParams['bottom'] ?? 0;
left = _spacingParams['left'] ?? 0;
right = _spacingParams['right'] ?? 0;
_spacing = EdgeInsets.fromLTRB(left, top, right, bottom);
}
return _spacing;
""");
sb.writeln('}');
sb.writeln('set ${name}Val($propertyType val) {');
sb.write('''
params[${name}Key] = {
"name" : "EdgeInsets.only",
"id" : "${name}KeyEdgeInsets",
"params" : {
"top" : val.top,
"bottom" : val.bottom,
"left" : val.left,
"right" : val.right,
}
};
''');
sb.writeln('widgetContext.onUpdate(id, widgetData);');
sb.writeln('}');
return sb.toString();
}
}
@@ -0,0 +1,77 @@
import 'impl.dart';
class EnumOptionTemplate extends SettingsImpl {
String defaultValue;
bool isPrivate;
List values;
@override
String name;
@override
String key;
@override
String propertyType;
@override
String access() {
final sb = StringBuffer();
sb.writeln("List<$propertyType> get ${name}Values => [");
for (final item in values) {
sb.writeln("${_getEnumValueFromString(item)},");
}
sb.writeln("];");
sb.writeln('');
sb.writeln('$propertyType get ${name}Val {');
sb.write("if (params[${name}Key] != null) ");
sb.writeln('{');
sb.write('final _value = ');
sb.writeln("params[${name}Key].toString().replaceAll('#', '');");
final _fallback =
defaultValue == null ? null : _getEnumValueFromString(defaultValue);
sb.writeln("""
return ${name}Values.firstWhere(
(element) => element.toString() == _value,
orElse: () => $_fallback,
)
""");
sb.writeln(';');
sb.writeln('}');
sb.writeln("return $_fallback;");
sb.writeln('}');
sb.writeln('set ${name}Val($propertyType val) {');
sb.writeln('params[${name}Key] = "\$val";');
sb.writeln('widgetContext.onUpdate(id, widgetData);');
sb.writeln('}');
return sb.toString();
}
String _getEnumValueFromString(item) {
if (item == null) return '';
String description = item.toString().replaceAll('#', '');
// if (!description.contains('(')) {
// return "$propertyType." + describeEnum(item);
// }
return description;
}
}
T getEnum<T>(String val, {T fallback, List<T> values}) {
if (val == null) return fallback;
final _value = val.replaceAll('#', '');
return values.firstWhere(
(element) => element.toString() == _value,
orElse: () => null,
);
}
String describeEnum(String enumEntry) {
final String description = enumEntry.toString();
if (!description.contains('.')) {
return description;
}
final int indexOfDot = description.indexOf('.');
assert(indexOfDot != -1 && indexOfDot < description.length - 1);
return description.substring(indexOfDot + 1);
}
@@ -0,0 +1,54 @@
import 'impl.dart';
class FunctionOptionTemplate extends SettingsImpl {
String defaultValue;
bool isPrivate;
@override
String name;
@override
String key;
@override
String propertyType;
@override
String access() {
final sb = StringBuffer();
sb.writeln('String get ${name}Val {');
sb.write("if (params[${name}Key] != null) ");
sb.writeln('{');
sb.write('return ');
sb.write('params[${name}Key] as String');
sb.writeln(';');
sb.writeln('}');
if (defaultValue != null) {
sb.writeln("return $defaultValue;");
} else {
sb.writeln("return null;");
}
sb.writeln('}');
sb.writeln('set ${name}Val(String val) {');
sb.writeln('params[${name}Key] = val;');
sb.writeln('widgetContext.onUpdate(id, widgetData);');
sb.writeln('}');
return sb.toString();
}
@override
String constructor() {
final sb = StringBuffer();
sb.write(' ');
if (key != null && int.tryParse(key) != null) {
sb.write('');
} else if (key != null) {
sb.write("$key: ");
} else {
sb.write("$name: ");
}
sb.writeln("() => onAction(context, ${name}Val)");
sb.writeln(',');
return sb.toString();
}
}
@@ -0,0 +1,37 @@
abstract class SettingsImpl {
@override
String toString() {
final sb = StringBuffer();
return sb.toString();
}
String access();
String constructor() {
final sb = StringBuffer();
sb.write(' ');
if (key != null && int.tryParse(key) != null) {
sb.write('${name}Val');
} else if (key != null) {
sb.write("$key: ${name}Val");
} else {
sb.write("$name: ${name}Val");
}
sb.writeln(',');
return sb.toString();
}
String keyValue() {
final sb = StringBuffer();
sb.write(' ');
sb.writeln("String ${name}Key = '${key ?? name}';");
return sb.toString();
}
String get name;
String get key;
String get propertyType;
}
@@ -0,0 +1,55 @@
import 'impl.dart';
class KeyOptionTemplate extends SettingsImpl {
String defaultValue;
bool isPrivate;
@override
String name;
@override
String key;
@override
String propertyType;
@override
String access() {
final sb = StringBuffer();
sb.writeln('$propertyType get ${name}Val {');
sb.write("if (params[${name}Key] != null) ");
sb.writeln('{');
sb.write("""
String _val = params[${name}Key].toString();
if (_val.startsWith('#')) {
_val = _val.substring(1);
if (_val.startsWith('ValueKey')) {
_val = _val.replaceAll('ValueKey', '');
_val = _val.replaceAll('<String>', '');
_val = _val.replaceAll('(', '');
_val = _val.replaceAll(')', '');
}
}
return ValueKey('\$_val')
""");
sb.writeln(';');
sb.writeln('}');
if (defaultValue != null) {
sb.writeln("return ValueKey<String>('$defaultValue');");
} else {
sb.writeln("return null;");
}
sb.writeln('}');
sb.writeln('set ${name}Val($propertyType val) {');
sb.write("""
if (val == null) {
params[${name}Key] = null;
} else {
params[${name}Key] = "#ValueKey('\$val')";
}
""");
sb.writeln('widgetContext.onUpdate(id, widgetData);');
sb.writeln('}');
return sb.toString();
}
}
@@ -0,0 +1,114 @@
import 'impl.dart';
class ListWidgetOptionTemplate extends SettingsImpl {
String fallback;
bool isPrivate;
bool empty;
String acceptType;
@override
String name;
@override
String key;
@override
String propertyType;
@override
String access() {
final sb = StringBuffer();
sb.writeln('final _${name}Listen = ValueNotifier<bool>(false);');
sb.writeln('List<WidgetBase> get ${name}Val {');
sb.write("if (params[${name}Key] != null) ");
sb.writeln('{');
sb.write("""
final _children = <WidgetBase>[];
final _list = List.from(params[${name}Key]);
for (final item in _list) {
if (item is Map<String, dynamic>) {
_children.add(widgetRender(widgetContext, item));
}
}
return _children;
""");
sb.writeln('}');
if (fallback != null) {
final random = DateTime.now().millisecondsSinceEpoch.toString();
sb.writeln("""
return [
widgetRender({
'id': '$random',
'name': '$fallback',
'params': {},
})
];
""");
} else {
sb.writeln("return null;");
}
sb.writeln('}');
sb.writeln('void ${name}ValUpdate(Map<String, dynamic> val) {');
sb.write("""
if (params[${name}Key] == null) {
params[${name}Key] = [];
}
params[${name}Key].add(val);
""");
sb.writeln('widgetContext.onUpdate(id, widgetData);');
sb.writeln('}');
return sb.toString();
}
@override
String constructor() {
final sb = StringBuffer();
sb.write(' ');
if (key != null && int.tryParse(key) != null) {
sb.write('');
} else if (key != null) {
sb.write("$key: ");
} else {
sb.write("$name: ");
}
sb.write("""
${name}Val == null && !widgetContext.isDragging ? ${empty ? '[]' : 'null'} : [
if (${name}Val != null)
for (final item in ${name}Val) item.build(context),
""");
if (acceptType != null && acceptType.isNotEmpty) {
sb.write("""
if (widgetContext.isDragging)
DragTarget<$acceptType>(
onAccept: (val) {
_${name}Listen.value = false;
if (val != null) {
${name}ValUpdate(val?.data);
}
},
onLeave: (val) {
_${name}Listen.value = false;
},
onWillAccept: (val) {
_${name}Listen.value = true;
return _${name}Listen.value;
},
builder: (context, accepted, rejected) {
return ValueListenableBuilder<bool>(
valueListenable: _${name}Listen,
builder: (context, _accepting, child) => SizedBox.fromSize(
size: Size(${30}, ${30}),
child: Placeholder(
color: !_accepting ?
Colors.grey :
Theme.of(context).accentColor,
),
));
},
),
""");
}
sb.writeln('],');
return sb.toString();
}
}
@@ -0,0 +1,91 @@
import 'impl.dart';
class Matrix4OptionTemplate extends SettingsImpl {
bool isPrivate;
@override
String name;
@override
String key;
@override
String propertyType;
@override
String access() {
final sb = StringBuffer();
sb.writeln('$propertyType get ${name}Val {');
sb.writeln("""
final _matrix = Matrix4.identity();
if (params[${name}Key] != null) {
if (params[${name}Key] is List) {
final values = List.from(params[${name}Key]);
_matrix.setValues(
values[0],
values[1],
values[2],
values[3],
values[4],
values[5],
values[6],
values[7],
values[8],
values[9],
values[10],
values[11],
values[12],
values[13],
values[14],
values[15],
);
} else if (params[${name}Key] is String) {
final description = params[${name}Key].toString();
final _entryMatches = 'setEntry('.allMatches(description).toList();
final _rotateXMatches = 'rotateX('.allMatches(description).toList();
final _rotateYMatches = 'rotateY('.allMatches(description).toList();
final _rotateZMatches = 'rotateZ('.allMatches(description).toList();
for (final idx in _entryMatches) {
int start = idx.end;
int end = description.indexOf(')', start);
final _values = description
.substring(start, end)
.split(',')
.map((e) => num.tryParse(e.trim()))
.toList();
_matrix.setEntry(
_values[0].toInt(),
_values[1].toInt(),
_values[2].toDouble(),
);
}
for (final idx in _rotateXMatches) {
int start = idx.end;
int end = description.indexOf(')', start);
final _value = num.tryParse(description.substring(start, end).trim());
_matrix.rotateX(_value.toDouble());
}
for (final idx in _rotateYMatches) {
int start = idx.end;
int end = description.indexOf(')', start);
final _value = num.tryParse(description.substring(start, end).trim());
_matrix.rotateY(_value.toDouble());
}
for (final idx in _rotateZMatches) {
int start = idx.end;
int end = description.indexOf(')', start);
final _value = num.tryParse(description.substring(start, end).trim());
_matrix.rotateZ(_value.toDouble());
}
}
}
return _matrix;
""");
sb.writeln('}');
sb.writeln('set ${name}Val($propertyType val) {');
sb.writeln('params[${name}Key] = val.storage.toList();');
sb.writeln('widgetContext.onUpdate(id, widgetData);');
sb.writeln('}');
return sb.toString();
}
}
@@ -0,0 +1,47 @@
import 'impl.dart';
class OffsetOptionTemplate extends SettingsImpl {
bool isPrivate;
@override
String name;
@override
String key;
@override
String propertyType;
@override
String access() {
final sb = StringBuffer();
sb.writeln('$propertyType get ${name}Val {');
sb.writeln("""
Offset _offset = Offset(0.0, 0.0);
if (params[${name}Key] != null) {
double dx = 0;
double dy = 0;
Map<String, dynamic> _offsetParams = params[${name}Key]['params'];
dx = _offsetParams['0'] ?? 0;
dy = _offsetParams['1'] ?? 0;
_offset = Offset(dx, dy);
}
return _offset;
""");
sb.writeln('}');
sb.writeln('set ${name}Val($propertyType val) {');
sb.write('''
params[${name}Key] = {
"name" : "Offset",
"id" : "${name}KeyOffset",
"params" : {
"0" : val.dx,
"1" : val.dy,
}
};
''');
sb.writeln('widgetContext.onUpdate(id, widgetData);');
sb.writeln('}');
return sb.toString();
}
}
@@ -0,0 +1,47 @@
import 'impl.dart';
class SizeOptionTemplate extends SettingsImpl {
bool isPrivate;
@override
String name;
@override
String key;
@override
String propertyType;
@override
String access() {
final sb = StringBuffer();
sb.writeln('$propertyType get ${name}Val {');
sb.writeln("""
Size _size = Size(0.0, 0.0);
if (params[${name}Key] != null) {
double width = 0;
double height = 0;
Map<String, dynamic> _sizeParams = params[${name}Key]['params'];
width = _sizeParams['0'] ?? 0;
height = _sizeParams['1'] ?? 0;
_size = Size(width, height);
}
return _size;
""");
sb.writeln('}');
sb.writeln('set ${name}Val($propertyType val) {');
sb.write('''
params[${name}Key] = {
"name" : "Size",
"id" : "${name}KeySize",
"params" : {
"0" : val.width,
"1" : val.height,
}
};
''');
sb.writeln('widgetContext.onUpdate(id, widgetData);');
sb.writeln('}');
return sb.toString();
}
}
@@ -0,0 +1,49 @@
import 'impl.dart';
class SupportedOptionTemplate extends SettingsImpl {
bool isPrivate;
@override
String name;
@override
String key;
@override
String propertyType;
@override
String access() {
final sb = StringBuffer();
sb.writeln('$propertyType get ${name}Val {');
sb.write("if (params[${name}Key] != null) ");
sb.writeln('{');
sb.write('return ');
sb.write('$propertyType(params[${name}Key], widgetContext, widgetRender)');
sb.writeln(';');
sb.writeln('}');
sb.writeln("return null;");
sb.writeln('}');
sb.writeln('set ${name}Val($propertyType val) {');
sb.writeln('params[${name}Key] = val;');
sb.writeln('widgetContext.onUpdate(id, widgetData);');
sb.writeln('}');
return sb.toString();
}
@override
String constructor() {
final sb = StringBuffer();
sb.write(' ');
if (key != null && int.tryParse(key) != null) {
sb.write('');
} else if (key != null) {
sb.write("$key: ");
} else {
sb.write("$name: ");
}
sb.writeln("${name}Val?.build(context)");
sb.writeln(',');
return sb.toString();
}
}
@@ -0,0 +1,122 @@
import 'impl.dart';
import 'package:shortid/shortid.dart';
class WidgetOptionTemplate extends SettingsImpl {
String fallback;
bool isPrivate;
String acceptType;
double acceptWidth;
double acceptHeight;
@override
String name;
@override
String key;
@override
String propertyType;
@override
String access() {
final sb = StringBuffer();
if (acceptType != null) {
sb.writeln('final _${name}Listen = ValueNotifier<bool>(false);');
}
sb.writeln('WidgetBase get ${name}Val {');
sb.write("if (params[${name}Key] != null) ");
sb.writeln('{');
sb.write('return ');
sb.write('widgetRender(widgetContext, params[${name}Key])');
sb.writeln(';');
sb.writeln('}');
sb.writeln("return null;");
sb.writeln('}');
sb.writeln('void ${name}ValUpdate(Map<String, dynamic> val) {');
sb.write("""
final _data = val;
_data['id'] = '${shortid.generate()}';
if (_data['name'] == 'Text') {
_data['params']['style']['id'] = '${shortid.generate()}';
}
if (_data['name'] == 'Icon') {
_data['params']['0']['id'] = '${shortid.generate()}';
}
""");
sb.writeln('params[${name}Key] = _data;');
sb.writeln('widgetContext.onUpdate(id, widgetData);');
sb.writeln('}');
return sb.toString();
}
@override
String constructor() {
final sb = StringBuffer();
sb.write(' ');
if (key != null && int.tryParse(key) != null) {
sb.write('');
} else if (key != null) {
sb.write("$key: ");
} else {
sb.write("$name: ");
}
if (acceptType == null) {
sb.writeln('${name}Val?.build(context)');
} else {
sb.write("""
!widgetContext.isDragging || (widgetContext.isDragging && ${name}Val?.build(context) != null) ?
(
${name}Val?.build(context)
""");
if (fallback != null) {
sb.write("""
?? (widgetRender(widgetContext, json.decode(json.encode({
'id': '${shortid.generate()}',
'name': '$fallback',
'params': {},
})))).build(context)
""");
}
sb.write("""
)
""");
sb.write("""
:
PreferredSize(
preferredSize: Size(${acceptWidth ?? 30}, ${acceptHeight ?? 30}),
child: DragTarget<$acceptType>(
onAccept: (val) {
_${name}Listen.value = false;
if (val != null) {
${name}ValUpdate(val?.data);
}
},
onLeave: (val) {
_${name}Listen.value = false;
},
onWillAccept: (val) {
_${name}Listen.value = true;
return _${name}Listen.value;
},
builder: (context, accepted, rejected) {
return ValueListenableBuilder<bool>(
valueListenable: _${name}Listen,
builder: (context, _accepting, child) => SizedBox.fromSize(
size: Size(${acceptWidth ?? 30}, ${acceptHeight ?? 30}),
child: Placeholder(
color: !_accepting ?
Colors.grey :
Theme.of(context).accentColor,
),
));
},
),
)
""");
}
sb.writeln(',');
return sb.toString();
}
}
@@ -0,0 +1,12 @@
class Rows<T> {
final List<T> _templates = [];
void add(T template) => _templates.add(template);
bool get isEmpty => _templates.isEmpty;
List get templates => _templates;
@override
String toString() =>
_templates.map((t) => t.toString()).where((s) => s.isNotEmpty).join('\n');
}
@@ -0,0 +1,15 @@
const _analyzerIgnores =
'// ignore_for_file: non_constant_identifier_names, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic, avoid_init_to_null';
class StoreFileTemplate {
Iterable<String> storeSources;
@override
String toString() => storeSources.isEmpty
? ''
: '''
$_analyzerIgnores
${storeSources.join('\n\n')}
''';
}
@@ -0,0 +1,43 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:source_gen/source_gen.dart';
import '../type_names.dart';
import 'params.dart';
// ignore: avoid_annotating_with_dynamic
String surroundNonEmpty(String prefix, String suffix, dynamic content) {
final contentStr = content.toString();
return contentStr.isEmpty ? '' : '$prefix$contentStr$suffix';
}
const _streamChecker = TypeChecker.fromRuntime(Stream);
class AsyncMethodChecker {
AsyncMethodChecker([TypeChecker checkStream]) {
_checkStream = checkStream ?? _streamChecker;
}
TypeChecker _checkStream;
bool returnsFuture(MethodElement method) =>
method.returnType.isDartAsyncFuture ||
(method.isAsynchronous &&
!method.isGenerator &&
method.returnType.isDynamic);
bool returnsStream(MethodElement method) =>
_checkStream.isAssignableFromType(method.returnType) ||
(method.isAsynchronous &&
method.isGenerator &&
method.returnType.isDynamic);
}
TypeParamTemplate typeParamTemplate(
TypeParameterElement param,
LibraryScopedNameFinder typeNameFinder,
) =>
TypeParamTemplate()
..name = param.name
..bound = param.bound != null
? typeNameFinder.findTypeParameterBoundsTypeName(param)
: null;
@@ -0,0 +1,106 @@
import 'comma_list.dart';
import 'params.dart';
import 'properties/impl.dart';
class MixinStoreTemplate extends StoreTemplate {
final String extendsClass;
double width, height;
MixinStoreTemplate(this.extendsClass);
String get typeName => '_\$$publicTypeName';
@override
String toString() {
final sb = StringBuffer();
sb.writeln('abstract class $typeName$typeParams extends $extendsClass {');
for (final setting in settings) {
sb.write(setting.keyValue());
}
sb.writeln('');
final _hasPreferredSize = width != null || height != null;
if (_hasPreferredSize) {
sb.writeln('@override');
sb.write('Size get preferredSize => ');
if (width != null && height != null) {
sb.write('Size($width, $height)');
} else if (width != null) {
sb.write('Size.fromWidth($width)');
} else if (height != null) {
sb.write('Size.fromHeight($height)');
}
sb.writeln(';');
}
sb.writeln('');
sb.writeln('@override');
sb.writeln('Map<String, String> get properties => {');
for (final setting in settings) {
sb.write("'${setting?.key ?? setting.name}'");
sb.write(':');
sb.write("'${setting.propertyType}'");
sb.writeln(',');
}
sb.writeln('};');
sb.writeln('');
for (final setting in settings) {
sb.writeln(setting.access());
}
sb.writeln('');
sb.writeln('@override');
sb.writeln('Object build(BuildContext context) {');
sb.write(' return ');
if (allowTap) {
if (_hasPreferredSize) {
sb.writeln('PreferredSize(');
sb.writeln('preferredSize: preferredSize,');
sb.writeln('child: ');
}
sb.writeln('GestureDetector(');
sb.writeln("onTap: () => widgetContext.onTap(id, widgetData),");
sb.writeln('child: ');
}
if (isAnimated) {
sb.write('Animated');
}
sb.writeln('$widgetName(');
settings.sort((a, b) => (a?.key ?? a.name).compareTo((b?.key ?? b.name)));
if (isAnimated) {
sb.writeln(
'duration: const Duration(milliseconds: $animatedDurationMilliseconds),');
}
for (final setting in settings) {
sb.writeln(setting.constructor());
}
sb.writeln(')');
if (allowTap) {
if (_hasPreferredSize) {
sb.write(',');
sb.writeln(')');
}
sb.write(',');
sb.writeln(')');
}
sb.write(';');
sb.writeln('}');
sb.writeln('');
sb.writeln('}');
return sb.toString();
}
}
abstract class StoreTemplate {
final SurroundedCommaList<TypeParamTemplate> typeParams =
SurroundedCommaList('<', '>', []);
final SurroundedCommaList<String> typeArgs =
SurroundedCommaList('<', '>', []);
String publicTypeName;
String parentTypeName;
String widgetName;
bool isAnimated;
int animatedDurationMilliseconds;
bool allowTap;
final List<SettingsImpl> settings = [];
@override
String toString();
}
@@ -0,0 +1,141 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'template/comma_list.dart';
/// Determines the names of types within the context of a library, determining
/// prefixes if applicable.
///
/// For example, if a library has been imported with a name, references to types
/// contained or exported by that library must be prefixed by that name.
///
/// ```dart
/// import 'dart:io' as io;
///
/// io.File someFile;
/// ```
///
/// If we had a reference to `someFile`'s [Element], [findVariableTypeName]
/// would return `"io.File"`.
class LibraryScopedNameFinder {
LibraryScopedNameFinder(this.library);
final LibraryElement library;
Map<Element, String> _namesByElement;
Map<Element, String> get namesByElement {
if (_namesByElement != null) {
return _namesByElement;
}
_namesByElement = {};
// Add all of this library's type-defining elements to the name map
final libraryElements =
library.topLevelElements.whereType<TypeDefiningElement>();
for (final element in libraryElements) {
_namesByElement[element] = element.name;
}
// Reverse each import's export namespace so we can map elements to their
// library-local names. Note that the definedNames include a prefix if there
// is one.
for (final import in library.imports) {
for (final entry in import.namespace.definedNames.entries) {
_namesByElement[entry.value] = entry.key;
}
}
return _namesByElement;
}
String findVariableTypeName(VariableElement variable) =>
_getDartTypeName(variable.type);
String findGetterTypeName(PropertyAccessorElement getter) {
assert(getter.isGetter);
return findReturnTypeName(getter);
}
String findParameterTypeName(ParameterElement parameter) =>
_getDartTypeName(parameter.type);
String findReturnTypeName(FunctionTypedElement executable) =>
_getDartTypeName(executable.returnType);
List<String> findReturnTypeArgumentTypeNames(ExecutableElement executable) {
final returnType = executable.returnType;
return returnType is ParameterizedType
? returnType.typeArguments.map(_getDartTypeName).toList()
: [];
}
String findTypeParameterBoundsTypeName(TypeParameterElement typeParameter) {
assert(typeParameter.bound != null);
return _getDartTypeName(typeParameter.bound);
}
/// Calculates a type name, including its type arguments
///
/// The returned string will include import prefixes on all applicable types.
String _getDartTypeName(DartType type) {
var typeElement = type.element;
if (type is FunctionType) {
// If we're dealing with a typedef, we let it undergo the standard name
// lookup. Otherwise, we special case the function naming.
if (typeElement?.enclosingElement is GenericTypeAliasElement) {
typeElement = typeElement.enclosingElement;
} else {
return _getFunctionTypeName(type);
}
} else if (
// Some types don't have associated elements, like void
typeElement == null ||
// This is a bare type param, like "T"
type is TypeParameterType) {
// TODO(shyndman): This ignored deprecation can be removed when we
// increase the analyzer dependency's lower bound to 0.39.2, and
// migrate to using `DartType.getDisplayString`.
// ignore: deprecated_member_use
return type.displayName;
}
return _getNamedElementTypeName(typeElement, type);
}
String _getFunctionTypeName(FunctionType type) {
final returnTypeName = _getDartTypeName(type.returnType);
final normalParameterTypeNames =
CommaList(type.normalParameterTypes.map(_getDartTypeName).toList());
final optionalParameterTypeNames = SurroundedCommaList(
'[', ']', type.optionalParameterTypes.map(_getDartTypeName).toList());
final namedParameterPairs = type.namedParameterTypes.entries
.map((entry) => '${_getDartTypeName(entry.value)} ${entry.key}')
.toList();
final namedParameterTypeNames =
SurroundedCommaList('{', '}', namedParameterPairs);
final parameterTypeNames = CommaList([
normalParameterTypeNames,
optionalParameterTypeNames,
namedParameterTypeNames,
]);
return '$returnTypeName Function($parameterTypeNames)';
}
String _getNamedElementTypeName(Element typeElement, DartType type) {
// Determine the name of the type, without type arguments.
assert(namesByElement.containsKey(typeElement));
// If the type is parameterized, we recursively name its type arguments
if (type is ParameterizedType && type.typeArguments.isNotEmpty) {
final typeArgNames = SurroundedCommaList(
'<', '>', type.typeArguments.map(_getDartTypeName).toList());
return '${namesByElement[typeElement]}$typeArgNames';
}
return namesByElement[typeElement];
}
}
@@ -0,0 +1,2 @@
export 'src/class_annotation_gen.dart';
export 'widget_gen_annotations.dart';
@@ -0,0 +1,184 @@
/// Declares configuration of a SettingsStore class.
/// Currently the only configuration used is boolean to indicate generation of toString method (true), or not (false)
class WidgetClass {
const WidgetClass(
this.name, {
this.animated = false,
this.durationMilliseconds = 250,
this.preferredHeight,
this.preferredWidth,
this.allowTap = true,
});
final bool allowTap;
final bool animated;
final int durationMilliseconds;
final String name;
final double preferredHeight;
final double preferredWidth;
}
class PropertyClass {
const PropertyClass(this.name);
final String name;
}
class PropertyKey {
const PropertyKey({
this.defaultValue,
this.key,
this.tryParse = false,
});
final String defaultValue;
final String key;
final bool tryParse;
}
class FunctionKey {
const FunctionKey({
this.defaultValue,
this.key,
});
final String defaultValue;
final String key;
}
class EnumKey {
const EnumKey({
this.propertyType,
this.key,
this.values,
this.defaultValue,
});
final String defaultValue;
final String key;
final String propertyType;
final List<String> values;
}
class ColorKey {
const ColorKey({
this.defaultValue,
this.key,
});
final int defaultValue;
final String key;
}
class SupportedKey {
const SupportedKey({
this.key,
});
final String key;
}
class WidgetKey {
const WidgetKey({
this.key,
this.defaultValue,
this.acceptType,
this.acceptWidth,
this.acceptHeight,
});
const WidgetKey.sizedWidget({
this.key,
this.defaultValue,
this.acceptWidth,
this.acceptHeight,
}) : acceptType = 'WidgetPreferredSizeBaseData';
const WidgetKey.widget({
this.key,
this.defaultValue,
this.acceptWidth,
this.acceptHeight,
}) : acceptType = 'WidgetBaseData';
final double acceptHeight;
final String acceptType;
final double acceptWidth;
final String defaultValue;
final String key;
}
class ListWidgetKey {
const ListWidgetKey({
this.key,
this.fallback,
this.empty = true,
this.acceptType,
});
const ListWidgetKey.widget({
this.key,
this.fallback,
this.empty = true,
}) : acceptType = 'WidgetBaseData';
final String acceptType;
final bool empty;
final String fallback;
final String key;
}
class TreeKey {
const TreeKey({
this.key,
this.fallback,
});
final String fallback;
final String key;
}
class Matrix4Key {
const Matrix4Key({
this.key,
});
final String key;
}
class EdgeInsetsKey {
const EdgeInsetsKey({
this.key,
this.defaultValue = 0,
});
final double defaultValue;
final String key;
}
class SizeKey {
const SizeKey({
this.key,
});
final String key;
}
class OffsetKey {
const OffsetKey({
this.key,
});
final String key;
}
class IconDataKey {
const IconDataKey({
this.defaultValue,
this.key,
});
final int defaultValue;
final String key;
}