content: // Copyright 2021 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 'package:cli_pkg/js.dart';
  import 'package:node_interop/js.dart';
  
  import '../../importer.dart';
  import '../../js/importer.dart';
  import '../../js/url.dart';
  import '../../js/utils.dart';
  import '../../util/nullable.dart';
  import '../canonicalize_context.dart';
  import 'utils.dart';
  
  /// A wrapper for a synchronous JS API importer that exposes it as a Dart
  /// [Importer].
  final class JSToDartImporter extends Importer {
    /// The wrapped canonicalize function.
    final Object? Function(String, CanonicalizeContext) _canonicalize;
  
    /// The wrapped load function.
    final Object? Function(JSUrl) _load;
  
    /// The set of URL schemes that this importer promises never to return from
    /// [canonicalize].
    final Set<String> _nonCanonicalSchemes;
  
    JSToDartImporter(
      this._canonicalize,
      this._load,
      Iterable<String>? nonCanonicalSchemes,
    ) : _nonCanonicalSchemes = nonCanonicalSchemes == null
              ? const {}
              : Set.unmodifiable(nonCanonicalSchemes) {
      _nonCanonicalSchemes.forEach(validateUrlScheme);
    }
  
    Uri? canonicalize(Uri url) {
      var result = wrapJSExceptions(
        () => _canonicalize(url.toString(), canonicalizeContext),
      );
      if (result == null) return null;
      if (isJSUrl(result)) return jsToDartUrl(result as JSUrl);
  
      if (isPromise(result)) {
        jsThrow(
          JsError(
            "The canonicalize() function can't return a Promise for synchronous "
            "compile functions.",
          ),
        );
      } else {
        jsThrow(JsError("The canonicalize() method must return a URL."));
      }
    }
  
    ImporterResult? load(Uri url) {
      var result = wrapJSExceptions(() => _load(dartToJSUrl(url)));
      if (result == null) return null;
  
      if (isPromise(result)) {
        jsThrow(
          JsError(
            "The load() function can't return a Promise for synchronous compile "
            "functions.",
          ),
        );
      }
  
      result as JSImporterResult;
      var contents = result.contents;
      if (!isJsString(contents)) {
        jsThrow(
          ArgumentError.value(
            contents,
            'contents',
            'must be a string but was: ${jsType(contents)}',
          ),
        );
      }
  
      var syntax = result.syntax;
      if (contents == null || syntax == null) {
        jsThrow(
          JsError(
            "The load() function must return an object with contents "
            "and syntax fields.",
          ),
        );
      }
  
      return ImporterResult(
        contents,
        syntax: parseSyntax(syntax),
        sourceMapUrl: result.sourceMapUrl.andThen(jsToDartUrl),
      );
    }
  
    bool isNonCanonicalScheme(String scheme) =>
        _nonCanonicalSchemes.contains(scheme);
  }
  