code_builder 3.0.3

  • README.md
  • CHANGELOG.md
  • Example
  • Installing
  • Versions
  • 93

code_builder

Pub package Build status Latest docs Gitter chat

code_builder is a fluent Dart API for generating valid Dart source 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 = new Class((b) => b
    ..name = 'Animal'
    ..extend = refer('Organism')
    ..methods.add(new Method.returnsVoid((b) => b
      ..name = 'eat'
      ..body = const Code('print(\'Yum\')'))));
  final emitter = new DartEmitter();
  print(new 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 = new Library((b) => b.body.addAll([
        new Method((b) => b
          ..body = const Code('')
          ..name = 'doThing'
          ..returns = refer('Thing', 'package:a/a.dart')),
        new Method((b) => b
          ..body = const Code('')
          ..name = 'doOther'
          ..returns = refer('Other', 'package:b/b.dart')),
      ]));
  final emitter = new DartEmitter(new Allocator.simplePrefixing());
  print(new 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:

$ pub 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. We expect this to be unnecessary in the future.

Use build_runner:

$ mv build.disabled.yaml build.yaml
$ pub run build_runner build --delete-conflicting-outputs
$ mv build.yaml build.disabled.yaml

3.0.3

  • Fix a bug that caused all downstream users of code_builder to crash due to build_runner trying to import our private builder (in tool/). Sorry for the inconvenience.

3.0.2

  • Require source_gen: ^0.7.5.

3.0.1

  • Upgrade to built_value 5.1.0.
  • Export the literalNum function.
  • BUG FIX: literal supports a Map.

3.0.0

  • Also infer Constructor.lambda for factory constructors.

3.0.0-alpha

  • Using equalsDart no longer formats automatically with dartfmt.

  • Removed deprecated Annotation and File classes.

  • Method.lambda is inferred based on Method.body where possible and now defaults to null.

2.4.0

  • Add equalTo, notEqualTo, greaterThan, lessThan, greateOrEqualTo, and lessOrEqualTo to Expression.

2.3.0

  • Using equalsDart and expecting dartfmt by default is deprecated. This requires this package to have a direct dependency on specific versions of dart_style (and transitively analyzer), which is problematic just for testing infrastructure. To future proof, we've exposed the EqualsDart class with a format override:
// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

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

final DartFormatter _dartfmt = new DartFormatter();
String _format(String source) {
  try {
    return _dartfmt.format(source);
  } on FormatException catch (_) {
    return _dartfmt.formatStatement(source);
  }
}

/// Should be invoked in `main()` of every test in `test/**_test.dart`.
void useDartfmt() => EqualsDart.format = _format;
  • Added Expression.isA and Expression.isNotA:
void main() {
  test('should emit an is check', () {
    expect(
      refer('foo').isA(refer('String')),
      equalsDart('foo is String'),
    );
  });
}
  • Deprecated Annotation. It is now legal to simply pass any Expression as a metadata annotation to Class, Method, Field, and Parameter. In 3.0.0, the Annotation class will be completely removed:
void main() {
  test('should create a class with a annotated constructor', () {
    expect(
      new Class((b) => b
        ..name = 'Foo'
        ..constructors.add(
          new Constructor((b) => b..annotations.add(refer('deprecated'))))),
      equalsDart(r'''
        class Foo {
          @deprecated
          Foo();
        }
      '''),
    );
  });
}
  • Added inference support for Method.lambda and Constructor.lambda. If not explicitly provided and the body of the function originated from an Expression then lambda is inferred to be true. This is not a breaking change yet, as it requires an explicit null value. In 3.0.0 this will be the default:
void main() {
  final animal = new Class((b) => b
    ..name = 'Animal'
    ..extend = refer('Organism')
    ..methods.add(new Method.returnsVoid((b) => b
      ..name = 'eat'
      // In 3.0.0, this may be omitted and still is inferred.
      ..lambda = null
      ..body = refer('print').call([literalString('Yum!')]).code)));
  final emitter = new DartEmitter();
  print(new DartFormatter().format('${animal.accept(emitter)}'));
}
  • Added nullSafeProperty to Expression to access properties with ?.
  • Added conditional to Expression to use the ternary operator ? :
  • Methods taking positionalArguments accept Iterable<Expression>
  • BUG FIX: Parameters can take a FunctionType as a type. Reference.type now returns a Reference. Note that this change is technically breaking but should not impacts most clients.

2.2.0

  • Imports are prefixed with _i1 rather than _1 which satisfies the lint lowercase_with_underscores. While not a strictly breaking change you may have to fix/regenerate golden file-like tests. We added documentation that the specific prefix is not considered stable.

  • Added Expression.index for accessing the [] operator:

void main() {
  test('should emit an index operator', () {
    expect(
      refer('bar').index(literalTrue).assignVar('foo').statement,
      equalsDart('var foo = bar[true];'),
    );
  });

  test('should emit an index operator set', () {
    expect(
      refer('bar')
        .index(literalTrue)
        .assign(literalFalse)
        .assignVar('foo')
        .statement,
      equalsDart('var foo = bar[true] = false;'),
    );
  });
}
  • literalList accepts an Iterable argument.

  • Fixed an NPE when a method had a return type of a FunctionType:

void main() {
  test('should create a method with a function type return type', () {
    expect(
      new Method((b) => b
        ..name = 'foo'
        ..returns = new FunctionType((b) => b
          ..returnType = refer('String')
          ..requiredParameters.addAll([
            refer('int'),
          ]))),
      equalsDart(r'''
        String Function(int) foo();
      '''),
    );
  });
}

2.1.0

We now require the Dart 2.0-dev branch SDK (>= 2.0.0-dev).

  • Added support for raw String literals.
  • Automatically escapes single quotes in now-raw String literals.
  • Deprecated File, which is now a redirect to the preferred class, Library.

This helps avoid symbol clashes when used with dart:io, a popular library. It is now safe to do the following and get full access to the code_builder API:

import 'dart:io';

import 'package:code_builder/code_builder.dart' hide File;

We will remove File in 3.0.0, so use Library instead.

2.0.0

Re-released without a direct dependency on package:analyzer!

For users of the 1.x branch of code_builder, this is a pretty big breaking change but ultimately is for the better - it's easier to evolve this library now and even add your own builders on top of the library.

// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

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

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

...outputs...

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

Major changes:

  • Builders now use built_value, and have a more consistent, friendly API.
  • Builders are now consistent - they don't any work until code is emitted.
  • It's possible to overwrite the built-in code emitting, formatting, etc by providing your own visitors. See DartEmitter as an example of the built-in visitor/emitter.
  • Most of the expression and statement level helpers were removed; in practice they were difficult to write and maintain, and many users commonly asked for opt-out type APIs. See the Code example below:
void main() {
  var code = new Code('x + y = z');
  code.expression;
  code.statement;
}

See the commit log, examples, and tests for full details. While we want to try and avoid breaking changes, suggestions, new features, and incremental updates are welcome!

2.0.0-beta

  • Added lazySpec and lazyCode to lazily create code on visit #145.

  • BUG FIX: equalsDart emits the failing source code #147.

  • BUG FIX: Top-level lambda Methods no longer emit invalid code #146.

2.0.0-alpha+3

  • Added Expression.annotation and Expression.annotationNamed.

  • Added Method.closure to create an Expression.

  • Added FunctionType.

  • Added {new|const}InstanceNamed to Expression #135.

    • Also added a typeArguments option to all invocations.
  • Added assign{...} variants to Expression #137.

  • Added .awaited and .returned to Expression #138.

  • BUG FIX: Block now implements Code #136.

  • BUG FIX: new DartEmitter.scoped() applies prefixing #139.

  • Renamed many of the .asFoo(...) and .toFoo(...) methods to single getter:

    • asCode() to code
    • asStatement() to statement
    • toExpression() to expression
  • Moved {new|const}Instance{[Named]} from Expression to Reference.

2.0.0-alpha+2

  • Upgraded build_runner from ^0.3.0 to >=0.4.0 <0.6.0.

  • Upgraded build_value{_generator} from ^1.0.0 to >=2.0.0 <5.0.0.

  • Upgraded source_gen from >=0.5.0 <0.7.0 to ^0.7.0.

  • Added MethodModifier to allow emit a Method with async|async*|sync*.

  • Added show|hide to Directive.

  • Added Directive.importDeferredAs.

  • Added a new line character after emitting some types (class, method, etc).

  • Added refer as a short-hand for new Reference(...).

    • Reference now implements Expression.
  • Added many classes/methods for writing bodies of Code fluently:

    • Expression
    • LiteralExpression
      • literal
      • literalNull
      • literalBool
      • literalTrue
      • literalFalse
      • literalNum
      • literalString
      • literalList and literalConstList
      • literalMap and literalConstMap
    • const Code(staticString)
    • const Code.scope((allocate) => '')
  • Removed SimpleSpecVisitor (it was unused).

  • Removed implements Reference from Method and Field; not a lot of value.

  • SpecVisitor<T>'s methods all have an optional [T context] parameter now.

    • This makes it much easier to avoid allocating extra StringBuffers.
  • equalsDart removes insignificant white space before comparing results.

2.0.0-alpha+1

  • Removed Reference.localScope. Just use Reference(symbol) now.
  • Allow Reference instead of an explicit TypeReference in most APIs.
    • toType() is performed for you as part the emitter process
final animal = new Class((b) => b
  ..name = 'Animal'
  // Used to need a suffix of .toType().
  ..extend = const Reference('Organism')
  ..methods.add(new Method.returnsVoid((b) => b
    ..name = 'eat'
    ..lambda = true
    ..body = new Code((b) => b..code = 'print(\'Yum\')'))));
  • We now support the Dart 2.0 pre-release SDKs (<2.0.0-dev.infinity)
  • Removed the ability to treat Class as a TypeReference.
    • Was required for compilation to dart2js, which is now tested on travis.

2.0.0-alpha

  • Complete re-write to not use package:analyzer.
  • Code generation now properly uses the builder pattern (via built_value).
  • See examples and tests for details.

1.0.4

  • Added isInstanceOf to ExpressionBuilder, which performs an is check:
expect(
  reference('foo').isInstanceOf(_barType), 
  equalsSource('foo is Bar'),
);

1.0.3

  • Support latest pkg/analyzer and pkg/func.

1.0.2

  • Update internals to use newer analyzer API

1.0.1

  • Support the latest version of package:dart_style.

1.0.0

First full release. At this point all changes until 2.0.0 will be backwards compatible (new features) or bug fixes that are not breaking. This doesn't mean that the entire Dart language is buildable with our API, though.

Contributions are welcome.

  • Exposed uri in ImportBuilder, ExportBuilder, and Part[Of]Builder.

1.0.0-beta+7

  • Added ExpressionBuilder#ternary.

1.0.0-beta+6

  • Added TypeDefBuilder.
  • Added FunctionParameterBuilder.
  • Added asAbstract to various MethodBuilder constructors.

1.0.0-beta+5

  • Re-published the package without merge conflicts.

1.0.0-beta+4

  • Renamed PartBuilder to PartOfBuilder.
  • Added a new class, PartBuilder, to represent part '...dart' directives.
  • Added the HasAnnotations interface to all library/part/directive builders.
  • Added asFactory and asConst to ConstructorBuilder.
  • Added ConstructorBuilder.redirectTo for a redirecting factory constructor.
  • Added a name getter to ReferenceBuilder.
  • Supplying an empty constructor name ('') is equivalent to null (default).
  • Automatically encodes string literals with multiple lines as '''.
  • Added asThrow to ExpressionBuilder.
  • Fixed a bug that prevented FieldBuilder from being used at the top-level.

1.0.0-beta+3

  • Added support for genericTypes parameter for ExpressionBuilder#invoke:
expect(
  explicitThis.invoke('doThing', [literal(true)], genericTypes: [
    lib$core.bool,
  ]),
  equalsSource(r'''
    this.doThing<bool>(true)
  '''),
);
  • Added a castAs method to ExpressionBuilder:
expect(
  literal(1.0).castAs(lib$core.num),
  equalsSource(r'''
    1.0 as num
  '''),
);

BREAKING CHANGES

  • Removed namedNewInstance and namedConstInstance, replaced with constructor::
expect(
  reference('Foo').newInstance([], constructor: 'other'),
  equalsSource(r'''
    new Foo.other()
  '''),
);
  • Renamed named parameter to namedArguments:
expect(
  reference('doThing').call(
    [literal(true)],
    namedArguments: {
      'otherFlag': literal(false),
    },
  ),
  equalsSource(r'''
    doThing(true, otherFlag: false)
  '''),
);

1.0.0-beta+2

BREAKING CHANGES

Avoid creating symbols that can collide with the Dart language:

  • MethodModifier.async -> MethodModifier.asAsync
  • MethodModifier.asyncStar -> MethodModifier.asAsyncStar
  • MethodModifier.syncStar -> MethodModifier.asSyncStar

1.0.0-beta+1

  • Add support for switch statements
  • Add support for a raw expression and statement
    • new ExpressionBuilder.raw(...)
    • new StatemnetBuilder.raw(...)

This should help cover any cases not covered with builders today.

  • Allow referring to a ClassBuilder and TypeBuilder as an expression
  • Add support for accessing the index [] operator on an expression

BREAKING CHANGES

  • Changed ExpressionBuilder.asAssign to always take an ExpressionBuilder as target and removed the value property. Most changes are pretty simple, and involve just using reference(...). For example:
literal(true).asAssign(reference('flag'))

... emits flag = true.

1.0.0-beta

  • Add support for async, sync, sync* functions
  • Add support for expression asAwait, asYield, asYieldStar
  • Add toExportBuilder and toImportBuilder to types and references
  • Fix an import scoping bug in return statements and named constructor invocations.
  • Added constructor initializer support
  • Add while and do {} while loop support
  • Add for and for-in support
  • Added a name getter for ParameterBuilder

1.0.0-alpha+7

  • Make use of new analyzer API in preparation for analyzer version 0.30.

1.0.0-alpha+6

  • MethodBuilder.closure emits properly as a top-level function

1.0.0-alpha+5

  • MethodBuilder with no statements will create an empty block instead of a semicolon.
// main() {}
method('main')
  • Fix lambdas and closures to not include a trailing semicolon when used as an expression.
 // () => false
 new MethodBuilder.closure(returns: literal(false));

1.0.0-alpha+4

  • Add support for latest pkg/analyzer.

1.0.0-alpha+3

  • BREAKING CHANGE: Added generics support to TypeBuilder:

importFrom becomes a named, not positional argument, and the named argument genericTypes is added (Iterable<TypeBuilder>).

// List<String>
new TypeBuilder('List', genericTypes: [reference('String')])
  • Added generic support to ReferenceBuilder:
// List<String>
reference('List').toTyped([reference('String')])
  • Fixed a bug where ReferenceBuilder.buildAst was not implemented
  • Added and and or methods to ExpressionBuilder:
// true || false
literal(true).or(literal(false));

// true && false
literal(true).and(literal(false));
  • Added support for creating closures - MethodBuilder.closure:
// () => true
new MethodBuilder.closure(
  returns: literal(true),
  returnType: lib$core.bool,
)

1.0.0-alpha+2

  • Added returnVoid to well, return;
  • Added support for top-level field assignments:
new LibraryBuilder()..addMember(literal(false).asConst('foo'))
  • Added support for specifying a target when using asAssign:
// Outputs bank.bar = goldBar
reference('goldBar').asAssign('bar', target: reference('bank'))
  • Added support for the cascade operator:
// Outputs foo..doThis()..doThat()
reference('foo').cascade((c) => <ExpressionBuilder> [
  c.invoke('doThis', []),
  c.invoke('doThat', []),
]);
  • Added support for accessing a property
// foo.bar
reference('foo').property('bar');

1.0.0-alpha+1

  • Slight updates to confusing documentation.
  • Added support for null-aware assignments.
  • Added show and hide support to ImportBuilder
  • Added deferred support to ImportBuilder
  • Added ExportBuilder
  • Added list and map literals that support generic types

1.0.0-alpha

  • Large refactor that makes the library more feature complete.

0.1.1

  • Add concept of Scope and change toAst to support it

Now your entire AST tree can be scoped and import directives automatically added to a LibraryBuilder for you if you use LibraryBuilder.scope.

0.1.0

  • Initial version

example/example.dart

// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

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

final _dartfmt = new DartFormatter();

void main() {
  print('animalClass():\n${'=' * 40}\n${animalClass()}');
  print('scopedLibrary():\n${'=' * 40}\n${scopedLibrary()}');
}

/// Outputs:
///
/// ```dart
/// class Animal extends Organism {
///   void eat() => print('Yum!');
/// }
/// ```
String animalClass() {
  final animal = new Class((b) => b
    ..name = 'Animal'
    ..extend = refer('Organism')
    ..methods.add(new Method.returnsVoid((b) => b
      ..name = 'eat'
      ..body = refer('print').call([literalString('Yum!')]).code)));
  return _dartfmt.format('${animal.accept(new DartEmitter())}');
}

/// Outputs:
///
/// ```dart
/// import 'package:a/a.dart' as _i1;
/// import 'package:b/b.dart' as _i2;
///
/// _i1.Thing doThing() {}
/// _i2.Other doOther() {}
/// ```
String scopedLibrary() {
  final methods = [
    new Method((b) => b
      ..body = const Code('')
      ..name = 'doThing'
      ..returns = refer('Thing', 'package:a/a.dart')),
    new Method((b) => b
      ..body = const Code('')
      ..name = 'doOther'
      ..returns = refer('Other', 'package:b/b.dart')),
  ];
  final library = new Library((b) => b.body.addAll(methods));
  return _dartfmt.format('${library.accept(new DartEmitter.scoped())}');
}

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  code_builder: "^3.0.3"

2. Install it

You can install packages from the command line:

with pub:


$ pub get

with Flutter:


$ flutter packages get

Alternatively, your editor might support pub get or packages get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:code_builder/code_builder.dart';
        
Version Uploaded Documentation Archive
3.0.3 Feb 10, 2018 Go to the documentation of code_builder 3.0.3 Download code_builder 3.0.3 archive
3.0.2 Feb 10, 2018 Go to the documentation of code_builder 3.0.2 Download code_builder 3.0.2 archive
3.0.1 Jan 30, 2018 Go to the documentation of code_builder 3.0.1 Download code_builder 3.0.1 archive
3.0.0 Jan 9, 2018 Go to the documentation of code_builder 3.0.0 Download code_builder 3.0.0 archive
2.4.0 Dec 11, 2017 Go to the documentation of code_builder 2.4.0 Download code_builder 2.4.0 archive
2.3.0 Nov 27, 2017 Go to the documentation of code_builder 2.3.0 Download code_builder 2.3.0 archive
2.2.0 Nov 22, 2017 Go to the documentation of code_builder 2.2.0 Download code_builder 2.2.0 archive
2.1.0 Nov 4, 2017 Go to the documentation of code_builder 2.1.0 Download code_builder 2.1.0 archive
2.0.0 Oct 28, 2017 Go to the documentation of code_builder 2.0.0 Download code_builder 2.0.0 archive
1.0.4 Jun 16, 2017 Go to the documentation of code_builder 1.0.4 Download code_builder 1.0.4 archive

All 36 versions...

Analysis

We analyzed this package on Apr 23, 2018, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.0.0-dev.49.0
  • pana: 0.10.6

Scores

Popularity:
Describes how popular the package is relative to other packages. [more]
86 / 100
Health:
Code health derived from static analysis. [more]
99 / 100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100 / 100
Overall score:
Weighted score of the above. [more]
93
Learn more about scoring.

Platforms

Detected platforms: Flutter, web, other

No platform restriction found in primary library package:code_builder/code_builder.dart.

Suggestions

  • The description is too short.

    Add more detail about the package, what it does and what is its target use case. Try to write at least 60 characters.

  • Fix analysis and formatting issues.

    Analysis or formatting checks reported 16 hints.

    Strong-mode analysis of lib/src/specs/code.dart gave the following hint:

    line: 98 col: 12
    The member 'visitAll' can only be used within 'emitter.dart' or a test.

    Strong-mode analysis of lib/src/specs/expression.dart gave the following hint:

    line: 357 col: 7
    The member 'visitAll' can only be used within 'emitter.dart' or a test.

    Similar analysis of the following files failed:

    • lib/src/specs/expression/invoke.dart (hint)
    • lib/src/specs/method.dart (hint)
    • lib/src/specs/reference.dart (hint)
    • lib/src/specs/type_reference.dart (hint)

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0-dev <2.0.0
built_collection >=1.0.0 <4.0.0 3.1.1
built_value ^5.1.0 5.4.3
matcher ^0.12.0 0.12.2
meta ^1.0.5 1.1.2
Transitive dependencies
analyzer 0.31.1 0.31.2-alpha.1
args 1.4.2
async 2.0.6
build_config 0.2.6+1
charcode 1.1.1
cli_util 0.1.2+1
collection 1.14.9
convert 2.0.1
crypto 2.0.2+1
csslib 0.14.1
fixnum 0.10.7
front_end 0.1.0-alpha.9 0.1.0-alpha.11
glob 1.1.5
html 0.13.3
isolate 1.1.0 2.0.0
kernel 0.3.0-alpha.9 0.3.0-alpha.11
logging 0.11.3+1
package_config 1.0.3
path 1.5.1
plugin 0.2.0+2
quiver 0.29.0+1
source_span 1.4.0
stack_trace 1.9.2
string_scanner 1.0.2
typed_data 1.1.5
utf 0.9.0+4
watcher 0.9.7+7
yaml 2.1.13
Dev dependencies
build ^0.12.0 0.12.2
build_runner ^0.7.9
built_value_generator ^5.1.0
dart_style ^1.0.0
source_gen ^0.7.5
test ^0.12.0