Skip to content

Commit

Permalink
Add support for the new importer API (#1522)
Browse files Browse the repository at this point in the history
  • Loading branch information
nex3 committed Oct 5, 2021
1 parent 4b0f008 commit c9e2f96
Show file tree
Hide file tree
Showing 8 changed files with 412 additions and 14 deletions.
56 changes: 56 additions & 0 deletions lib/src/importer/node_to_dart/async.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// 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 'dart:async';

import 'package:node_interop/js.dart';
import 'package:node_interop/util.dart';

import '../../node/importer.dart';
import '../../node/url.dart';
import '../../node/utils.dart';
import '../../util/nullable.dart';
import '../async.dart';
import '../result.dart';

/// A wrapper for a potentially-asynchronous JS API importer that exposes it as
/// a Dart [AsyncImporter].
class NodeToDartAsyncImporter extends AsyncImporter {
/// The wrapped canonicalize function.
final Object? Function(String, CanonicalizeOptions) _canonicalize;

/// The wrapped load function.
final Object? Function(JSUrl) _load;

NodeToDartAsyncImporter(this._canonicalize, this._load);

FutureOr<Uri?> canonicalize(Uri url) async {
var result = _canonicalize(
url.toString(), CanonicalizeOptions(fromImport: fromImport));
if (isPromise(result)) result = await promiseToFuture(result as Promise);
if (result == null) return null;

if (isJSUrl(result)) return jsToDartUrl(result as JSUrl);

jsThrow(JsError("The canonicalize() method must return a URL."));
}

FutureOr<ImporterResult?> load(Uri url) async {
var result = _load(dartToJSUrl(url));
if (isPromise(result)) result = await promiseToFuture(result as Promise);
if (result == null) return null;

result as NodeImporterResult;
var contents = result.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));
}
}
80 changes: 80 additions & 0 deletions lib/src/importer/node_to_dart/async_file.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// 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 'dart:async';

import 'package:node_interop/js.dart';
import 'package:node_interop/util.dart';
import 'package:path/path.dart' as p;

import '../../io.dart' as io;
import '../../node/importer.dart';
import '../../node/utils.dart';
import '../../syntax.dart';
import '../async.dart';
import '../filesystem.dart';
import '../result.dart';
import '../utils.dart';

/// A filesystem importer to use for most implementation details of
/// [NodeToDartAsyncFileImporter].
///
/// This allows us to avoid duplicating logic between the two importers.
final _filesystemImporter = FilesystemImporter('.');

/// A wrapper for a potentially-asynchronous JS API file importer that exposes
/// it as a Dart [AsyncImporter].
class NodeToDartAsyncFileImporter extends AsyncImporter {
/// The wrapped `findFileUrl` function.
final Object? Function(String, CanonicalizeOptions) _findFileUrl;

/// A map from canonical URLs to the `sourceMapUrl`s associated with them.
final _sourceMapUrls = <Uri, Uri>{};

NodeToDartAsyncFileImporter(this._findFileUrl);

FutureOr<Uri?> canonicalize(Uri url) async {
if (url.scheme != 'file' && url.scheme != '') return null;

var result = _findFileUrl(
url.toString(), CanonicalizeOptions(fromImport: fromImport));
if (isPromise(result)) result = await promiseToFuture(result as Promise);
if (result == null) return null;

result as NodeFileImporterResult;
var dartUrl = result.url;
var sourceMapUrl = result.sourceMapUrl;
if (dartUrl == null) {
jsThrow(JsError(
"The findFileUrl() method must return an object a url field."));
}

var resultUrl = jsToDartUrl(dartUrl);
if (resultUrl.scheme != 'file') {
jsThrow(JsError(
'The findFileUrl() must return a URL with scheme file://, was '
'"$url".'));
}

var canonical = _filesystemImporter.canonicalize(resultUrl);
if (canonical == null) return null;
if (sourceMapUrl != null) {
_sourceMapUrls[canonical] = jsToDartUrl(sourceMapUrl);
}

return canonical;
}

ImporterResult? load(Uri url) {
var path = p.fromUri(url);
return ImporterResult(io.readFile(path),
sourceMapUrl: _sourceMapUrls[url] ?? url, syntax: Syntax.forPath(path));
}

DateTime modificationTime(Uri url) =>
_filesystemImporter.modificationTime(url);

bool couldCanonicalize(Uri url, Uri canonicalUrl) =>
_filesystemImporter.couldCanonicalize(url, canonicalUrl);
}
82 changes: 82 additions & 0 deletions lib/src/importer/node_to_dart/file.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// 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:node_interop/js.dart';
import 'package:path/path.dart' as p;

