├── CHANGELOG.md ├── .gitattributes ├── lib ├── src │ ├── constants.dart │ ├── interpreter │ │ ├── IExpression.dart │ │ ├── scope.dart │ │ ├── other │ │ │ ├── argument_item.dart │ │ │ ├── raw_code.dart │ │ │ ├── parameter_item.dart │ │ │ ├── import.dart │ │ │ ├── enum.dart │ │ │ ├── parameter.dart │ │ │ └── argument.dart │ │ ├── oop │ │ │ ├── annotation.dart │ │ │ ├── attribute.dart │ │ │ ├── interface.dart │ │ │ ├── method │ │ │ │ ├── setter.dart │ │ │ │ ├── getter.dart │ │ │ │ └── method.dart │ │ │ ├── constructor.dart │ │ │ └── class.dart │ │ ├── conditions │ │ │ ├── else.dart │ │ │ ├── if.dart │ │ │ └── else_if.dart │ │ ├── statements │ │ │ ├── call.dart │ │ │ ├── assignment.dart │ │ │ └── return.dart │ │ ├── loops │ │ │ ├── while.dart │ │ │ ├── for.dart │ │ │ └── for_each.dart │ │ └── editor_context.dart │ ├── extensions │ │ ├── list_extensions.dart │ │ └── string_extension.dart │ └── helpers │ │ └── dart_helper.dart └── dart_writer.dart ├── .gitignore ├── pubspec.yaml ├── example ├── hello_world.dart ├── interface.dart ├── statements.dart ├── loops.dart ├── conditions.dart ├── singleton.dart ├── full_class.dart └── flutter_widgets.dart ├── LICENSE ├── analysis_options.yaml └── README.md /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [0.0.1] - First Release -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /lib/src/constants.dart: -------------------------------------------------------------------------------- 1 | class Constants { 2 | static const int INDENT_LEN = 2; 3 | } -------------------------------------------------------------------------------- /lib/src/interpreter/IExpression.dart: -------------------------------------------------------------------------------- 1 | import 'editor_context.dart'; 2 | 3 | abstract class IExpression { 4 | String interpret(EditorContext context); 5 | } -------------------------------------------------------------------------------- /lib/src/interpreter/scope.dart: -------------------------------------------------------------------------------- 1 | enum Scope { 2 | CLASS, 3 | INTERFACE, 4 | CONSTRUCTOR, 5 | METHOD, 6 | ENUM, 7 | IF, 8 | ELIF, 9 | ELSE, 10 | FOR, 11 | FOR_EACH, 12 | WHILE, 13 | GET, 14 | SET 15 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Don’t commit the following directories created by pub. 2 | .buildlog 3 | .pub/ 4 | .dart_tool/ 5 | .idea/ 6 | build/ 7 | .packages 8 | 9 | # Or the files created by dart2js. 10 | *.dart.js 11 | *.js_ 12 | *.js.deps 13 | *.js.map 14 | 15 | # Include when developing application packages. 16 | pubspec.lock -------------------------------------------------------------------------------- /lib/src/extensions/list_extensions.dart: -------------------------------------------------------------------------------- 1 | extension ListExtension on List { 2 | String get seperateWithComma { 3 | var list = this; 4 | var result = ''; 5 | list.forEach((element) { 6 | result += element; 7 | if (element != list.last) result += ', '; 8 | }); 9 | return result; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dart_writer 2 | version: 0.0.1 3 | homepage: https://github.com/ahm3tcelik/dart_writer 4 | description: DartWriter provides API to generate Dart source code. It can make your job easier while developing flutter/dart tools. You can also generate Flutter UI code. 5 | 6 | environment: 7 | sdk: ">=2.12.0 <3.0.0" 8 | 9 | dependencies: 10 | dart_style: ^2.0.0 11 | 12 | dev_dependencies: 13 | pedantic: ^1.11.0 -------------------------------------------------------------------------------- /lib/src/extensions/string_extension.dart: -------------------------------------------------------------------------------- 1 | extension StringExtension on String { 2 | String get putSemicolon { 3 | var code = this; 4 | if (code.endsWith(';')) { 5 | return this; 6 | } 7 | return '$code;'; 8 | } 9 | 10 | String get removeSemicolon { 11 | var code = this; 12 | if (code.endsWith(';')) { 13 | return code.substring(0,code.length - 1); 14 | } 15 | return '$code;'; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/src/interpreter/other/argument_item.dart: -------------------------------------------------------------------------------- 1 | class ArgumentItem { 2 | final dynamic arg; 3 | final String? name; 4 | 5 | /// Example 6 | ///```dart 7 | /// Argument([ 8 | /// ArgumentItem('user'), 9 | /// ArgumentItem('user1', name: 'user'), 10 | /// ]), 11 | ///``` 12 | /// [Output]: (user, user: user1) 13 | /// Argument(arg, name: named argument?), 14 | /// [name]: name of argument 15 | ArgumentItem(this.arg, {this.name}); 16 | } -------------------------------------------------------------------------------- /example/hello_world.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_writer/dart_writer.dart'; 2 | 3 | void main() { 4 | var context = EditorContext(enableDartFormatter: true); 5 | var code = Method( 6 | name: 'main', 7 | returnType: 'void', 8 | statements: [ 9 | Call('print', 10 | argument: Argument([ 11 | ArgumentItem("'Hello World!'") 12 | ]) 13 | ), 14 | Return('0') 15 | ] 16 | ); 17 | print(context.build([code])); 18 | } -------------------------------------------------------------------------------- /example/interface.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_writer/dart_writer.dart'; 2 | 3 | /// [Output]: 4 | // abstract class Flyable extends Breathable { 5 | // void doFly(); 6 | // } 7 | void main() { 8 | var context = EditorContext(enableDartFormatter: true); 9 | var code = Interface('Flyable', 10 | baseClass: 'Breathable', 11 | prototypes: [ 12 | Method(name: 'doFly', returnType: 'void') 13 | ] 14 | ); 15 | print(context.build([code])); 16 | } -------------------------------------------------------------------------------- /example/statements.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_writer/dart_writer.dart'; 2 | 3 | /// [Output]: 4 | /// ```dart 5 | /// int do() { 6 | /// var i = 5; 7 | /// var name = getName(); 8 | /// return i; 9 | /// } 10 | /// ``` 11 | void main() { 12 | var context = EditorContext(); 13 | var code = Method(name: 'do', returnType: 'int', 14 | statements: [ 15 | Assign('var i', '5'), 16 | Assign('var name', Call('getName')), 17 | Return('i') 18 | ] 19 | ); 20 | print(context.build([code])); 21 | } -------------------------------------------------------------------------------- /lib/src/interpreter/oop/annotation.dart: -------------------------------------------------------------------------------- 1 | import '../IExpression.dart'; 2 | import '../editor_context.dart'; 3 | 4 | class Annotation implements IExpression { 5 | final String name; 6 | 7 | /// Example 8 | ///```dart 9 | /// Annotation('override'), 10 | ///``` 11 | /// [Output]: @override 12 | Annotation(this.name); 13 | 14 | @override 15 | String interpret(EditorContext context) { 16 | var buffer = StringBuffer(); 17 | buffer.write(context.indent()); 18 | buffer.writeln('@$name'); 19 | return buffer.toString(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/src/interpreter/other/raw_code.dart: -------------------------------------------------------------------------------- 1 | import '../IExpression.dart'; 2 | import '../editor_context.dart'; 3 | 4 | class RawCode implements IExpression { 5 | final String code; 6 | 7 | /// Example 8 | /// ```dart 9 | /// RawCode('var name = user?.name ?? "'ahmet'"') 10 | /// ``` 11 | /// [Output]: var name = user?.name ?? 'ahmet' 12 | RawCode(this.code); 13 | 14 | @override 15 | String interpret(EditorContext context) { 16 | var buffer = StringBuffer(); 17 | buffer.write(context.indent()); 18 | buffer.write(code); 19 | return buffer.toString(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /example/loops.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_writer/dart_writer.dart'; 2 | 3 | void main() { 4 | var context = EditorContext(enableDartFormatter: true); 5 | var code = Method( 6 | name: 'loops', 7 | returnType: 'void', 8 | statements: [ 9 | For('i = 0', 'i < 5', 'i++', 10 | statements: [RawCode('print(i);')] 11 | ), 12 | ForEach('item', 'userList', 13 | statements: [ 14 | Return('UserCard(item)') 15 | ] 16 | ), 17 | While('i < 5', 18 | statements: [ RawCode('print(i);'), Assign('i', 'i + 1')] 19 | ) 20 | ] 21 | ); 22 | print(context.build([code])); 23 | } -------------------------------------------------------------------------------- /lib/src/interpreter/conditions/else.dart: -------------------------------------------------------------------------------- 1 | import '../editor_context.dart'; 2 | import '../IExpression.dart'; 3 | import '../scope.dart'; 4 | 5 | class Else implements IExpression { 6 | final List? statements; 7 | Else({this.statements}); 8 | 9 | @override 10 | String interpret(EditorContext context) { 11 | var buffer = StringBuffer(); 12 | buffer.write(context.indent()); 13 | buffer.write('else'); 14 | buffer.writeln(context.openScope(Scope.ELSE)); 15 | 16 | if (statements != null) { 17 | statements!.forEach((statement) { 18 | buffer.write(statement.interpret(context)); 19 | }); 20 | } 21 | 22 | buffer.write(context.closeScope()); 23 | return buffer.toString(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/src/interpreter/other/parameter_item.dart: -------------------------------------------------------------------------------- 1 | class ParameterItem { 2 | 3 | final String name; 4 | final bool? isNamed; 5 | final bool? isRequired; 6 | 7 | /// Example 8 | ///```dart 9 | /// Parameter([ 10 | /// ParameterItem('BuildContext context'), 11 | /// ParameterItem('User user', isNamed: true, isRequired: true), 12 | /// ParameterItem('String? result', isNamed: true, isRequired: false) 13 | /// ]), 14 | ///``` 15 | /// ParameterItem(paramName, isNamed: isNamedParamter?, 16 | /// [name]: parameter ex: String name 17 | /// [isNamed]: is named parameter? ex: {int x} 18 | /// [isRequired]: is required for named parameter RequiredForNamedParameter) 19 | ParameterItem(this.name, {this.isNamed, this.isRequired}); 20 | } -------------------------------------------------------------------------------- /lib/src/interpreter/conditions/if.dart: -------------------------------------------------------------------------------- 1 | import '../editor_context.dart'; 2 | import '../IExpression.dart'; 3 | import '../scope.dart'; 4 | 5 | class If implements IExpression { 6 | final String condition; 7 | final List? statements; 8 | If({required this.condition, this.statements}); 9 | 10 | @override 11 | String interpret(EditorContext context) { 12 | var buffer = StringBuffer(); 13 | buffer.write(context.indent()); 14 | buffer.write('if ($condition)'); 15 | buffer.writeln(context.openScope(Scope.IF)); 16 | 17 | if (statements != null) { 18 | statements!.forEach((statement) { 19 | buffer.write(statement.interpret(context)); 20 | }); 21 | } 22 | 23 | buffer.write(context.closeScope()); 24 | return buffer.toString(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/src/interpreter/other/import.dart: -------------------------------------------------------------------------------- 1 | import '../editor_context.dart'; 2 | import '../IExpression.dart'; 3 | import '../../extensions/string_extension.dart'; 4 | 5 | class Import implements IExpression { 6 | final String path; 7 | final String? asName; 8 | 9 | /// Example 10 | /// ```dart 11 | /// Import('package:dart_writer/dart_writer.dart', as: 'writer') 12 | /// ``` 13 | /// [Output]: import 'package:dart_writer/dart_writer.dart as writer; 14 | Import(this.path, {this.asName}); 15 | 16 | @override 17 | String interpret(EditorContext context) { 18 | var buffer = StringBuffer(); 19 | buffer.write("import '$path'"); 20 | if (asName?.isNotEmpty ?? false) { 21 | buffer.write(' as $asName'); 22 | } 23 | buffer.writeln(''.putSemicolon); 24 | return buffer.toString(); 25 | } 26 | } -------------------------------------------------------------------------------- /lib/src/interpreter/conditions/else_if.dart: -------------------------------------------------------------------------------- 1 | import '../editor_context.dart'; 2 | import '../IExpression.dart'; 3 | import '../scope.dart'; 4 | 5 | class ElseIf implements IExpression { 6 | final String condition; 7 | final List? statements; 8 | ElseIf({required this.condition, this.statements}); 9 | 10 | @override 11 | String interpret(EditorContext context) { 12 | var buffer = StringBuffer(); 13 | buffer.write(context.indent()); 14 | buffer.write('else if ($condition)'); 15 | buffer.writeln(context.openScope(Scope.ELIF)); 16 | 17 | if (statements != null) { 18 | statements!.forEach((statement) { 19 | buffer.write(statement.interpret(context)); 20 | }); 21 | } 22 | 23 | buffer.write(context.closeScope()); 24 | return buffer.toString(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/src/interpreter/statements/call.dart: -------------------------------------------------------------------------------- 1 | import '../IExpression.dart'; 2 | import '../editor_context.dart'; 3 | import '../../extensions/string_extension.dart'; 4 | import '../other/argument.dart'; 5 | 6 | class Call implements IExpression { 7 | final String name; 8 | final Argument? argument; 9 | 10 | /// Example 11 | /// ```dart 12 | /// Call('Card', argument: Argument([MapEntry('name', "'Ahmet'")])) 13 | /// ``` 14 | /// [Output]: Card(name: 'Ahmet') 15 | Call(this.name, {this.argument}); 16 | 17 | @override 18 | String interpret(EditorContext context) { 19 | var buffer = StringBuffer(); 20 | var argsText = ''; 21 | if (argument?.args?.isNotEmpty ?? false) { 22 | argsText = argument!.interpret(context); 23 | } 24 | buffer.write('$name($argsText)'.putSemicolon); 25 | return buffer.toString(); 26 | } 27 | } -------------------------------------------------------------------------------- /example/conditions.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_writer/dart_writer.dart'; 2 | 3 | /// [Output]: 4 | /// ```dart 5 | /// int getMin() { 6 | /// var num1 = 5; 7 | /// var num2 = 10; 8 | /// if (num1 < num2) { 9 | /// return num1; 10 | /// } else if (num1 == num2) { 11 | /// return num1; 12 | /// } else { 13 | /// return num2; 14 | /// } 15 | /// } 16 | /// ``` 17 | void main() { 18 | var context = EditorContext(enableDartFormatter: true); 19 | var code = Method( 20 | name: 'getMin', 21 | returnType: 'int', 22 | statements: [ 23 | Assign('var num1', '5'), 24 | Assign('var num2', '10'), 25 | If(condition: 'num1 < num2', statements: [Return('num1')]), 26 | ElseIf(condition: 'num1 == num2', statements: [Return('num1')]), 27 | Else(statements: [Return('num2')]) 28 | ] 29 | ); 30 | print(context.build([code])); 31 | } -------------------------------------------------------------------------------- /lib/src/interpreter/loops/while.dart: -------------------------------------------------------------------------------- 1 | import '../editor_context.dart'; 2 | import '../IExpression.dart'; 3 | import '../scope.dart'; 4 | 5 | class While implements IExpression { 6 | final String condition; 7 | final List? statements; 8 | 9 | /// Example 10 | /// ```dart 11 | /// While('i < 5',statements: [ RawCode('print(i);'), Assign('i', 'i + 1')]) 12 | /// ``` 13 | /// [Output]: while (i < 5) { print(i); i = i + 1; } 14 | While(this.condition, {this.statements}); 15 | 16 | @override 17 | String interpret(EditorContext context) { 18 | var buffer = StringBuffer(); 19 | buffer.write(context.indent()); 20 | buffer.write('while ($condition)'); 21 | buffer.writeln(context.openScope(Scope.WHILE)); 22 | 23 | if (statements != null) { 24 | statements!.forEach((statement) { 25 | buffer.write(statement.interpret(context)); 26 | }); 27 | } 28 | 29 | buffer.write(context.closeScope()); 30 | return buffer.toString(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/src/interpreter/other/enum.dart: -------------------------------------------------------------------------------- 1 | import '../editor_context.dart'; 2 | import '../IExpression.dart'; 3 | import '../scope.dart'; 4 | 5 | class Enum implements IExpression { 6 | final String name; 7 | final List enums; 8 | 9 | /// Example 10 | /// ```dart 11 | /// Enum('Roles', enums: ['USER', 'ADMIN', 'DEVELOPER']) 12 | /// ``` 13 | /// [Output]: enum Roles { USER, ADMIN, DEVELOPER } 14 | Enum(this.name, {required this.enums}); 15 | 16 | @override 17 | String interpret(EditorContext context) { 18 | var buffer = StringBuffer(); 19 | buffer.write(context.indent()); 20 | buffer.write('enum $name'); 21 | buffer.writeln(context.openScope(Scope.ENUM)); 22 | 23 | enums.forEach((element) { 24 | buffer.write(context.indent()); 25 | buffer.write(element); 26 | if (element != enums.last) { 27 | buffer.writeln(', '); 28 | } else { 29 | buffer.writeln(); 30 | } 31 | }); 32 | 33 | buffer.write(context.closeScope()); 34 | return buffer.toString(); 35 | } 36 | } -------------------------------------------------------------------------------- /lib/src/interpreter/loops/for.dart: -------------------------------------------------------------------------------- 1 | import '../editor_context.dart'; 2 | import '../IExpression.dart'; 3 | import '../scope.dart'; 4 | 5 | class For implements IExpression { 6 | final String init; 7 | final String condition; 8 | final String action; 9 | final List? statements; 10 | 11 | /// Example 12 | /// ```dart 13 | /// For('i = 0', 'i < 5', 'i++', statements: [RawCode('print(i);')]) 14 | /// ``` 15 | /// [Output]: for (var i = 0; i < 5; i++) { print(i); } 16 | For(this.init, this.condition, this.action, {this.statements}); 17 | 18 | @override 19 | String interpret(EditorContext context) { 20 | var buffer = StringBuffer(); 21 | buffer.write(context.indent()); 22 | buffer.write('for (var $init; $condition; $action)'); 23 | buffer.writeln(context.openScope(Scope.FOR)); 24 | 25 | if (statements != null) { 26 | statements!.forEach((statement) { 27 | buffer.write(statement.interpret(context)); 28 | }); 29 | } 30 | 31 | buffer.write(context.closeScope()); 32 | return buffer.toString(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/src/interpreter/loops/for_each.dart: -------------------------------------------------------------------------------- 1 | import '../editor_context.dart'; 2 | import '../IExpression.dart'; 3 | import '../scope.dart'; 4 | 5 | class ForEach implements IExpression { 6 | final String iterationVar; 7 | final String iterable; 8 | final List? statements; 9 | 10 | /// Example 11 | /// ```dart 12 | /// ForEach('item', 'userList', statements: [ Return('UserCard(item')]) 13 | /// ``` 14 | /// [Output]: for (var item in userList) { return UserCard(item); } 15 | ForEach(this.iterationVar, this.iterable, {this.statements}); 16 | 17 | @override 18 | String interpret(EditorContext context) { 19 | var buffer = StringBuffer(); 20 | buffer.write(context.indent()); 21 | buffer.write('for (var $iterationVar in $iterable)'); 22 | buffer.writeln(context.openScope(Scope.FOR_EACH)); 23 | 24 | if (statements != null) { 25 | statements!.forEach((statement) { 26 | buffer.write(statement.interpret(context)); 27 | }); 28 | } 29 | 30 | buffer.write(context.closeScope()); 31 | return buffer.toString(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/src/interpreter/statements/assignment.dart: -------------------------------------------------------------------------------- 1 | import '../IExpression.dart'; 2 | import '../editor_context.dart'; 3 | import '../../extensions/string_extension.dart'; 4 | 5 | class Assign implements IExpression { 6 | final String dest; 7 | final dynamic source; 8 | final bool isAsync; 9 | 10 | /// Example 11 | /// ```dart 12 | /// Assign('var i', '5') 13 | /// ``` 14 | /// [Output]: var i = 5; 15 | Assign(this.dest, this.source, {this.isAsync = false}); 16 | 17 | @override 18 | String interpret(EditorContext context) { 19 | var buffer = StringBuffer(); 20 | buffer.write(context.indent()); 21 | String sourceValue; 22 | if (source is IExpression) { 23 | sourceValue = _getStringFromExpression(context, source); 24 | } else { 25 | sourceValue = source; 26 | } 27 | buffer.writeln('$dest =${isAsync ? ' await' : ''} $sourceValue'.putSemicolon); 28 | return buffer.toString(); 29 | } 30 | 31 | String _getStringFromExpression(EditorContext context, IExpression exp) { 32 | return exp.interpret(context).removeSemicolon; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 ahm3tcelik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/src/interpreter/statements/return.dart: -------------------------------------------------------------------------------- 1 | import '../IExpression.dart'; 2 | import '../editor_context.dart'; 3 | import '../../extensions/string_extension.dart'; 4 | 5 | class Return implements IExpression { 6 | final dynamic returnValue; 7 | 8 | /// [returnValue] must be [String] or [IExpression] 9 | 10 | /// Example # 1 11 | ///```dart 12 | /// Return('name') 13 | ///``` 14 | /// [Output]: return name; 15 | /// 16 | /// Example # 2 17 | ///```dart 18 | /// Return(Call('getName')) 19 | ///``` 20 | /// [Output]: return getName(); 21 | Return(this.returnValue); 22 | 23 | @override 24 | String interpret(EditorContext context) { 25 | var buffer = StringBuffer(); 26 | buffer.write(context.indent()); 27 | String value; 28 | if (returnValue is IExpression) { 29 | value = _getStringFromExpression(context, returnValue); 30 | } else { 31 | value = returnValue; 32 | } 33 | buffer.writeln('return $value'.putSemicolon); 34 | return buffer.toString(); 35 | } 36 | 37 | String _getStringFromExpression(EditorContext context, IExpression exp) { 38 | return exp.interpret(context).removeSemicolon; 39 | } 40 | } -------------------------------------------------------------------------------- /lib/src/interpreter/oop/attribute.dart: -------------------------------------------------------------------------------- 1 | import '../IExpression.dart'; 2 | import '../editor_context.dart'; 3 | import '../../extensions/string_extension.dart'; 4 | 5 | class Attribute implements IExpression { 6 | final String name; 7 | final String type; 8 | final String? modifiers; 9 | final String? value; 10 | 11 | /// Example 12 | ///```dart 13 | /// Attribute(modifiers: 'final', type: 'String?', name: 'name'), 14 | /// Attribute(modifiers: 'final', type: 'String?', name: 'surname', value: "'Star'") 15 | ///``` 16 | /// [Output]: final String? name; 17 | /// [Output]: final String? surname = 'Star'; 18 | Attribute({ 19 | required this.name, 20 | required this.type, 21 | this.modifiers, 22 | this.value 23 | }); 24 | 25 | @override 26 | String interpret(EditorContext context) { 27 | var buffer = StringBuffer(); 28 | buffer.write(context.indent()); 29 | 30 | if (modifiers?.isNotEmpty ?? false) { 31 | buffer.write('$modifiers '); 32 | } 33 | // static final int LEN; 34 | // static final int LEN = 5; 35 | buffer.write('$type $name'); 36 | if (value?.isNotEmpty ?? false) { 37 | buffer.write(' = $value'); 38 | } 39 | buffer.writeln(''.putSemicolon); 40 | return buffer.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/src/interpreter/oop/interface.dart: -------------------------------------------------------------------------------- 1 | import '../IExpression.dart'; 2 | import '../editor_context.dart'; 3 | import '../scope.dart'; 4 | 5 | class Interface implements IExpression { 6 | final String name; 7 | 8 | /// [extends] $baseClass 9 | final String? baseClass; 10 | final List? prototypes; 11 | 12 | /// Example 13 | /// ```dart 14 | /// Interface('Flyable', baseClass: 'Breathable', prototypes: [ 15 | /// Method(name: 'doFly', returnType: 'void') 16 | /// ]), 17 | /// ``` 18 | /// [Output]: abstract class Flyable extends Breathable { void doFly(); } 19 | Interface(this.name, {this.baseClass, this.prototypes}); 20 | 21 | @override 22 | String interpret(EditorContext context) { 23 | var buffer = StringBuffer(); 24 | buffer.write(context.indent()); 25 | buffer.write('abstract class $name'); 26 | 27 | /// [extends] $baseClass 28 | if (baseClass != null) { 29 | buffer.write(' extends $baseClass'); 30 | } 31 | buffer.writeln(context.openScope(Scope.INTERFACE)); 32 | 33 | if (prototypes != null) { 34 | prototypes!.forEach((element) { 35 | buffer.write(element.interpret(context)); 36 | }); 37 | } 38 | buffer.write(context.closeScope()); 39 | return buffer.toString(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/src/interpreter/editor_context.dart: -------------------------------------------------------------------------------- 1 | import 'dart:collection'; 2 | import 'package:dart_writer/dart_writer.dart'; 3 | 4 | import 'IExpression.dart'; 5 | import '../constants.dart'; 6 | import 'scope.dart'; 7 | 8 | class EditorContext { 9 | final Queue _scopes = Queue(); 10 | final StringBuffer _buffer = StringBuffer(); 11 | bool enableDartFormatter; 12 | 13 | EditorContext({this.enableDartFormatter = false}); 14 | 15 | String build(List codeList) { 16 | codeList.forEach((e) => _buffer.write(e.interpret(this))); 17 | if (enableDartFormatter) { 18 | return DartFormatter().format(_buffer.toString()); 19 | } 20 | return _buffer.toString(); 21 | } 22 | 23 | String openScope(Scope scope) { 24 | _scopes.addLast(scope); 25 | return ' {'; 26 | } 27 | 28 | String closeScope({int stepNum = 1}) { 29 | var _buffer = StringBuffer(); 30 | for (var i = 0; i < stepNum; i++) { 31 | _scopes.removeLast(); 32 | _buffer.write(indent()); 33 | _buffer.writeln('}'); 34 | } 35 | return _buffer.toString(); 36 | } 37 | 38 | String space({int spaceNum = 1}) { 39 | return (' ' * spaceNum); 40 | } 41 | 42 | String indent() { 43 | return space(spaceNum: _scopes.length * Constants.INDENT_LEN); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /example/singleton.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_writer/dart_writer.dart'; 2 | 3 | /// [ Output ] 4 | /* 5 | class Singleton { 6 | static Singleton? _instance; 7 | 8 | Singleton._init(); 9 | 10 | static Singleton get instance { 11 | if (_instance == null) { 12 | _instance = Singleton._init(); 13 | } 14 | return _instance!; 15 | } 16 | 17 | } 18 | */ 19 | 20 | void main() { 21 | var editor = EditorContext(); 22 | var singletonCode = editor.build([ 23 | Class('Singleton', 24 | baseClass: 'Base', 25 | attributes: [ 26 | Attribute(name: '_instance', type: 'Singleton?', modifiers: 'static'), 27 | Attribute(name: 'list', type: 'List', modifiers: 'final'), 28 | ], methods: [ 29 | Getter( 30 | name: 'instance', 31 | returnType: 'Singleton', 32 | modifier: 'static', 33 | statements: [ 34 | If( 35 | condition: '_instance == null', 36 | statements: [Assign('_instance', 'Singleton._init()')]), 37 | Return('_instance!') 38 | ]) 39 | ], constructors: [ 40 | Constructor( 41 | className: 'Singleton', 42 | constructorName: '_init' 43 | ) 44 | ]), 45 | ]); 46 | 47 | print(singletonCode); 48 | } 49 | -------------------------------------------------------------------------------- /example/full_class.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_writer/dart_writer.dart'; 2 | 3 | /// [Output]: 4 | // class Bird extends Animal with Feather, Walk implements Flyable, Crowable { 5 | // final String name; 6 | 7 | // Bird.fromName({required this.name}) : super(name); 8 | 9 | // double onFly(double height) { 10 | // return height * 2; 11 | // } 12 | // } 13 | void main() { 14 | var context = EditorContext(enableDartFormatter: true); 15 | var code = Class( 16 | 'Bird', 17 | baseClass: 'Animal', 18 | interfaces: ['Flyable', 'Crowable'], 19 | mixins: ['Feather', 'Walk'], 20 | attributes: [ 21 | Attribute(modifiers: 'final', type: 'String', name: 'name'), 22 | ], 23 | constructors: [ 24 | Constructor( 25 | className: 'Bird', 26 | constructorName: 'fromName', 27 | param: Parameter([ParameterItem('this.name', isRequired: true, isNamed: true)]), 28 | superArgument: Argument([ArgumentItem('name')]) 29 | ), 30 | ], 31 | methods: [ 32 | Method( 33 | name: 'onFly', 34 | returnType: 'double', 35 | param: Parameter([ParameterItem('double height')]), 36 | statements: [Return('height * 2')] 37 | ), 38 | ] 39 | ); 40 | 41 | print(context.build([code])); 42 | 43 | } -------------------------------------------------------------------------------- /lib/src/interpreter/oop/method/setter.dart: -------------------------------------------------------------------------------- 1 | import '../../IExpression.dart'; 2 | import '../../editor_context.dart'; 3 | import '../../scope.dart'; 4 | import '../../../extensions/string_extension.dart'; 5 | 6 | class Setter implements IExpression { 7 | final String name; 8 | final String param; 9 | final List? statements; 10 | 11 | /// Example Abstract Setter 12 | ///```dart 13 | /// Setter( 14 | /// name: 'name', 15 | /// param: 'String name', 16 | /// ) 17 | ///``` 18 | /// [Output]: set name(String name); 19 | 20 | /// Example 21 | ///```dart 22 | /// Setter( 23 | /// name: 'name', 24 | /// param: 'String name', 25 | /// statements: [ 26 | /// Assign('this.name', 'name') 27 | /// ] 28 | /// ) 29 | ///``` 30 | /// [Output]: set name(String name) { this.name = name; } 31 | Setter({required this.name, required this.param, this.statements}); 32 | 33 | @override 34 | String interpret(EditorContext context) { 35 | var buffer = StringBuffer(); 36 | buffer.write(context.indent()); 37 | 38 | buffer.write('set $name($param)'); 39 | 40 | if (statements != null) { 41 | buffer.writeln(context.openScope(Scope.SET)); 42 | statements!.forEach((statement) { 43 | buffer.write(statement.interpret(context)); 44 | }); 45 | buffer.writeln(context.closeScope()); 46 | } 47 | /// [Abstract setter] ex: set name(String s); 48 | else { 49 | buffer.writeln(''.putSemicolon); 50 | } 51 | 52 | return buffer.toString(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /example/flutter_widgets.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:dart_writer/dart_writer.dart'; 3 | import 'package:dart_writer/src/interpreter/other/parameter_item.dart'; 4 | 5 | 6 | void main() { 7 | var context = EditorContext(enableDartFormatter: true); 8 | var dartHelper = DartHelper.instance; 9 | Map map = jsonDecode(json); 10 | 11 | var homePage = Class('HomePage', 12 | baseClass: 'StatelessWidget', 13 | methods: [ 14 | Annotation('override'), 15 | Method( 16 | name: 'build', 17 | returnType: 'Widget', 18 | param: Parameter([ 19 | ParameterItem('BuildContext context'), 20 | ]), 21 | statements: [ Return(dartHelper.getCodeFromMap(map)) ] 22 | ) 23 | ] 24 | ); 25 | 26 | print(context.build([ 27 | Import('package:flutter/material.dart'), 28 | homePage 29 | ])); 30 | } 31 | 32 | String json = ''' 33 | { 34 | "as": "Scaffold", 35 | "appBar": { 36 | "as": "AppBar", 37 | "title": { 38 | "as": "Text", 39 | "params": [ 40 | "'Ahmet'" 41 | ] 42 | }, 43 | "centerTitle": "false" 44 | }, 45 | "body": { 46 | "as": "Center", 47 | "child": { 48 | "as": "Row", 49 | "children": [ 50 | { 51 | "as": "Icon", 52 | "params": ["Icons.add"], 53 | "color": "Colors.red" 54 | }, 55 | { 56 | "as": "Text", 57 | "params": ["'Ahmet'"], 58 | "textAlign": "TextAlign.center" 59 | } 60 | ] 61 | } 62 | } 63 | } 64 | '''; 65 | -------------------------------------------------------------------------------- /lib/dart_writer.dart: -------------------------------------------------------------------------------- 1 | library dart_writer; 2 | 3 | export 'package:dart_style/dart_style.dart'; 4 | 5 | export './src/helpers/dart_helper.dart'; 6 | export './src/interpreter/IExpression.dart'; 7 | export './src/interpreter/editor_context.dart'; 8 | export './src/extensions/string_extension.dart'; 9 | 10 | // Statements 11 | export './src/interpreter/statements/assignment.dart'; 12 | export './src/interpreter/statements/call.dart'; 13 | export './src/interpreter/statements/return.dart'; 14 | 15 | // Conditions 16 | export './src/interpreter/conditions/if.dart'; 17 | export './src/interpreter/conditions/else.dart'; 18 | export './src/interpreter/conditions/else_if.dart'; 19 | 20 | // Loops 21 | export './src/interpreter/loops/for.dart'; 22 | export './src/interpreter/loops/for_each.dart'; 23 | export './src/interpreter/loops/while.dart'; 24 | 25 | // Other 26 | export './src/interpreter/other/import.dart'; 27 | export './src/interpreter/other/parameter.dart'; 28 | export './src/interpreter/other/parameter_item.dart'; 29 | export './src/interpreter/other/argument.dart'; 30 | export './src/interpreter/other/argument_item.dart'; 31 | export './src/interpreter/other/enum.dart'; 32 | export './src/interpreter/other/raw_code.dart'; 33 | 34 | // OOP 35 | export './src/interpreter/oop/class.dart'; 36 | export './src/interpreter/oop/interface.dart'; 37 | export './src/interpreter/oop/constructor.dart'; 38 | export './src/interpreter/oop/attribute.dart'; 39 | export './src/interpreter/oop/annotation.dart'; 40 | 41 | // OOP / Method 42 | export './src/interpreter/oop/method/method.dart'; 43 | export './src/interpreter/oop/method/getter.dart'; 44 | export './src/interpreter/oop/method/setter.dart'; -------------------------------------------------------------------------------- /lib/src/interpreter/other/parameter.dart: -------------------------------------------------------------------------------- 1 | import '../../extensions/list_extensions.dart'; 2 | import 'parameter_item.dart'; 3 | import '../IExpression.dart'; 4 | import '../editor_context.dart'; 5 | 6 | class Parameter implements IExpression { 7 | final List? parameters; 8 | 9 | /// Example 10 | ///```dart 11 | /// Parameter([ 12 | /// ParameterItem('BuildContext context'), 13 | /// ParameterItem('String name', isNamed: true, isRequired: true), 14 | /// ParameterItem('String? name', isNamed: true, isRequired: false) 15 | /// ]), 16 | ///``` 17 | /// [Usage]: Parameter([ParameterItem() ...), ....]) 18 | /// [Output]: BuildContext context, {required String name, String? name} 19 | Parameter(this.parameters); 20 | 21 | @override 22 | String interpret(EditorContext context) { 23 | var buffer = StringBuffer(); 24 | var namedParams = []; 25 | var positionalParams = []; 26 | 27 | if (parameters != null) { 28 | parameters!.forEach((param) { 29 | if (param.isNamed ?? false) { 30 | /// [named] - [required] 31 | if (param.isRequired ?? false) { 32 | namedParams.add('required ${param.name}'); 33 | } 34 | /// [named] - [optional] param 35 | else { 36 | namedParams.add(param.name); 37 | } 38 | } 39 | /// [positional] 40 | else { 41 | positionalParams.add(param.name); 42 | } 43 | }); 44 | } 45 | 46 | buffer.write(positionalParams.seperateWithComma); 47 | if (positionalParams.isNotEmpty && namedParams.isNotEmpty) buffer.write(', '); 48 | if (namedParams.isNotEmpty) buffer.write('{${namedParams.seperateWithComma}}'); 49 | 50 | return buffer.toString(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /lib/src/interpreter/oop/method/getter.dart: -------------------------------------------------------------------------------- 1 | import '../../IExpression.dart'; 2 | import '../../editor_context.dart'; 3 | import '../../scope.dart'; 4 | import '../../../extensions/string_extension.dart'; 5 | 6 | class Getter implements IExpression { 7 | final String name; 8 | final String returnType; 9 | final List? statements; 10 | final String? modifier; 11 | 12 | /// Example Abstract Getter 13 | ///```dart 14 | /// Getter( 15 | /// name: 'name', 16 | /// returnType: 'String', 17 | /// ) 18 | ///``` 19 | /// [Output]: String get name; 20 | 21 | /// Example Getter 22 | ///```dart 23 | /// Getter( 24 | /// name: 'getName', 25 | /// returnType: 'String', 26 | /// modifier: 'static', 27 | /// statements: [ 28 | /// Return("'name'") 29 | /// ] 30 | /// ) 31 | ///``` 32 | /// [Output]: static String get getName { return 'name'; } 33 | Getter( 34 | {required this.name, 35 | required this.returnType, 36 | this.modifier, 37 | this.statements}); 38 | 39 | @override 40 | String interpret(EditorContext context) { 41 | var buffer = StringBuffer(); 42 | buffer.write(context.indent()); 43 | 44 | // example: static modifier 45 | if (modifier?.isNotEmpty ?? false) { 46 | buffer.write('$modifier '); 47 | } 48 | 49 | if (returnType.isNotEmpty) { 50 | buffer.write('$returnType '); 51 | } 52 | buffer.write('get $name'); 53 | 54 | if (statements != null) { 55 | buffer.writeln(context.openScope(Scope.GET)); 56 | statements!.forEach((statement) { 57 | buffer.write(statement.interpret(context)); 58 | }); 59 | buffer.writeln(context.closeScope()); 60 | } 61 | /// [Abstract getter] ex: String get name; 62 | else { 63 | buffer.writeln(''.putSemicolon); 64 | } 65 | 66 | return buffer.toString(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | linter: 2 | rules: 3 | - always_declare_return_types 4 | - always_require_non_null_named_parameters 5 | - annotate_overrides 6 | - avoid_init_to_null 7 | - avoid_null_checks_in_equality_operators 8 | - avoid_relative_lib_imports 9 | - avoid_return_types_on_setters 10 | - avoid_shadowing_type_parameters 11 | - avoid_single_cascade_in_expression_statements 12 | - avoid_types_as_parameter_names 13 | - await_only_futures 14 | - camel_case_extensions 15 | - curly_braces_in_flow_control_structures 16 | - empty_catches 17 | - empty_constructor_bodies 18 | - library_names 19 | - library_prefixes 20 | - no_duplicate_case_values 21 | - null_closures 22 | - omit_local_variable_types 23 | - prefer_adjacent_string_concatenation 24 | - prefer_collection_literals 25 | - prefer_conditional_assignment 26 | - prefer_contains 27 | - prefer_equal_for_default_values 28 | - prefer_final_fields 29 | - prefer_for_elements_to_map_fromIterable 30 | - prefer_generic_function_type_aliases 31 | - prefer_if_null_operators 32 | - prefer_inlined_adds 33 | - prefer_is_empty 34 | - prefer_is_not_empty 35 | - prefer_iterable_whereType 36 | - prefer_single_quotes 37 | - prefer_spread_collections 38 | - recursive_getters 39 | - slash_for_doc_comments 40 | - sort_child_properties_last 41 | - type_init_formals 42 | - unawaited_futures 43 | - unnecessary_brace_in_string_interps 44 | - unnecessary_const 45 | - unnecessary_getters_setters 46 | - unnecessary_new 47 | - unnecessary_null_in_if_null_operators 48 | - unnecessary_this 49 | - unrelated_type_equality_checks 50 | - unsafe_html 51 | - use_full_hex_values_for_flutter_colors 52 | - use_function_type_syntax_for_parameters 53 | - use_rethrow_when_possible 54 | - valid_regexps 55 | -------------------------------------------------------------------------------- /lib/src/interpreter/other/argument.dart: -------------------------------------------------------------------------------- 1 | import 'argument_item.dart'; 2 | import '../IExpression.dart'; 3 | import '../editor_context.dart'; 4 | import '../../extensions/string_extension.dart'; 5 | 6 | class Argument implements IExpression { 7 | final List? args; 8 | /// Example 9 | /// ```dart 10 | /// Argument([ 11 | /// ArgumentItem('name'), 12 | /// ArgumentItem("'Star'", name:'surname') 13 | /// ]) 14 | /// ``` 15 | /// [Output]: name, surname: 'Star' 16 | Argument(this.args); 17 | 18 | @override 19 | String interpret(EditorContext context) { 20 | var buffer = StringBuffer(); 21 | if (args?.isNotEmpty ?? false) { 22 | String value; 23 | args!.forEach((arg) { 24 | 25 | value = _evaluate(context, arg.arg); 26 | 27 | // Positonal Argument ex: (200, 300) 28 | if (arg.name == null) { 29 | buffer.write(value); 30 | } 31 | // Named Argument ex: (width: 200, height: 300) 32 | else { 33 | buffer.write('${arg.name}: $value'); 34 | } 35 | 36 | if (arg != args!.last) { 37 | buffer.write(', '); 38 | } 39 | }); 40 | } 41 | return buffer.toString(); 42 | } 43 | 44 | String _evaluate(EditorContext context, dynamic value) { 45 | if (value is IExpression) { 46 | return _getStringFromExpression(context, value); 47 | } 48 | else if (value is List) { 49 | var result = StringBuffer(); 50 | result.write('[ '); 51 | value.forEach((element) { 52 | result.write(_evaluate(context, element)); 53 | if (element != value.last) { 54 | result.write(', '); 55 | } 56 | }); 57 | result.write(' ]'); 58 | return result.toString(); 59 | } 60 | else { 61 | return value; 62 | } 63 | } 64 | 65 | String _getStringFromExpression(EditorContext context, IExpression exp) { 66 | return exp.interpret(context).removeSemicolon; 67 | } 68 | } -------------------------------------------------------------------------------- /lib/src/helpers/dart_helper.dart: -------------------------------------------------------------------------------- 1 | import '../interpreter/other/argument_item.dart'; 2 | import '../interpreter/IExpression.dart'; 3 | import '../interpreter/statements/call.dart'; 4 | import '../interpreter/other/argument.dart'; 5 | 6 | class DartHelper { 7 | static DartHelper? _instance; 8 | static DartHelper get instance { 9 | _instance ??= DartHelper._init(); 10 | return _instance!; 11 | } 12 | 13 | DartHelper._init(); 14 | 15 | ///```dart 16 | /// { 17 | /// "as": "Scaffold", 18 | /// "appBar": { 19 | /// "as": "AppBar", 20 | /// "title": "'Ahmet'", 21 | /// "centerTitle": "false" 22 | /// }, 23 | /// } 24 | /// ``` 25 | /// [Output]: Scaffold(appBar: AppBar(title: 'Ahmet', centerTitle: false)) 26 | IExpression getCodeFromMap(Map map) { 27 | return Call(map['as'], argument: _getArgument(map)); 28 | } 29 | 30 | Argument _getArgument(Map data) { 31 | var list = []; 32 | for (var entry in data.entries) { 33 | if (entry.key == 'as') continue; 34 | 35 | // Positional params ex: {as: 'Text', params: ["Ahmet", 5]} --> Text('Ahmet', 5) 36 | if (entry.key == 'params') { 37 | List positionalArgs = entry.value; 38 | positionalArgs.forEach((arg) { 39 | list.add(ArgumentItem(arg)); 40 | }); 41 | continue; 42 | } 43 | 44 | if (entry.value is Map) { 45 | var innerArg = _getArgument(entry.value); 46 | 47 | var arg = Call(entry.value['as'], argument: innerArg); 48 | list.add(ArgumentItem(arg, name: entry.key)); 49 | } 50 | else if (entry.value is List) { 51 | List children = entry.value; 52 | var callList = []; 53 | children.forEach((child) { 54 | var innerArg = _getArgument(child); 55 | callList.add(Call(child['as'], argument: innerArg)); 56 | }); 57 | list.add(ArgumentItem(callList, name:'children')); 58 | } else { 59 | list.add(ArgumentItem(entry.value, name: entry.key)); 60 | } 61 | } 62 | 63 | return Argument(list); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lib/src/interpreter/oop/constructor.dart: -------------------------------------------------------------------------------- 1 | import '../other/argument.dart'; 2 | import '../IExpression.dart'; 3 | import '../editor_context.dart'; 4 | import '../scope.dart'; 5 | import '../../extensions/string_extension.dart'; 6 | import '../other/parameter.dart'; 7 | 8 | class Constructor implements IExpression { 9 | final String className; 10 | final String? constructorName; 11 | final Parameter? param; 12 | final List? statements; 13 | final Argument? superArgument; 14 | final String modifier; 15 | 16 | /// Example 17 | ///```dart 18 | /// Constructor( 19 | /// className: 'Bird', 20 | /// constructorName: 'fromName', 21 | /// param: Parameter(ParameterItem('this.name', isNamed: true, isRequired: true)), 22 | /// superArgument: Argument([MapEntry(null, 'name')]), 23 | /// statements: [ 24 | /// Call('initialize', argument: Argument([MapEntry(null, '5')])) 25 | /// ] 26 | /// ) 27 | ///``` 28 | /// [Output]: Bird.fromName({required this.name}) : super(name) { initialize(5); } 29 | Constructor( 30 | {required this.className, 31 | this.constructorName, 32 | this.param, 33 | this.modifier = '', 34 | this.statements, 35 | this.superArgument}); 36 | 37 | @override 38 | String interpret(EditorContext context) { 39 | var buffer = StringBuffer(); 40 | buffer.write(context.indent()); 41 | 42 | /// example: [factory] modifier 43 | buffer.write(modifier.isEmpty ? '' : '$modifier '); 44 | buffer.write(className); 45 | if (constructorName?.isNotEmpty ?? false) { 46 | buffer.write('.$constructorName'); 47 | } 48 | buffer.write('(${param?.interpret(context) ?? ''})'); 49 | 50 | if (superArgument != null) { 51 | buffer.write(' : super(${superArgument!.interpret(context)})'); 52 | } 53 | 54 | if (statements != null) { 55 | buffer.writeln(context.openScope(Scope.METHOD)); 56 | statements!.forEach((element) { 57 | buffer.write(element.interpret(context)); 58 | }); 59 | buffer.write(context.closeScope()); 60 | } else { 61 | buffer.writeln(''.putSemicolon); 62 | } 63 | return buffer.toString(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lib/src/interpreter/oop/method/method.dart: -------------------------------------------------------------------------------- 1 | import '../../IExpression.dart'; 2 | import '../../editor_context.dart'; 3 | import '../../scope.dart'; 4 | import '../../../extensions/string_extension.dart'; 5 | import '../../other/parameter.dart'; 6 | 7 | class Method implements IExpression { 8 | final String name; 9 | final String? returnType; 10 | final bool isAsync; 11 | final Parameter? param; 12 | final List? statements; 13 | final String modifier; 14 | 15 | /// Example Abstract Method 16 | ///```dart 17 | /// Method( 18 | /// name: 'walk', 19 | /// returnType: 'void', 20 | /// param: Parameter([ 21 | /// ParameterItem('int step', isRequired: true, isNamed: true), 22 | /// ]), 23 | /// ) 24 | ///``` 25 | /// [Output]: void walk({required int step}); 26 | 27 | /// Example 28 | ///```dart 29 | /// Method( 30 | /// name: 'changeUser', 31 | /// modifier: 'static', 32 | /// returnType: 'User', 33 | /// isAsync: true, 34 | /// param: Parameter([ 35 | /// ParameterItem('String name', isRequired: true, isNamed: true), 36 | /// ParameterItem('String surname', isRequired: true, isNamed: true), 37 | /// ParameterItem('int? age', isRequired: false, isNamed: true) 38 | /// ]), 39 | /// statements: [ 40 | /// Return('newUser') 41 | /// ] 42 | /// ) 43 | ///``` 44 | /// [Output]: static User changeUser({required String name, required String surname, int? age}) async { return newUser; } 45 | Method( 46 | {required this.name, 47 | this.returnType, 48 | this.param, 49 | this.isAsync = false, 50 | this.modifier = '', 51 | this.statements}); 52 | 53 | @override 54 | String interpret(EditorContext context) { 55 | var buffer = StringBuffer(); 56 | buffer.write(context.indent()); 57 | 58 | // example: static modifier 59 | buffer.write(modifier.isEmpty ? '' : '$modifier '); 60 | 61 | if (returnType != null) { 62 | buffer.write('$returnType '); 63 | } 64 | 65 | buffer.write('$name(${param?.interpret(context) ?? ''})'); 66 | 67 | if (statements != null) { 68 | buffer.write(isAsync ? ' async' : ''); 69 | buffer.writeln(context.openScope(Scope.METHOD)); 70 | statements!.forEach((statement) { 71 | buffer.write(statement.interpret(context)); 72 | }); 73 | buffer.writeln(context.closeScope()); 74 | } 75 | /// [Abstract method] ex: void change(); 76 | else { 77 | buffer.writeln(''.putSemicolon); 78 | } 79 | 80 | return buffer.toString(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /lib/src/interpreter/oop/class.dart: -------------------------------------------------------------------------------- 1 | import 'constructor.dart'; 2 | import '../IExpression.dart'; 3 | import '../editor_context.dart'; 4 | import '../scope.dart'; 5 | import 'attribute.dart'; 6 | 7 | class Class implements IExpression { 8 | final String className; 9 | final bool? isAbstract; 10 | final List? constructors; 11 | 12 | /// [extends] $baseClass 13 | final String? baseClass; 14 | 15 | /// [with] $mixins[i] 16 | final List? mixins; 17 | 18 | /// [implements] $interfaces[i] 19 | final List? interfaces; 20 | final List? attributes; 21 | final List? methods; 22 | 23 | /// Example 24 | /// ```dart 25 | /// Class( 26 | /// 'Bird', 27 | /// baseClass: 'Animal', 28 | /// interfaces: ['Flyable', 'Crowable'], 29 | /// mixins: ['Feather', 'Walk'], 30 | /// attributes: [ 31 | /// Attribute(modifiers: 'final', type: 'String', name: 'name'), 32 | /// ], 33 | /// constructors: [ 34 | /// Constructor( 35 | /// className: 'Bird', 36 | /// constructorName: 'fromName', 37 | /// param: Parameter([ParameterItem('this.name', isRequired: true, isNamed: true)]), 38 | /// superArgument: Argument([ArgumentItem('name')]) 39 | /// ), 40 | /// ], 41 | /// methods: [ 42 | /// Method( 43 | /// name: 'onFly', 44 | /// returnType: 'double', 45 | /// param: Parameter([ParameterItem('double height')]), 46 | /// statements: [Return('height * 2')] 47 | /// ), 48 | /// ] 49 | /// ); 50 | /// ``` 51 | /// [Output] 52 | // class Bird extends Animal with Feather, Walk implements Flyable, Crowable { 53 | // final String name; 54 | 55 | // Bird.fromName({required this.name}) : super(name); 56 | 57 | // double onFly(double height) { 58 | // return height * 2; 59 | // } 60 | // } 61 | Class(this.className, 62 | {this.isAbstract, 63 | this.constructors, 64 | this.baseClass, 65 | this.mixins, 66 | this.interfaces, 67 | this.attributes, 68 | this.methods}); 69 | 70 | @override 71 | String interpret(EditorContext context) { 72 | var buffer = StringBuffer(); 73 | buffer.write(context.indent()); 74 | 75 | if (isAbstract ?? false) { 76 | buffer.write('abstract '); 77 | } 78 | 79 | buffer.write('class $className'); 80 | 81 | /// [extends] $baseClass 82 | if (baseClass != null) { 83 | buffer.write(' extends $baseClass'); 84 | } 85 | 86 | /// [with] $mixins[0], $mixins[1] 87 | if (mixins != null) { 88 | buffer.write(' with '); 89 | mixins!.forEach((element) { 90 | buffer.write(element); 91 | if (element != mixins!.last) { 92 | buffer.write(', '); 93 | } 94 | }); 95 | } 96 | 97 | /// [implements] $interfaces[0], $interfaces[1] 98 | if (interfaces != null) { 99 | buffer.write(' implements '); 100 | interfaces!.forEach((element) { 101 | buffer.write(element); 102 | if (element != interfaces!.last) { 103 | buffer.write(', '); 104 | } 105 | }); 106 | } 107 | 108 | buffer.writeln(context.openScope(Scope.CLASS)); 109 | 110 | if (attributes != null) { 111 | attributes!.forEach((element) { 112 | buffer.write(element.interpret(context)); 113 | }); 114 | buffer.writeln(); 115 | } 116 | 117 | if (constructors != null) { 118 | constructors!.forEach((element) { 119 | buffer.write(element.interpret(context)); 120 | }); 121 | buffer.writeln(); 122 | } 123 | 124 | if (methods != null) { 125 | methods!.forEach((element) { 126 | buffer.write(element.interpret(context)); 127 | }); 128 | } 129 | 130 | buffer.write(context.closeScope()); 131 | 132 | return buffer.toString(); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DartWriter 2 | 3 | `DartWriter` provides API to generate Dart source code. It can make your job easier while developing flutter/dart tools. You can also generate Flutter UI code. 4 | 5 | ### Hello World Example 6 | 7 | ```dart 8 | var context = EditorContext(enableDartFormatter: true); 9 | var code = Method( 10 | name: 'main', 11 | returnType: 'void', 12 | statements: [ 13 | Call('print', 14 | argument: Argument([ 15 | ArgumentItem("'Hello World!'") 16 | ]) 17 | ), 18 | Return('0') 19 | ] 20 | ); 21 | print(context.build([code])); 22 | ``` 23 | Generated as below: 24 | ```dart 25 | void main() { 26 | print('Hello World!'); 27 | return 0; 28 | } 29 | ``` 30 | 31 | ### Flutter Stateless Widget Example 32 | Input 33 | ```json 34 | { 35 | "as": "Scaffold", 36 | "appBar": { 37 | "as": "AppBar", 38 | "title": { 39 | "as": "Text", 40 | "params": [ 41 | "'Ahmet'" 42 | ] 43 | }, 44 | "centerTitle": "false" 45 | }, 46 | "body": { 47 | "as": "Center", 48 | "child": { 49 | "as": "Row", 50 | "children": [ 51 | { 52 | "as": "Icon", 53 | "params": ["Icons.add"], 54 | "color": "Colors.red" 55 | }, 56 | { 57 | "as": "Text", 58 | "params": ["'Ahmet'"], 59 | "textAlign": "TextAlign.center" 60 | } 61 | ] 62 | } 63 | } 64 | } 65 | ``` 66 | Code: 67 | ```dart 68 | var context = EditorContext(enableDartFormatter: true); 69 | var dartHelper = DartHelper.instance; 70 | Map map = jsonDecode(json); 71 | 72 | var homePage = Class('HomePage', 73 | baseClass: 'StatelessWidget', 74 | methods: [ 75 | Annotation('override'), 76 | Method( 77 | name: 'build', 78 | returnType: 'Widget', 79 | param: Parameter([ 80 | ParameterItem('BuildContext context'), 81 | ]), 82 | statements: [ Return(dartHelper.getCodeFromMap(map)) ] 83 | ) 84 | ] 85 | ); 86 | 87 | print(context.build([ 88 | Import('package:flutter/material.dart'), 89 | homePage 90 | ])); 91 | ``` 92 | Generated ui code: 93 | ```dart 94 | import 'package:flutter/material.dart'; 95 | 96 | class HomePage extends StatelessWidget { 97 | @override 98 | Widget build(BuildContext context) { 99 | return Scaffold( 100 | appBar: AppBar(title: Text('Ahmet'), centerTitle: false), 101 | body: Center( 102 | child: Row(children: [ 103 | Icon(Icons.add, color: Colors.red), 104 | Text('Ahmet', textAlign: TextAlign.center) 105 | ]))); 106 | } 107 | } 108 | ``` 109 | 110 | ## Installation 111 | 112 | In the `pubspec.yaml` of your **Flutter** / **Dart** project, add the following dependency: 113 | 114 | ```yaml 115 | dependencies: 116 | ... 117 | dart_writer: any 118 | ``` 119 | 120 | In your library file add the following import: 121 | 122 | ```dart 123 | import 'package:dart_writer/dart_writer.dart'; 124 | ``` 125 | 126 | ## API Documentation 127 | 128 | - [Documentation Guideline](#documentation-guideline) 129 | - [Conditions](#conditions) 130 | - [If](#conditions) 131 | - [Else If](#conditions) 132 | - [Else](#conditions) 133 | - [Loops](#loops) 134 | - [For](#loops) 135 | - [Foreach](#loops) 136 | - [While](#loops) 137 | - [Statements](#statements) 138 | - [Assignment](#statements) 139 | - [Call](#statements) 140 | - [Return](#statements) 141 | - [OOP Concepts](#oop-concepts) 142 | - [Class](#class) 143 | - [Attributes](#attributes) 144 | - [Constructors](#constructors) 145 | - [Methods](#methods) 146 | - [Method](#method) 147 | - [Getter](#getter) 148 | - [Setter](#setter) 149 | - [Interface](#interface) 150 | - Other(#other) 151 | - [Annotations](#other) 152 | - [Import](#other) 153 | - [Enum](#other) 154 | - [Argument](#other) 155 | - [Parameter](#other) 156 | 157 | ### Conditions 158 | ```dart 159 | Method( 160 | name: 'getMin', 161 | returnType: 'int', 162 | statements: [ 163 | Assign('var num1', '5'), 164 | Assign('var num2', '10'), 165 | If(condition: 'num1 < num2', statements: [Return('num1')]), 166 | ElseIf(condition: 'num1 == num2', statements: [Return('num1')]), 167 | Else(statements: [Return('num2')]) 168 | ] 169 | ) 170 | ``` 171 | Generated code: 172 | ```dart 173 | int getMin() { 174 | var num1 = 5; 175 | var num2 = 10; 176 | if (num1 < num2) { 177 | return num1; 178 | } else if (num1 == num2) { 179 | return num1; 180 | } else { 181 | return num2; 182 | } 183 | } 184 | ``` 185 | 186 | ### Loops 187 | ```dart 188 | Method( 189 | name: 'loops', 190 | returnType: 'void', 191 | statements: [ 192 | For('i = 0', 'i < 5', 'i++', 193 | statements: [RawCode('print(i);')] 194 | ), 195 | ForEach('item', 'userList', 196 | statements: [ 197 | Return('UserCard(item)') 198 | ] 199 | ), 200 | While('i < 5', 201 | statements: [ RawCode('print(i);'), Assign('i', 'i + 1')] 202 | ) 203 | ] 204 | ) 205 | ``` 206 | Generated code: 207 | ```dart 208 | void loops() { 209 | for (var i = 0; i < 5; i++) { 210 | print(i); 211 | } 212 | for (var item in userList) { 213 | return UserCard(item); 214 | } 215 | while (i < 5) { 216 | print(i); 217 | i = i + 1; 218 | } 219 | } 220 | ``` 221 | ### Statements 222 | ```dart 223 | Method(name: 'do', returnType: 'int', 224 | statements: [ 225 | Assign('var i', '5'), 226 | Assign('var name', Call('getName')), 227 | Return('i') 228 | ] 229 | ) 230 | ``` 231 | Generated code: 232 | ```dart 233 | int do() { 234 | var i = 5; 235 | var name = getName(); 236 | return i; 237 | } 238 | ``` 239 | 240 | ### OOP Concepts 241 | 242 | #### Class 243 | | Parameter | Description | Output | 244 | | ----------- | ----------- | ----------- | 245 | | String className | Class Name | `class Bird` | 246 | | bool isAbstract? | Generating abstract class if value is true | `abstract class Animal` or `class Animal` | 247 | | List\? | more than one constructor can be defined | `Singleton._init()` , `Singleton({this.a}) : super(a)` | 248 | | String? baseClass | extends to base class | `class Bird extends Animal` | 249 | | List\? mixins | indicates the use of mixins | `class Bird with Feather, Walk` | 250 | | List\? interfaces | implements interface | `class Bird implements Flyable, Crowable` | 251 | | List\? attributes; | attributes of class | `final String name;` | 252 | | List\? methods; | all methods of class such as Method, Getters, Settters | `final String name;` | 253 | 254 | #### Constructor 255 | | Parameter | Description | Output | 256 | | ----------- | ----------- | ----------- | 257 | | String className | Class Name | `class Singleton` | 258 | | String consturctorName? | if value is null Default constructor. if not value, named constructor. | `Singleton._init()` , `Singleton({this.a})` | 259 | | Parameter? param | Constructor parameters | `Singleton({required this.a})`, `Singleton(this.a, {this.b})` | 260 | | String? superArgument | call constructor of base class | `Singleton(this.a) : super(a)` | 261 | | String? modifier | modifier of constructor such as `factory` | `factory Singleton()` | 262 | 263 | #### Attribute 264 | | Parameter | Description | Output | 265 | | ----------- | ----------- | ----------- | 266 | | String name | Attribute Name | `name` | 267 | | String type | Attribute type | `String name` | 268 | | String? modifiers | Attribute modifiers | `final String name` | 269 | | String? value | initialize value to attribute | `final String name = 'Ahmet'` | 270 | 271 | ### Methods 272 | 273 | #### Method 274 | | Parameter | Description | Output | 275 | | ----------- | ----------- | ----------- | 276 | | String name | Method Name | `walk` | 277 | | String returnType? | Return type | `void walk` | 278 | | Parameter? param | Method parameters | `void walk({required int step})` | 279 | | bool? isAsync | is async method? | `void walk({required int step}) async {}` | 280 | | String? modifier | Modifier of method such as `static` | `static void walk` | 281 | | List\? statements | body of method. | `Code here...` | 282 | 283 | #### Getter 284 | | Parameter | Description | Output | 285 | | ----------- | ----------- | ----------- | 286 | | String name | Getter Name | `get walk` | 287 | | String returnType? | Return type | `void get walk` | 288 | | String? modifier | Modifier of method such as `static` | `static void get name` | 289 | | List\? statements | body of method. | `Code here...` | 290 | 291 | #### Setter 292 | | Parameter | Description | Output | 293 | | ----------- | ----------- | ----------- | 294 | | String name | Getter Name | `set name` | 295 | | String param? | Return type | `set name(String name)` | 296 | | List\? statements | body of method. | `Code here...` | 297 | 298 | Example Class Code: 299 | 300 | ```dart 301 | Class( 302 | 'Bird', 303 | baseClass: 'Animal', 304 | interfaces: ['Flyable', 'Crowable'], 305 | mixins: ['Feather', 'Walk'], 306 | attributes: [ 307 | Attribute(modifiers: 'final', type: 'String', name: 'name'), 308 | ], 309 | constructors: [ 310 | Constructor( 311 | className: 'Bird', 312 | constructorName: 'fromName', 313 | param: Parameter([ParameterItem('this.name', isRequired: true, isNamed: true)]), 314 | superArgument: Argument([ArgumentItem('name')]) 315 | ), 316 | ], 317 | methods: [ 318 | Method( 319 | name: 'onFly', 320 | returnType: 'double', 321 | param: Parameter([ParameterItem('double height')]), 322 | statements: [Return('height * 2')] 323 | ), 324 | ] 325 | ); 326 | ``` 327 | Generated code: 328 | ```dart 329 | class Bird extends Animal with Feather, Walk implements Flyable, Crowable { 330 | final String name; 331 | 332 | Bird.fromName({required this.name}) : super(name); 333 | 334 | double onFly(double height) { 335 | return height * 2; 336 | } 337 | } 338 | ``` 339 | 340 | ### Interface 341 | | Parameter | Description | Output | 342 | | ----------- | ----------- | ----------- | 343 | | String name | Interface Name | `interface Flyable` | 344 | | String? baseClass | extends class | `interface Flyable extends Breathable` | 345 | | List\? prototypes | abstract methods of interface | `void doFly();` | 346 | 347 | Example Interface 348 | ```dart 349 | Interface('Flyable', 350 | baseClass: 'Breathable', 351 | prototypes: [ 352 | Method(name: 'doFly', returnType: 'void') 353 | ] 354 | ) 355 | ``` 356 | Generated code: 357 | ```dart 358 | abstract class Flyable extends Breathable { 359 | void doFly(); 360 | } 361 | ``` 362 | ### Other 363 | 364 | | Expression | Example Code | Output | 365 | | ----------- | ----------- | ----------- | 366 | | Annotation | Annotation('override') | `@override` | 367 | | Import | Import('package:dart_writer/dart_writer.dart', as: 'writer') | `import 'package:dart_writer/dart_writer.dart' as writer;` | 368 | | Enum | Enum('Roles', enums: ['USER', 'ADMIN', 'DEVELOPER']) | `enum Roles { USER, ADMIN, DEVELOPER }` | 369 | | Paramter | Parameter([ParameterItem('String name', isNamed: true, isRequired: true)]) | `{required String name}` | 370 | | Argument | Argument([ArgumentItem("'Star'", name:'surname']) | `surname: 'Star'` | 371 | | RawCode | RawCode('var name = user?.name ?? "'ahmet'"') | `[Output]: var name = user?.name ?? 'ahmet'` | 372 | 373 | 374 | ## TASK LIST 375 | - [ ] Unit Tests 376 | --------------------------------------------------------------------------------