lean_builder

1.2.2

A streamlined Dart build system that applies lean principles to minimize waste and maximize speed. Designed for developers who value efficiency and performance.

Download archive

Readme

Lean Builder

A streamlined Dart build system that applies lean principles to minimize waste and maximize speed.

Disclaimer

Some core concepts and code-abstractions are borrowed from the Dart build system. However, Lean Builder is designed as a more efficient and user-friendly alternative, not a direct replacement. It prioritizes performance and simplicity while offering a streamlined approach to code generation.

Current Status

Lean Builder is in active development and is not yet fully tested.

  • Feedback from the community is welcome to help improve the system.
  • Adding more tests is a priority to ensure stability and reliability.
  • The Api is considered stable, but some changes may occur based on feedback and testing.

Overview

Lean Builder is a code generation system designed to be fast, efficient, and easy to use. It provides a streamlined alternative to other build systems with a focus on performance and developer experience.

Features

  • Fast incremental builds
  • it doesn't relay on mirrors so it can be compiled to native code
  • Parallel processing for maximum efficiency
  • Watch mode with hot reload support for faster generator development
  • Simple, declarative builder configuration using annotations
  • Comprehensive asset tracking and dependency management
  • Support for shared part builders, library builders, and standard builders
  • and much more!

Installation

Add Lean Builder to your pubspec.yaml as a dependency:

dev_dependencies:
  lean_builder: <latest-version>

using pub:

 flutter pub add lean_builder --dev

Note: Add lean_builder to your dependenciespe section, if you plan to use it inside of a generator package.

Basic Usage

One-time Build

To build once, use the following command:

dart run lean_builder build

Watch Mode

For continuous builds on file changes, use the watch mode:

dart run lean_builder watch

Use the --dev flag for development mode with hot reload support:

dart run lean_builder watch --dev

Use the clean command to delete caches and precompiled script:

dart run lean_builder clean

Creating Builders

Lean Builder offers multiple ways to create code generators, from simple generators to custom builders.

Using LeanGenerator

Library Generator

Create a generator that outputs standalone library files:

@LeanGenerator({'.lib.dart'})
class MyGenerator extends GeneratorForAnnotatedClass<MyAnnotation> {
  @override
  Future<String> generateForClass(buildStep, element, annotation) async {
    return '// Generated code for ${element.name}';
  }
}

Shared Part Generator

Create a generator that outputs (.g.dart) part files, which can collect multiple outputs from different generators:

@LeanGenerator.shared()
class MySharedGenerator extends GeneratorForAnnotatedClass<MyAnnotation> {
  @override
  Future<String> generateForClass(buildStep, element, annotation) async {
    return '// Generated code for ${element.name}';
  }
}

Custom Builders

For more control, create a custom builder by extending the Builder class:

@LeanBuilder()
class MyBuilder extends Builder {

  @override
  Set<String> get outputExtensions => {'.lib.dart'};

  @override
  bool shouldBuildFor(BuildCandidate candidate) {
    return candidate.isDartSource && candidate.hasTopLevelMetadata;
  }

  @override
  FutureOr<void> build(BuildStep buildStep) {
    final resolver = buildStep.resolver;
    final library = resolver.resolveLibrary(buildStep.asset);
    final elements = library.annotatedWith('<type-checker>');
    // logic
    buildStep.writeAsString('// Generated code', extension: '.lib.dart');
  }
}

Registering Runtime Types

Since LeanBuilder does not relay on reflections, to use your runtime types with type checkers, you need to register them first:

@LeanBuilder(registerTypes: {MyAnnotation})
class MyBuilder extends Builder {
  // ...
  @override
  FutureOr<void> build(BuildStep buildStep) async {
    final resolver = buildStep.resolver;
    final myAnnotationChecker = resolver.typeCheckerOf<MyAnnotation>();
    // Use the type checker in your build logic
  }
}

Note: Generic types of GeneratorForAnnotation<Type> and friends are automatically registered.

Reading Constant Values

To read constant values from annotations, use the ConstantReader class:

void readConstantValues(ElementAnnotation elementAnnotation) {
    Constant constant = elementAnnotation.constant;
  
    if (constant is ConstString) {
      constant.value; // the String value
    }
  
    if (constant is ConstLiteral) {
      constant.literalValue; // the literal value of this constant
    }
  
    if (constant is ConstObject) {
      constant.props; // all the props of the object
      constant.getBool('boolKey')?.value; // ConstBool
      constant.getTypeRef('typeKey')?.value; // ConstType
      constant.getObject('NestedObjKey'); // ConstObject?;
      constant.get('constKey'); // Constant?;
    }
  
    if (constant is ConstList) {
      constant.value; // List<Constant>
      constant.literalValue; // List<dynamic>, dart values
    }
  
    if (constant is ConstFunctionReference) {
      constant.name; // the name of the function
      constant.type; // the type of the function
      constant.element; // the executable element of the function
    }
  }

