228 lines
5.4 KiB
Dart
228 lines
5.4 KiB
Dart
import "dart:io";
|
|
|
|
import "package:build/build.dart";
|
|
import "package:yaml/yaml.dart";
|
|
|
|
String joinString(List<String> strings, String sep) {
|
|
String joined = "";
|
|
|
|
for (final str in strings) {
|
|
joined += "$str$sep";
|
|
}
|
|
|
|
return joined;
|
|
}
|
|
|
|
String _getAttributeType(dynamic data) {
|
|
if (data is String) {
|
|
return data;
|
|
}
|
|
|
|
return (data as YamlMap)["type"]!;
|
|
}
|
|
|
|
bool _getAttributeDeserialise(dynamic data) {
|
|
if (data is YamlMap) {
|
|
return data["deserialise"] ?? false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
String _generateAttributes(YamlMap data) {
|
|
if (data["attributes"] == null) {
|
|
return "";
|
|
}
|
|
|
|
List<String> attrs = [];
|
|
data["attributes"].forEach((key, value) {
|
|
final type_ = _getAttributeType(value);
|
|
assert(!type_.endsWith(" "));
|
|
attrs.add("\tfinal $type_ $key;");
|
|
});
|
|
|
|
final joined = joinString(attrs, "\n");
|
|
return joined.substring(0, joined.length - 1);
|
|
}
|
|
|
|
String _generateInitializers(YamlMap data) {
|
|
if (data["attributes"] == null) {
|
|
return "";
|
|
}
|
|
|
|
List<String> attrs = [];
|
|
data["attributes"].forEach((key, value) {
|
|
final type_ = _getAttributeType(value);
|
|
final defaultValue = value is YamlMap
|
|
? value["default"]
|
|
: null;
|
|
final defaultString = defaultValue != null
|
|
? " = const $defaultValue"
|
|
: "";
|
|
final isRequired = !type_.endsWith("?") && defaultValue == null;
|
|
final requiredString = isRequired ? "required " : "";
|
|
|
|
attrs.add("\t\t${requiredString}this.$key$defaultString,");
|
|
});
|
|
|
|
final joined = joinString(attrs, "\n");
|
|
return joined.substring(0, joined.length - 1);
|
|
}
|
|
|
|
String _generateToJson(YamlMap data) {
|
|
String json = '''
|
|
\t@override
|
|
\tMap<String, dynamic> toJson() => {\n
|
|
''';
|
|
|
|
if (data["attributes"] != null) {
|
|
data["attributes"].forEach((key, _) {
|
|
json += "\t\t\"$key\": $key,\n";
|
|
});
|
|
}
|
|
|
|
json += '''
|
|
\t\t"type": "${data["name"]!}"
|
|
\t};\n
|
|
''';
|
|
return json;
|
|
}
|
|
|
|
String _generateFromJson(YamlMap data) {
|
|
final name = data["name"]!;
|
|
String json = "\tstatic $name fromJson(Map<String, dynamic> json) => $name(";
|
|
|
|
if (data["attributes"] != null) {
|
|
json += "\n";
|
|
data["attributes"].forEach((key, value) {
|
|
final type_ = _getAttributeType(value);
|
|
if (type_.startsWith("List<")) {
|
|
final exp = RegExp(r"List\<(.*?)\>");
|
|
final listType = exp.firstMatch(type_)!.group(1)!;
|
|
|
|
final suffix = type_.endsWith("?") ? " ?? []" : "!";
|
|
String attr = '(json["$key"]$suffix)';
|
|
if (_getAttributeDeserialise(value)) {
|
|
attr += ".map((item) => $listType.fromJson(item))";
|
|
}
|
|
|
|
json += "\t\t$key: List<$listType>.from($attr),\n";
|
|
} else {
|
|
if (_getAttributeDeserialise(value)) {
|
|
if (type_.endsWith("?")) {
|
|
final attrTypeNoNull = type_.substring(0, type_.length - 1);
|
|
json += '\t\t$key: json["$key"] != null ? $attrTypeNoNull.fromJson(json["$key"]) : null,\n';
|
|
} else {
|
|
json += '\t\t$key: $type_.fromJson(json["$key"]!),\n';
|
|
}
|
|
} else {
|
|
final nullString = type_.endsWith("?")
|
|
? "" : "!";
|
|
json += '\t\t$key: json["$key"]$nullString,\n';
|
|
}
|
|
}
|
|
});
|
|
json += "\t);";
|
|
} else {
|
|
json += ");";
|
|
}
|
|
|
|
return json;
|
|
}
|
|
|
|
String generateClassFromData(YamlMap data) {
|
|
String impls = "";
|
|
for (final impl in data["implements"]) {
|
|
impls += "$impl, ";
|
|
}
|
|
final constructor = data["attributes"] != null
|
|
? '''
|
|
\t${data["name"]!}({
|
|
${_generateInitializers(data)}
|
|
\t});
|
|
'''
|
|
: '\t${data["name"]!}();';
|
|
return '''
|
|
class ${data["name"]!} extends ${data["extends"]} implements ${impls.substring(0, impls.length - 2)} {
|
|
${_generateAttributes(data)}
|
|
$constructor
|
|
|
|
\t// JSON Stuff
|
|
${_generateToJson(data)}
|
|
${_generateFromJson(data)}
|
|
}
|
|
|
|
''';
|
|
}
|
|
|
|
String _generateBuilder(String name, String baseClass, YamlList classes) {
|
|
String func = '''
|
|
$baseClass? get${name}FromJson(Map<String, dynamic> json) {
|
|
\tswitch(json["type"]!) {
|
|
''';
|
|
|
|
for (final class_ in classes) {
|
|
final name = class_["name"]!;
|
|
func += '\t\tcase "$name": return $name.fromJson(json);\n';
|
|
}
|
|
|
|
func += "\t\tdefault: return null;\n";
|
|
func += "\t}\n}";
|
|
return func;
|
|
}
|
|
|
|
String generateFileFromData(YamlMap data) {
|
|
String file = '''
|
|
//// AUTO-GENERATED by build_runner ////
|
|
/// DO NOT EDIT BY HAND
|
|
part of "${data["partof"]!}";
|
|
|
|
''';
|
|
|
|
data["classes"].forEach((attributes) {
|
|
file += generateClassFromData(attributes);
|
|
});
|
|
if (data["generate_builder"]) {
|
|
file += "\n\n";
|
|
file += _generateBuilder(
|
|
data["builder_name"],
|
|
data["builder_baseclass"],
|
|
data["classes"]
|
|
);
|
|
}
|
|
|
|
return file;
|
|
}
|
|
|
|
class DataClassBuilder implements Builder {
|
|
@override
|
|
Future build(BuildStep step) async {
|
|
final file = File(step.inputId.path);
|
|
final data = loadYaml(await file.readAsString());
|
|
|
|
for (final asset in step.allowedOutputs) {
|
|
if (asset.path.endsWith("commands.moxxy.dart")) {
|
|
await step.writeAsString(
|
|
asset,
|
|
generateFileFromData(data["files"]["commands"]!)
|
|
);
|
|
} else if (asset.path.endsWith("events.moxxy.dart")) {
|
|
await step.writeAsString(
|
|
asset,
|
|
generateFileFromData(data["files"]["events"]!)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
@override
|
|
final buildExtensions = const {
|
|
"data_classes.yaml": [
|
|
"shared/commands.moxxy.dart",
|
|
"shared/events.moxxy.dart"
|
|
]
|
|
};
|
|
}
|
|
|
|
Builder dataClassBuilder(BuilderOptions options) => DataClassBuilder();
|