fromJson static method

PackageGraph fromJson(
  1. Object? json
)

Parses a decoded package_graph.json value.

Throws FormatException if the file is not a valid package graph file.

Implementation

static PackageGraph fromJson(final Object? json) {
  if (json is! Map) {
    throw const FormatException(
      'Expected package_graph.json top level to be a map',
    );
  }
  final map = Map<String, dynamic>.from(json);

  if (map['configVersion'] != _supportedConfigVersion) {
    throw FormatException(
      'Unsupported package_graph.json configVersion: '
      '${map['configVersion']}',
    );
  }

  final rootNames = _parseStringList(map, 'roots');
  final packagesJson = map['packages'];
  if (packagesJson is! List) {
    throw const FormatException('Expected `packages` to be a list');
  }

  final packagesByName = <String, PgPackage>{};
  final dependencyNamesByPackage = <String, List<String>>{};
  final devDependencyNamesByPackage = <String, List<String>>{};

  for (final entry in packagesJson) {
    if (entry is! Map) {
      throw const FormatException('Expected each package to be a map');
    }
    final packageMap = Map<String, dynamic>.from(entry);
    final name = packageMap['name'];
    if (name is! String) {
      throw const FormatException('Expected package `name` to be a string');
    }
    final version = packageMap['version'];
    if (version is! String) {
      throw const FormatException(
        'Expected package `version` to be a string',
      );
    }

    packagesByName[name] = PgPackage(
      name: name,
      version: version,
      dependencies: [],
      devDependencies: [],
      references: [],
      devReferences: [],
    );
    dependencyNamesByPackage[name] = _parseStringList(
      packageMap,
      'dependencies',
    );
    devDependencyNamesByPackage[name] = _parseStringList(
      packageMap,
      'devDependencies',
    );
  }

  for (final MapEntry(key: name, value: package) in packagesByName.entries) {
    final dependencyNames = dependencyNamesByPackage[name];
    if (dependencyNames == null) {
      throw FormatException('Missing dependency list for package "$name"');
    }
    for (final depName in dependencyNames) {
      final dependency = packagesByName[depName];
      if (dependency == null) {
        throw FormatException(
          'Package "$name" depends on unknown package "$depName"',
        );
      }
      package.dependencies.add(dependency);
      dependency.references.add(package);
    }

    final devDependencyNames = devDependencyNamesByPackage[name];
    if (devDependencyNames == null) {
      throw FormatException('Missing devDependency list for package "$name"');
    }
    for (final depName in devDependencyNames) {
      final dependency = packagesByName[depName];
      if (dependency == null) {
        throw FormatException(
          'Package "$name" has unknown dev dependency "$depName"',
        );
      }
      package.devDependencies.add(dependency);
      dependency.devReferences.add(package);
    }
  }

  final roots = <PgPackage>[];
  for (final rootName in rootNames) {
    final root = packagesByName[rootName];
    if (root == null) {
      throw FormatException('Unknown root package "$rootName"');
    }
    roots.add(root);
  }

  return PackageGraph(roots: roots);
}