Skip to content

Commit 10a25e3

Browse files
authored
[native_assets_cli] Split up syntax generator (#2106)
1 parent e72e187 commit 10a25e3

File tree

11 files changed

+754
-877
lines changed

11 files changed

+754
-877
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
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+
/// Wraps the [input] in curly braces if it's not empty.
6+
String wrapBracesIfNotEmpty(String input) => input.isEmpty ? input : '{$input}';
7+
8+
/// Wraps the [input] in curly braces or adds a semicolon if it's empty.
9+
String wrapInBracesOrSemicolon(String input) =>
10+
input.isEmpty ? ';' : '{ $input }';
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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+
import '../model/class_info.dart';
6+
7+
class EnumGenerator {
8+
final EnumClassInfo classInfo;
9+
10+
EnumGenerator(this.classInfo);
11+
12+
String generate() {
13+
final buffer = StringBuffer();
14+
final className = classInfo.name;
15+
final enumValues = classInfo.enumValues;
16+
17+
final staticFinals = <String>[];
18+
for (final value in enumValues) {
19+
final valueName = value.name;
20+
final jsonValue = value.jsonValue;
21+
staticFinals.add(
22+
'static const $valueName = $className._(\'$jsonValue\');',
23+
);
24+
}
25+
26+
buffer.writeln('''
27+
class $className {
28+
final String name;
29+
30+
const $className._(this.name);
31+
32+
${staticFinals.join('\n\n')}
33+
34+
static const List<$className> values = [
35+
${enumValues.map((e) => e.name).join(',')}
36+
];
37+
38+
static final Map<String, $className> _byName = {
39+
for (final value in values) value.name: value,
40+
};
41+
42+
$className.unknown(this.name) : assert(!_byName.keys.contains(name));
43+
44+
factory $className.fromJson(String name) {
45+
final knownValue = _byName[name];
46+
if(knownValue != null) {
47+
return knownValue;
48+
}
49+
return $className.unknown(name);
50+
}
51+
52+
bool get isKnown => _byName[name] != null;
53+
54+
@override
55+
String toString() => name;
56+
}
57+
''');
58+
return buffer.toString();
59+
}
60+
}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ extension on Map<String, Object?> {
4141
return list.cast();
4242
}
4343
44+
List<T>? optionalListParsed<T extends Object?>(
45+
String key,
46+
T Function(Object?) elementParser,
47+
) {
48+
final jsonValue = optionalList(key);
49+
if (jsonValue == null) return null;
50+
return [for (final element in jsonValue) elementParser(element)];
51+
}
52+
4453
Map<String, T> map$<T extends Object?>(String key) =>
4554
_castMap<T>(get<Map<String, Object?>>(key), key);
4655
@@ -92,6 +101,14 @@ extension on Map<String, Object?> {
92101
}
93102
return Uri.file(path);
94103
}
104+
105+
void setOrRemove(String key, Object? value) {
106+
if (value == null) {
107+
remove(key);
108+
} else {
109+
this[key] = value;
110+
}
111+
}
95112
}
96113
97114
extension on List<Uri> {
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
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+
import '../model/class_info.dart';
6+
import 'code_generation_helpers.dart';
7+
import 'property_generator.dart';
8+
9+
class ClassGenerator {
10+
final NormalClassInfo classInfo;
11+
12+
ClassGenerator(this.classInfo);
13+
14+
String generate() {
15+
final buffer = StringBuffer();
16+
final className = classInfo.name;
17+
final superclass = classInfo.superclass;
18+
final superclassName = superclass?.name;
19+
final properties = classInfo.properties;
20+
final identifyingSubtype = classInfo.taggedUnionKey;
21+
22+
final constructorParams = <String>[];
23+
final setupParams = <String>[];
24+
final constructorSetterCalls = <String>[];
25+
final accessors = <String>[];
26+
final superParams = <String>[];
27+
28+
final propertyNames =
29+
{
30+
for (final property in properties) property.name,
31+
if (superclass != null)
32+
for (final property in superclass.properties) property.name,
33+
}.toList()
34+
..sort();
35+
for (final propertyName in propertyNames) {
36+
final superClassProperty = superclass?.getProperty(propertyName);
37+
final thisClassProperty = classInfo.getProperty(propertyName);
38+
final property = superClassProperty ?? thisClassProperty!;
39+
if (superClassProperty != null) {
40+
if (identifyingSubtype == null) {
41+
constructorParams.add(
42+
'${property.isRequired ? 'required ' : ''}super.${property.name}',
43+
);
44+
} else {
45+
superParams.add("type: '$identifyingSubtype'");
46+
}
47+
} else {
48+
final dartType = property.type;
49+
constructorParams.add(
50+
'${property.isRequired ? 'required ' : ''}$dartType ${property.name}',
51+
);
52+
setupParams.add(
53+
'${property.isRequired ? 'required' : ''} $dartType ${property.name}',
54+
);
55+
if (property.setterPrivate) {
56+
constructorSetterCalls.add('_${property.name} = ${property.name};');
57+
} else {
58+
constructorSetterCalls.add(
59+
'this.${property.name} = ${property.name};',
60+
);
61+
}
62+
}
63+
if (thisClassProperty != null) {
64+
accessors.add(PropertyGenerator(thisClassProperty).generate());
65+
}
66+
}
67+
68+
if (constructorSetterCalls.isNotEmpty) {
69+
constructorSetterCalls.add('json.sortOnKey();');
70+
}
71+
72+
if (superclass != null) {
73+
buffer.writeln('''
74+
class $className extends $superclassName {
75+
$className.fromJson(super.json) : super.fromJson();
76+
77+
$className(${wrapBracesIfNotEmpty(constructorParams.join(', '))})
78+
: super(${superParams.join(',')})
79+
${wrapInBracesOrSemicolon(constructorSetterCalls.join('\n '))}
80+
''');
81+
if (setupParams.isNotEmpty) {
82+
buffer.writeln('''
83+
/// Setup all fields for [$className] that are not in
84+
/// [$superclassName].
85+
void setup (
86+
${wrapBracesIfNotEmpty(setupParams.join(','))}
87+
) {
88+
${constructorSetterCalls.join('\n')}
89+
}
90+
''');
91+
}
92+
93+
buffer.writeln('''
94+
${accessors.join('\n')}
95+
96+
@override
97+
String toString() => '$className(\$json)';
98+
}
99+
''');
100+
} else {
101+
buffer.writeln('''
102+
class $className {
103+
final Map<String, Object?> json;
104+
105+
$className.fromJson(this.json);
106+
107+
$className(${wrapBracesIfNotEmpty(constructorParams.join(', '))}) : json = {} {
108+
${constructorSetterCalls.join('\n ')}
109+
}
110+
111+
${accessors.join('\n')}
112+
113+
@override
114+
String toString() => '$className(\$json)';
115+
}
116+
''');
117+
}
118+
119+
if (identifyingSubtype != null) {
120+
buffer.writeln('''
121+
extension ${className}Extension on $superclassName {
122+
bool get is$className => type == '$identifyingSubtype';
123+
124+
$className get as$className => $className.fromJson(json);
125+
}
126+
''');
127+
}
128+
129+
return buffer.toString();
130+
}
131+
}

0 commit comments

Comments
 (0)