Skip to content

Commit 2b23133

Browse files
authored
feat(dart_frog_gen): include endpoints in RouteConfiguration (#198)
1 parent c652340 commit 2b23133

File tree

2 files changed

+244
-1
lines changed

2 files changed

+244
-1
lines changed

packages/dart_frog_gen/lib/src/build_route_configuration.dart

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ RouteConfiguration buildRouteConfiguration(Directory directory) {
2323
)
2424
: null;
2525

26+
final endpoints = <String, List<RouteFile>>{};
2627
final middleware = <MiddlewareFile>[
2728
if (globalMiddleware != null) globalMiddleware
2829
];
@@ -32,13 +33,21 @@ RouteConfiguration buildRouteConfiguration(Directory directory) {
3233
routesDirectory: routesDirectory,
3334
onRoute: routes.add,
3435
onMiddleware: middleware.add,
36+
onEndpoint: (endpoint, file) {
37+
if (!endpoints.containsKey(endpoint)) {
38+
endpoints[endpoint] = [file];
39+
} else {
40+
endpoints[endpoint]!.add(file);
41+
}
42+
},
3543
);
3644
final publicDirectory = Directory(path.join(directory.path, 'public'));
3745
return RouteConfiguration(
3846
globalMiddleware: globalMiddleware,
3947
middleware: middleware,
4048
directories: directories,
4149
routes: routes,
50+
endpoints: endpoints,
4251
serveStaticFiles: publicDirectory.existsSync(),
4352
);
4453
}
@@ -48,6 +57,7 @@ List<RouteDirectory> _getRouteDirectories({
4857
required Directory routesDirectory,
4958
required void Function(RouteFile route) onRoute,
5059
required void Function(MiddlewareFile route) onMiddleware,
60+
required void Function(String endpoint, RouteFile file) onEndpoint,
5161
}) {
5262
final directories = <RouteDirectory>[];
5363
final entities = directory.listSync().sorted();
@@ -85,10 +95,20 @@ List<RouteDirectory> _getRouteDirectories({
8595
),
8696
];
8797

98+
final baseRoute = directoryPath.toRoute();
99+
for (final file in files) {
100+
var endpoint = (baseRoute + file.route.toRoute()).replaceAll('//', '/');
101+
if (endpoint.endsWith('/')) {
102+
endpoint = endpoint.substring(0, endpoint.length - 1);
103+
}
104+
if (endpoint.isEmpty) endpoint = '/';
105+
onEndpoint(endpoint, file);
106+
}
107+
88108
directories.add(
89109
RouteDirectory(
90110
name: directoryPath.toAlias(),
91-
route: directoryPath.toRoute(),
111+
route: baseRoute,
92112
middleware: middleware,
93113
files: files,
94114
),
@@ -102,6 +122,7 @@ List<RouteDirectory> _getRouteDirectories({
102122
routesDirectory: routesDirectory,
103123
onRoute: onRoute,
104124
onMiddleware: onMiddleware,
125+
onEndpoint: onEndpoint,
105126
),
106127
);
107128
}
@@ -229,6 +250,7 @@ class RouteConfiguration {
229250
required this.middleware,
230251
required this.directories,
231252
required this.routes,
253+
required this.endpoints,
232254
this.serveStaticFiles = false,
233255
});
234256

@@ -248,6 +270,9 @@ class RouteConfiguration {
248270

249271
/// List of all route files.
250272
final List<RouteFile> routes;
273+
274+
/// A map of all endpoint paths to resolved route files.
275+
final Map<String, List<RouteFile>> endpoints;
251276
}
252277

253278
/// {@template route_directory}

packages/dart_frog_gen/test/src/build_route_configuration_test.dart

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,41 @@ void main() {
4949
expect(configuration.globalMiddleware, isNotNull);
5050
});
5151

