โ† Reflection
In the worksrole: extensionlicense: BSD-3-Clause

tom_reflector

tom_reflector ยท v1.0.0

Analyzer-based code reflection engine for the Tom framework. It walks Dart sources with the Dart analyzer and produces a structured snapshot of a codebase's API.

See License
Status
In the works
LOC
15.0k
Tests
191
Test LOC
223.6k

Overview

From the module readme.md file:

What it enables

Enables API extraction, *.r.dart reflection output, Stable downstream API surface.

Relationships

Standalone โ€” no declared relationships.

tom_reflector

> Part of the Tom Framework reflection toolkit โ€” an original analyzer-based > build-time reflection engine ยฉ 2024โ€“2026 Peter Nicolai Alexis Kyaw > (BSD-3-Clause). Unlike its engine-1 siblings > tom_reflection / > tom_reflection_generator โ€” which are > derived from the reflectable package > by the Dart team ("Copyright (c) 2015, Dart", BSD-3-Clause) โ€” tom_reflector > shares no lineage or code with reflectable. See LICENSE.

Build-time, structural reflection for Dart. tom_reflector is engine 2 of the Tom reflection toolkit: instead of mirrors on live objects, it walks the Dart analyzer element model and produces a serializable object graph of your code's shape โ€” classes, methods, parameters, types, annotations โ€” plus optional *.r.dart reflection output that tooling consumes at build time.

This is original work (renamed from tom_analyzer), with no shared lineage with reflectable. For runtime mirrors on real instances, use the sibling engine tom_reflection instead โ€” see the repo README for how to choose.

Overview

A code generator or workspace tool often needs to know the shape of code โ€” "what classes are here, what do they implement, what are their members and annotations?" โ€” without running that code. dart:mirrors can't help (it's runtime and unavailable in AOT), and re-running the analyzer in every downstream tool is slow and couples you to a specific analyzer/Dart version.

tom_reflector solves this by analyzing once and emitting a stable, pre-resolved model (tom_reflector_model) that any tool can read as plain data. The model is comprehensive (modifiers, type parameters with bounds, annotations with arguments, source locations), round-trips through JSON/YAML, and uses cycle-safe ID references when serialized. That stability is the point: downstream generators are insulated from analyzer churn.

   your sources           tom_reflector (analyzer)            outputs
lib/models.dart  โ”€โ”€โ”€โ”€โ”€โ–บ  reachability / barrel analysis  โ”€โ–บ  models.r.dart
lib/app.dart             + element walking                   + AnalysisResult graph
                                                               (tom_reflector_model)

Installation

tom_reflector is an internal workspace package (publish_to: none); depend on it by path from within the workspace:

dependencies:
  tom_reflector:
    path: ../tom_reflector

SDK: Dart ^3.10.4; uses analyzer ^8. The compiled reflector binary is produced by the workspace build (~/.tom/bin/<platform>/reflector) and is also reachable as buildkit :reflector.

Two generation modes

ModeDriven byUse it when
Legacy (barrel) a barrel file whose exports are all analyzed you want reflection for everything a package exports.
Entry-point (reachability) entry points + include/exclude filters you want precise control โ€” reflect only what's reachable and wanted.

Legacy (barrel) mode

# buildkit.yaml
tom_reflector:
  barrels:
    - lib/my_package.dart
  follow_re_exports: true
  skip_re_exports:
    - dart.core

Generates lib/my_package.r.dart for all exports of the barrel.

Entry-point (reachability) mode

Performs reachability analysis from entry points, with rich filters, configurable transitive dependency resolution, and fine-grained coverage:

# buildkit.yaml
tom_reflector:
  entry_points:
    - lib/my_app.dart
  output: lib/generated/reflection.r.dart

  defaults:
    exclude_packages: ['dart.*']
    include_annotations: ['Reflectable']

  filters:
    - include: { packages: ['my_package'] }
    - exclude: { annotations: ['DoNotReflect'] }

  dependency_config:
    superclasses:   { enabled: true, depth: -1 }
    interfaces:     { enabled: true }
    mixins:         { enabled: true }
    type_arguments: { enabled: true }
    code_bodies:    { enabled: false }

  coverage_config:
    instance_members: { enabled: true }
    static_members:   { enabled: true }
    constructors:     { enabled: true }
    metadata:         { enabled: true }

Configuration reference (entry-point mode):

SectionKeyDefaultPurpose
top-level entry_points [] Roots for reachability analysis.
output (derived) Output path; .r.dart appended automatically.
include_private false Include private members.
defaults exclude_packages / include_packages [] Package globs always excluded / included.
include_annotations [] Annotations that auto-include their target.
filters include / exclude selectors [] Ordered rules by packages , annotations , paths , types , elements .
dependency_config superclasses , interfaces , mixins , type_arguments , code_bodies varies Transitive resolution ( enabled , depth , external_depth , exclude_types ).
coverage_config instance_members , static_members , constructors , metadata enabled: true Which invokers/data to generate.

CLI

Run over a configured project, or scan the whole workspace:

reflector                 # generate for the current project (reads buildkit.yaml)
reflector -R              # recursively scan the workspace for tom_reflector: projects
reflector -e lib/app.dart # entry-point mode (bypasses barrel config)
reflector --list          # list projects that would be processed (no action)
buildkit :reflector       # equivalent, nested under buildkit

dart run bin/reflector.dart [options] is equivalent before the binary is compiled.

Options (navigation flags like -R, -s, -p come from tom_build_base):

