Skip to content

Commit 3e66afe

Browse files
authored
refactor(dart_frog_cli): use server validation from dart_frog_gen (#615)
1 parent 53bec93 commit 3e66afe

18 files changed

+465
-1022
lines changed

bricks/dart_frog_dev_server/hooks/pre_gen.dart

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@ import 'dart:async';
22
import 'dart:io' as io;
33

44
import 'package:dart_frog_gen/dart_frog_gen.dart';
5-
import 'package:mason/mason.dart' show HookContext;
5+
import 'package:mason/mason.dart'
6+
show HookContext, defaultForeground, lightCyan;
67

78
import 'src/exit_overrides.dart';
8-
import 'src/report_external_path_dependencies.dart';
9-
import 'src/report_rogue_routes.dart';
10-
import 'src/report_route_conflicts.dart';
119

1210
typedef RouteConfigurationBuilder = RouteConfiguration Function(
1311
io.Directory directory,
@@ -19,9 +17,12 @@ Future<void> run(HookContext context) async => preGen(context);
1917

2018
Future<void> preGen(
2119
HookContext context, {
20+
io.Directory? directory,
2221
RouteConfigurationBuilder buildConfiguration = buildRouteConfiguration,
2322
void Function(int exitCode) exit = _defaultExit,
2423
}) async {
24+
final projectDirectory = directory ?? io.Directory.current;
25+
2526
final RouteConfiguration configuration;
2627
try {
2728
configuration = buildConfiguration(io.Directory.current);
@@ -30,9 +31,44 @@ Future<void> preGen(
3031
return exit(1);
3132
}
3233

33-
reportRouteConflicts(context, configuration);
34-
reportRogueRoutes(context, configuration);
35-
await reportExternalPathDependencies(context, io.Directory.current);
34+
reportRouteConflicts(
35+
configuration,
36+
onViolationStart: () {
37+
context.logger.info('');
38+
},
39+
onRouteConflict: (
40+
originalFilePath,
41+
conflictingFilePath,
42+
conflictingEndpoint,
43+
) {
44+
context.logger.err(
45+
'''Route conflict detected. ${lightCyan.wrap(originalFilePath)} and ${lightCyan.wrap(conflictingFilePath)} both resolve to ${lightCyan.wrap(conflictingEndpoint)}.''',
46+
);
47+
},
48+
);
49+
reportRogueRoutes(
50+
configuration,
51+
onViolationStart: () {
52+
context.logger.info('');
53+
},
54+
onRogueRoute: (filePath, idealPath) {
55+
context.logger.err(
56+
'''Rogue route detected.${defaultForeground.wrap(' ')}Rename ${lightCyan.wrap(filePath)} to ${lightCyan.wrap(idealPath)}.''',
57+
);
58+
},
59+
);
60+
await reportExternalPathDependencies(
61+
projectDirectory,
62+
onViolationStart: () {
63+
context.logger
64+
..info('')
65+
..err('All path dependencies must be within the project.')
66+
..err('External path dependencies detected:');
67+
},
68+
onExternalPathDependency: (dependencyName, dependencyPath) {
69+
context.logger.err(' \u{2022} $dependencyName from $dependencyPath');
70+
},
71+
);
3672

3773
context.vars = {
3874
'port': context.vars['port'] ?? '8080',

bricks/dart_frog_dev_server/hooks/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ environment:
55
sdk: ">=2.19.0 <3.0.0"
66

77
dependencies:
8-
dart_frog_gen: ^0.3.2
8+
dart_frog_gen: ^0.3.3
99
mason: ^0.1.0-dev.39
1010
pubspec_parse: ^1.2.0
1111

bricks/dart_frog_dev_server/hooks/src/report_external_path_dependencies.dart

Lines changed: 0 additions & 38 deletions
This file was deleted.

bricks/dart_frog_dev_server/hooks/src/report_rogue_routes.dart

Lines changed: 0 additions & 24 deletions
This file was deleted.

bricks/dart_frog_dev_server/hooks/src/report_route_conflicts.dart

Lines changed: 0 additions & 25 deletions
This file was deleted.

bricks/dart_frog_dev_server/hooks/test/pre_gen_test.dart

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
import 'dart:io';
2+
13
import 'package:dart_frog_gen/dart_frog_gen.dart';
24
import 'package:mason/mason.dart';
35
import 'package:mocktail/mocktail.dart';
6+
import 'package:path/path.dart' as path;
47
import 'package:test/test.dart';
58

69
import '../pre_gen.dart';
@@ -57,6 +60,131 @@ void main() {
5760
verify(() => logger.err(exception.toString())).called(1);
5861
});
5962

63+
test('complains about route conflicts', () async {
64+
const configuration = RouteConfiguration(
65+
middleware: [],
66+
directories: [],
67+
routes: [],
68+
rogueRoutes: [],
69+
endpoints: {
70+
'/': [
71+
RouteFile(
72+
name: 'index',
73+
path: 'index.dart',
74+
route: '/',
75+
params: [],
76+
),
77+
],
78+
'/hello': [
79+
RouteFile(
80+
name: 'hello',
81+
path: 'hello.dart',
82+
route: '/hello',
83+
params: [],
84+
),
85+
RouteFile(
86+
name: 'hello_index',
87+
path: 'hello/index.dart',
88+
route: '/',
89+
params: [],
90+
)
91+
]
92+
},
93+
);
94+
95+
final exitCalls = <int>[];
96+
await preGen(
97+
context,
98+
buildConfiguration: (_) => configuration,
99+
exit: exitCalls.add,
100+
);
101+
102+
verify(
103+
() => logger.err(
104+
'''Route conflict detected. ${lightCyan.wrap('routes/hello.dart')} and ${lightCyan.wrap('routes/hello/index.dart')} both resolve to ${lightCyan.wrap('/hello')}.''',
105+
),
106+
);
107+
expect(exitCalls, isEmpty);
108+
});
109+
110+
test('complains about rogue routes', () async {
111+
const configuration = RouteConfiguration(
112+
middleware: [],
113+
directories: [],
114+
routes: [],
115+
rogueRoutes: [
116+
RouteFile(
117+
name: 'hello',
118+
path: 'hello.dart',
119+
route: '/hello',
120+
params: [],
121+
),
122+
],
123+
endpoints: {},
124+
);
125+
126+
final exitCalls = <int>[];
127+
await preGen(
128+
context,
129+
buildConfiguration: (_) => configuration,
130+
exit: exitCalls.add,
131+
);
132+
133+
verify(
134+
() => logger.err(
135+
'''Rogue route detected.${defaultForeground.wrap(' ')}Rename ${lightCyan.wrap('routes/hello.dart')} to ${lightCyan.wrap('routes/hello/index.dart')}.''',
136+
),
137+
);
138+
expect(exitCalls, isEmpty);
139+
});
140+
141+
test('complains about r external dependencies', () async {
142+
const configuration = RouteConfiguration(
143+
middleware: [],
144+
directories: [],
145+
routes: [],
146+
rogueRoutes: [],
147+
endpoints: {},
148+
);
149+
150+
final directory = Directory.systemTemp.createTempSync();
151+
File(path.join(directory.path, 'pubspec.yaml')).writeAsStringSync(
152+
'''
153+
name: example
154+
version: 0.1.0
155+
environment:
156+
sdk: ^2.17.0
157+
dependencies:
158+
mason: any
159+
foo:
160+
path: ../../foo
161+
dev_dependencies:
162+
test: any
163+
''',
164+
);
165+
166+
final exitCalls = <int>[];
167+
await preGen(
168+
context,
169+
buildConfiguration: (_) => configuration,
170+
exit: exitCalls.add,
171+
directory: directory,
172+
);
173+
174+
verify(
175+
() => logger.err('All path dependencies must be within the project.'),
176+
).called(1);
177+
verify(
178+
() => logger.err('External path dependencies detected:'),
179+
).called(1);
180+
verify(
181+
() => logger.err(' \u{2022} foo from ../../foo'),
182+
).called(1);
183+
expect(exitCalls, isEmpty);
184+
185+
directory.delete(recursive: true).ignore();
186+
});
187+
60188
test('retains custom port if specified', () async {
61189
const customPort = '8081';
62190
context.vars['port'] = customPort;

0 commit comments

Comments
 (0)