build method
Generates the outputs for a given BuildStep.
Implementation
@override
Future<void> build(BuildStep step) async {
try {
Map<String, dynamic> pubspec = Map<String, dynamic>.from(
loadYaml(File("pubspec.yaml").readAsStringSync()),
);
artifactConfig =
Map<String, dynamic>.from(pubspec["artifact"] ?? {}) ?? {};
artifactConfig["name"] = pubspec["name"] ?? "unknown_package";
verbose("Loaded Config ${artifactConfig}");
} catch (e) {
error(e);
warn(
"Couldn't read ${File("pubspec.yaml").absolute.path} for configuration defaults! Using built-in defaults. Override with @Artifact(...) annotations only.",
);
artifactConfig = {"name": "couldnt_find_pubspec"};
}
assert(step.inputId.path == r'$lib$');
registerDef("ArtifactCodecUtil");
registerDef("ArtifactDataUtil");
registerDef("ArtifactSecurityUtil");
registerDef("ArtifactReflection");
registerDef("ArtifactMirror");
registerDef("Map<String,dynamic>");
registerDef("List<String>");
registerDef("String");
registerDef("dynamic");
registerDef("int");
registerDef("ArtifactModelExporter");
registerDef("ArgumentError");
registerDef("Exception");
List<ClassElement> artifacts = <ClassElement>[];
await for (AssetId asset in step.findAssets($dartFilesInLib)) {
if (!await step.resolver.isLibrary(asset)) continue;
LibraryElement lib = await step.resolver.libraryFor(asset);
for (Element e in lib.classes) {
if (e is! ClassElement) continue;
$iClassMap[e.name ?? ""] = e;
if (!$artifactChecker.hasAnnotationOf(e, throwOnUnresolved: false)) {
continue;
}
registerDef(e.name ?? "");
artifacts.add(e);
InterfaceType? supType = e.supertype;
while (supType != null) {
ClassElement sup = supType.element as ClassElement;
if ($artifactChecker.hasAnnotationOf(sup, throwOnUnresolved: false)) {
$linkSubclass(e, sup);
}
supType = supType.element.supertype;
}
}
}
Set<Uri> imports = <Uri>{};
List<StringBuffer> classBuffers = <StringBuffer>[];
List<Future<void>> work = <Future<void>>[];
List<String> codecs = [];
for (ClassElement art in artifacts) {
imports.add(art.library.uri);
work.add(
generate(art, step).then((v) {
imports.addAll(v.$1);
classBuffers.add(v.$2);
}),
);
codecs.addAll(
$codecChecker
.annotationsOf(art, throwOnUnresolved: false)
.followedBy(
art.fields.expand(
(j) => $codecChecker.annotationsOf(j, throwOnUnresolved: false),
),
)
.followedBy(
art.methods.expand(
(j) => $codecChecker.annotationsOf(j, throwOnUnresolved: false),
),
)
.followedBy(
art.constructors.expand(
(j) => $codecChecker.annotationsOf(j, throwOnUnresolved: false),
),
)
.map((i) => i.getField("c"))
.whereType<DartObject>()
.map((i) {
imports.add($getImport(i.type as InterfaceType, art.library));
return i.type?.getDisplayString(withNullability: false);
})
.whereType<String>()
.unique
.map((i) {
registerDef(i);
return "${applyDefsF(i)}()";
}),
);
}
String codecRegistry = "const ${applyDefsF("int")} _=0;";
registerDef("ArtifactAccessor");
StringBuffer sb = StringBuffer();
sb.write("${applyDefsF("int")} _ = ((){");
if (codecs.isNotEmpty) {
sb.write(
"${applyDefsF("ArtifactCodecUtil")}.r(const [${codecs.join(",")}]);",
);
}
sb.write(
"if(!${applyDefsF("ArtifactAccessor")}.\$i(${stringD(step.inputId.package)})){${applyDefsF("ArtifactAccessor")}.\$r(${stringD(step.inputId.package)},${applyDefsF("ArtifactAccessor")}(isArtifact: \$isArtifact,artifactMirror:${artifacts.any((c) => $artifactChecker.firstAnnotationOf(c, throwOnUnresolved: false)?.getField("reflection")?.toBoolValue() ?? false) ? "\$artifactMirror" : "{}"},constructArtifact:\$constructArtifact,artifactToMap:\$artifactToMap,artifactFromMap:\$artifactFromMap));}",
);
sb.write("return 0;");
sb.writeln("})();");
codecRegistry = sb.toString();
StringBuffer rbuf = StringBuffer();
if (artifacts.any(
(c) =>
$artifactChecker
.firstAnnotationOf(c, throwOnUnresolved: false)
?.getField("reflection")
?.toBoolValue() ??
false,
)) {
registerDef("\$AClass");
rbuf.write(
"Map<Type,${applyDefsF("\$AClass")}> get \$artifactMirror => {",
);
for (ClassElement i in artifacts) {
if ($artifactChecker
.firstAnnotationOf(i, throwOnUnresolved: false)
?.getField("reflection")
?.toBoolValue() ??
false) {
registerDef(applyDefsF(i.supertype!.element.name ?? ""));
for (String i in i.interfaces.map((i) => i.element.name ?? "")) {
registerDef(i);
}
for (String i in i.mixins.map((i) => i.element.name ?? "")) {
registerDef(i);
}
for (InterfaceType i in i.allSupertypes) {
imports.add(i.element.library.uri);
}
registerDef("\$AClass<${i.name ?? ""}>");
rbuf.write(applyDefsF(i.name ?? ""));
rbuf.write(":");
rbuf.write(applyDefsF("\$AClass<${i.name ?? ""}>("));
rbuf.write("\$${i.name}.\$annotations,");
rbuf.write("\$${i.name}.\$fields,");
rbuf.write("\$${i.name}.\$methods,");
rbuf.write("()=>\$${i.name}.newInstance,");
rbuf.write("${applyDefsF(i.supertype!.element.name ?? "")},");
rbuf.write(
"[${i.interfaces.map((i) => applyDefsF(i.element.name ?? "")).join(",")}],",
);
rbuf.write(
"[${i.mixins.map((i) => applyDefsF(i.element.name ?? "")).join(",")}],",
);
rbuf.write("${typeDescriptorCode(i.thisType, this)},");
rbuf.write("),");
}
}
rbuf.writeln("};");
}
/// int _v = _register();
//
// int _register() {
// ArtifactAccessor.register(
// "something",
// ArtifactAccessor(
// isArtifact: $isArtifact,
// artifactMirror: $artifactMirror,
// constructArtifact: $constructArtifact,
// artifactToMap: $artifactToMap,
// artifactFromMap: $artifactFromMap,
// ),
// );
// return 0;
// }
await Future.wait(work);
registerDef("List<dynamic>");
imports.add(Uri.parse("package:artifact/artifact.dart"));
StringBuffer outBuf =
StringBuffer()
..writeln('// GENERATED – do not modify by hand\n')
..writeln(
[
"camel_case_types",
"non_constant_identifier_names",
"constant_identifier_names",
"library_private_types_in_public_api",
"unused_element",
].map((i) => "// ignore_for_file: $i").join("\n"),
)
..writeln(
imports
.where((i) => i.toString().trim().isNotEmpty)
.map((i) => 'import "$i";')
.toSet()
.toList()
.join(),
)
..writeln(
compression
? defs.entries.map((i) => "typedef ${i.key}=${i.value};").join()
: "",
)
..writeln(
"${applyDefsF("ArgumentError")} __x(${applyDefsF("String")} c,${applyDefsF("String")} f)=>${applyDefsF("ArgumentError")}('\${${stringD("Missing required ")}}\$c.\$f');",
)
..write(
compression
? "const ${applyDefsF("List<String>")} _S=[${strDD.map((i) => "'$i'").join(",")}];"
: "",
)
..write(
compression
? "const ${applyDefsF("List<dynamic>")} _V=[${valDD.map((i) => " $i ".replaceAll(" const ", "").trim()).join(",")}];"
: "",
)
..write("const ${applyDefsF("bool")} _T=true;")
..write("const ${applyDefsF("bool")} _F=false;")
..writeln(codecRegistry);
StringBuffer mainBuf = StringBuffer();
for (StringBuffer cb in classBuffers) {
mainBuf.writeln(cb);
}
String r = mainBuf.toString();
outBuf.writeln(r);
if (artifacts.isEmpty) {
outBuf.writeln("bool \$isArtifact(dynamic v)=>false;");
} else {
outBuf.write(
"bool \$isArtifact(dynamic v)=>v==null?false : v is! Type ?\$isArtifact(v.runtimeType):",
);
for (ClassElement i in artifacts) {
outBuf.write(
"v == ${applyDefsF(i.name ?? "")} ${i == artifacts.last ? "" : "||"}",
);
}
outBuf.writeln(";");
}
outBuf.write(rbuf);
if (artifacts.isEmpty) {
outBuf.writeln(
"T \$constructArtifact<T>() => throw ${applyDefsF("Exception")}();",
);
} else {
outBuf.write("T \$constructArtifact<T>() => ");
for (ClassElement i in artifacts) {
outBuf.write(
"T==${applyDefsF(i.name ?? "")} ?\$${(i.name)}.newInstance as T ${i == artifacts.last ? "" : ":"}",
);
}
outBuf.writeln(": throw ${applyDefsF("Exception")}();");
}
if (artifacts.isEmpty) {
outBuf.writeln(
"${applyDefsF("Map<String,dynamic>")} \$artifactToMap(Object o)=>throw ${applyDefsF("Exception")}();",
);
} else {
outBuf.write(
"${applyDefsF("Map<String,dynamic>")} \$artifactToMap(Object o)=>",
);
for (ClassElement i in artifacts) {
outBuf.write(
"o is ${applyDefsF(i.name ?? "")} ?o.toMap()${i == artifacts.last ? "" : ":"}",
);
}
outBuf.writeln(":throw ${applyDefsF("Exception")}();");
}
if (artifacts.isEmpty) {
outBuf.writeln(
"T \$artifactFromMap<T>(${applyDefsF("Map<String,dynamic>")} m)=>throw ${applyDefsF("Exception")}();",
);
} else {
outBuf.write(
"T \$artifactFromMap<T>(${applyDefsF("Map<String,dynamic>")} m)=>",
);
for (ClassElement i in artifacts) {
outBuf.write(
"T==${applyDefsF(i.name ?? "")} ?\$${i.name}.fromMap(m) as T${i == artifacts.last ? "" : ":"}",
);
}
outBuf.writeln(":throw ${applyDefsF("Exception")}();");
}
AssetId out = AssetId(step.inputId.package, 'lib/gen/artifacts.gen.dart');
await step.writeAsString(out, outBuf.toString());
bool autoExport = artifactConfig["export"] ?? false;
Stream<AssetId> assets = step.findAssets(Glob('lib/**.dart'));
List<Future<String?>> worker = [];
await for (AssetId i in assets) {
String exportUri = i.uri.path;
if (exportUri != '${artifactConfig["name"]}/gen/exports.gen.dart' &&
exportUri !=
'${artifactConfig["name"]}/${artifactConfig["name"]}.dart') {
bool readable = await step.canRead(i);
if (!readable) {
verbose("Skipping unreadable export analysis for: ${i.uri}");
continue;
}
worker.add(
step.readAsString(i).then((v) {
Iterable<SyntacticEntity> ast =
parseString(content: v).unit.childEntities;
for (SyntacticEntity j in ast) {
if (j is PartOfDirective) {
return null;
}
}
return getExpString(ast, exportUri, autoExport);
}),
);
} else {
verbose("Skipping export analysis for: ${i.uri}");
}
}
List<String> s = (await Future.wait(worker)).whereType<String>().toList();
s.add("export 'artifacts.gen.dart';");
if (s.isNotEmpty) {
AssetId outExports = AssetId(
step.inputId.package,
'lib/gen/exports.gen.dart',
);
await step.writeAsString(outExports, s.join("\n"));
} else {
warn("No exports generated.");
}
}