coregen-cli 3.1.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. coregen.py +1585 -0
  2. coregen_cli-3.1.6.dist-info/METADATA +1211 -0
  3. coregen_cli-3.1.6.dist-info/RECORD +172 -0
  4. coregen_cli-3.1.6.dist-info/WHEEL +5 -0
  5. coregen_cli-3.1.6.dist-info/entry_points.txt +2 -0
  6. coregen_cli-3.1.6.dist-info/top_level.txt +2 -0
  7. generators/__init__.py +1 -0
  8. generators/assets/__init__.py +1 -0
  9. generators/assets/assets.py +30 -0
  10. generators/assets/main.py +4 -0
  11. generators/config/__init__.py +1 -0
  12. generators/config/analisy_options.py +42 -0
  13. generators/config/main.py +11 -0
  14. generators/config/pubspec.py +139 -0
  15. generators/cursor/__init__.py +3 -0
  16. generators/cursor/setup.py +87 -0
  17. generators/helpers/__init__.py +56 -0
  18. generators/helpers/component.py +1030 -0
  19. generators/helpers/config.py +255 -0
  20. generators/helpers/data_source.py +180 -0
  21. generators/helpers/domain.py +469 -0
  22. generators/helpers/feature.py +654 -0
  23. generators/helpers/navigation.py +274 -0
  24. generators/helpers/page.py +63 -0
  25. generators/helpers/project.py +33 -0
  26. generators/helpers/utils.py +338 -0
  27. generators/helpers/validation.py +364 -0
  28. generators/initializator.py +68 -0
  29. generators/main.py +81 -0
  30. generators/static/assets/logo.png +0 -0
  31. generators/static/assets/mock/auth_user.json +5 -0
  32. generators/static/assets/svgs/apple.svg +4 -0
  33. generators/static/assets/svgs/google.svg +2 -0
  34. generators/static/cursor/AGENTS.md.jinja +37 -0
  35. generators/static/cursor/agents/doc-writer.md +20 -0
  36. generators/static/cursor/agents/epic-orchestrator.md +28 -0
  37. generators/static/cursor/agents/feature-implementer.md +29 -0
  38. generators/static/cursor/agents/integration-wiring.md +30 -0
  39. generators/static/cursor/agents/layer-application.md +21 -0
  40. generators/static/cursor/agents/layer-guardian.md +21 -0
  41. generators/static/cursor/agents/layer-infrastructure.md +31 -0
  42. generators/static/cursor/agents/layer-model.md +24 -0
  43. generators/static/cursor/agents/layer-presentation.md +33 -0
  44. generators/static/cursor/docs/architecture/APIS_AND_INTEGRATION.md.jinja +42 -0
  45. generators/static/cursor/docs/architecture/CARAVAGGIO_COMPONENTS.md.jinja +317 -0
  46. generators/static/cursor/docs/architecture/DDD_LAYERS.md.jinja +32 -0
  47. generators/static/cursor/docs/architecture/FILE_TEMPLATES.md.jinja +76 -0
  48. generators/static/cursor/docs/architecture/MOCK_AND_REMOTE_DATA.md.jinja +87 -0
  49. generators/static/cursor/docs/architecture/REFERENCE_IMPLEMENTATIONS.md.jinja +48 -0
  50. generators/static/cursor/docs/architecture/WIDGETS_AND_CARAVAGGIO.md.jinja +76 -0
  51. generators/static/cursor/docs/epics/README.md +17 -0
  52. generators/static/cursor/lib/domain/AGENTS.md +23 -0
  53. generators/static/cursor/lib/features/AGENTS.md +23 -0
  54. generators/static/cursor/lib/widgets/AGENTS.md +21 -0
  55. generators/static/cursor/rules/apis-layer.mdc.jinja +21 -0
  56. generators/static/cursor/rules/application-layer.mdc.jinja +12 -0
  57. generators/static/cursor/rules/architecture-core.mdc.jinja +43 -0
  58. generators/static/cursor/rules/dart-conventions.mdc.jinja +14 -0
  59. generators/static/cursor/rules/domain-layer.mdc.jinja +24 -0
  60. generators/static/cursor/rules/login-context.mdc.jinja +16 -0
  61. generators/static/cursor/rules/presentation-layer.mdc.jinja +15 -0
  62. generators/static/cursor/rules/quality-gate.mdc.jinja +14 -0
  63. generators/static/cursor/rules/ui-caravaggio.mdc.jinja +22 -0
  64. generators/static/cursor/skills/caravaggio-ui/SKILL.md +138 -0
  65. generators/static/cursor/skills/epic-delivery/SKILL.md +74 -0
  66. generators/static/cursor/skills/epic-delivery/templates/epic-status.md +14 -0
  67. generators/static/cursor/skills/epic-delivery/templates/epic.md +36 -0
  68. generators/static/templates/apis/common/constants_template.jinja +48 -0
  69. generators/static/templates/apis/common/data_source_config_template.jinja +47 -0
  70. generators/static/templates/apis/core/api_injectable_module_template.jinja +14 -0
  71. generators/static/templates/apis/interceptors/api_logger_template.jinja +135 -0
  72. generators/static/templates/apis/interceptors/auth_interceptor_template.jinja +207 -0
  73. generators/static/templates/auth/application/auth_bloc_template.jinja +36 -0
  74. generators/static/templates/auth/application/auth_event_template.jinja +7 -0
  75. generators/static/templates/auth/application/auth_state_template.jinja +8 -0
  76. generators/static/templates/auth/infrastructure/auth_facade_module_template.jinja +16 -0
  77. generators/static/templates/auth/infrastructure/auth_facade_template.jinja +288 -0
  78. generators/static/templates/auth/infrastructure/mock_auth_facade_template.jinja +106 -0
  79. generators/static/templates/auth/model/auth_failure_template.jinja +11 -0
  80. generators/static/templates/auth/model/i_auth_facade_template.jinja +24 -0
  81. generators/static/templates/auth/model/user_template.jinja +34 -0
  82. generators/static/templates/auth/model/value_objects_template.jinja +54 -0
  83. generators/static/templates/auth/presentation/login_screen_template.jinja +24 -0
  84. generators/static/templates/auth/sign_in_form/application/sign_in_form_bloc_template.jinja +139 -0
  85. generators/static/templates/auth/sign_in_form/application/sign_in_form_event_template.jinja +15 -0
  86. generators/static/templates/auth/sign_in_form/application/sign_in_form_state_template.jinja +26 -0
  87. generators/static/templates/auth/sign_in_form/presentation/apple_form_template.jinja +16 -0
  88. generators/static/templates/auth/sign_in_form/presentation/email_password_form_template_INACTIVE.jinja +94 -0
  89. generators/static/templates/auth/sign_in_form/presentation/google_form_template.jinja +15 -0
  90. generators/static/templates/auth/sign_in_form/presentation/sign_in_form_template.jinja +381 -0
  91. generators/static/templates/component/component_bloc_template.jinja +49 -0
  92. generators/static/templates/component/component_event_template.jinja +7 -0
  93. generators/static/templates/component/component_form_bloc_template.jinja +56 -0
  94. generators/static/templates/component/component_form_event_template.jinja +7 -0
  95. generators/static/templates/component/component_form_state_template.jinja +18 -0
  96. generators/static/templates/component/component_form_widget_template.jinja +130 -0
  97. generators/static/templates/component/component_list_widget_template.jinja +95 -0
  98. generators/static/templates/component/component_state_template.jinja +9 -0
  99. generators/static/templates/component/component_widget_template.jinja +113 -0
  100. generators/static/templates/core/bloc/base_form_bloc_template.jinja +32 -0
  101. generators/static/templates/core/errors/error_localizer_template.jinja +61 -0
  102. generators/static/templates/core/infrastructure/base_mapper_template.jinja +21 -0
  103. generators/static/templates/core/infrastructure/base_repository_mixin_template.jinja +78 -0
  104. generators/static/templates/core/infrastructure/firebase_injectable_module_template.jinja +11 -0
  105. generators/static/templates/core/infrastructure/firestore_helpers_template.jinja +22 -0
  106. generators/static/templates/core/infrastructure/repository_error_handler_template.jinja +44 -0
  107. generators/static/templates/core/model/common_interfaces_template.jinja +3 -0
  108. generators/static/templates/core/model/entity_template.jinja +5 -0
  109. generators/static/templates/core/model/errors_template.jinja +15 -0
  110. generators/static/templates/core/model/failures_template.jinja +97 -0
  111. generators/static/templates/core/model/value_objects_template.jinja +135 -0
  112. generators/static/templates/core/model/value_validators_template.jinja +105 -0
  113. generators/static/templates/core/presentation/app_drawer_template.jinja +52 -0
  114. generators/static/templates/core/presentation/app_widget_template.jinja +41 -0
  115. generators/static/templates/core/presentation/bottom_nav_bar_template.jinja +32 -0
  116. generators/static/templates/domain/domain_mapper_template.jinja +39 -0
  117. generators/static/templates/domain/domain_remote_service_template.jinja +46 -0
  118. generators/static/templates/domain/domain_repository_template.jinja +90 -0
  119. generators/static/templates/domain/domain_service_module_template.jinja +23 -0
  120. generators/static/templates/domain/enum_template.jinja +3 -0
  121. generators/static/templates/domain/i_domain_service_template.jinja +18 -0
  122. generators/static/templates/domain/mock_domain_service_template.jinja +73 -0
  123. generators/static/templates/feature/feature_bloc_template.jinja +104 -0
  124. generators/static/templates/feature/feature_dto_template.jinja +26 -0
  125. generators/static/templates/feature/feature_entity_template.jinja +23 -0
  126. generators/static/templates/feature/feature_event_template.jinja +20 -0
  127. generators/static/templates/feature/feature_extensions_template.jinja +25 -0
  128. generators/static/templates/feature/feature_failure_template.jinja +11 -0
  129. generators/static/templates/feature/feature_page_template.jinja +113 -0
  130. generators/static/templates/feature/feature_repository_template.jinja +112 -0
  131. generators/static/templates/feature/feature_state_template.jinja +20 -0
  132. generators/static/templates/feature/i_feature_repository_template.jinja +21 -0
  133. generators/static/templates/feature/value_object_field_template.jinja +0 -0
  134. generators/static/templates/feature/value_object_template.jinja +0 -0
  135. generators/static/templates/feature/value_validators_template.jinja +57 -0
  136. generators/static/templates/home/home_screen_template.jinja +68 -0
  137. generators/static/templates/home/presentation/home_screen_template.jinja +52 -0
  138. generators/static/templates/home/screen_template.jinja +12 -0
  139. generators/static/templates/injection_template.jinja +8 -0
  140. generators/static/templates/logging/analytics_logging_template.jinja +42 -0
  141. generators/static/templates/logging/console_template.jinja +50 -0
  142. generators/static/templates/logging/logger_injectable_module_template.jinja +24 -0
  143. generators/static/templates/logging/logger_template.jinja +118 -0
  144. generators/static/templates/main_template.jinja +43 -0
  145. generators/static/templates/page_template.jinja +29 -0
  146. generators/static/templates/router_template.jinja +26 -0
  147. generators/static/templates/splash/presentation/splash_screen_auth_template.jinja +97 -0
  148. generators/static/templates/splash/presentation/splash_screen_template.jinja +51 -0
  149. generators/static/templates/storage/storage_repository_template.jinja +80 -0
  150. generators/static/templates/user_profile/infrastructure/user_profile_dto_template.jinja +27 -0
  151. generators/static/templates/user_profile/infrastructure/user_profile_mapper_template.jinja +43 -0
  152. generators/static/templates/user_profile/infrastructure/user_profile_repository_template.jinja +82 -0
  153. generators/static/templates/user_profile/infrastructure/user_profile_service_template.jinja +27 -0
  154. generators/static/templates/user_profile/model/i_user_profile_repository_template.jinja +34 -0
  155. generators/static/templates/user_profile/model/user_profile_failure_template.jinja +11 -0
  156. generators/static/templates/user_profile/model/user_profile_template.jinja +31 -0
  157. generators/static/templates/widgets/common/custom_scaffold_template.jinja +52 -0
  158. generators/static/templates/widgets/common/error_widget_template.jinja +22 -0
  159. generators/static/templates/widgets/common/loading_widget_template.jinja +14 -0
  160. generators/static/templates/widgets/common/unknown_state_widget_template.jinja +23 -0
  161. generators/templates/__init__.py +1 -0
  162. generators/templates/_core/core_generator.py +121 -0
  163. generators/templates/apis/apis_generator.py +50 -0
  164. generators/templates/auth/auth_generator.py +40 -0
  165. generators/templates/auth/sign_in_form_generator.py +22 -0
  166. generators/templates/copier.py +51 -0
  167. generators/templates/home/home_generator.py +26 -0
  168. generators/templates/lib/lib_generator.py +40 -0
  169. generators/templates/logging/logging_generator.py +28 -0
  170. generators/templates/main.py +75 -0
  171. generators/templates/splash/splash_generator.py +20 -0
  172. generators/templates/storage/storage_generator.py +5 -0
