Git Product home page Git Product logo

code_builder's Introduction

Dart CI Pub package package publisher Gitter chat

A fluent, builder-based library for generating valid Dart code.

Usage

code_builder has a narrow and user-friendly API.

See the example and test folders for additional examples.

For example creating a class with a method:

import 'package:code_builder/code_builder.dart';
import 'package:dart_style/dart_style.dart';

void main() {
  final animal = Class((b) => b
    ..name = 'Animal'
    ..extend = refer('Organism')
    ..methods.add(Method.returnsVoid((b) => b
      ..name = 'eat'
      ..body = const Code("print('Yum!');"))));
  final emitter = DartEmitter();
  print(DartFormatter().format('${animal.accept(emitter)}'));
}

Outputs:

class Animal extends Organism {
  void eat() => print('Yum!');
}

Have a complicated set of dependencies for your generated code? code_builder supports automatic scoping of your ASTs to automatically use prefixes to avoid symbol conflicts:

import 'package:code_builder/code_builder.dart';
import 'package:dart_style/dart_style.dart';

void main() {
  final library = Library((b) => b.body.addAll([
        Method((b) => b
          ..body = const Code('')
          ..name = 'doThing'
          ..returns = refer('Thing', 'package:a/a.dart')),
        Method((b) => b
          ..body = const Code('')
          ..name = 'doOther'
          ..returns = refer('Other', 'package:b/b.dart')),
      ]));
  final emitter = DartEmitter.scoped();
  print(DartFormatter().format('${library.accept(emitter)}'));
}

Outputs:

import 'package:a/a.dart' as _i1;
import 'package:b/b.dart' as _i2;

_i1.Thing doThing() {}
_i2.Other doOther() {}

Contributing

If a feature is missing (the Dart language is always evolving) or you'd like an easier or better way to do something, consider opening a pull request. You can always file an issue, but generally speaking, feature requests will be on a best-effort basis.

NOTE: Due to the evolving Dart SDK the local dartfmt must be used to format this repository. You can run it simply from the command-line:

$ dart run dart_style:format -w .

Updating generated (.g.dart) files

NOTE: There is currently a limitation in build_runner that requires a workaround for developing this package since it is a dependency of the build system.

Make a snapshot of the generated build_runner build script and run from the snapshot instead of from source to avoid problems with deleted files. These steps must be run without deleting the source files.

./tool/regenerate.sh 

code_builder's People

Contributors

alorenzen avatar chalin avatar davidmorgan avatar ddashenkov avatar dependabot[bot] avatar devoncarew avatar dnys1 avatar donny-dont avatar jakemac53 avatar kevmoo avatar leptopoda avatar matanlurey avatar mosuem avatar natebosch avatar nshahan avatar rhalff avatar saintgabriel0 avatar simolus3 avatar smkhalsa avatar smolck avatar snehal-singh174 avatar srawlins avatar srujzs avatar stereotype441 avatar tarekkma avatar thosakwe avatar vsevolod19860507 avatar yanok avatar ydiev avatar yjbanov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

code_builder's Issues

FR: Support creation of string literals that include newlines

AFAIK, creating """string""" literals isn't supported. When supplying literal() with a multi-line string, it will output a string with single ' delimiters and the original newlines, resulting in syntax errors. Creating the literal manually isn't possible — StringLiteral isn't an exported class.

There's a workaround — never using """ in the generated code (for example, by escaping all newlines with \n).

I wonder if I'm missing something. If not and this functionality is supposed to be supported, let me know. I'd love to make a PR.

MethodBuilder.closure() not treated as an expression

expect(
list([1, 2, 3]).invoke('where', [
new MethodBuilder.closure(returns: literal(true))
..addPositional(parameter('', []))
]),
equalsSource('[1,2,3].where((
) => true)'));