Advanced Type Checking

The TypeChecker provides a robust way to identify and compare types across libraries.

// Check for a specific type from a package
final myChecker = TypeChecker.typeNamed(MyType, inPackage: 'my_package');

// Check for deep assignability
if (myChecker.isAssignableFromType(someType)) {
  // logic
}

// Or use a URL-based check
final urlChecker = TypeChecker.fromUrl('package:my_package/src/models.dart#MyModel');

Deep Element Model

Lean Builder provides a comprehensive element model that stays up-to-date with modern Dart features:

  • Class Modifiers: Full support for sealed, final, base, and interface classes.
  • Modern Syntax: Accurate resolution for extension type, records, and mixins.
  • Core Annotations: Built-in awareness of package:meta annotations (e.g., @internal, @protected, @visibleForTesting).

Using LeanBuilder directly inside of a project

LeanBuilder is designed to be used inside of generator packages and directly inside of a project. To use LeanBuilder directly inside of a project, it's recommended that you put your generator code inside a folder named codegen in same level as the lib folder. This way, you'll be able to import from dev_dependencies with no linter warnings.

Notes:

  • Do not name the folder other than codegen because the build system will only process the following folders: [lib, bin, test, codegen].
  • Annotations used by the generator should be imported from your lib folder or other packages.

More documentation:

Changelog

1.2.2

  • Feat: Add automatic recovery mechanism in lean_builder.dart to rebuild pre-build script and retry when isolate spawning fails.
  • Fix: Update extension type handling to use namePart instead of primaryConstructor for compatibility with latest analyzer.
  • Fix: Correct isAbstract property in method building to use !node.isComplete instead of node.isAbstract.
  • Chore: Add analyzer exclusions for build and platform-specific directories in analysis_options.yaml.
  • Chore: Update visibility annotations in test utilities for better API clarity.
  • Fix: Widen _fe_analyzer_shared bounds to >=98.0.0 <106.0.0 and dart_style to >=3.1.8 <4.0.0 to match the declared analyzer range.

1.2.1

  • Chore: Update analyzer to support versions 10.0.0 to 14.x and bump _fe_analyzer_shared to ^105.0.0.

1.2.0

  • Feat: Support private named parameters in constructors.
  • Chore: Update analyzer and _fe_analyzer_shared dependency versions.
  • Chore: Set minimum Dart SDK version to 3.12.0.

0.1.11

  • Chore: update to analyzer 13.x and compatible _fe_analyzer_shared versions

0.1.10

  • Chore: allow fe_analyzer_shared 93.0.0

0.1.9

  • FIX: fix a compatibility issue with analyzer 12.0.0

0.1.8

  • Chore: update analyzer and _fe_analyzer_shared version constraints

0.1.7

  • Chore: change analyzer constrans to support 10.0.0 and fix depericatons
  • Chore: bump watcher version to 1.2.1

0.1.6

  • Chore: Add test helpers for lean_builder package
  • fix: revert to using watcher 1.1.4 because 1.2 is broken on macos

0.1.5

  • feat: improve build performance and efficiency
  • fix: minor bug fixes and stability improvements

0.1.4

  • chore: update dependencies

0.1.3

  • fix: a couple windows related path issues
  • fix: correctly resolve relative asset imports
  • fix: URI handling for directories with spaces in their paths
  • fix: stop canonicalizing paths from package: URIs
  • fix: update references from name2 to name in IdentifierRef and related classes
  • chore: downgrade meta package to version ^1.12.0 for compatibility

0.1.2

  • chore: update analyzer packages to a compatible version range

0.1.1

  • chore: update dependencies

0.1.0+1

  • chore: downgrade some pinned dependencies to avoid breaking changes

0.1.0

  • chore: update analyzer packages and remove deprecated code
  • chore: update dependencies

0.1.0-alpha.13

  • fix: preBuildScriptUri path decoding error #4

0.1.0-alpha.12

  • chore: update lints package constrain to ^6.0.0
  • fix: track changes of path hosted packages

0.1.0-alpha.11

  • chore: Remove flutter_test dependency from pubspec.yaml

0.1.0-alpha.10

  • feat: introduce PathMatcher for flexible asset finding
  • fix: assets reader does not follow symlinks now
  • fix: formatter page-width role is now included before any generated content'

0.1.0-alpha.9

  • fix: exclude none-dart files from being scanned for references by ReferencesScanner

0.1.0-alpha.8

  • fix: add missing 'applies' property to @LeanBuilder
  • fix: none dart outputs are now properly tracked

