resolveReflectables function

Future<ReflectableOutput> resolveReflectables({
  1. required LibraryElement from,
  2. required CompilerFlags flags,
  3. required BuildStep buildStep,
})

Given the provided library, returns the ReflectableOutput.

This is a combination of classes, functions, and libraries that need to be referenced and linked in the generator initReflector() function in each .template.dart file.

Implementation

Future<ReflectableOutput> resolveReflectables({
  required LibraryElement from,
  required CompilerFlags flags,
  required BuildStep buildStep,
}) {
  // Resolves the URI in the context of [buildStep].
  //
  // Returns null if the URI is unsupported.
  AssetId? tryResolvedAsset(String uri) {
    try {
      return AssetId.resolve(Uri.parse(uri), from: buildStep.inputId);
    } on UnsupportedError catch (_) {
      return null;
    }
  }

  // `canRead`/`resolver.isLibrary` on a *generated* output can trigger a
  // reentrant build in build_runner ("Cannot recurse at later or equal
  // phase"). Detect it so we can degrade gracefully instead of crashing the
  // whole compiler.
  bool isReentrancyError(Object e) =>
      e is StateError && '$e'.contains('recurse');

  final reader = ReflectableReader(
    recordInjectableFactories: flags.emitInjectableFactories,
    recordComponentFactories: flags.emitComponentFactories,
    // For a given import or export directive, return whether we have the
    // Dart file's URI in our inputs (for Bazel, it will be in the srcs =
    // [ ... ]).
    //
    // For example, if the template processor is running on an input set
    // of generate_for = [a.dart, b.dart], and we are currently running on
    // a.dart, and a.dart imports b.dart, we can assume that there will be
    // a generated b.template.dart that we need to import/initReflector().
    hasInput: (uri) async {
      final placeholder = tryResolvedAsset(_ngPlaceholderName(uri));
      if (placeholder == null) {
        return false;
      }
      try {
        return await buildStep.canRead(placeholder);
      } catch (e) {
        if (!isReentrancyError(e)) rethrow;
        // The `.ng_placeholder` only exists as a *generated* output, which
        // means the corresponding source will generate a `.template.dart`.
        // Treat the input as present so it is linked via `initReflector()`.
        return true;
      }
    },
    // For a given import or export directive, return whether a generated
    // .template.dart file already exists. If it does we will need to link
    // to it and call initReflector().
    isLibrary: (uri) async {
      final assetId = tryResolvedAsset(uri);
      if (assetId == null) {
        return false;
      }
      try {
        return await buildStep.resolver.isLibrary(assetId);
      } catch (e) {
        if (!isReentrancyError(e)) rethrow;
        // A generated output is not a committed source, so it is not a
        // library; linking is handled by `hasInput` instead.
        return false;
      }
    },
  );

  return reader.resolve(from);
}