fails with
Expected: '[1,2,3].where(() => true)' ignoring whitespace
Actual: <Instance of 'MethodInvocationBuilder'>
Which: '[1, 2, 3].where((
) => true;)'is '[1, 2, 3].where((
) => true;)' with whitespace compressed

Empty return as a statement.

As far as I can tell, there's not way to create an empty return statement, such as "if (true) return;"

All I could find was ExpressionBuilder.asReturn(), which requires an actual expression to return.

`Function` causes exception

'package:code_builder/dart/core.dart': error: line 111 pos 26: unexpected token 'Function'
  final ReferenceBuilder Function = _ref('Function');
                         ^
Process finished with exit code 254

https://github.com/dart-lang/code_builder/blob/master/lib/dart/core.dart#L111

  /// References [dart_core.Function].
  final ReferenceBuilder Function = _ref('Function');

Dart VM version: 1.22.0-edge.8cca41772d807594955c7e9312b36ab691cfc7fe (Fri Jan 27 14:35:59 2017) on "linux_x64"

code_builder-1.0.0-beta+1

Might be related to dart-lang/sdk#27527 (comment)

Split FileBuilder into LibraryBuilder and PartBuilder

FileBuilder currently allows building both libraries and parts and it uses a runtime check to make sure we don't put import directives and such into part files. Instead, FileBuilder could be abstract and we could have LibraryBuilder and PartBuilder concrete implementations that prevent incorrect directives at the API level.

Strawman:

abstract class FileBuilder {
  void addClass();
  void addVariable();
  void addFunction();
}

class LibraryBuilder extends FileBuilder {
  void addImport();
  void addExport();
}

class PartBuilder extends FileBuilder {
  PartBuilder(String libraryName);
}

Use astFactory for Async and Yield

This is blocking the internal sync which uses a newer version of analyzer where things like AsyncExpression are now abstract classes and require the use of astFactory. Should be a simple fix.

ExpressionBuilder should be assignable to StatementBuilder

An expression is also a statement. For example:

void main() {
  "blah".substring(1);  // expression used as statement
}

So this should be allowed:

var methodBuilder = new MethodBuilder(...);
methodBuilder.addStatement(new ExpressionBuilder.invoke('substring'd));

Need a ClosureBuilder

Right now, there's no way to create a closure expression. All we have is lamba() for MethodBuilders.

Example:
args.map((String arg) => doSomething(arg));

StatementBuilder is missing generics

the following doesn't work:
new LibraryBuilder().addMember(literal(false).asConst('foo'));

ERROR: The argument type 'StatementBuilder' can't be assigned to the parameter type 'AstBuilder'.

Add a new Statement/Expression.raw(...)

... to allow opt-outs for more advanced scenarios we won't/can't cover with builders.

Example use:

new ExpressionBuilder.raw('5 + 90 >> 2 | 3')
new StatementBuilder.raw(r'''
  switch (value) {
    case: ...
  }
''')

We also need to be able to support auto-scoping - we could use mustache:

new StatementBuilder.raw(r'''
  switch ({{value}}) {
    case 1:
      break;
    case 2:
      break;
  }
''')

Would ~roughly translate to:

switch ($scoped.value) {
  ...
}

Static mehtods

I might be missing something obvious but I can't find a way of marking a method as static, I can see that static is mentioned in buildMethod but I can't find how to utilise this from MethodBuilder.

Potentially MethodModifier could be developed to support statics?

Support lazy ASTs wherever possible

(@yjbanov suggested offline, here is my understanding)

Some builders are lazy, they don't actually emit an AST until toAst() is called. Others are behind-the-scenes writing to an AST object the entire time. This second pattern should be removed and replaced with lazy emitters.

Advantages:

  • Performance (?): We aren't building AST objects until actually needed
  • Consistency: i.e. You should be able to add builder A to builder B and mutate A after
  • Support for alternative APIs (see below)
// Classic method.
clazz.addMethod(new MethodBuilder.returnVoid(name: 'foo'));

