1
- import 'dart:io' ;
1
+ import 'dart:async' ;
2
+ import 'dart:io' as io;
2
3
3
4
import 'package:dart_frog_gen/dart_frog_gen.dart' ;
4
- import 'package:io/io.dart' ;
5
+ import 'package:io/io.dart' show copyPath ;
5
6
import 'package:mason/mason.dart' ;
6
7
import 'package:path/path.dart' as path;
7
8
import 'package:pubspec_parse/pubspec_parse.dart' ;
8
9
9
- Future <void > run (HookContext context) async {
10
- final projectDirectory = Directory .current;
11
- final buildDirectoryPath = path.join (projectDirectory.path, 'build' );
12
- final buildDirectory = Directory (buildDirectoryPath);
13
- final dartFrogDirectoryPath = path.join (projectDirectory.path, '.dart_frog' );
14
- final dartFrogDirectory = Directory (dartFrogDirectoryPath);
15
-
16
- final pubspec = Pubspec .parse (
17
- await File (path.join (projectDirectory.path, 'pubspec.yaml' )).readAsString (),
18
- );
19
-
20
- final dependencies = pubspec.dependencies;
21
- final devDependencies = pubspec.devDependencies;
22
- final pathDependencies = [
23
- ...dependencies.entries,
24
- ...devDependencies.entries,
25
- ]
26
- .where ((entry) => entry.value is PathDependency )
27
- .map ((entry) => (entry.value as PathDependency ).path)
28
- .toList ();
10
+ typedef RouteConfigurationBuilder = RouteConfiguration Function (
11
+ io.Directory directory,
12
+ );
29
13
30
- final bundlingProgress = context.logger.progress ('Bundling sources' );
31
- if (await buildDirectory.exists ()) {
32
- await buildDirectory.delete (recursive: true );
33
- }
14
+ Future <void > run (HookContext context) => preGen (context);
34
15
35
- if (await dartFrogDirectory.exists ()) {
36
- await dartFrogDirectory.delete (recursive: true );
37
- }
38
-
39
- final tempDirectory = await Directory .systemTemp.createTemp ();
40
- try {
41
- await copyPath ('.' , '${tempDirectory .path }${path .separator }' );
42
- bundlingProgress.complete ();
43
- } catch (error) {
44
- bundlingProgress.fail ();
45
- context.logger.err ('$error ' );
46
- exit (1 );
47
- }
16
+ Future <void > preGen (
17
+ HookContext context, {
18
+ io.Directory ? directory,
19
+ RouteConfigurationBuilder buildConfiguration = buildRouteConfiguration,
20
+ void Function (int exitCode)? exit,
21
+ }) async {
22
+ final _exit = exit ?? ExitOverrides .current? .exit ?? io.exit;
23
+ final projectDirectory = directory ?? io.Directory .current;
48
24
49
- await tempDirectory. rename (buildDirectoryPath );
25
+ await createBundle (context, projectDirectory, _exit );
50
26
51
27
final RouteConfiguration configuration;
52
28
try {
53
- configuration = buildRouteConfiguration ( Directory .current);
29
+ configuration = buildConfiguration (io. Directory .current);
54
30
} catch (error) {
55
31
context.logger.err ('$error ' );
56
- exit (1 );
32
+ return _exit (1 );
57
33
}
58
34
35
+ reportRouteConflicts (context, configuration, _exit);
36
+
59
37
context.vars = {
60
38
'directories' : configuration.directories
61
39
.map ((c) => c.toJson ())
@@ -67,6 +45,106 @@ Future<void> run(HookContext context) async {
67
45
'globalMiddleware' : configuration.globalMiddleware != null
68
46
? configuration.globalMiddleware! .toJson ()
69
47
: false ,
70
- 'pathDependencies' : pathDependencies ,
48
+ 'pathDependencies' : await getPathDependencies (projectDirectory) ,
71
49
};
72
50
}
51
+
52
+ Future <void > createBundle (
53
+ HookContext context,
54
+ io.Directory projectDirectory,
55
+ void Function (int exitCode) exit,
56
+ ) async {
57
+ final buildDirectoryPath = path.join (projectDirectory.path, 'build' );
58
+ final buildDirectory = io.Directory (buildDirectoryPath);
59
+ final dartFrogDirectoryPath = path.join (projectDirectory.path, '.dart_frog' );
60
+ final dartFrogDirectory = io.Directory (dartFrogDirectoryPath);
61
+ final bundlingProgress = context.logger.progress ('Bundling sources' );
62
+ final tempDirectory = await io.Directory .systemTemp.createTemp ();
63
+
64
+ if (buildDirectory.existsSync ()) {
65
+ await buildDirectory.delete (recursive: true );
66
+ }
67
+
68
+ if (dartFrogDirectory.existsSync ()) {
69
+ await dartFrogDirectory.delete (recursive: true );
70
+ }
71
+
72
+ try {
73
+ await copyPath (
74
+ projectDirectory.path,
75
+ '${tempDirectory .path }${path .separator }' ,
76
+ );
77
+ bundlingProgress.complete ();
78
+ } catch (error) {
79
+ bundlingProgress.fail ();
80
+ context.logger.err ('$error ' );
81
+ return exit (1 );
82
+ }
83
+
84
+ await tempDirectory.rename (buildDirectory.path);
85
+ }
86
+
87
+ Future <List <String >> getPathDependencies (io.Directory directory) async {
88
+ final pubspec = Pubspec .parse (
89
+ await io.File (path.join (directory.path, 'pubspec.yaml' )).readAsString (),
90
+ );
91
+
92
+ final dependencies = pubspec.dependencies;
93
+ final devDependencies = pubspec.devDependencies;
94
+ return [...dependencies.entries, ...devDependencies.entries]
95
+ .where ((entry) => entry.value is PathDependency )
96
+ .map ((entry) => (entry.value as PathDependency ).path)
97
+ .toList ();
98
+ }
99
+
100
+ void reportRouteConflicts (
101
+ HookContext context,
102
+ RouteConfiguration configuration,
103
+ void Function (int exitCode) exit,
104
+ ) {
105
+ final conflictingEndpoints =
106
+ configuration.endpoints.entries.where ((entry) => entry.value.length > 1 );
107
+ if (conflictingEndpoints.isNotEmpty) {
108
+ for (final conflict in conflictingEndpoints) {
109
+ final originalFilePath = path.normalize (
110
+ path.join ('routes' , conflict.value.first.path),
111
+ );
112
+ final conflictingFilePath = path.normalize (
113
+ path.join ('routes' , conflict.value.last.path),
114
+ );
115
+ context.logger.err (
116
+ '''Route conflict detected. ${lightCyan .wrap (originalFilePath )} and ${lightCyan .wrap (conflictingFilePath )} both resolve to ${lightCyan .wrap (conflict .key )}.''' ,
117
+ );
118
+ }
119
+ exit (1 );
120
+ }
121
+ }
122
+
123
+ const _asyncRunZoned = runZoned;
124
+
125
+ abstract class ExitOverrides {
126
+ static final _token = Object ();
127
+
128
+ static ExitOverrides ? get current {
129
+ return Zone .current[_token] as ExitOverrides ? ;
130
+ }
131
+
132
+ static R runZoned <R >(R Function () body, {void Function (int )? exit}) {
133
+ final overrides = _ExitOverridesScope (exit);
134
+ return _asyncRunZoned (body, zoneValues: {_token: overrides});
135
+ }
136
+
137
+ void Function (int exitCode) get exit => io.exit;
138
+ }
139
+
140
+ class _ExitOverridesScope extends ExitOverrides {
141
+ _ExitOverridesScope (this ._exit);
142
+
143
+ final ExitOverrides ? _previous = ExitOverrides .current;
144
+ final void Function (int exitCode)? _exit;
145
+
146
+ @override
147
+ void Function (int exitCode) get exit {
148
+ return _exit ?? _previous? .exit ?? super .exit;
149
+ }
150
+ }
0 commit comments