52+
test('endpoint includes multiple routes when conflicts exist', () {
53+
final directory = Directory(
54+
path.join(
55+
Directory.current.path,
56+
'test',
57+
'.fixtures',
58+
'single_conflict',
59+
),
60+
)..createSync(recursive: true);
61+
final routes = Directory(path.join(directory.path, 'routes'))
62+
..createSync();
63+
File(path.join(routes.path, 'users.dart')).createSync();
64+
final usersDirectory = Directory(path.join(routes.path, 'users'))
65+
..createSync();
66+
File(path.join(usersDirectory.path, 'index.dart')).createSync();
67+
final configuration = buildRouteConfiguration(directory);
68+
expect(
69+
configuration.endpoints,
70+
equals({
71+
'/users': [
72+
isA<RouteFile>().having(
73+
(r) => r.path,
74+
'path',
75+
'../routes/users.dart',
76+
),
77+
isA<RouteFile>().having(
78+
(r) => r.path,
79+
'path',
80+
'../routes/users/index.dart',
81+
)
82+
]
83+
}),
84+
);
85+
});
86+
5287
test('includes single index route', () {
5388
const expected = [
5489
{
@@ -71,6 +106,18 @@ void main() {
71106
configuration.directories.map((d) => d.toJson()).toList(),
72107
equals(expected),
73108
);
109+
expect(
110+
configuration.endpoints,
111+
equals({
112+
'/': [
113+
isA<RouteFile>().having(
114+
(r) => r.path,
115+
'path',
116+
'../routes/index.dart',
117+
)
118+
]
119+
}),
120+
);
74121
});
75122

76123
test('includes multiple top-level routes', () {
@@ -102,6 +149,25 @@ void main() {
102149
configuration.directories.map((d) => d.toJson()).toList(),
103150
equals(expected),
104151
);
152+
expect(
153+
configuration.endpoints,
154+
equals({
155+
'/': [
156+
isA<RouteFile>().having(
157+
(r) => r.path,
158+
'path',
159+
'../routes/index.dart',
160+
)
161+
],
162+
'/hello': [
163+
isA<RouteFile>().having(
164+
(r) => r.path,
165+
'path',
166+
'../routes/hello.dart',
167+
)
168+
]
169+
}),
170+
);
105171
});
106172

107173
test('includes nested routes', () {
@@ -141,6 +207,25 @@ void main() {
141207
configuration.directories.map((d) => d.toJson()).toList(),
142208
equals(expected),
143209
);
210+
expect(
211+
configuration.endpoints,
212+
equals({
213+
'/': [
214+
isA<RouteFile>().having(
215+
(r) => r.path,
216+
'path',
217+
'../routes/index.dart',
218+
)
219+
],
220+
'/echo/message': [
221+
isA<RouteFile>().having(
222+
(r) => r.path,
223+
'path',
224+
'../routes/echo/message.dart',
225+
)
226+
]
227+
}),
228+
);
144229
});
145230

146231
test('includes nested directories', () {
@@ -185,6 +270,18 @@ void main() {
185270
configuration.directories.map((d) => d.toJson()).toList(),
186271
equals(expected),
187272
);
273+
expect(
274+
configuration.endpoints,
275+
equals({
276+
'/echo/message': [
277+
isA<RouteFile>().having(
278+
(r) => r.path,
279+
'path',
280+
'../routes/echo/message/index.dart',
281+
)
282+
]
283+
}),
284+
);
188285
});
189286

190287
test('includes dynamic route', () {
@@ -224,6 +321,25 @@ void main() {
224321
configuration.directories.map((d) => d.toJson()).toList(),
225322
equals(expected),
226323
);
324+
expect(
325+
configuration.endpoints,
326+
equals({
327+
'/': [
328+
isA<RouteFile>().having(
329+
(r) => r.path,
330+
'path',
331+
'../routes/index.dart',
332+
)
333+
],
334+
'/echo/<message>': [
335+
isA<RouteFile>().having(
336+
(r) => r.path,
337+
'path',
338+
'../routes/echo/[message].dart',
339+
)
340+
]
341+
}),
342+
);
227343
});
228344

229345
test('includes dynamic nested directory routes', () {
@@ -269,6 +385,32 @@ void main() {
269385
configuration.directories.map((d) => d.toJson()).toList(),
270386
equals(expected),
271387
);
388+
expect(
389+
configuration.endpoints,
390+
equals({
391+
'/': [
392+
isA<RouteFile>().having(
393+
(r) => r.path,
394+
'path',
395+
'../routes/index.dart',
396+
)
397+
],
398+
'/<user>/<name>': [
399+
isA<RouteFile>().having(
400+
(r) => r.path,
401+
'path',
402+
'../routes/[user]/[name].dart',
403+
)
404+
],
405+
'/<user>/<id>': [
406+
isA<RouteFile>().having(
407+
(r) => r.path,
408+
'path',
409+
'../routes/[user]/[id]/index.dart',
410+
)
411+
]
412+
}),
413+
);
272414
});
273415

274416
test('supports /[id]/api/index.dart', () {
@@ -308,6 +450,25 @@ void main() {
308450
configuration.directories.map((d) => d.toJson()).toList(),
309451
equals(expected),
310452
);
453+
expect(
454+
configuration.endpoints,
455+
equals({
456+
'/': [
457+
isA<RouteFile>().having(
458+
(r) => r.path,
459+
'path',
460+
'../routes/index.dart',
461+
)
462+
],
463+
'/<id>/api': [
464+
isA<RouteFile>().having(
465+
(r) => r.path,
466+
'path',
467+
'../routes/[id]/api/index.dart',
468+
)
469+
],
470+
}),
471+
);
311472
});
312473

313474
test('supports /[id]/api/test.dart', () {
@@ -347,6 +508,25 @@ void main() {
347508
configuration.directories.map((d) => d.toJson()).toList(),
348509
equals(expected),
349510
);
511+
expect(
512+
configuration.endpoints,
513+
equals({
514+
'/': [
515+
isA<RouteFile>().having(
516+
(r) => r.path,
517+
'path',
518+
'../routes/index.dart',
519+
)
520+
],
521+
'/<id>/api/test': [
522+
isA<RouteFile>().having(
523+
(r) => r.path,
524+
'path',
525+
'../routes/[id]/api/test.dart',
526+
)
527+
],
528+
}),
529+
);
350530
});
351531

352532
test('supports /[id]/api/[name]/index.dart', () {
@@ -388,6 +568,25 @@ void main() {
388568
configuration.directories.map((d) => d.toJson()).toList(),
389569
equals(expected),
390570
);
571+
expect(
572+
configuration.endpoints,
573+
equals({
574+
'/': [
575+
isA<RouteFile>().having(
576+
(r) => r.path,
577+
'path',
578+
'../routes/index.dart',
579+
)
580+
],
581+
'/<id>/api/<name>': [
582+
isA<RouteFile>().having(
583+
(r) => r.path,
584+
'path',
585+
'../routes/[id]/api/[name]/index.dart',
586+
)
587+
],
588+
}),
589+
);
391590
});
392591

393592
test('supports /[id]/api/[name]/test.dart', () {
@@ -429,6 +628,25 @@ void main() {
429628
configuration.directories.map((d) => d.toJson()).toList(),
430629
equals(expected),
431630
);
631+
expect(
632+
configuration.endpoints,
633+
equals({
634+
'/': [
635+
isA<RouteFile>().having(
636+
(r) => r.path,
637+
'path',
638+
'../routes/index.dart',
639+
)
640+
],
641+
'/<id>/api/<name>/test': [
642+
isA<RouteFile>().having(
643+
(r) => r.path,
644+
'path',
645+
'../routes/[id]/api/[name]/test.dart',
646+
)
647+
],
648+
}),
649+
);
432650
});
433651
});
434652
}

0 commit comments

Comments
 (0)