0.1.0-alpha.7

  • fix: downgrade lints package version from 6.0.0 to 5.1.1

0.1.0-alpha.6

  • fix: Add default constructor for classes with no constructors.
  • feat: Add page_width role with fixed number for all generated files.

0.1.0-alpha.5

  • pre-build script snapshot is now generated on run not shipped

0.1.0-alpha.4

  • expose Asset
  • fix fields are bing resolved multiple times

0.1.0-alpha.3

  • clean up some code

0.1.0-alpha.2

  • fix: fix some early bugs.

0.1.0-alpha.1

  • cleanup: remove unused code

0.1.0-alpha

  • Initial version.

Installing

export PUB_HOSTED_URL=https://pub.mirror.p-hatan.ir
flutter pub add lean_builder
pubspec.yaml
name: lean_builder
description: A streamlined Dart build system that applies lean principles to minimize waste and maximize speed. Designed for developers who value efficiency and performance.
version: 1.2.2
repository: https://github.com/Milad-Akarie/lean_builder
platforms:
  macos:
  linux:
  windows:

topics:
  - build
  - build-system
  - dart-build-system
  - code-generation
  - codegen

executables:
  lean_builder:

environment:
  sdk: '>=3.12.0 <4.0.0'

dependencies:
  _fe_analyzer_shared: '>=98.0.0 <106.0.0'
  analyzer: '>=10.0.0 <15.0.0'
  args: ^2.7.0
  xxh3: ^1.2.0
  path: ^1.9.1
  collection: ^1.18.0
  meta: ^1.16.0
  glob: ^2.1.3
  watcher: ^1.2.1
  dart_style: '>=3.1.8 <4.0.0'
  ansicolor: ^2.0.3
  source_span: ^1.10.2
  stack_trace: ^1.12.1
  frontend_server_client: ^4.0.0
  yaml: ^3.1.3
  hotreloader: ^4.4.0

dev_dependencies:
  lints: ^6.1.0
  test: ^1.25.15
  coverage: ^1.15.0

Version history

VersionPublishedArchiveSHA-256
0.1.0-alphaOn demandDownload7a0cbc36…08fe2e
0.1.0-alpha.1On demandDownload0ce9ef76…07dbf8
0.1.0-alpha.2On demandDownload53f7c9a8…faa3e6
0.1.0-alpha.3On demandDownload2799ac46…6101a9
0.1.0-alpha.4On demandDownload6f5a69e2…c260f2
0.1.0-alpha.5On demandDownloadefdf9296…3df5d8
0.1.0-alpha.6On demandDownload891131f3…797cbc
0.1.0-alpha.7On demandDownloadd8cdef4d…ad0a5d
0.1.0-alpha.8On demandDownload1dd21965…5fd9b2
0.1.0-alpha.9On demandDownload4ef6d3a9…92a568
0.1.0-alpha.10On demandDownloadc45eadd4…71b99a
0.1.0-alpha.11On demandDownload8efb801a…d8f8f6
0.1.0-alpha.12On demandDownloadac129cd2…e6ca8a
0.1.0-alpha.13On demandDownloaddca2165c…c7e1b9
0.1.0On demandDownload68c370f5…6698dd
0.1.0+1On demandDownload83306955…d85528
0.1.1On demandDownload3d3a04c9…aa8164
0.1.2On demandDownloadef5cd5f9…323ee9
0.1.3On demandDownload6511c632…af7035
0.1.4On demandDownloadf3ddb3b2…bc02d8
0.1.5On demandDownload4f3d70c3…f06942
0.1.6On demandDownload6af3cfbf…250d76
0.1.7On demandDownloadee4117b0…1b3a53
0.1.8On demandDownload2603a2a6…7689be
0.1.9On demandDownload2e60947a…48759f
0.1.10On demandDownloadc16e95dd…1e96c0
1.2.0On demandDownload123eef9f…3fbded
1.2.1On demandDownloadca394837…50d57d
1.2.2Cached · Upstream SHA-256 matchedDownload5acef085…e67917

Dependencies

_fe_analyzer_shared "\u003e=98.0.0 \u003c106.0.0"

analyzer "\u003e=10.0.0 \u003c15.0.0"

ansicolor "^2.0.3"

args "^2.7.0"

collection "^1.18.0"

dart_style "\u003e=3.1.8 \u003c4.0.0"

frontend_server_client "^4.0.0"

glob "^2.1.3"

hotreloader "^4.4.0"

meta "^1.16.0"

path "^1.9.1"

source_span "^1.10.2"

stack_trace "^1.12.1"

watcher "^1.2.1"

xxh3 "^1.2.0"

yaml "^3.1.3"