// Builder-type method
clazz.addMethod()
  ..setName('foo')
  ..setReturnVoid();

We could accomplish by having an API like:

MethodBuilder addMethod([MethodBuilder builder]) {
  builder ??= new MethodBuilder();
  _builders.add(builder);
  return builder;
}

Assigned to @yjbanov to review design before implementation 😀

ExpressionBuilders should have an `asThrow` method.

It would be very helpful if we could do something like:

new TypeBuilder('StateError').newInstance(['Blah blah blah']).asThrow();

This would also work, and might be better than the original suggestion I had:

new ThrowExpression(...)

I have a branch where this change is implemented as an asThrow method on ExpressionBuilder instances, but it wouldn't be difficult for me to just expose the _ThrowExpression class I created.

Thoughts on this? Can I go ahead and submit a PR, or was I too vague and need to clarify?

Thanks in advance.

Add `toExportBuilder` to `ReferenceBuilder`

https://gitter.im/dart-lang/TALK-general/archives/2016/12/01

I could see a Reference.toExportBuilder, would that help?

from

Günter Zöchbauer @zoechi Dec 01 18:56
@matanlurey code_builder question.
Do you know a way to get the import path back from a reference('name', 'path').
I try to create an export and I thing it would be nice if I could use the reference I already have.

Matan Lurey @matanlurey Dec 01 19:06
@zoechi No that is not possible. I don't expose anything you used to build - just complicates the API.

Günter Zöchbauer @zoechi Dec 01 19:08
@matanlurey didn't mean anyting, but it seemes reasonable to use a reference to build an export.

Matan Lurey @matanlurey Dec 01 19:09
I could see a Reference.toExportBuilder, would that help?

Invalid argument type errors

Cloned from master and after running pub get I'm getting 15 Invalid argument type errors relating to: ValidClassMember ValidMemberMember & ValidConstructorMember. Example below:

file: '/code_builder/lib/src/builders/class.dart'
severity: 'Error'
message: 'The argument type 'ValidClassMember' can't be assigned to the parameter type 'AnnotationBuilder'.'
at: '26,27'
source: 'dart'

screen shot 2017-02-18 at 14 37 35

Is there a way from `ClassBuilder` to `ExpressionBuilder`

I build the class declaration for class AppComponent (for library a_lib) and need the type as parameter like

ClassBuilder appComponent = ...;
final mainMethod = new MethodBuilder.returnVoid('main')
..addStatement(AngularPlatformBrowser.bootstrapFunction
        .call([appComponent]))
               ^^^^^^^^^^^^

What is a good way to get from appComponent to the ExpressionBuilder required by call([...])

I hope you don't mind that I ask a few questions here to master the first hurdles.

Builders should provide accessors to their fields

For example, imagine I was to construct a factory that forwards its parameters to a constructor:

class Foo {
  factory Foo(A a, B b, C c) {
    return new Foo._(a, b, c);
  }

  Foo._(A a, B b, C c);
}

To generate factory Foo(A a, B b, C c) I will have a List<ParameterBuilder>. To forward the parameters to Foo._, I want to be able to convert List<ParameterBuilder> to a List<ExpressionBuilder> args and pass that to myType.newInstance(args).

Example:

List<ExpressionBuilder> forwardParamsToArgs(List<ParameterBuilder> params) {
  return params.map<ExpressionBuilder>((p) => reference(p.name)).toList();
}

Unfortunately p.name does not exist.

Add support for `as SomeType`

I tried to generate code like

final dataConnection =  connections.getByName('foo') as FhirDataConnection;

but couldn't find a way.

Does not handle empty methods properly

expect(
new LibraryBuilder()
..addMember(new MethodBuilder.returnVoid('main')),
equalsSource('void main {}'));

Expected: 'void main {}' ignoring whitespace
Actual: <Instance of 'LibraryBuilder'>
Which: 'void main();'is 'void main();' with whitespace compressed

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.