import '../../io.dart' as io;
import '../../importer.dart';
import '../../node/importer.dart';
import '../../node/utils.dart';
import '../../syntax.dart';
import '../filesystem.dart';
import '../result.dart';
import '../utils.dart';

/// A filesystem importer to use for most implementation details of
/// [NodeToDartAsyncFileImporter].
///
/// This allows us to avoid duplicating logic between the two importers.
final _filesystemImporter = FilesystemImporter('.');

/// A wrapper for a potentially-asynchronous JS API file importer that exposes
/// it as a Dart [AsyncImporter].
class NodeToDartFileImporter extends Importer {
/// The wrapped `findFileUrl` function.
final Object? Function(String, CanonicalizeOptions) _findFileUrl;

/// A map from canonical URLs to the `sourceMapUrl`s associated with them.
final _sourceMapUrls = <Uri, Uri>{};

NodeToDartFileImporter(this._findFileUrl);

Uri? canonicalize(Uri url) {
if (url.scheme != 'file' && url.scheme != '') return null;

var result = _findFileUrl(
url.toString(), CanonicalizeOptions(fromImport: fromImport));
if (result == null) return null;

if (isPromise(result)) {
jsThrow(JsError(
"The canonicalize() function can't return a Promise for synchronous "
"compile functions."));
}

result as NodeFileImporterResult;
var dartUrl = result.url;
var sourceMapUrl = result.sourceMapUrl;
if (dartUrl == null) {
jsThrow(JsError(
"The findFileUrl() method must return an object a url field."));
}

var resultUrl = jsToDartUrl(dartUrl);
if (resultUrl.scheme != 'file') {
jsThrow(JsError(
'The findFileUrl() must return a URL with scheme file://, was '
'"$url".'));
}

var canonical = _filesystemImporter.canonicalize(resultUrl);
if (canonical == null) return null;
if (sourceMapUrl != null) {
_sourceMapUrls[canonical] = jsToDartUrl(sourceMapUrl);
}

return canonical;
}

ImporterResult? load(Uri url) {
var path = p.fromUri(url);
return ImporterResult(io.readFile(path),
sourceMapUrl: _sourceMapUrls[url] ?? url, syntax: Syntax.forPath(path));
}

DateTime modificationTime(Uri url) =>
_filesystemImporter.modificationTime(url);

bool couldCanonicalize(Uri url, Uri canonicalUrl) =>
_filesystemImporter.couldCanonicalize(url, canonicalUrl);
}
62 changes: 62 additions & 0 deletions lib/src/importer/node_to_dart/sync.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// 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:node_interop/js.dart';

import '../../importer.dart';
import '../../node/importer.dart';
import '../../node/url.dart';
import '../../node/utils.dart';
import '../../util/nullable.dart';
import '../result.dart';

/// A wrapper for a synchronous JS API importer that exposes it as a Dart
/// [Importer].
class NodeToDartImporter extends Importer {
/// The wrapped canonicalize function.
final Object? Function(String, CanonicalizeOptions) _canonicalize;

/// The wrapped load function.
final Object? Function(JSUrl) _load;

NodeToDartImporter(this._canonicalize, this._load);

Uri? canonicalize(Uri url) {
var result = _canonicalize(
url.toString(), CanonicalizeOptions(fromImport: fromImport));
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 = _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 NodeImporterResult;
var contents = result.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));
}
}

0 comments on commit c9e2f96

Please sign in to comment.