Skip to content

Commit 329b975

Browse files
authored
[native_assets_cli] Make generated syntax files stand on their own (#2102)
Bug: #1826 `package:json_syntax_generator` is only reusable if the files are self contained. _Alternatively, we could make the generator take a config option for a JSON import. However, the downside would be that we would need copy paste the library file to multiple places._ Additionally, this PR cleans up all other uses of the `utils/json.dart` in `package:native_assets_cli`. The only remaining JSON helper is `sortOnKey()` because the asset-extension touches JSON manually and needs to sort the keys. (This could be addressed when addressing #2090.)
1 parent a3aad77 commit 329b975

File tree

12 files changed

+478
-208
lines changed

12 files changed

+478
-208
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// Helper methods for the code generator that are added to the generated file.
6+
///
7+
/// This simplifies the code generator.
8+
const helperLib = r'''
9+
extension on Map<String, Object?> {
10+
T get<T extends Object?>(String key) {
11+
final value = this[key];
12+
if (value is T) return value;
13+
if (value == null) {
14+
throw FormatException('No value was provided for required key: $key');
15+
}
16+
throw FormatException(
17+
'Unexpected value \'$value\' for key \'.$key\'. '
18+
'Expected a $T.',
19+
);
20+
}
21+
22+
List<T> list<T extends Object?>(String key) =>
23+
_castList<T>(get<List<Object?>>(key), key);
24+
25+
List<T>? optionalList<T extends Object?>(String key) =>
26+
switch (get<List<Object?>?>(key)?.cast<T>()) {
27+
null => null,
28+
final l => _castList<T>(l, key),
29+
};
30+
31+
/// [List.cast] but with [FormatException]s.
32+
static List<T> _castList<T extends Object?>(List<Object?> list, String key) {
33+
for (final value in list) {
34+
if (value is! T) {
35+
throw FormatException(
36+
'Unexpected value \'$list\' (${list.runtimeType}) for key \'.$key\'. '
37+
'Expected a ${List<T>}.',
38+
);
39+
}
40+
}
41+
return list.cast();
42+
}
43+
44+
Map<String, T> map$<T extends Object?>(String key) =>
45+
_castMap<T>(get<Map<String, Object?>>(key), key);
46+
47+
Map<String, T>? optionalMap<T extends Object?>(String key) =>
48+
switch (get<Map<String, Object?>?>(key)) {
49+
null => null,
50+
final m => _castMap<T>(m, key),
51+
};
52+
53+
/// [Map.cast] but with [FormatException]s.
54+
static Map<String, T> _castMap<T extends Object?>(
55+
Map<String, Object?> map_,
56+
String key,
57+
) {
58+
for (final value in map_.values) {
59+
if (value is! T) {
60+
throw FormatException(
61+
'Unexpected value \'$map_\' (${map_.runtimeType}) for key \'.$key\'.'
62+
'Expected a ${Map<String, T>}.',
63+
);
64+
}
65+
}
66+
return map_.cast();
67+
}
68+
69+
List<String>? optionalStringList(String key) => optionalList<String>(key);
70+
71+
List<String> stringList(String key) => list<String>(key);
72+
73+
Uri path(String key) => _fileSystemPathToUri(get<String>(key));
74+
75+
Uri? optionalPath(String key) {
76+
final value = get<String?>(key);
77+
if (value == null) return null;
78+
return _fileSystemPathToUri(value);
79+
}
80+
81+
List<Uri>? optionalPathList(String key) {
82+
final strings = optionalStringList(key);
83+
if (strings == null) {
84+
return null;
85+
}
86+
return [for (final string in strings) _fileSystemPathToUri(string)];
87+
}
88+
89+
static Uri _fileSystemPathToUri(String path) {
90+
if (path.endsWith(Platform.pathSeparator)) {
91+
return Uri.directory(path);
92+
}
93+
return Uri.file(path);
94+
}
95+
}
96+
97+
extension on List<Uri> {
98+
List<String> toJson() => [for (final uri in this) uri.toFilePath()];
99+
}
100+
101+
extension <K extends Comparable<K>, V extends Object?> on Map<K, V> {
102+
void sortOnKey() {
103+
final result = <K, V>{};
104+
final keysSorted = keys.toList()..sort();
105+
for (final key in keysSorted) {
106+
result[key] = this[key] as V;
107+
}
108+
clear();
109+
addAll(result);
110+
}
111+
}
112+
''';

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

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import '../model/class_info.dart';
66
import '../model/dart_type.dart';
77
import '../model/property_info.dart';
88
import '../model/schema_info.dart';
9+
import 'helper_library.dart';
910

1011
/// Generates Dart code from a [SchemaInfo].
1112
///
@@ -35,13 +36,17 @@ class SyntaxGenerator {
3536
3637
// This file is generated, do not edit.
3738
38-
import '../utils/json.dart';
39+
// ignore_for_file: unused_element
40+
41+
import 'dart:io';
3942
''');
4043

4144
for (final classInfo in schemaInfo.classes) {
4245
buffer.writeln(_generateClass(classInfo));
4346
}
4447

48+
buffer.writeln(helperLib);
49+
4550
return buffer.toString();
4651
}
4752

@@ -301,7 +306,7 @@ class $className {
301306
case EnumClassInfo():
302307
if (required) {
303308
buffer.writeln('''
304-
$dartType get $fieldName => $classType.fromJson( json.string('$jsonKey') );
309+
$dartType get $fieldName => $classType.fromJson( json.get<String>('$jsonKey') );
305310
''');
306311
if (!property.isOverride) {
307312
buffer.writeln('''
@@ -313,7 +318,7 @@ set $setterName($dartType value) {
313318
} else {
314319
buffer.writeln('''
315320
$dartType get $fieldName {
316-
final string = json.optionalString('$jsonKey');
321+
final string = json.get<String?>('$jsonKey');
317322
if(string == null) return null;
318323
return $classType.fromJson(string);
319324
}
@@ -384,7 +389,7 @@ set $setterName($dartType value) {
384389
case 'String':
385390
if (required) {
386391
buffer.writeln('''
387-
String get $fieldName => json.string('$jsonKey');
392+
String get $fieldName => json.get<String>('$jsonKey');
388393
389394
set $setterName(String value) {
390395
json['$jsonKey'] = value;
@@ -393,7 +398,7 @@ set $setterName(String value) {
393398
''');
394399
} else {
395400
buffer.writeln('''
396-
String? get $fieldName => json.optionalString('$jsonKey');
401+
String? get $fieldName => json.get<String?>('$jsonKey');
397402
398403
set $setterName(String? value) {
399404
if (value == null) {
@@ -415,7 +420,7 @@ set $setterName(int value) => json['$jsonKey'] = value;
415420
''');
416421
} else {
417422
buffer.writeln('''
418-
int? get $fieldName => json.getOptional<int>('$jsonKey');
423+
int? get $fieldName => json.get<int?>('$jsonKey');
419424
420425
set $setterName(int? value) {
421426
if (value == null) {
@@ -440,7 +445,7 @@ set $setterName(bool value) {
440445
''');
441446
} else {
442447
buffer.writeln('''
443-
bool? get $fieldName => json.getOptional<bool>('$jsonKey');
448+
bool? get $fieldName => json.get<bool?>('$jsonKey');
444449
445450
set $setterName(bool? value) {
446451
if (value == null) {

0 commit comments

Comments
 (0)