build method
Generates the outputs for a given BuildStep.
Implementation
@override
Future<void> build(BuildStep buildStep) async {
final inputId = buildStep.inputId;
if (inputId.path.endsWith(_generatedExtension)) return;
if (!await buildStep.resolver.isLibrary(inputId)) return;
// The trigger library imports the not-yet-generated output, so tolerate the
// resulting unresolved import while looking for the annotation.
final entryLibrary =
await buildStep.resolver.libraryFor(inputId, allowSyntaxErrors: true);
// The trigger annotation lives on a top-level `const previews` variable;
// scan every top-level element kind to remain robust to where it's placed.
final topLevel = <Element>[
...entryLibrary.classes,
...entryLibrary.enums,
...entryLibrary.mixins,
...entryLibrary.extensions,
...entryLibrary.extensionTypes,
...entryLibrary.typeAliases,
...entryLibrary.topLevelFunctions,
...entryLibrary.topLevelVariables,
...entryLibrary.getters,
...entryLibrary.setters,
];
final trigger = topLevel.firstWhereOrNull(
(e) => previewRegistryChecker.hasAnnotationOf(e, throwOnUnresolved: false),
);
if (trigger == null) return;
// The generated symbol mirrors the annotated variable's name: an
// `@PreviewRegistry() final myPreviews = $myPreviews;` trigger yields a
// `$myPreviews` field. Falls back to `$previews` for an unnamed element.
final triggerName = trigger.name;
final registryName =
'\$${triggerName == null || triggerName.isEmpty ? 'previews' : triggerName}';
// Scan every library under lib/ for previews.
final detected = <DetectedPreview>[];
await for (final assetId in buildStep.findAssets(Glob('lib/**.dart'))) {
if (assetId.path.endsWith(_generatedExtension)) continue;
if (!await buildStep.resolver.isLibrary(assetId)) continue;
final library = await buildStep.resolver.libraryFor(
assetId,
allowSyntaxErrors: true,
);
detected.addAll(detectPreviews(library));
}
final source = _generate(detected, registryName);
await buildStep.writeAsString(
inputId.changeExtension(_generatedExtension),
source,
);
}