-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(katana_router_builder): Create a mechanism for automatic Routing …
…generation
- Loading branch information
Showing
15 changed files
with
314 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
102 changes: 102 additions & 0 deletions
102
packages/katana_router_builder/lib/common/router_class.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
part of katana_router_builder; | ||
|
||
List<Class> routerClass( | ||
List<QueryValue> queries, | ||
) { | ||
return [ | ||
Class( | ||
(c) => c | ||
..name = r"AppRouter" | ||
..extend = const Reference("AppRouterBase") | ||
..constructors = ListBuilder([ | ||
Constructor( | ||
(c) => c | ||
..optionalParameters = ListBuilder([ | ||
Parameter( | ||
(p) => p | ||
..name = "unknown" | ||
..named = true | ||
..toSuper = true, | ||
), | ||
Parameter( | ||
(p) => p | ||
..name = "boot" | ||
..named = true | ||
..toSuper = true, | ||
), | ||
Parameter( | ||
(p) => p | ||
..name = "initialPath" | ||
..toSuper = true | ||
..named = true | ||
..defaultTo = const Code("\"/\""), | ||
), | ||
Parameter( | ||
(p) => p | ||
..name = "redirect" | ||
..toSuper = true | ||
..named = true | ||
..defaultTo = const Code("const []"), | ||
), | ||
Parameter( | ||
(p) => p | ||
..name = "observers" | ||
..toSuper = true | ||
..named = true | ||
..defaultTo = const Code("const []"), | ||
), | ||
Parameter( | ||
(p) => p | ||
..name = "redirectLimit" | ||
..toSuper = true | ||
..named = true | ||
..defaultTo = const Code("5"), | ||
), | ||
Parameter( | ||
(p) => p | ||
..name = "navigatorKey" | ||
..named = true | ||
..toSuper = true, | ||
), | ||
Parameter( | ||
(p) => p | ||
..name = "restorationScopeId" | ||
..named = true | ||
..toSuper = true, | ||
), | ||
Parameter( | ||
(p) => p | ||
..name = "defaultRouteQuery" | ||
..named = true | ||
..toSuper = true, | ||
), | ||
]) | ||
..initializers = ListBuilder([ | ||
Code( | ||
"super(pages: [${queries.map((e) => e.query).join(",")}])", | ||
), | ||
]), | ||
) | ||
]) | ||
..fields = ListBuilder([ | ||
...queries.map((query) { | ||
return Field( | ||
(f) => f | ||
..name = query.element.name.toCamelCase() | ||
..static = true | ||
..modifier = FieldModifier.constant | ||
..assignment = Code(query.query), | ||
); | ||
}), | ||
Field( | ||
(f) => f | ||
..name = "queryMap" | ||
..type = const Reference("Map<RouteQueryBuilder, String>") | ||
..assignment = Code( | ||
"{${queries.map((q) => "${q.query}:\"/${q.path}\"").join(",")}}", | ||
), | ||
) | ||
]), | ||
), | ||
]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
119 changes: 119 additions & 0 deletions
119
packages/katana_router_builder/lib/generator/router_generator.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
part of katana_router_builder; | ||
|
||
class RouterGenerator extends GeneratorForAnnotation<AppRoute> { | ||
RouterGenerator(); | ||
|
||
static const _typeChecker = TypeChecker.fromRuntime(PagePath); | ||
static const _pageRouteQueryChecker = TypeChecker.fromRuntime(PageRouteQuery); | ||
|
||
static final _regExp = RegExp(r"^/(?<packageName>[^/]+)/lib/(?<path>.+)$"); | ||
|
||
@override | ||
FutureOr<String> generateForAnnotatedElement( | ||
Element element, | ||
ConstantReader annotation, | ||
BuildStep buildStep, | ||
) async { | ||
if (!element.library!.isNonNullableByDefault) { | ||
throw InvalidGenerationSourceError( | ||
"Generator cannot target libraries that have not been migrated to " | ||
"null-safety.", | ||
element: element, | ||
); | ||
} | ||
|
||
if (element is! TopLevelVariableElement) { | ||
throw InvalidGenerationSourceError( | ||
"`@AppRoute()`はトップレベルのフィールドにのみ付与してください。\n" | ||
"```\n" | ||
"\n" | ||
"```\n", | ||
element: element, | ||
); | ||
} | ||
|
||
final queries = <QueryValue>[]; | ||
final assets = buildStep.findAssets(Glob("**.dart")); | ||
await for (final asset in assets) { | ||
if (!await buildStep.resolver.isLibrary(asset)) { | ||
continue; | ||
} | ||
final lib = LibraryReader( | ||
await buildStep.resolver.libraryFor( | ||
asset, | ||
allowSyntaxErrors: false, | ||
), | ||
); | ||
for (final annotatedElement in lib.annotatedWith(_typeChecker)) { | ||
final element = annotatedElement.element; | ||
if (element is! ClassElement) { | ||
continue; | ||
} | ||
final annotation = annotatedElement.annotation; | ||
final path = annotation.read("path").stringValue.trimString("/"); | ||
for (final field in element.fields) { | ||
if (_pageRouteQueryChecker.hasAnnotationOfExact(field)) { | ||
if (!field.isStatic || !field.isConst) { | ||
throw InvalidGenerationSourceError( | ||
"The `@pageRouteQuery()` can only be given to static and const fields.", | ||
element: field, | ||
); | ||
} | ||
final library = _getImportLibrary(lib.element); | ||
if (library.isEmpty) { | ||
continue; | ||
} | ||
queries.add( | ||
QueryValue( | ||
library: library!, | ||
path: path, | ||
query: "${element.name}.${field.name}", | ||
element: element, | ||
), | ||
); | ||
} | ||
} | ||
} | ||
} | ||
|
||
final sorted = queries.sortTo((a, b) => a.path.compareTo(b.path)); | ||
|
||
final generated = Library( | ||
(l) => l | ||
..directives = ListBuilder([ | ||
Directive.import( | ||
"package:katana_router/katana_router.dart", | ||
), | ||
...sorted | ||
.map((e) => e.library) | ||
.distinct() | ||
.map((e) => Directive.import(e)), | ||
Directive.export( | ||
"package:katana_router/katana_router.dart", | ||
), | ||
...sorted | ||
.map((e) => e.library) | ||
.distinct() | ||
.map((e) => Directive.export(e)) | ||
]) | ||
..body.addAll( | ||
[ | ||
...routerClass(sorted), | ||
], | ||
), | ||
); | ||
final emitter = DartEmitter(); | ||
return DartFormatter().format( | ||
"${generated.accept(emitter)}", | ||
); | ||
} | ||
|
||
String? _getImportLibrary(LibraryElement element) { | ||
final path = element.librarySource.toString(); | ||
final match = _regExp.firstMatch(path); | ||
if (match == null) { | ||
return null; | ||
} | ||
return "package:${match.namedGroup("packageName")}/${match.namedGroup("path")}"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.