@@ -0,0 +1,274 @@
1
+ """Navigation functions (drawer and bottom navigation)"""
2
+
3
+ import click
4
+ from pathlib import Path
5
+ from generators.templates.copier import generate_file
6
+ from .project import get_project_name
7
+ from .page import generate_page_file, update_router
8
+
9
+
10
+ def create_drawer_page(project_dir: Path, drawer_item_name: str, project_name: str) -> None:
11
+ """Create a page for the drawer item"""
12
+ lib_path = project_dir / "lib"
13
+
14
+ # Create page directory structure
15
+ page_dir = lib_path / drawer_item_name
16
+ page_dir.mkdir(exist_ok=True)
17
+
18
+ # Create presentation layer
19
+ presentation_dir = page_dir / "presentation"
20
+ presentation_dir.mkdir(exist_ok=True)
21
+
22
+ # Generate page file
23
+ generate_page_file(drawer_item_name, presentation_dir, project_name)
24
+
25
+ # Update router
26
+ update_router(project_dir, drawer_item_name, project_name)
27
+
28
+
29
+ def update_home_page_with_drawer(project_dir: Path, project_name: str) -> None:
30
+ """Update the home screen to include a drawer"""
31
+ home_page_path = project_dir / "lib" / "features" / "home" / "home_page.dart"
32
+
33
+ if not home_page_path.exists():
34
+ click.echo("⚠️ Home screen not found, creating basic drawer implementation")
35
+ return
36
+
37
+ content = home_page_path.read_text()
38
+
39
+ # Check if drawer is already implemented
40
+ if "drawer:" in content:
41
+ click.echo("ℹ️ Drawer already exists in home screen")
42
+ return
43
+
44
+ # Add drawer import if not present
45
+ drawer_import = f"import 'package:{project_name}/core/presentation/app_drawer.dart';"
46
+ if drawer_import not in content:
47
+ # Add import after existing imports
48
+ lines = content.split('\n')
49
+ insert_index = 0
50
+ for i, line in enumerate(lines):
51
+ if line.startswith('import'):
52
+ insert_index = i + 1
53
+ elif line.strip() and not line.startswith('//'):
54
+ break
55
+
56
+ lines.insert(insert_index, drawer_import)
57
+ content = '\n'.join(lines)
58
+
59
+ # Modify the Scaffold to include drawer
60
+ if "return const Scaffold(" in content:
61
+ content = content.replace(
62
+ "return const Scaffold(",
63
+ "return Scaffold(\n drawer: const AppDrawer(),"
64
+ )
65
+ elif "return Scaffold(" in content:
66
+ if "drawer:" not in content:
67
+ content = content.replace(
68
+ "return Scaffold(",
69
+ "return Scaffold(\n drawer: const AppDrawer(),"
70
+ )
71
+
72
+ home_page_path.write_text(content)
73
+
74
+
75
+ def create_drawer_widget(project_dir: Path, drawer_item_name: str, project_name: str) -> None:
76
+ """Create or update the drawer widget using Jinja template"""
77
+ core_presentation_dir = project_dir / "lib" / "core" / "presentation"
78
+ core_presentation_dir.mkdir(parents=True, exist_ok=True)
79
+
80
+ drawer_path = core_presentation_dir / "app_drawer.dart"
81
+
82
+ # Get all drawer items
83
+ drawer_items = []
84
+
85
+ if drawer_path.exists():
86
+ content = drawer_path.read_text()
87
+ lines = content.split('\n')
88
+
89
+ for line in lines:
90
+ if f'package:{project_name}/' in line and '_page.dart' in line:
91
+ import_match = line.strip()
92
+ if import_match.startswith("import 'package:") and import_match.endswith("_page.dart';"):
93
+ start = import_match.find(f'package:{project_name}/') + len(f'package:{project_name}/')
94
+ end = import_match.find('/presentation/', start)
95
+ if start != -1 and end != -1:
96
+ existing_item = import_match[start:end]
97
+ if existing_item != 'home':
98
+ drawer_items.append({"name": existing_item})
99
+
100
+ if not any(item["name"] == drawer_item_name for item in drawer_items):
101
+ drawer_items.append({"name": drawer_item_name})
102
+
103
+ generate_file(project_name, core_presentation_dir, "core/presentation/app_drawer_template.jinja", "app_drawer.dart", {
104
+ "project_name": project_name,
105
+ "drawer_items": drawer_items
106
+ })
107
+
108
+
109
+ def update_router_for_drawer_item(project_dir: Path, drawer_item_name: str) -> None:
110
+ """Update router to include the drawer item route if needed"""
111
+ router_path = project_dir / "lib" / "router.dart"
112
+
113
+ if not router_path.exists():
114
+ click.echo("⚠️ router.dart not found, skipping router update")
115
+ return
116
+
117
+ content = router_path.read_text()
118
+
119
+ route_pattern = f"path: '/{drawer_item_name}'"
120
+ if route_pattern in content:
121
+ click.echo("ℹ️ Route already exists in router")
122
+ return
123
+
124
+ route_line = f"""GoRoute(
125
+ path: '/{drawer_item_name}',
126
+ builder: (BuildContext context, GoRouterState state) => const Placeholder(),
127
+ ),"""
128
+
129
+ if route_line not in content:
130
+ if 'routes: <RouteBase>[' in content:
131
+ content = content.replace(' ],', f' {route_line}\n ],')
132
+ elif 'routes: [' in content:
133
+ content = content.replace(' ],', f' {route_line}\n ],')
134
+ else:
135
+ click.echo("⚠️ Could not find routes list in router.dart")
136
+
137
+ router_path.write_text(content)
138
+
139
+
140
+ def create_bottom_nav_page(project_dir: Path, bottom_nav_item_name: str) -> None:
141
+ """Create a screen for the bottom nav item in features/home using Jinja template"""
142
+ home_dir = project_dir / "lib" / "features" / "home"
143
+ home_dir.mkdir(parents=True, exist_ok=True)
144
+
145
+ project_name = get_project_name(project_dir)
146
+
147
+ generate_file(project_name, home_dir, "home/screen_template.jinja", f"{bottom_nav_item_name}_screen.dart", {
148
+ "screen_name": bottom_nav_item_name.capitalize(),
149
+ "screen_title": bottom_nav_item_name.replace("_", " ").capitalize()
150
+ })
151
+
152
+
153
+ def update_home_page_with_bottom_nav(project_dir: Path, bottom_nav_item_name: str, project_name: str) -> None:
154
+ """Update the home screen to include bottom navigation"""
155
+ home_page_path = project_dir / "lib" / "features" / "home" / "home_page.dart"
156
+
157
+ if not home_page_path.exists():
158
+ click.echo("⚠️ Home screen not found, creating basic bottom nav implementation")
159
+ return
160
+
161
+ content = home_page_path.read_text()
162
+
163
+ if "BottomNavigationBar" in content or "BottomNavBar" in content:
164
+ class_name = bottom_nav_item_name.capitalize() + 'Screen'
165
+
166
+ screen_import = f"import 'package:{project_name}/features/home/{bottom_nav_item_name}_screen.dart';"
167
+ if screen_import not in content:
168
+ lines = content.split('\n')
169
+ insert_index = 0
170
+ for i, line in enumerate(lines):
171
+ if line.startswith('import'):
172
+ insert_index = i + 1
173
+ elif line.strip() and not line.startswith('//'):
174
+ break
175
+
176
+ lines.insert(insert_index, screen_import)
177
+ content = '\n'.join(lines)
178
+
179
+ lines = content.split('\n')
180
+ pages_list_start = -1
181
+ for i, line in enumerate(lines):
182
+ if 'final List<Widget> _pages = [' in line or '_pages = [' in line:
183
+ pages_list_start = i
184
+ break
185
+
186
+ if pages_list_start != -1:
187
+ bracket_count = 0
188
+ for j in range(pages_list_start, len(lines)):
189
+ bracket_count += lines[j].count('[')
190
+ bracket_count -= lines[j].count(']')
191
+ if bracket_count == 0 and '];' in lines[j]:
192
+ lines.insert(j, f' const {class_name}(),')
193
+ break
194
+
195
+ content = '\n'.join(lines)
196
+ else:
197
+ capitalized_name = bottom_nav_item_name.replace('_', ' ').title()
198
+ class_name = bottom_nav_item_name.capitalize() + 'Screen'
199
+
200
+ existing_content = home_page_path.read_text()
201
+ has_drawer = "drawer:" in existing_content
202
+ drawer_import_needed = "import 'package:" + project_name + "/core/presentation/app_drawer.dart';" in existing_content
203
+
204
+ imports = f"""import 'package:flutter/material.dart';
205
+ import 'package:{project_name}/core/presentation/bottom_nav_bar.dart';
206
+ import 'package:{project_name}/features/home/{bottom_nav_item_name}_screen.dart';"""
207
+
208
+ if drawer_import_needed:
209
+ imports += f"\nimport 'package:{project_name}/core/presentation/app_drawer.dart';"
210
+
211
+ drawer_line = ""
212
+ if has_drawer:
213
+ drawer_line = " drawer: const AppDrawer(),"
214
+
215
+ content = f"""{imports}
216
+
217
+ class HomePage extends StatefulWidget {{
218
+ static const String routeName = '/home';
219
+
220
+ const HomePage({{super.key}});
221
+
222
+ @override
223
+ State<HomePage> createState() => _HomePageState();
224
+ }}
225
+
226
+ class _HomePageState extends State<HomePage> {{
227
+ int _selectedIndex = 0;
228
+
229
+ final List<Widget> _pages = [
230
+ const Center(child: Text('Home Content')),
231
+ const {class_name}(),
232
+ ];
233
+
234
+ void _onItemTapped(int index) {{
235
+ setState(() {{
236
+ _selectedIndex = index;
237
+ }});
238
+ }}
239
+
240
+ @override
241
+ Widget build(BuildContext context) {{
242
+ return Scaffold(
243
+ appBar: AppBar(
244
+ title: const Text('Home'),
245
+ ),
246
+ {drawer_line}
247
+ body: _pages[_selectedIndex],
248
+ bottomNavigationBar: BottomNavBar(
249
+ currentIndex: _selectedIndex,
250
+ onTap: _onItemTapped,
251
+ ),
252
+ );
253
+ }}
254
+ }}
255
+ """
256
+
257
+ home_page_path.write_text(content)
258
+
259
+
260
+ def create_bottom_nav_widget(project_dir: Path, bottom_nav_item_name: str) -> None:
261
+ """Create or update the bottom navigation widget using Jinja template"""
262
+ core_presentation_dir = project_dir / "lib" / "core" / "presentation"
263
+ core_presentation_dir.mkdir(parents=True, exist_ok=True)
264
+
265
+ bottom_nav_path = core_presentation_dir / "bottom_nav_bar.dart"
266
+
267
+ project_name = project_dir.name
268
+
269
+ nav_items = [{"name": bottom_nav_item_name}]
270
+
271
+ generate_file(project_name, core_presentation_dir, "core/presentation/bottom_nav_bar_template.jinja", "bottom_nav_bar.dart", {
272
+ "nav_items": nav_items
273
+ })
274
+
@@ -0,0 +1,63 @@
1
+ """Page generation functions"""
2
+
3
+ import click
4
+ from pathlib import Path
5
+ from typing import Optional
6
+ from generators.templates.copier import generate_file
7
+
8
+
9
+ def generate_page_file(page_name: str, presentation_dir: Path, project_name: str) -> None:
10
+ """Generate a basic page file using Jinja template"""
11
+ generate_file(project_name, presentation_dir, "page_template.jinja", f"{page_name}_page.dart", {
12
+ "page_name": page_name
13
+ })
14
+
15
+
16
+ def update_router(project_dir: Path, page_name: str, project_name: str, folder: Optional[str] = None) -> None:
17
+ """Update the router.dart file to include the new page"""
18
+ router_path = project_dir / "lib" / "router.dart"
19
+ if not router_path.exists():
20
+ click.echo("⚠️ router.dart not found, skipping router update")
21
+ return
22
+
23
+ # Build the import path prefix
24
+ if folder:
25
+ import_prefix = f"{folder.replace('/', '/')}/{page_name}"
26
+ else:
27
+ import_prefix = page_name
28
+
29
+ # Read current router
30
+ content = router_path.read_text()
31
+
32
+ # Add import
33
+ import_line = f"import 'package:{project_name}/{import_prefix}/{page_name}_page.dart';"
34
+ if import_line not in content:
35
+ # Find where to insert import (after other imports)
36
+ lines = content.split('\n')
37
+ insert_index = 0
38
+ for i, line in enumerate(lines):
39
+ if line.startswith('import'):
40
+ insert_index = i + 1
41
+ elif line.strip() and not line.startswith('//'):
42
+ break
43
+
44
+ lines.insert(insert_index, import_line)
45
+ content = '\n'.join(lines)
46
+
47
+ # Add route
48
+ route_line = f"""GoRoute(
49
+ path: {page_name.capitalize()}Page.routeName,
50
+ builder: (BuildContext context, GoRouterState state) => const {page_name.capitalize()}Page(),
51
+ ),"""
52
+ if route_line not in content:
53
+ # Find routes list and add the new route before the closing bracket
54
+ if 'routes: <RouteBase>[' in content:
55
+ # Replace the closing bracket with the new route + closing bracket
56
+ content = content.replace(' ],', f' {route_line}\n ],')
57
+ elif 'routes: [' in content:
58
+ content = content.replace(' ],', f' {route_line}\n ],')
59
+ else:
60
+ click.echo("⚠️ Could not find routes list in router.dart")
61
+
62
+ router_path.write_text(content)
63
+
@@ -0,0 +1,33 @@
1
+ """Project validation and utility functions"""
2
+
3
+ import sys
4
+ from pathlib import Path
5
+ from rich.console import Console
6
+
7
+ console = Console()
8
+
9
+
10
+ def get_project_name(project_dir: Path) -> str:
11
+ """Extract project name from pubspec.yaml"""
12
+ pubspec_path = project_dir / "pubspec.yaml"
13
+ if pubspec_path.exists():
14
+ with open(pubspec_path, 'r') as f:
15
+ for line in f:
16
+ if line.strip().startswith('name:'):
17
+ return line.split(':', 1)[1].strip().strip('"').strip("'")
18
+ return project_dir.name
19
+
20
+
21
+ def validate_flutter_project(project_dir: Path) -> tuple[Path, str]:
22
+ """Validate Flutter project and return lib_path and project_name"""
23
+ if not (project_dir / "pubspec.yaml").exists():
24
+ console.print("[bold red]❌ Not a valid Flutter project. pubspec.yaml not found.[/bold red]")
25
+ sys.exit(1)
26
+
27
+ lib_path = project_dir / "lib"
28
+ if not lib_path.exists():
29
+ console.print("[bold red]❌ lib directory not found.[/bold red]")
30
+ sys.exit(1)
31
+
32
+ return lib_path, get_project_name(project_dir)
33
+