OptionShortDefaultDescription
--config=<path> -c buildkit.yaml Config file path.
--entry=<file> -e Entry point(s), repeatable/comma-separated โ€” switches to entry-point mode.
--barrel=<path> (from config) Barrel for legacy mode (overrides config).
--output=<path> (auto) Output file path.
--list -l false List target projects, take no action.
--verbose -v false Verbose output.

Override precedence: buildkit.yaml tom_reflector: loads first โ†’ --barrel overrides barrels โ†’ --output overrides the derived path โ†’ --entry bypasses barrel config entirely and switches to entry-point mode.

Programmatic usage

Barrel analysis โ†’ model

import 'package:tom_reflector/tom_reflector.dart';

Future<void> main() async {
  final runner = AnalyzerRunner();
  final AnalysisResult result = await runner.analyzeBarrel(
    barrelPath: 'lib/models.dart',
    skipReExports: const ['dart.core'],
  );

  for (final cls in result.allClasses) {
    print('${cls.name}: ${cls.methods.length} methods'); // Order: 3 methods
  }
}

Entry-point reachability โ†’ model

import 'package:tom_reflector/tom_reflector.dart';

Future<void> main() async {
  final config = ReflectionConfig(
    entryPoints: const ['lib/my_app.dart'],
    defaults: const ReflectionDefaults(includeAnnotations: ['Reflectable']),
  );
  final analyzer = EntryPointAnalyzer(config);
  final result = await analyzer.analyze();
  // result holds the reachable, filtered set; feed it to ReflectionGenerator.
}

.r.dart output

In either mode the ReflectionGenerator emits a *.r.dart file holding the reflection data alongside the source. Treat *.r.dart as a build output โ€” never hand-edit it; fix the generator/config and regenerate.

Architecture

package:tom_reflector/tom_reflector.dart   (public API; re-exports tom_reflector_model)
โ”œโ”€โ”€ src/analyzer/         drive the analyzer & build the model
โ”‚   โ”œโ”€โ”€ AnalyzerRunner            barrel analysis โ†’ AnalysisResult
โ”‚   โ”œโ”€โ”€ AnalyzerContextBuilder    analysis context setup
โ”‚   โ”œโ”€โ”€ BarrelAnalyzer            legacy barrel mode
โ”‚   โ”œโ”€โ”€ ElementVisitor / TypeResolver, AnnotationParser
โ”œโ”€โ”€ src/reflection/generator/    entry-point reachability
โ”‚   โ”œโ”€โ”€ EntryPointAnalyzer        reachability + filters โ†’ ReflectionAnalysisResult
โ”‚   โ”œโ”€โ”€ ReflectionConfig          filters, dependency & coverage config
โ”‚   โ””โ”€โ”€ ReflectionGenerator       emits *.r.dart
โ””โ”€โ”€ src/v2/   reflectorTool + ReflectorExecutor (tom_build_base CLI)

bin/reflector.dart  โ†’ ToolRunner(reflectorTool)  โ†’ `reflector` / `buildkit :reflector`

Key types

TypeResponsibility
AnalyzerRunner Entry point for barrel analysis ( analyzeBarrel ) โ†’ AnalysisResult .
AnalyzerContextBuilder Builds the analyzer AnalysisContextCollection.
BarrelAnalyzerLegacy barrel-export walking.
EntryPointAnalyzer Reachability analysis from entry points (analyze()).
ReflectionConfig Entry-point configuration: entryPoints , filters , dependencyConfig , coverageConfig , includePrivate ; load() / fromMap() .
ReflectionGenerator Emits *.r.dart from the analyzed model.
ReflectionModelIn-memory reflection model for generation.
reflectorTool / ReflectorExecutor tom_build_base CLI surface (reflector).

The pure data model itself (AnalysisResult, ClassInfo, โ€ฆ) lives in tom_reflector_model and is re-exported here.

Ecosystem

tom_reflector_model   pure serializable model (AnalysisResult, ClassInfo, โ€ฆ)
      โ–ฒ re-exports
tom_reflector         THIS PACKAGE โ€” analyzer engine + `reflector` CLI โ†’ *.r.dart
      โ”‚ builds on
      โ”œโ”€โ”€ tom_build_base   v2 tool framework (CLI, navigation, version flags)
      โ””โ”€โ”€ tom_d4rt_ast     AST modelling (cross-repo: tom_ai/d4rt/)

> tom_d4rt_ast lives in the d4rt repo; changes there can affect this > package โ€” coordinate with the d4rt quest on breaking changes.

This is the engine-2 generator. The runtime mirror engine (tom_reflection) is a separate technology with its own generator emitting *.reflection.dart.

Further documentation

Runnable samples (engine 2)

โ†’ reflector_parser_advanced_sample - Codegen mode (*.r.dart): reflector_reflection_introduction_sample โ†’ reflector_reflection_advanced_sample

> Naming note: some doc/ files predate the tom_analyzer โ†’ tom_reflector > rename and still say "tom_analyzer"/"tom_analyzer_model". Read those names as > the pre-rename identity of tom_reflector/tom_reflector_model.

Status

  • Version: 1.0.0 (publish_to: none, internal workspace package).
  • SDK: Dart ^3.10.4; analyzer ^8.
  • Modes: legacy barrel + entry-point reachability, both implemented.
  • CLI: reflector standalone and buildkit :reflector, on tom_build_base

navigation.

License

BSD 3-Clause โ€” original Tom Framework work (no reflectable lineage). See LICENSE.

License
BSD 3-Clause License

Copyright (c) 2024-2026, Peter Nicolai Alexis Kyaw
Find me on LinkedIn under Alexis Kyaw
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
   contributors may be used to endorse or promote products derived from
   this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.