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);
}
});
}