Skip to content

Commit 4e534d3

Browse files
authored
[native_assets_cli] Syntax validation (#2115)
1 parent 8604847 commit 4e534d3

File tree

11 files changed

+1014
-129
lines changed

11 files changed

+1014
-129
lines changed

pkgs/json_syntax_generator/lib/src/generator/helper_library.dart

Lines changed: 97 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,52 +22,98 @@ class JsonReader {
2222
T get<T extends Object?>(String key) {
2323
final value = json[key];
2424
if (value is T) return value;
25-
final pathString = _jsonPathToString([key]);
26-
if (value == null) {
27-
throw FormatException("No value was provided for '$pathString'.");
28-
}
2925
throwFormatException(value, T, [key]);
3026
}
3127
28+
List<String> validate<T extends Object?>(String key) {
29+
final value = json[key];
30+
if (value is T) return [];
31+
return [
32+
errorString(value, T, [key]),
33+
];
34+
}
35+
3236
List<T> list<T extends Object?>(String key) =>
3337
_castList<T>(get<List<Object?>>(key), key);
3438
39+
List<String> validateList<T extends Object?>(String key) {
40+
final listErrors = validate<List<Object?>>(key);
41+
if (listErrors.isNotEmpty) {
42+
return listErrors;
43+
}
44+
return _validateListElements(get<List<Object?>>(key), key);
45+
}
46+
3547
List<T>? optionalList<T extends Object?>(String key) =>
3648
switch (get<List<Object?>?>(key)?.cast<T>()) {
3749
null => null,
3850
final l => _castList<T>(l, key),
3951
};
4052
53+
List<String> validateOptionalList<T extends Object?>(String key) {
54+
final listErrors = validate<List<Object?>?>(key);
55+
if (listErrors.isNotEmpty) {
56+
return listErrors;
57+
}
58+
final list = get<List<Object?>?>(key);
59+
if (list == null) {
60+
return [];
61+
}
62+
return _validateListElements(list, key);
63+
}
64+
4165
/// [List.cast] but with [FormatException]s.
4266
List<T> _castList<T extends Object?>(List<Object?> list, String key) {
43-
var index = 0;
44-
for (final value in list) {
67+
for (final (index, value) in list.indexed) {
4568
if (value is! T) {
4669
throwFormatException(value, T, [key, index]);
4770
}
48-
index++;
4971
}
5072
return list.cast();
5173
}
5274
53-
List<T>? optionalListParsed<T extends Object?>(
75+
List<String> _validateListElements<T extends Object?>(
76+
List<Object?> list,
5477
String key,
55-
T Function(Object?) elementParser,
5678
) {
57-
final jsonValue = optionalList(key);
58-
if (jsonValue == null) return null;
59-
return [for (final element in jsonValue) elementParser(element)];
79+
final result = <String>[];
80+
for (final (index, value) in list.indexed) {
81+
if (value is! T) {
82+
result.add(errorString(value, T, [key, index]));
83+
}
84+
}
85+
return result;
6086
}
6187
6288
Map<String, T> map$<T extends Object?>(String key) =>
6389
_castMap<T>(get<Map<String, Object?>>(key), key);
6490
91+
List<String> validateMap<T extends Object?>(String key) {
92+
final mapErrors = validate<Map<String, Object?>>(key);
93+
if (mapErrors.isNotEmpty) {
94+
return mapErrors;
95+
}
96+
return _validateMapElements<T>(get<Map<String, Object?>>(key), key);
97+
}
98+
6599
Map<String, T>? optionalMap<T extends Object?>(String key) =>
66100
switch (get<Map<String, Object?>?>(key)) {
67101
null => null,
68102
final m => _castMap<T>(m, key),
69103
};
70104
105+
List<String> validateOptionalMap<T extends Object?>(String key) {
106+
final mapErrors = validate<Map<String, Object?>?>(key);
107+
if (mapErrors.isNotEmpty) {
108+
return mapErrors;
109+
}
110+
final map = get<Map<String, Object?>?>(key);
111+
if (map == null) {
112+
return [];
113+
}
114+
return _validateMapElements<T>(map, key);
115+
}
116+
71117
/// [Map.cast] but with [FormatException]s.
72118
Map<String, T> _castMap<T extends Object?>(
73119
Map<String, Object?> map_,
@@ -81,18 +127,40 @@ class JsonReader {
81127
return map_.cast();
82128
}
83129
130+
List<String> _validateMapElements<T extends Object?>(
131+
Map<String, Object?> map_,
132+
String parentKey,
133+
) {
134+
final result = <String>[];
135+
for (final MapEntry(:key, :value) in map_.entries) {
136+
if (value is! T) {
137+
result.add(errorString(value, T, [parentKey, key]));
138+
}
139+
}
140+
return result;
141+
}
142+
84143
List<String>? optionalStringList(String key) => optionalList<String>(key);
85144
145+
List<String> validateOptionalStringList(String key) =>
146+
validateOptionalList<String>(key);
147+
86148
List<String> stringList(String key) => list<String>(key);
87149
150+
List<String> validateStringList(String key) => validateList<String>(key);
151+
88152
Uri path$(String key) => _fileSystemPathToUri(get<String>(key));
89153
154+
List<String> validatePath(String key) => validate<String>(key);
155+
90156
Uri? optionalPath(String key) {
91157
final value = get<String?>(key);
92158
if (value == null) return null;
93159
return _fileSystemPathToUri(value);
94160
}
95161
162+
List<String> validateOptionalPath(String key) => validate<String?>(key);
163+
96164
List<Uri>? optionalPathList(String key) {
97165
final strings = optionalStringList(key);
98166
if (strings == null) {
@@ -101,6 +169,9 @@ class JsonReader {
101169
return [for (final string in strings) _fileSystemPathToUri(string)];
102170
}
103171
172+
List<String> validateOptionalPathList(String key) =>
173+
validateOptionalStringList(key);
174+
104175
static Uri _fileSystemPathToUri(String path) {
105176
if (path.endsWith(Platform.pathSeparator)) {
106177
return Uri.directory(path);
@@ -115,12 +186,22 @@ class JsonReader {
115186
Object? value,
116187
Type expectedType,
117188
List<Object> pathExtension,
189+
) {
190+
throw FormatException(errorString(value, expectedType, pathExtension));
191+
}
192+
193+
String errorString(
194+
Object? value,
195+
Type expectedType,
196+
List<Object> pathExtension,
118197
) {
119198
final pathString = _jsonPathToString(pathExtension);
120-
throw FormatException(
121-
"Unexpected value '$value' (${value.runtimeType}) for '$pathString'. "
122-
'Expected a $expectedType.',
123-
);
199+
if (value == null) {
200+
return "No value was provided for '$pathString'."
201+
' Expected a $expectedType.';
202+
}
203+
return "Unexpected value '$value' (${value.runtimeType}) for '$pathString'."
204+
' Expected a $expectedType.';
124205
}
125206
}
126207

pkgs/json_syntax_generator/lib/src/generator/normal_class_generator.dart

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class ClassGenerator {
2424
final constructorSetterCalls = <String>[];
2525
final accessors = <String>[];
2626
final superParams = <String>[];
27+
final validateCalls = <String>[];
2728

2829
final propertyNames =
2930
{
@@ -62,6 +63,7 @@ class ClassGenerator {
6263
}
6364
if (thisClassProperty != null) {
6465
accessors.add(PropertyGenerator(thisClassProperty).generate());
66+
validateCalls.add('...${property.validateName}()');
6567
}
6668
}
6769

@@ -95,6 +97,12 @@ class $className extends $superclassName {
9597
buffer.writeln('''
9698
${accessors.join('\n')}
9799
100+
@override
101+
List<String> validate() => [
102+
...super.validate(),
103+
${validateCalls.join(',\n')}
104+
];
105+
98106
@override
99107
String toString() => '$className(\$json)';
100108
}
@@ -121,6 +129,10 @@ class $className {
121129
122130
${accessors.join('\n')}
123131
132+
List<String> validate() => [
133+
${validateCalls.join(',\n')}
134+
];
135+
124136
@override
125137
String toString() => '$className(\$json)';
126138
}
@@ -132,7 +144,7 @@ class $className {
132144
extension ${className}Extension on $superclassName {
133145
bool get is$className => type == '$identifyingSubtype';
134146
135-
$className get as$className => $className.fromJson(json);
147+
$className get as$className => $className.fromJson(json, path: path);
136148
}
137149
''');
138150
}

0 commit comments

Comments
 (0)