// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. import 'dart:async'; import 'dart:convert'; import 'package:analyzer/dart/element/element.dart'; import 'package:crypto/crypto.dart'; import 'package:glob/glob.dart'; import 'package:package_config/package_config_types.dart'; import 'asset_id.dart'; import 'resolver.dart'; import 'resource.dart'; /// A single step in `build_runner` build. /// /// See the `Builder` class API for more information on what causes build steps /// to run during a builder. The `Builder` class has a `build` method that /// accepts a [BuildStep] and uses it to read inputs, resolve Dart source and /// write outputs. abstract class BuildStep implements AssetReader, AssetWriter { /// The primary input that this build step is for. AssetId get inputId; /// Resolves the library in [inputId]. /// /// Throws [NonLibraryAssetException] if [inputId] is not a Dart library file. /// /// Throws [SyntaxErrorInAssetException] if [inputId] contains syntax errors. /// /// To resolve allowing syntax errors, instead use /// `resolver.libraryFor(buildStep.inputId, allowSyntaxErrors: true)`. Future get inputLibrary; /// A [Resolver] that can parse or resolve any Dart source code visible to /// this build step. /// /// That means all source files in all transitive deps of the current package, /// all source files in the current package and all files output by builders /// that run _before_ the current builder in the current build. Resolver get resolver; /// Reads the bytes from [id]. /// /// - Throws a `PackageNotFoundException` if `id.package` is not found. /// - Throws an `AssetNotFoundException` if `id.path` is not found. /// - Throws an `InvalidInputException` if [id] is an invalid input. An input /// is invalid if it is a non-public member of a dependency package; for /// example by default `lib` contains public assets but `test` does not. @override Future> readAsBytes(AssetId id); /// Reads the text contents of [id] using [encoding]. /// /// - Throws a `PackageNotFoundException` if `id.package` is not found. /// - Throws an `AssetNotFoundException` if `id.path` is not found. /// - Throws an `InvalidInputException` if [id] is an invalid input. An input /// is invalid if it is a non-public member of a dependency package; for /// example by default `lib` contains public assets but `test` does not. @override Future readAsString(AssetId id, {Encoding encoding = utf8}); /// Indicates whether [id] can be read by this build step. /// /// That means the file exists, _and_ it is visible to this build step. /// /// Files that are generated by builders that run after the current builder /// are hidden, even if they physically exist on disk due to an earlier build. /// For such files, `canRead` returns `false` and the `read` methods will /// throw `AssetNotFoundException`. @override Future canRead(AssetId id); /// Returns all readable assets matching [glob] under the current package. /// /// This includes generated assets output by builders that run before the /// current builder, but _not_ generated assets that will be output by /// builders that will run after the current builder. @override Stream findAssets(Glob glob); /// Assets that are allowed to be written by this build step. /// /// These are determined by the `buildExtensions` of the `Builder` running /// in this step; see that API in `Builder` for more information. Iterable get allowedOutputs; /// Writes [bytes] to [id]. /// /// The [id] must be one of [allowedOutputs] or an `UnexpectedOutputException` /// is thrown. /// /// The [id] must not have been written before or an `InvalidOutputException` /// is thrown. @override Future writeAsBytes(AssetId id, FutureOr> bytes); /// Writes [contents] to [id] using [encoding]. /// /// The [id] must be one of [allowedOutputs] or an `UnexpectedOutputException` /// is thrown. And, this must be the first write to it, or an /// `InvalidOutputException` is thrown. @override Future writeAsString( AssetId id, FutureOr contents, { Encoding encoding = utf8, }); /// Fetches [resource]. /// /// See the [Resource] docs for how resources are created, shared and /// disposed. Future fetchResource(Resource resource); /// Tracks performance of [action] separately. /// /// If performance tracking is enabled, tracks [action] as separate stage /// identified by [label]. Otherwise just runs [action]. /// /// You can specify [action] as [isExternal] (waiting for some external /// resource like network, process or file IO). In that case [action] will /// be tracked as a single time slice from the beginning of the stage until /// completion of the `Future` returned by [action]. /// /// Otherwise all separate time slices of asynchronous execution will be /// tracked, but waiting for external resources will be a gap. /// /// Returns the value returned by [action]. /// /// Async [action]s that return a `Future` are supported. T trackStage(String label, T Function() action, {bool isExternal = false}); /// Indicates that [ids] were read but their content has no impact on the /// outputs of this step. /// /// If [ids] change then `build_runner` might optimize by not running this /// step. void reportUnusedAssets(Iterable ids); /// The [PackageConfig] of the current isolate. /// /// URIs in the config are `asset:$package/$path` URIs that work with /// [AssetId.resolve], allowing files to be read with [readAsString] or /// [readAsBytes]. Future get packageConfig; } /// The "write" part of the [BuildStep] API. /// /// See [BuildStep] for details. abstract class AssetWriter { Future writeAsBytes(AssetId id, List bytes); Future writeAsString( AssetId id, String contents, { Encoding encoding = utf8, }); } /// The "read" part of the [BuildStep] API. /// /// See [BuildStep] for details. abstract class AssetReader { Future> readAsBytes(AssetId id); Future readAsString(AssetId id, {Encoding encoding = utf8}); Future canRead(AssetId id); Stream findAssets(Glob glob); /// Returns a [Digest] representing a hash of the contents of [id]. /// /// This is not intended for use by builders: `build_runner` already checks /// input digests to only run build steps if inputs changed. Future digest(AssetId id); }