fromNpm static method

Future<InteropProject> fromNpm({
  1. required String package,
  2. required String version,
  3. required String targetPath,
  4. required String dirName,
  5. Iterable<String> files = const [],
  6. ({bool import, bool typings}) packageJson = (typings: true, import: true),
  7. String? contextCheck,
  8. Iterable<String> distFiles = const [],
  9. Iterable<String> uses = const {},
  10. String? targetMainFile,
  11. bool force = false,
  12. bool fetchExternals = true,
})

Implementation

static Future<InteropProject> fromNpm(
    {required String package,
    required String version,
    required String targetPath,
    required String dirName,
    Iterable<String> files = const [],
    ({bool typings, bool import}) packageJson = (typings: true, import: true),
    String? contextCheck,
    Iterable<String> distFiles = const [],
    Iterable<String> uses = const {},
    String? targetMainFile,
    bool force = false,
    bool fetchExternals = true}) async {
  final mainFiles = files.toList();
  final transpiller = Transpiler(
      package: package,
      targetPath: targetPath,
      dirName: dirName,
      contextCheck: contextCheck,
      uses: uses,
      targetMainFile: targetMainFile,
      distFiles: distFiles.toList());
  final outDir = Directory(transpiller.dir('out/package'));
  final dir = transpiller.dir;
  var crawlTsFiles = false;

  assert(!packageJson.typings || mainFiles.isEmpty,
      'Either use packageJson.typings=true or files($mainFiles)');

  assert(!packageJson.import || distFiles.isEmpty,
      'Either use packageJson.typings=true or distFiles($distFiles)');

  if (!outDir.existsSync() || force) {
    await Directory(dir()).create(recursive: true);

    // http://registry.npmjs.org/typescript/latest
    final buf = await http.read(Uri(
        scheme: 'http',
        host: 'registry.npmjs.org',
        path: '$package/$version'));
    final map = (conv.json.decode(buf) as Map).cast<String, dynamic>();
    final {'tarball': String tarballUrl} = map.prop<Map>('dist');
    final tarballUri = Uri.parse(tarballUrl);
    final tarballName = basename(tarballUri.path);
    final tarballPath = dir(tarballName);

    final request = await HttpClient().getUrl(tarballUri);
    final response = await request.close();

    await response.pipe(File(tarballPath).openWrite());

    await extractFileToDisk(tarballPath, dir('out'));

    assert(outDir.existsSync());
  }

  if (packageJson.import || packageJson.typings) {
    final pkg = conv.json
            .decode(File(dir('out/package/package.json')).readAsStringSync())
        as Map<String, dynamic>;

    if (packageJson.typings) {
      final typings = pkg.prop<String?>('typings');
      final types = pkg.prop<String?>('types');

      if (typings != null) {
        mainFiles.add(typings);
      } else if (types != null) {
        crawlTsFiles = true;
        mainFiles.add(types);
      } else {
        final useTypesVersions = 1 > 0;

        if (useTypesVersions) {
          final tv = pkg['typesVersions'];

          if (tv case Map rawMap) {
            Iterable<String> digFiles(Map rawMap) sync* {
              final map = rawMap.cast<String, dynamic>();

              for (final value in map.values) {
                if (value is Map) {
                  yield* digFiles(value);
                } else if (value is Iterable) {
                  for (final item in value) {
                    if (item is String) {
                      final paths = {
                        '$item.d.ts',
                        '$item/index.d.ts',
                        '$item/types.d.ts'
                      };

                      for (final path in paths) {
                        if (File(dir('out/package/$path')).existsSync()) {
                          yield path;
                        }
                      }
                    }
                  }
                }
              }
            }

            mainFiles.addAll(digFiles(rawMap).toSet());
          }
        } else {
          final tsFiles = Glob(dir('out/package/**.d.ts'));

          for (final entity in tsFiles.listSync()) {
            mainFiles.add(entity.path.substring(
                entity.path.indexOf('out/package/') + 'out/package/'.length));
          }
        }
      }
    }

    if (packageJson.import) {
      transpiller.distFiles.add(pkg.prop('main'));
    }
  }

  final fileArgs = <String>[];

  for (final path in mainFiles) {
    if (path.startsWith('https://')) {
      final segs = File(path).uri.normalizePath().pathSegments.toList();
      final fileName = segs.removeLast();
      final dirPath = dir('out/temp/${segs.join('/')}');
      final handle = Directory(dirPath);

      if (!handle.existsSync()) {
        handle.createSync(recursive: true);
      }

      final filePath = '$dirPath/$fileName';
      final fileHandle = File(filePath);

      if (!fileHandle.existsSync()) {
        final request = await HttpClient().getUrl(Uri.parse(path));
        final response = await request.close();

        await response.pipe(fileHandle.openWrite());
      }

      fileArgs.add(filePath);
    } else {
      fileArgs.add('out/package/$path');
    }
  }

  return transpiller._createProject(
      fileArgs: fileArgs,
      crawlTsFiles: crawlTsFiles,
      fetchExternals: fetchExternals);
}