adding packages
This commit is contained in:
@@ -0,0 +1,270 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:flutter_ast/src/generator/parser.dart';
|
||||
import 'package:flutter_ast_core/flutter_ast_core.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
import 'package:build_cli_annotations/build_cli_annotations.dart';
|
||||
import "package:console/console.dart";
|
||||
import 'package:flutter_ast/flutter_ast.dart';
|
||||
import 'package:mustache_template/mustache_template.dart';
|
||||
import 'package:recase/recase.dart';
|
||||
|
||||
part 'generator.g.dart';
|
||||
|
||||
@CliOptions()
|
||||
class Options {
|
||||
@CliOption(
|
||||
abbr: 'p',
|
||||
help: 'Required. The path to the Directory of widgets or Single File',
|
||||
)
|
||||
final String path;
|
||||
|
||||
@CliOption(
|
||||
abbr: 'o',
|
||||
help: 'The path to the Directory output.',
|
||||
defaultsTo: 'build',
|
||||
)
|
||||
final String output;
|
||||
|
||||
@CliOption(
|
||||
negatable: false,
|
||||
help: 'Prints usage information.',
|
||||
)
|
||||
bool help;
|
||||
|
||||
Options(this.path, this.output);
|
||||
}
|
||||
|
||||
const kBasePath =
|
||||
'/Users/rodydavis/Developer/GitHub/protoypes/widget_studio/third_party/flutter_dynamic_widget/third_party/flutter_ast';
|
||||
|
||||
final cache = Cache();
|
||||
// dart ./bin/flutter_gen.dart -p /Users/rodydavis/Developer/GitHub/protoypes/widget_studio/third_party/flutter/packages/flutter/lib/src/material
|
||||
void main(List<String> args) {
|
||||
Console.init();
|
||||
final options = parseOptions(args);
|
||||
final output = Directory(options.output);
|
||||
final inputDir = Directory(options.path);
|
||||
final inputFile = File(options.path);
|
||||
final _paths = <String>[];
|
||||
if (inputDir.existsSync()) {
|
||||
_processDirectory(inputDir, inputDir, output, _paths);
|
||||
} else if (inputFile.existsSync()) {
|
||||
_paths.add(inputFile.path);
|
||||
} else {
|
||||
throw Exception('Not a valid path!');
|
||||
}
|
||||
|
||||
final template = _getTemplate('widget');
|
||||
var progress = ProgressBar(complete: _paths.length);
|
||||
var i = 0;
|
||||
final parser = GenParser();
|
||||
for (final path in _paths) {
|
||||
_processFile(output, File(path), template, parser);
|
||||
progress.update(++i);
|
||||
}
|
||||
_getFile(output.path, 'base.dart').writeAsStringSync(_base);
|
||||
final files = Directory(p.join(output.path, 'classes')).listSync();
|
||||
final imports = files
|
||||
.map((item) => "export 'classes/${p.basename(item.path)}';")
|
||||
.toList();
|
||||
imports.sort();
|
||||
_getFile(output.path, 'index.dart').writeAsStringSync(imports.join('\n'));
|
||||
final sb = StringBuffer();
|
||||
sb.writeln("import 'index.dart';");
|
||||
sb.writeln("import 'base.dart';");
|
||||
sb.writeln();
|
||||
sb.writeln("Map<String, BaseWidget> widgetLibrary = {");
|
||||
final List<String> _names = [];
|
||||
for (final file in files) {
|
||||
final _result = cache.getCache(p.basename(file.path));
|
||||
if (_result == null) continue;
|
||||
for (final item in _result.file.classes) {
|
||||
if (item.isValid) _names.add(item.name);
|
||||
}
|
||||
}
|
||||
_names.sort();
|
||||
for (final name in _names) {
|
||||
sb.writeln(" '${name}': ${name}Base.readOnly(),");
|
||||
}
|
||||
sb.writeln('};');
|
||||
_getFile(output.path, 'library.dart').writeAsStringSync(sb.toString());
|
||||
// writeIndex(_paths, output);
|
||||
print(parser.toString());
|
||||
}
|
||||
|
||||
Template _getTemplate(String name) {
|
||||
final _typePath = File('$kBasePath/templates/$name.dart.mustache');
|
||||
final _template = Template(
|
||||
_typePath.readAsStringSync(),
|
||||
name: _typePath.path,
|
||||
lenient: true,
|
||||
htmlEscapeValues: false,
|
||||
);
|
||||
return _template;
|
||||
}
|
||||
|
||||
void _processDirectory(
|
||||
Directory dir,
|
||||
Directory input,
|
||||
Directory output,
|
||||
List<String> paths,
|
||||
) {
|
||||
for (final file in dir.listSync(recursive: true)) {
|
||||
if (file is Directory) {
|
||||
_processDirectory(file, input, output, paths);
|
||||
} else {
|
||||
paths.add(p.relative(file.path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _processFile(
|
||||
Directory output, File input, Template template, GenParser parser) {
|
||||
final source = input.readAsStringSync();
|
||||
parser.merge(source);
|
||||
final result = parseSource(source, input.path);
|
||||
cache.setCache(p.basename(input.path), result);
|
||||
final _base = result.file;
|
||||
if (_base?.classes != null && _base.classes.isNotEmpty) {
|
||||
for (final item in _base.classes) {
|
||||
if (item.isValid) {
|
||||
if (!cache.addName(item.name)) continue;
|
||||
final _template = _processClass(item, input);
|
||||
if (_template == null) continue;
|
||||
final name = ReCase(item.name).snakeCase;
|
||||
final _path = 'classes/' + name + '.dart';
|
||||
final _file = _getFile(output.path, _path);
|
||||
final _output = template.renderString(_template);
|
||||
if (_output.trim().isEmpty) {
|
||||
_file.deleteSync();
|
||||
return;
|
||||
}
|
||||
_file.writeAsStringSync(_output);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> _processClass(
|
||||
DartClass item,
|
||||
File input,
|
||||
) {
|
||||
if (!item.name.startsWith('_') &&
|
||||
!input.path.contains('.g.dart') &&
|
||||
!item.isAbstract) {
|
||||
final _comments = item.comments?.map((e) => e.comment)?.toList() ?? [];
|
||||
final _root = <String, dynamic>{
|
||||
"imports": [
|
||||
{'path': "import '../base.dart';"},
|
||||
],
|
||||
'class': item.name,
|
||||
'constructors': [],
|
||||
'fields': [],
|
||||
'static': [],
|
||||
'comments': _comments,
|
||||
'description': _comments.join('/n'),
|
||||
};
|
||||
for (final sub in item.constructors) {
|
||||
final isDefault = item.name == sub.name;
|
||||
final _name = isDefault ? '${item.name}' : '${item.name}.${sub.name}';
|
||||
if (_name.startsWith('_') || _name.contains('._')) continue;
|
||||
_root['constructors'].add(buildConstructor(_name, sub));
|
||||
}
|
||||
for (final field in item.fields) {
|
||||
if (field is DartField) {
|
||||
_root['fields'].add({
|
||||
'key': field?.name ?? '',
|
||||
'type': field?.type ?? 'dynamic',
|
||||
'value': field?.value?.value ?? 'null',
|
||||
});
|
||||
}
|
||||
}
|
||||
_root['constructor_divider'] =
|
||||
List.from(_root['fields']).isEmpty ? '' : ':';
|
||||
if (List.from(_root['constructors']).isNotEmpty) return _root;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, dynamic> buildConstructor(String name, DartConstructor item) {
|
||||
return {
|
||||
'name': name,
|
||||
'widget': '$name()',
|
||||
'json': jsonEncode({
|
||||
'name': '$name',
|
||||
'params': {},
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
class Cache {
|
||||
final _files = <String, DartResult>{};
|
||||
final _names = <String>{};
|
||||
|
||||
void setCache(String path, DartResult result) => _files[path] = result;
|
||||
DartResult getCache(String path) => _files[path];
|
||||
|
||||
bool addName(String name) => _names.add(name);
|
||||
List<String> get name => _names.toList();
|
||||
}
|
||||
|
||||
extension on DartClass {
|
||||
String get extendedClasses {
|
||||
final _extends = (this?.extendsClause ?? '').replaceAll('extends ', '');
|
||||
if (_extends.isEmpty) return '';
|
||||
return _extends;
|
||||
}
|
||||
|
||||
bool get isValid {
|
||||
if (this.name.startsWith('_')) return false;
|
||||
if (this.isAbstract) return false;
|
||||
if (extendedClasses.isEmpty) return false;
|
||||
if ([
|
||||
'StatelessWidget',
|
||||
'StatefulWidget',
|
||||
'MaterialButton',
|
||||
'InheritedWidget',
|
||||
'InheritedTheme',
|
||||
'InlineSpan',
|
||||
'RenderObjectWidget',
|
||||
'BoxScrollView',
|
||||
'ScrollView',
|
||||
'SingleChildRenderObjectWidget',
|
||||
].contains(extendedClasses)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
File _getFile(String output, String filename) {
|
||||
final metaData = File('$output/$filename');
|
||||
if (!metaData.existsSync()) metaData.createSync(recursive: true);
|
||||
return metaData;
|
||||
}
|
||||
|
||||
String get _base => '''
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
export 'package:flutter/material.dart';
|
||||
export 'package:flutter/cupertino.dart' hide RefreshCallback;
|
||||
|
||||
abstract class BaseWidget extends ValueNotifier<Map<String, dynamic>> implements Base {
|
||||
BaseWidget() : super({});
|
||||
Map<String, Object> flavors(BuildContext context);
|
||||
List<String> get constructors;
|
||||
Map<String, String> get properties;
|
||||
String get constructor;
|
||||
Object render(BuildContext context) => flavors(context)[constructor];
|
||||
bool isWidget(BuildContext context) => render(context) is Widget;
|
||||
dynamic getProperty(String key);
|
||||
setProperty(String key, dynamic value);
|
||||
}
|
||||
|
||||
abstract class Base {
|
||||
Map<String, dynamic> toJson();
|
||||
String get description;
|
||||
}
|
||||
''';
|
||||
@@ -0,0 +1,25 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'generator.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// CliGenerator
|
||||
// **************************************************************************
|
||||
|
||||
Options _$parseOptionsResult(ArgResults result) =>
|
||||
Options(result['path'] as String, result['output'] as String)
|
||||
..help = result['help'] as bool;
|
||||
|
||||
ArgParser _$populateOptionsParser(ArgParser parser) => parser
|
||||
..addOption('path',
|
||||
abbr: 'p', help: 'Required. The path to the Directory of widgets.')
|
||||
..addOption('output',
|
||||
abbr: 'o', help: 'The path to the Directory output.', defaultsTo: 'build')
|
||||
..addFlag('help', help: 'Prints usage information.', negatable: false);
|
||||
|
||||
final _$parserForOptions = _$populateOptionsParser(ArgParser());
|
||||
|
||||
Options parseOptions(List<String> args) {
|
||||
final result = _$parserForOptions.parse(args);
|
||||
return _$parseOptionsResult(result);
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import 'package:analyzer/dart/analysis/utilities.dart';
|
||||
import 'package:analyzer/error/error.dart';
|
||||
import 'package:flutter_ast_core/flutter_ast_core.dart';
|
||||
|
||||
import 'src/index.dart';
|
||||
export 'src/index.dart';
|
||||
|
||||
DartResult parseSource(String source, [String path]) {
|
||||
assert(source != null && source.isNotEmpty);
|
||||
final result = parseString(
|
||||
content: source,
|
||||
path: path,
|
||||
throwIfDiagnostics: false,
|
||||
);
|
||||
final root = result.unit.root;
|
||||
final file = root.toDartFile();
|
||||
final output = DartResult(file);
|
||||
if (result.errors.isNotEmpty) {
|
||||
output.errors.addAll(result.errors);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
class DartResult {
|
||||
DartResult(this.file);
|
||||
final DartFile file;
|
||||
final List<AnalysisError> errors = [];
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'file': file,
|
||||
'errors': [
|
||||
for (final error in errors) error,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => toJson().prettyPrint();
|
||||
}
|
||||
|
||||
extension AnalysisErrorUtils on AnalysisError {
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'message': this.message,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void printMembers(CompilationUnit unit) {
|
||||
for (CompilationUnitMember unitMember in unit.declarations) {
|
||||
if (unitMember is ClassDeclaration) {
|
||||
print(unitMember.name.name);
|
||||
for (ClassMember classMember in unitMember.members) {
|
||||
if (classMember is MethodDeclaration) {
|
||||
print(' ${classMember.name}');
|
||||
} else if (classMember is FieldDeclaration) {
|
||||
for (VariableDeclaration field in classMember.fields.variables) {
|
||||
print(' ${field.name.name}');
|
||||
}
|
||||
} else if (classMember is ConstructorDeclaration) {
|
||||
if (classMember.name == null) {
|
||||
print(' ${unitMember.name.name}');
|
||||
} else {
|
||||
print(' ${unitMember.name.name}.${classMember.name.name}');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export 'package:analyzer/dart/ast/ast.dart';
|
||||
export 'package:analyzer/src/dart/ast/ast.dart';
|
||||
export 'package:analyzer/dart/analysis/utilities.dart';
|
||||
export 'package:analyzer/dart/ast/syntactic_entity.dart';
|
||||
export 'package:_fe_analyzer_shared/src/scanner/token_impl.dart';
|
||||
export 'package:analyzer/dart/analysis/results.dart';
|
||||
@@ -0,0 +1,38 @@
|
||||
import 'package:flutter_ast_core/flutter_ast_core.dart';
|
||||
|
||||
import 'analyzer.dart';
|
||||
import 'comment.dart';
|
||||
import 'index.dart';
|
||||
|
||||
extension ClauseDeclarationImplUtils on ClassDeclarationImpl {
|
||||
DartClass toDartClass(DartFile parent) {
|
||||
DartClass base = DartClass(name: this.name.toString());
|
||||
final List<DartField> fields = [];
|
||||
for (final item in this.childEntities.whereType<FieldDeclarationImpl>()) {
|
||||
fields.add(item.toDartField());
|
||||
}
|
||||
final List<DartConstructor> constructors = [];
|
||||
for (final item
|
||||
in this.childEntities.whereType<ConstructorDeclarationImpl>()) {
|
||||
constructors.add(item.toDartConstructor(base));
|
||||
}
|
||||
final List<DartMethod> methods = [];
|
||||
for (final item in this.childEntities.whereType<MethodDeclarationImpl>()) {
|
||||
methods.add(item.toDartMethod(base));
|
||||
}
|
||||
final List<DartComment> comments = [];
|
||||
for (final item in this.childEntities.whereType<CommentImpl>()) {
|
||||
comments.add(item.toDartComment());
|
||||
}
|
||||
return base.copyWith(
|
||||
isAbstract: this?.abstractKeyword != null,
|
||||
extendsClause: this?.extendsClause?.toString(),
|
||||
implementsClause: this?.implementsClause?.toString(),
|
||||
withClause: this?.withClause?.toString(),
|
||||
fields: fields,
|
||||
constructors: constructors,
|
||||
methods: methods,
|
||||
comments: comments,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import 'package:flutter_ast_core/flutter_ast_core.dart';
|
||||
|
||||
import 'analyzer.dart';
|
||||
import 'index.dart';
|
||||
|
||||
extension DartCommentUtils on CommentImpl {
|
||||
DartComment toDartComment() {
|
||||
final _lines = <String>[];
|
||||
for (final child in this.childEntities) {
|
||||
final _desc = child.toString();
|
||||
if (_desc.contains('///')) {
|
||||
final line = _desc.replaceFirst('/// ', '').replaceFirst('///', '');
|
||||
_lines.add(line);
|
||||
}
|
||||
}
|
||||
return DartComment(lines: _lines);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import 'package:flutter_ast_core/flutter_ast_core.dart';
|
||||
|
||||
import 'analyzer.dart';
|
||||
import 'index.dart';
|
||||
|
||||
extension ConstructorDeclarationImplUtils on ConstructorDeclarationImpl {
|
||||
DartConstructor toDartConstructor(DartClass parent) {
|
||||
DartConstructor base;
|
||||
String _name = '';
|
||||
for (final node in this.childEntities) {
|
||||
if (node is SimpleIdentifierImpl) {
|
||||
_name = node.name;
|
||||
}
|
||||
if (node is DeclaredSimpleIdentifier) {
|
||||
_name = node.name;
|
||||
}
|
||||
base = DartConstructor(name: _name);
|
||||
if (node is FormalParameterListImpl) {
|
||||
for (final child in node.childEntities) {
|
||||
if (child is DefaultFormalParameterImpl) {
|
||||
final _props = List<DartProperty>.from(base.properties);
|
||||
_props.add(child.toDartProperty(parent.fields));
|
||||
base = base.copyWith(properties: _props);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return base;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import 'package:flutter_ast_core/flutter_ast_core.dart';
|
||||
|
||||
import 'analyzer.dart';
|
||||
|
||||
extension LiteralImplUtils on LiteralImpl {
|
||||
DartCore toDartCore() {
|
||||
final value = this;
|
||||
if (value is BooleanLiteralImpl) {
|
||||
return DartCore(
|
||||
type: 'bool',
|
||||
value: value.value.toString(),
|
||||
);
|
||||
}
|
||||
if (value is IntegerLiteralImpl) {
|
||||
return DartCore(
|
||||
type: 'int',
|
||||
value: value.value.toString(),
|
||||
);
|
||||
}
|
||||
if (value is DoubleLiteralImpl) {
|
||||
return DartCore(
|
||||
type: 'double',
|
||||
value: value.value.toString(),
|
||||
);
|
||||
}
|
||||
if (value is StringLiteralImpl) {
|
||||
return DartCore(
|
||||
type: 'String',
|
||||
value: value.stringValue.toString(),
|
||||
);
|
||||
}
|
||||
if (value is SetOrMapLiteralImpl) {
|
||||
return DartCore(
|
||||
type: 'Map',
|
||||
value: value.toString(),
|
||||
);
|
||||
}
|
||||
if (value is ListLiteralImpl) {
|
||||
return DartCore(
|
||||
type: 'List',
|
||||
value: value.toString(),
|
||||
);
|
||||
}
|
||||
return DartCore(
|
||||
type: null,
|
||||
value: value.toString(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import 'package:flutter_ast_core/flutter_ast_core.dart';
|
||||
|
||||
import 'analyzer.dart';
|
||||
import 'index.dart';
|
||||
|
||||
extension EnumDeclarationImplUtils on EnumDeclarationImpl {
|
||||
DartEnum toDartEnum() {
|
||||
final _name = this.name.toString();
|
||||
final _values = this.constants.map((e) => e.name.toString()).toList();
|
||||
return DartEnum(
|
||||
name: _name,
|
||||
values: _values,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import 'dart:convert';
|
||||
|
||||
extension Utils on Object {
|
||||
String get description => '${this.runtimeType} -> $this';
|
||||
void debug() => print(description);
|
||||
}
|
||||
|
||||
extension MapUtils on Map {
|
||||
String prettyPrint() {
|
||||
JsonEncoder encoder = new JsonEncoder.withIndent(' ');
|
||||
return encoder.convert(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
import 'package:flutter_ast_core/flutter_ast_core.dart';
|
||||
|
||||
import 'analyzer.dart';
|
||||
import 'index.dart';
|
||||
|
||||
extension FieldDeclarationImplUtils on FieldDeclarationImpl {
|
||||
DartField toDartField() {
|
||||
DartField _base;
|
||||
for (final node in this.root.childEntities) {
|
||||
if (node is VariableDeclarationListImpl) {
|
||||
_base = _process(node);
|
||||
}
|
||||
}
|
||||
return _base;
|
||||
}
|
||||
}
|
||||
|
||||
extension TopLevelVariableDeclarationImplUtils
|
||||
on TopLevelVariableDeclarationImpl {
|
||||
DartField toDartField() {
|
||||
DartField _base;
|
||||
for (final node in this.root.childEntities) {
|
||||
if (node is VariableDeclarationListImpl) {
|
||||
_base = _process(node);
|
||||
}
|
||||
}
|
||||
return _base;
|
||||
}
|
||||
}
|
||||
|
||||
extension DefaultFormalParameterImplUtils on DefaultFormalParameterImpl {
|
||||
DartProperty toDartProperty(List<DartField> fields) {
|
||||
DartProperty base;
|
||||
bool _hasValue = false;
|
||||
for (final node in this.root.childEntities) {
|
||||
if (node is SimpleFormalParameterImpl) {
|
||||
base = _processProperty(node);
|
||||
for (final child in node.childEntities) {
|
||||
if (child is DeclaredSimpleIdentifier) {
|
||||
base = base.copyWith(name: child.toString());
|
||||
}
|
||||
if (child is TypeNameImpl) {
|
||||
base = base.copyWith(type: child.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node is FieldFormalParameterImpl) {
|
||||
base = _processProperty(node);
|
||||
for (final child in node.childEntities) {
|
||||
if (child is SimpleIdentifierImpl) {
|
||||
base = base.copyWith(name: child.toString());
|
||||
}
|
||||
}
|
||||
if (fields != null)
|
||||
for (final field in fields) {
|
||||
if (field.name == base.name) {
|
||||
base = base.copyWith(type: field.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node.runtimeType.toString() == 'SimpleToken' &&
|
||||
node.toString() == '=') {
|
||||
_hasValue = true;
|
||||
continue;
|
||||
}
|
||||
if (_hasValue && node is LiteralImpl) {
|
||||
base = base.copyWith(value: node.toDartCore());
|
||||
}
|
||||
}
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
DartField _processField(FormalParameter node) {
|
||||
return DartField(
|
||||
name: null,
|
||||
type: null,
|
||||
isConst: node.isConst,
|
||||
isFinal: node.isFinal,
|
||||
);
|
||||
}
|
||||
|
||||
DartProperty _processProperty(FormalParameter node) {
|
||||
return DartProperty(
|
||||
name: null,
|
||||
type: null,
|
||||
isNamed: node.isNamed,
|
||||
isOptional: node.isOptional,
|
||||
isPositional: node.isPositional,
|
||||
isRequired: node.isRequired,
|
||||
isRequiredPositional: node.isRequiredPositional,
|
||||
isSynthetic: node.isSynthetic,
|
||||
isRequiredNamed: node.isRequiredNamed,
|
||||
isOptionalNamed: node.isOptionalNamed,
|
||||
);
|
||||
}
|
||||
|
||||
DartField _process(VariableDeclarationListImpl node) {
|
||||
String _type, _name;
|
||||
for (final child in node.childEntities) {
|
||||
if (child is TypeNameImpl) {
|
||||
final TypeNameImpl _node = child;
|
||||
_type = _node.toString();
|
||||
}
|
||||
if (child is VariableDeclarationImpl) {
|
||||
_name = child.name.toString();
|
||||
}
|
||||
}
|
||||
return DartField(
|
||||
type: _type,
|
||||
name: _name,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import 'package:flutter_ast_core/flutter_ast_core.dart';
|
||||
|
||||
import 'analyzer.dart';
|
||||
import 'index.dart';
|
||||
|
||||
extension AstNodeUtils on AstNode {
|
||||
DartFile toDartFile([String path]) {
|
||||
DartFile base = DartFile(path: path);
|
||||
|
||||
final List<String> imports = [];
|
||||
for (final node in root.childEntities.whereType<ImportDirectiveImpl>()) {
|
||||
final ImportDirectiveImpl _node = node;
|
||||
final _url = _node.uri.stringValue;
|
||||
imports.add(_url);
|
||||
}
|
||||
base = base.copyWith(imports: imports);
|
||||
|
||||
final List<DartField> fields = [];
|
||||
for (final node
|
||||
in root.childEntities.whereType<TopLevelVariableDeclarationImpl>()) {
|
||||
fields.add(node.toDartField());
|
||||
}
|
||||
base = base.copyWith(fields: fields);
|
||||
|
||||
final List<DartMethod> methods = [];
|
||||
for (final node
|
||||
in root.childEntities.whereType<FunctionDeclarationImpl>()) {
|
||||
methods.add(node.toDartMethod());
|
||||
}
|
||||
base = base.copyWith(methods: methods);
|
||||
|
||||
final List<DartClass> classes = [];
|
||||
for (final node in root.childEntities.whereType<ClassDeclarationImpl>()) {
|
||||
final ClassDeclarationImpl _node = node;
|
||||
classes.add(_node.toDartClass(base));
|
||||
}
|
||||
base = base.copyWith(classes: classes);
|
||||
|
||||
final List<DartEnum> enums = [];
|
||||
for (final node in root.childEntities.whereType<EnumDeclarationImpl>()) {
|
||||
final EnumDeclarationImpl _node = node;
|
||||
enums.add(_node.toDartEnum());
|
||||
}
|
||||
base = base.copyWith(enums: enums);
|
||||
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
extension DartFileUtils on DartFile {
|
||||
String toDart() {
|
||||
final sb = StringBuffer();
|
||||
// TODO: Write back out to Dart
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import 'package:flutter_ast_core/flutter_ast_core.dart';
|
||||
|
||||
import '../../flutter_ast.dart';
|
||||
|
||||
class GenParser {
|
||||
GenParser();
|
||||
|
||||
List<DartClass> get classes => _classes.values.toList(growable: false);
|
||||
final Map<String, DartClass> _classes = {};
|
||||
DartClass getClass(String key) =>
|
||||
_classes.containsKey(key) ? _classes[key] : null;
|
||||
|
||||
List<DartEnum> get enums => _enums.toList(growable: false);
|
||||
final Set<DartEnum> _enums = {};
|
||||
|
||||
List<DartField> get fields => _fields.toList(growable: false);
|
||||
final Set<DartField> _fields = {};
|
||||
|
||||
List<DartMethod> get methods => _methods.toList(growable: false);
|
||||
final Set<DartMethod> _methods = {};
|
||||
|
||||
List<String> get imports => _imports.toList(growable: false);
|
||||
final Set<String> _imports = {};
|
||||
|
||||
factory GenParser.fromString(String source) {
|
||||
final base = GenParser();
|
||||
base.merge(source);
|
||||
return base;
|
||||
}
|
||||
|
||||
factory GenParser.fromListString(List<String> sources) {
|
||||
final base = GenParser();
|
||||
for (final source in sources) {
|
||||
base.merge(source);
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
void merge(String source) {
|
||||
final DartResult result = parseSource(source);
|
||||
if (result?.file != null) {
|
||||
if (result?.file?.classes != null) {
|
||||
for (final item in result.file.classes) {
|
||||
this._classes.putIfAbsent(item.name, () => item);
|
||||
}
|
||||
}
|
||||
if (result?.file?.enums != null) {
|
||||
this._enums.addAll(result.file.enums);
|
||||
}
|
||||
if (result?.file?.fields != null) {
|
||||
this._fields.addAll(result.file.fields);
|
||||
}
|
||||
if (result?.file?.methods != null) {
|
||||
this._methods.addAll(result.file.methods);
|
||||
}
|
||||
if (result?.file?.imports != null) {
|
||||
this._imports.addAll(result.file.imports);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final sb = StringBuffer();
|
||||
sb.writeln('-- RESULTS --');
|
||||
sb.writeln('Classes: ${this.classes.length}');
|
||||
sb.writeln('Enums: ${this.enums.length}');
|
||||
sb.writeln('Imports: ${this.imports.length}');
|
||||
sb.writeln('Methods: ${this.methods.length}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export 'analyzer.dart';
|
||||
export 'class.dart';
|
||||
export 'comment.dart';
|
||||
export 'constructor.dart';
|
||||
export 'core.dart';
|
||||
export 'enum.dart';
|
||||
export 'extensions.dart';
|
||||
export 'field.dart';
|
||||
export 'file.dart';
|
||||
export 'method.dart';
|
||||
@@ -0,0 +1,225 @@
|
||||
import 'package:flutter_ast_core/flutter_ast_core.dart';
|
||||
|
||||
import 'analyzer.dart';
|
||||
import 'core.dart';
|
||||
|
||||
extension MethodDeclarationImplUtils on MethodDeclarationImpl {
|
||||
DartMethod toDartMethod(DartClass parent) {
|
||||
return DartMethod(
|
||||
name: this.name.toString(),
|
||||
body: _check(this),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension FunctionBodyImplUtils on FunctionBodyImpl {
|
||||
DartMethod toDartMethod(DartClass parent) {
|
||||
return DartMethod(
|
||||
name: null,
|
||||
body: _check(this),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension FunctionDeclarationImplUtils on FunctionDeclarationImpl {
|
||||
DartMethod toDartMethod() {
|
||||
return DartMethod(
|
||||
name: this.name.toString(),
|
||||
body: _check(this),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MethodNode _check(SyntacticEntity node) {
|
||||
if (node is FunctionDeclarationImpl) {
|
||||
return _processFunctionDeclaration(node);
|
||||
}
|
||||
if (node is MethodDeclarationImpl) {
|
||||
return _processMethodDeclarationImpl(node);
|
||||
}
|
||||
if (node is FunctionExpressionImpl) {
|
||||
return _processFunction(node);
|
||||
}
|
||||
if (node is DeclaredSimpleIdentifier) {
|
||||
return _processDeclaration(node);
|
||||
}
|
||||
if (node is MethodInvocationImpl) {
|
||||
return _processMethod(node);
|
||||
}
|
||||
if (node is ReturnStatementImpl) {
|
||||
return _processReturn(node);
|
||||
}
|
||||
if (node is IfStatementImpl) {
|
||||
return _processIfStatement(node);
|
||||
}
|
||||
if (node is ConditionalExpressionImpl) {
|
||||
return _processConditional(node);
|
||||
}
|
||||
if (node is BlockFunctionBodyImpl) {
|
||||
return _processBlockBody(node);
|
||||
}
|
||||
if (node is BlockImpl) {
|
||||
return _processBlock(node);
|
||||
}
|
||||
if (node is BinaryExpressionImpl) {
|
||||
return _processBinary(node);
|
||||
}
|
||||
if (node is SimpleIdentifierImpl) {
|
||||
return MethodNode.simple(
|
||||
name: 'name',
|
||||
value: node.name,
|
||||
);
|
||||
}
|
||||
if (node is LiteralImpl) {
|
||||
return MethodNode.simple(
|
||||
name: 'value',
|
||||
value: node.toDartCore(),
|
||||
);
|
||||
}
|
||||
if (node is TypeNameImpl) {
|
||||
return MethodNode.simple(
|
||||
name: 'type',
|
||||
value: node.toString(),
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
MethodNode _processFunctionDeclaration(FunctionDeclarationImpl node) {
|
||||
final List<MethodNode> values = [];
|
||||
for (final child in node.childEntities) {
|
||||
_checkAndAdd(child, values);
|
||||
}
|
||||
return MethodNode.values(
|
||||
name: 'function_declaration',
|
||||
values: values,
|
||||
);
|
||||
}
|
||||
|
||||
MethodNode _processMethodDeclarationImpl(MethodDeclarationImpl node) {
|
||||
final List<MethodNode> values = [];
|
||||
for (final child in node.childEntities) {
|
||||
_checkAndAdd(child, values);
|
||||
}
|
||||
return MethodNode.values(
|
||||
name: 'method_declaration',
|
||||
values: values,
|
||||
);
|
||||
}
|
||||
|
||||
MethodNode _processIfStatement(IfStatementImpl node) {
|
||||
final List<MethodNode> values = [];
|
||||
for (final child in node.childEntities) {
|
||||
_checkAndAdd(child, values);
|
||||
}
|
||||
return MethodNode.values(
|
||||
name: 'if',
|
||||
values: values,
|
||||
);
|
||||
}
|
||||
|
||||
MethodNode _processFunction(FunctionExpressionImpl node) {
|
||||
final List<MethodNode> values = [];
|
||||
for (final child in node.childEntities) {
|
||||
_checkAndAdd(child, values);
|
||||
}
|
||||
return MethodNode.values(
|
||||
name: 'function',
|
||||
values: values,
|
||||
);
|
||||
}
|
||||
|
||||
MethodNode _processDeclaration(DeclaredSimpleIdentifier node) {
|
||||
final List<MethodNode> values = [];
|
||||
// Check name meta getter/setter
|
||||
for (final child in node.childEntities) {
|
||||
_checkAndAdd(child, values);
|
||||
}
|
||||
return MethodNode.values(
|
||||
name: 'declaration',
|
||||
values: values,
|
||||
);
|
||||
}
|
||||
|
||||
MethodNode _processMethod(MethodInvocationImpl node) {
|
||||
final Map<String, MethodNode> arguments = {};
|
||||
final args = node.argumentList;
|
||||
for (var i = 0; i < args.arguments.length; i++) {
|
||||
final arg = args.arguments[i];
|
||||
if (arg is LiteralImpl) {
|
||||
arguments['$i'] = MethodNode.simple(
|
||||
name: 'value',
|
||||
value: arg.toDartCore(),
|
||||
);
|
||||
}
|
||||
if (arg is NamedExpressionImpl) {
|
||||
arguments[arg.name.label.toString()] = _check(arg.expression);
|
||||
}
|
||||
}
|
||||
return MethodNode.constructor(
|
||||
name: 'constructor',
|
||||
value: node.methodName.name,
|
||||
arguments: arguments,
|
||||
);
|
||||
}
|
||||
|
||||
MethodNode _processBinary(BinaryExpressionImpl node) {
|
||||
final _children = node.childEntities.toList();
|
||||
return MethodNode.binary(
|
||||
name: 'binary',
|
||||
left: _check(_children[0]),
|
||||
right: _check(_children[2]),
|
||||
operation: _children[1].toString(),
|
||||
);
|
||||
}
|
||||
|
||||
MethodNode _processConditional(ConditionalExpressionImpl node) {
|
||||
final List<MethodNode> values = [];
|
||||
for (final child in node.childEntities) {
|
||||
_checkAndAdd(child, values);
|
||||
}
|
||||
return MethodNode.values(
|
||||
name: 'conditional',
|
||||
values: values,
|
||||
);
|
||||
}
|
||||
|
||||
MethodNode _processReturn(ReturnStatementImpl node) {
|
||||
final List<MethodNode> values = [];
|
||||
for (final child in node.childEntities) {
|
||||
_checkAndAdd(child, values);
|
||||
}
|
||||
return MethodNode.values(
|
||||
name: 'return',
|
||||
values: values,
|
||||
);
|
||||
}
|
||||
|
||||
MethodNode _processBlock(BlockImpl node) {
|
||||
final List<MethodNode> values = [];
|
||||
for (final child in node.childEntities) {
|
||||
_checkAndAdd(child, values);
|
||||
}
|
||||
return MethodNode.values(
|
||||
name: 'block',
|
||||
values: values,
|
||||
);
|
||||
}
|
||||
|
||||
MethodNode _processBlockBody(BlockFunctionBodyImpl node) {
|
||||
final List<MethodNode> values = [];
|
||||
for (final child in node.childEntities) {
|
||||
_checkAndAdd(child, values);
|
||||
}
|
||||
return MethodNode.values(
|
||||
name: 'block_body',
|
||||
values: values,
|
||||
);
|
||||
}
|
||||
|
||||
void _checkAndAdd(SyntacticEntity child, List<MethodNode> values) {
|
||||
final _value = _check(child);
|
||||
if (_value != null && _value.name != null) {
|
||||
values.add(_value);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user