dart-lang / source_gen

Automatic source code generation for Dart
https://pub.dev/packages/source_gen
BSD 3-Clause "New" or "Revised" License
482 stars 104 forks source link
dart-build-system

Dart CI

Pub Package Version

Join the chat on Gitter

Overview

source_gen provides utilities for automated source code generation for Dart:

Its main purpose is to expose a developer-friendly API on top of lower-level packages like the analyzer or build. You don't have to use source_gen in order to generate source code; we also expose a set of library APIs that might be useful in your generators.

Quick Start Guide for writing a Generator

Add a dependency on source_gen in your pubspec.

dependencies:
  source_gen:

If you're only using source_gen in your own project to generate code and you won't publish your Generator for others to use, it can be a dev_dependency:

dev_dependencies:
  source_gen:

Once you have source_gen setup, you should reference the examples below.

Writing a generator to output Dart source code

Extend the Generator or GeneratorForAnnotation class and source_gen will call your generator for a Dart library or for each element within a library tagged with the annotation you are interested in.

Configuring and Running generators

source_gen is based on the build package and exposes options for using your Generator in a Builder. Choose a Builder based on where you want the generated code to end up:

In order to get the Builder used with build_runner it must be configured in a build.yaml file. See build_config for more details. Whenever you are publishing a package that includes a build.yaml file you should include a dependency on build_config in your pubspec.

When using SharedPartBuilder it should always be configured to build_to: cache (hidden files) and apply the combining_builder from this package. The combining builder reads in all the pieces written by different shared part builders and writes them to the final .g.dart output in the user's source directory. You should never use the .g.dart extension for any other Builder.

builders:
  some_cool_builder:
    import: "package:this_package/builder.dart"
    builder_factories: ["someCoolBuilder"]
    # The `partId` argument to `SharedPartBuilder` is "some_cool_builder"
    build_extensions: {".dart": [".some_cool_builder.g.part"]}
    auto_apply: dependents
    build_to: cache
    # To copy the `.g.part` content into `.g.dart` in the source tree
    applies_builders: ["source_gen:combining_builder"]

Configuring combining_builder

ignore_for_file

Sometimes generated code does not support all of the lints specified in the target package. When using a Builder based on package:source_gen which applies combining_builder, set the ignore_for_file option to a list of lints you wish to be ignored in all generated libraries.

Example build.yaml configuration:

targets:
  $default:
    builders:
      source_gen:combining_builder:
        options:
          ignore_for_file:
          - lint_alpha
          - lint_beta

preamble

When using a Builder based on package:source_gen which applies combining_builder, set the preamble option to a string you wish to be prepended to all generated libraries.

Example build.yaml configuration:

targets:
  $default:
    builders:
      source_gen:combining_builder:
        options:
          preamble: |
                // Foo

                // Bar

Hint: When both ignore_for_file and preamble are used the generated libraries will contain the lints of ignore_for_file on top of the preamble.

If you provide a builder that uses SharedPartBuilder and combining_builder, you should document these features for your users.

Generating files in different directories

The output location for an input file can be changed:

By default, a .g.dart or .some_name.dart file is generated next to the input. To change this, set the build_extensions option on the corresponding builder. In the options, build_extensions is a map from String to String, where the key is matches inputs and the value is a single build output. For more details on build extensions, see the docs in the build package.

For example, you can use these options to generate files under lib/generated with the following build configuration:

targets:
  $default:
    builders:
      # A SharedPartBuilder which uses the combining builder
      source_gen:combining_builder:
        options:
          build_extensions:
            '^lib/{{}}.dart': 'lib/generated/{{}}.g.dart'

      # A PartBuilder or LibraryBuilder
      some_cool_builder:
        options:
          build_extensions:
            '^lib/models/{{}}.dart': 'lib/models/generated/{{}}.foo.dart'

Remember to change the part statement in the input to refer to the correct output file in the other directory.

Note that builder options are part of source_gen's public api! When using them in a build configuration, always add a dependency on source_gen as well:

dev_dependencies:
  source_gen: ^1.1.0

FAQ

What is the difference between source_gen and build?

Build is a platform-agnostic framework for Dart asset or code generation that is pluggable into build systems including bazel, and standalone tools like build_runner. You could also build your own.

Meanwhile, source_gen provides an API and tooling that is easily usable on top of build to make common tasks easier and more developer friendly. For example the PartBuilder class wraps one or more Generator instances to make a Builder which creates part of files, while the LibraryBuilder class wraps a single Generator to make a Builder which creates Dart library files.

Publishing automation

For information about our publishing automation and release process, see https://github.com/dart-lang/ecosystem/wiki/Publishing-automation.