PackageConfig parsePackageConfigJson()

in lib/src/package_config_json.dart [82:222]


PackageConfig parsePackageConfigJson(
    Object? json, Uri baseLocation, void Function(Object error) onError) {
  if (!baseLocation.hasScheme || baseLocation.isScheme('package')) {
    throw PackageConfigArgumentError(baseLocation.toString(), 'baseLocation',
        'Must be an absolute non-package: URI');
  }

  if (!baseLocation.path.endsWith('/')) {
    baseLocation = baseLocation.resolveUri(Uri(path: '.'));
  }

  String typeName<T>() {
    if (0 is T) return 'int';
    if ('' is T) return 'string';
    if (const [] is T) return 'array';
    return 'object';
  }

  T? checkType<T>(Object? value, String name, [String? packageName]) {
    if (value is T) return value;
    // The only types we are called with are [int], [String], [List<Object?>]
    // and Map<String, Object?>. Recognize which to give a better error message.
    var message =
        "$name${packageName != null ? " of package $packageName" : ""}"
        ' is not a JSON ${typeName<T>()}';
    onError(PackageConfigFormatException(message, value));
    return null;
  }

  Package? parsePackage(Map<String, Object?> entry) {
    String? name;
    String? rootUri;
    String? packageUri;
    String? languageVersion;
    Map<String, Object?>? extraData;
    var hasName = false;
    var hasRoot = false;
    var hasVersion = false;
    entry.forEach((key, value) {
      switch (key) {
        case _nameKey:
          hasName = true;
          name = checkType<String>(value, _nameKey);
          break;
        case _rootUriKey:
          hasRoot = true;
          rootUri = checkType<String>(value, _rootUriKey, name);
          break;
        case _packageUriKey:
          packageUri = checkType<String>(value, _packageUriKey, name);
          break;
        case _languageVersionKey:
          hasVersion = true;
          languageVersion = checkType<String>(value, _languageVersionKey, name);
          break;
        default:
          (extraData ??= {})[key] = value;
          break;
      }
    });
    if (!hasName) {
      onError(PackageConfigFormatException('Missing name entry', entry));
    }
    if (!hasRoot) {
      onError(PackageConfigFormatException('Missing rootUri entry', entry));
    }
    if (name == null || rootUri == null) return null;
    var parsedRootUri = Uri.parse(rootUri!);
    var relativeRoot = !hasAbsolutePath(parsedRootUri);
    var root = baseLocation.resolveUri(parsedRootUri);
    if (!root.path.endsWith('/')) root = root.replace(path: root.path + '/');
    var packageRoot = root;
    if (packageUri != null) packageRoot = root.resolve(packageUri!);
    if (!packageRoot.path.endsWith('/')) {
      packageRoot = packageRoot.replace(path: packageRoot.path + '/');
    }

    LanguageVersion? version;
    if (languageVersion != null) {
      version = parseLanguageVersion(languageVersion, onError);
    } else if (hasVersion) {
      version = SimpleInvalidLanguageVersion('invalid');
    }

    return SimplePackage.validate(
        name!, root, packageRoot, version, extraData, relativeRoot, (error) {
      if (error is ArgumentError) {
        onError(
            PackageConfigFormatException(error.message, error.invalidValue));
      } else {
        onError(error);
      }
    });
  }

  var map = checkType<Map<String, Object?>>(json, 'value');
  if (map == null) return const SimplePackageConfig.empty();
  Map<String, Object?>? extraData;
  List<Package>? packageList;
  int? configVersion;
  map.forEach((key, value) {
    switch (key) {
      case _configVersionKey:
        configVersion = checkType<int>(value, _configVersionKey) ?? 2;
        break;
      case _packagesKey:
        var packageArray = checkType<List<Object?>>(value, _packagesKey) ?? [];
        var packages = <Package>[];
        for (var package in packageArray) {
          var packageMap =
              checkType<Map<String, Object?>>(package, 'package entry');
          if (packageMap != null) {
            var entry = parsePackage(packageMap);
            if (entry != null) {
              packages.add(entry);
            }
          }
        }
        packageList = packages;
        break;
      default:
        (extraData ??= {})[key] = value;
        break;
    }
  });
  if (configVersion == null) {
    onError(PackageConfigFormatException('Missing configVersion entry', json));
    configVersion = 2;
  }
  if (packageList == null) {
    onError(PackageConfigFormatException('Missing packages list', json));
    packageList = [];
  }
  return SimplePackageConfig(configVersion!, packageList!, extraData, (error) {
    if (error is ArgumentError) {
      onError(PackageConfigFormatException(error.message, error.invalidValue));
    } else {
      onError(error);
    }
  });
}