content: // Copyright 2017 Google Inc. Use of this source code is governed by an
  // MIT-style license that can be found in the LICENSE file or at
  // https://opensource.org/licenses/MIT.
  
  import 'dart:async';
  
  import 'package:meta/meta.dart';
  
  import 'canonicalize_context.dart';
  import 'result.dart';
  import 'utils.dart' as utils;
  
  /// An interface for importers that resolves URLs in `@import`s to the contents
  /// of Sass files.
  ///
  /// Importers should override [toString] to provide a human-readable description
  /// of the importer. For example, the default filesystem importer returns its
  /// load path.
  ///
  /// This class should only be extended by importers that *need* to do
  /// asynchronous work. It's only compatible with the asynchronous `compile()`
  /// methods. If an importer can work synchronously, it should extend [Importer]
  /// instead.
  ///
  /// Subclasses should extend [AsyncImporter], not implement it.
  ///
  /// {@category Importer}
  abstract class AsyncImporter {
    /// Whether the current [canonicalize] invocation comes from an `@import`
    /// rule.
    ///
    /// When evaluating `@import` rules, URLs should canonicalize to an
    /// [import-only file] if one exists for the URL being canonicalized.
    /// Otherwise, canonicalization should be identical for `@import` and `@use`
    /// rules.
    ///
    /// [import-only file]: https://sass-lang.com/documentation/at-rules/import#import-only-files
    ///
    /// Subclasses should only access this from within calls to [canonicalize].
    /// Outside of that context, its value is undefined and subject to change.
    @protected
    @nonVirtual
    bool get fromImport => utils.fromImport;
  
    /// The canonical URL of the stylesheet that caused the current [canonicalize]
    /// invocation.
    ///
    /// This is only set when the containing stylesheet has a canonical URL, and
    /// when the URL being canonicalized is either relative or has a scheme for
    /// which [isNonCanonicalScheme] returns `true`. This restriction ensures that
    /// canonical URLs are always interpreted the same way regardless of their
    /// context.
    ///
    /// Subclasses should only access this from within calls to [canonicalize].
    /// Outside of that context, its value is undefined and subject to change.
    @protected
    @nonVirtual
    Uri? get containingUrl => utils.canonicalizeContext.containingUrl;
  
    /// The canonicalize context of the stylesheet that caused the current
    /// [canonicalize] invocation.
    ///
    /// Subclasses should only access this from within calls to [canonicalize].
    /// Outside of that context, its value is undefined and subject to change.
    ///
    /// @nodoc
    @internal
    @protected
    @nonVirtual
    CanonicalizeContext get canonicalizeContext => utils.canonicalizeContext;
  
    /// If [url] is recognized by this importer, returns its canonical format.
    ///
    /// Note that canonical URLs *must* be absolute, including a scheme. Returning
    /// `file:` URLs is encouraged if the imported stylesheet comes from a file on
    /// disk.
    ///
    /// If Sass has already loaded a stylesheet with the returned canonical URL,
    /// it re-uses the existing parse tree. This means that importers **must
    /// ensure** that the same canonical URL always refers to the same stylesheet,
    /// *even across different importers*.
    ///
    /// This may return `null` if [url] isn't recognized by this importer.
    ///
    /// If this importer's URL format supports file extensions, it should
    /// canonicalize them the same way as the default filesystem importer:
    ///
    /// * The importer should look for stylesheets by adding the prefix `_` to the
    ///   URL's basename, and by adding the extensions `.sass` and `.scss` if the
    ///   URL doesn't already have one of those extensions. For example, if the
    ///   URL was `foo/bar/baz`, the importer would look for:
    ///   * `foo/bar/baz.sass`
    ///   * `foo/bar/baz.scss`
    ///   * `foo/bar/_baz.sass`
    ///   * `foo/bar/_baz.scss`
    ///
    ///   If the URL was `foo/bar/baz.scss`, the importer would just look for:
    ///   * `foo/bar/baz.scss`
    ///   * `foo/bar/_baz.scss`
    ///
    ///   If the importer finds a stylesheet at more than one of these URLs, it
    ///   should throw an exception indicating that the import is ambiguous. Note
    ///   that if the extension is explicitly specified, a stylesheet with the
    ///   opposite extension may exist.
    ///
    /// * If none of the possible paths is valid, the importer should perform the
    ///   same resolution on the URL followed by `/index`. In the example above,
    ///   it would look for:
    ///   * `foo/bar/baz/_index.sass`
    ///   * `foo/bar/baz/index.sass`
    ///   * `foo/bar/baz/_index.scss`
    ///   * `foo/bar/baz/index.scss`
    ///
    ///   As above, if the importer finds a stylesheet at more than one of these
    ///   URLs, it should throw an exception indicating that the import is
    ///   ambiguous.
    ///
    /// If no stylesheets are found, the importer should return `null`.
    ///
    /// Calling [canonicalize] multiple times with the same URL must return the
    /// same result. Calling [canonicalize] with a URL returned by [canonicalize]
    /// must return that URL. Calling [canonicalize] with a URL relative to one
    /// returned by [canonicalize] must return a meaningful result.
    FutureOr<Uri?> canonicalize(Uri url);
  
    /// Loads the Sass text for the given [url], or returns `null` if
    /// this importer can't find the stylesheet it refers to.
    ///
    /// The [url] comes from a call to [canonicalize] for this importer.
    ///
    /// When Sass encounters an `@import` rule in a stylesheet, it first calls
    /// [canonicalize] and [load] on the importer that first loaded that
    /// stylesheet with the imported URL resolved relative to the stylesheet's
    /// original URL. If either of those returns `null`, it then calls
    /// [canonicalize] and [load] on each importer in order with the URL as it
    /// appears in the `@import` rule.
    ///
    /// If the importer finds a stylesheet at [url] but it fails to load for some
    /// reason, or if [url] is uniquely associated with this importer but doesn't
    /// refer to a real stylesheet, the importer may throw an exception that will
    /// be wrapped by Sass. If the exception object has a `message` property, it
    /// will be used as the wrapped exception's message; otherwise, the exception
    /// object's `toString()` will be used. This means it's safe for importers to
    /// throw plain strings.
    FutureOr<ImporterResult?> load(Uri url);
  
    /// Returns the time that the Sass file at [url] was last modified.
    ///
    /// The [url] comes from a call to [canonicalize] for this importer.
    ///
    /// By default, this returns the current time, indicating that [url] should be
    /// reloaded on every compilation. If implementations override this to provide
    /// a more accurate time, Sass will be better able to avoid recompiling it
    /// unnecessarily.
    ///
    /// If this throws an exception, the exception is ignored and the current time
    /// is used as the modification time.
    FutureOr<DateTime> modificationTime(Uri url) => DateTime.now();
  
    /// Without accessing the filesystem, returns whether or not passing [url] to
    /// [canonicalize] could possibly return [canonicalUrl].
    ///
    /// This is expected to be very efficient, and subclasses are allowed to
    /// return false positives if it would be inefficient to determine whether
    /// [url] would actually resolve to [canonicalUrl]. Subclasses are not allowed
    /// to return false negatives.
    FutureOr<bool> couldCanonicalize(Uri url, Uri canonicalUrl) => true;
  
    /// Returns whether the given URL scheme (without `:`) should be considered
    /// "non-canonical" for this importer.
    ///
    /// An importer may not return a URL with a non-canonical scheme from
    /// [canonicalize]. In exchange, [containingUrl] is available within
    /// [canonicalize] for absolute URLs with non-canonical schemes so that the
    /// importer can resolve those URLs differently based on where they're loaded.
    ///
    /// This must always return the same value for the same [scheme]. It is
    /// expected to be very efficient.
    FutureOr<bool> isNonCanonicalScheme(String scheme) => false;
  }
  