decodeData static method
Retains explicit types on JavaScript, where 1 and 1.0 share a number type.
Implementation
static DecodedPreferences decodeData(String contents) {
final decoded = jsonDecode(contents);
if (decoded is! Map<String, dynamic>) {
throw const FormatException('Preferences must contain a JSON object.');
}
if (decoded['format'] is! String || decoded['values'] is! Map) {
final values = copyPreferences(decoded);
return DecodedPreferences(
values,
values.map(
(key, value) => MapEntry(key, switch (value) {
String() => 'string',
bool() => 'bool',
int() => 'int',
double() => 'double',
List<String>() => 'list',
_ => throw const FormatException('Unsupported preference type.'),
}),
),
);
}
if (decoded['format'] != _format) {
throw const FormatException('Unsupported preferences format version.');
}
final result = <String, Object?>{};
final types = <String, String>{};
for (final entry in (decoded['values'] as Map<String, dynamic>).entries) {
final item = entry.value;
if (item is! List || item.length != 2) {
throw const FormatException('Malformed preference value.');
}
final Object? value = item[1];
if (item[0] is! String) {
throw const FormatException('Malformed preference type.');
}
types[entry.key] = item[0] as String;
result[entry.key] = switch (item[0]) {
'string' when value is String => value,
'bool' when value is bool => value,
'int' when value is String => int.parse(value),
'double' when value is String => double.parse(value),
'list'
when value is List &&
value.every((Object? item) => item is String) =>
List<String>.from(value),
_ => throw const FormatException('Malformed preference type.'),
};
}
return DecodedPreferences(copyPreferences(result), types);
}