DevToolsExtensionConfig.parse constructor
Implementation
factory DevToolsExtensionConfig.parse(Map<String, Object?> json) {
// Default to true if this value is not specified in the JSON.
final requiresConnectionValue = json[requiresConnectionKey];
final requiresConnection =
requiresConnectionValue != false && requiresConnectionValue != 'false';
if (json
case {
// The exptected keys below are required fields in the extension's
// config.yaml file.
nameKey: final String name,
issueTrackerKey: final String issueTracker,
versionKey: final String version,
// ignore: avoid-unnecessary-type-assertions, this can be a String or an int
materialIconCodePointKey: final Object codePointFromJson,
// The expected keys below are not from the extension's config.yaml
// file; they are generated during the extension detection mechanism
// in the DevTools server.
extensionAssetsPathKey: final String extensionAssetsPath,
devtoolsOptionsUriKey: final String devtoolsOptionsUri,
isPubliclyHostedKey: final String isPubliclyHosted,
detectedFromStaticContextKey: final String detectedFromStaticContext,
// Note that the field [requiresConnectionKey] is not required for
// this check because it is optional.
}) {
final underscoresAndLetters = RegExp(r'^[a-z0-9_]*$');
if (!underscoresAndLetters.hasMatch(name)) {
throw StateError(
'The "name" field in the extension config.yaml should only contain '
'lowercase letters, numbers, and underscores but instead was '
'"$name". This should be a valid Dart package name that matches the '
'package name this extension belongs to.',
);
}
// Defaults to the code point for [Icons.extensions_outlined] if parsing
// fails.
final int codePoint;
const defaultCodePoint = 0xf03f;
if (codePointFromJson is String) {
codePoint = int.tryParse(codePointFromJson) ?? defaultCodePoint;
} else {
codePoint = codePointFromJson as int;
}
return DevToolsExtensionConfig._(
// These values are required fields in the extension's config.yaml file.
name: name,
issueTrackerLink: issueTracker,
version: version,
materialIconCodePoint: codePoint,
// These values are optional fields in the extension's config.yaml file
// and will use default values if not specified.
requiresConnection: requiresConnection,
// These values are generated by the DevTools server.
extensionAssetsPath: extensionAssetsPath,
devtoolsOptionsUri: devtoolsOptionsUri,
isPubliclyHosted: bool.parse(isPubliclyHosted),
detectedFromStaticContext: bool.parse(detectedFromStaticContext),
);
} else {
_assertGeneratedKeysPresent(json);
final jsonKeysFromConfigFile = Set.of(json.keys.toSet())
..removeAll([
..._serverGeneratedKeys,
..._optionalKeys,
]);
final diff = _requiredKeys.toSet().difference(
jsonKeysFromConfigFile,
);
if (diff.isNotEmpty) {
throw StateError(
'Missing required fields ${diff.toString()} in the extension '
'config.yaml.',
);
} else {
// All the required keys are present, but the value types did not match.
final sb = StringBuffer();
for (final entry in json.entries) {
sb.writeln(
' ${entry.key}: ${entry.value} (${entry.value.runtimeType})',
);
}
throw StateError(
'Unexpected value types in the extension config.yaml. Expected all '
'values to be of type String, but one or more had a different type:\n'
'${sb.toString()}',
);
}
}
}