@corbat-tech/coding-standards-mcp 1.0.3 → 2.0.0
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.
- package/README.md +233 -337
- package/dist/agent.d.ts +5 -6
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +95 -217
- package/dist/agent.js.map +1 -1
- package/dist/analysis/code-analyzer.d.ts +44 -0
- package/dist/analysis/code-analyzer.d.ts.map +1 -0
- package/dist/analysis/code-analyzer.js +528 -0
- package/dist/analysis/code-analyzer.js.map +1 -0
- package/dist/errors.d.ts +58 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +112 -0
- package/dist/errors.js.map +1 -0
- package/dist/guardrails.d.ts +35 -0
- package/dist/guardrails.d.ts.map +1 -0
- package/dist/guardrails.js +303 -0
- package/dist/guardrails.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +36 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +63 -0
- package/dist/logger.js.map +1 -0
- package/dist/metrics.d.ts +40 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +97 -0
- package/dist/metrics.js.map +1 -0
- package/dist/profiles.d.ts +1 -1
- package/dist/profiles.d.ts.map +1 -1
- package/dist/profiles.js +239 -108
- package/dist/profiles.js.map +1 -1
- package/dist/prompts.js +1 -1
- package/dist/prompts.js.map +1 -1
- package/dist/tools/definitions.d.ts +143 -0
- package/dist/tools/definitions.d.ts.map +1 -0
- package/dist/tools/definitions.js +229 -0
- package/dist/tools/definitions.js.map +1 -0
- package/dist/tools/handlers/get-context.d.ts +12 -0
- package/dist/tools/handlers/get-context.d.ts.map +1 -0
- package/dist/tools/handlers/get-context.js +233 -0
- package/dist/tools/handlers/get-context.js.map +1 -0
- package/dist/tools/handlers/health.d.ts +11 -0
- package/dist/tools/handlers/health.d.ts.map +1 -0
- package/dist/tools/handlers/health.js +57 -0
- package/dist/tools/handlers/health.js.map +1 -0
- package/dist/tools/handlers/index.d.ts +12 -0
- package/dist/tools/handlers/index.d.ts.map +1 -0
- package/dist/tools/handlers/index.js +12 -0
- package/dist/tools/handlers/index.js.map +1 -0
- package/dist/tools/handlers/init.d.ts +12 -0
- package/dist/tools/handlers/init.d.ts.map +1 -0
- package/dist/tools/handlers/init.js +102 -0
- package/dist/tools/handlers/init.js.map +1 -0
- package/dist/tools/handlers/profiles.d.ts +11 -0
- package/dist/tools/handlers/profiles.d.ts.map +1 -0
- package/dist/tools/handlers/profiles.js +25 -0
- package/dist/tools/handlers/profiles.js.map +1 -0
- package/dist/tools/handlers/search.d.ts +12 -0
- package/dist/tools/handlers/search.d.ts.map +1 -0
- package/dist/tools/handlers/search.js +58 -0
- package/dist/tools/handlers/search.js.map +1 -0
- package/dist/tools/handlers/validate.d.ts +15 -0
- package/dist/tools/handlers/validate.d.ts.map +1 -0
- package/dist/tools/handlers/validate.js +71 -0
- package/dist/tools/handlers/validate.js.map +1 -0
- package/dist/tools/handlers/verify.d.ts +38 -0
- package/dist/tools/handlers/verify.d.ts.map +1 -0
- package/dist/tools/handlers/verify.js +172 -0
- package/dist/tools/handlers/verify.js.map +1 -0
- package/dist/tools/index.d.ts +22 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +75 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/schemas.d.ts +29 -0
- package/dist/tools/schemas.d.ts.map +1 -0
- package/dist/tools/schemas.js +20 -0
- package/dist/tools/schemas.js.map +1 -0
- package/dist/tools.js +2 -2
- package/dist/tools.js.map +1 -1
- package/dist/types.d.ts +141 -71
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +92 -40
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
- package/profiles/examples/microservice-kafka.yaml +122 -0
- package/profiles/examples/startup-fast.yaml +67 -0
- package/profiles/examples/strict-enterprise.yaml +62 -0
- package/profiles/templates/angular.yaml +614 -0
- package/profiles/templates/csharp-dotnet.yaml +529 -0
- package/profiles/templates/flutter.yaml +547 -0
- package/profiles/templates/go.yaml +1276 -0
- package/profiles/templates/java-spring-backend.yaml +326 -0
- package/profiles/templates/kotlin-spring.yaml +417 -0
- package/profiles/templates/nextjs.yaml +536 -0
- package/profiles/templates/nodejs.yaml +594 -0
- package/profiles/templates/python.yaml +546 -0
- package/profiles/templates/react.yaml +456 -0
- package/profiles/templates/rust.yaml +508 -0
- package/profiles/templates/vue.yaml +483 -0
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
# ============================================================================
|
|
2
|
+
# CORBAT MCP - Flutter/Dart Profile
|
|
3
|
+
# ============================================================================
|
|
4
|
+
# Production-ready standards for Flutter cross-platform applications.
|
|
5
|
+
# Based on Flutter best practices, Dart style guide, and clean architecture.
|
|
6
|
+
# ============================================================================
|
|
7
|
+
|
|
8
|
+
name: "Flutter Dart Standards"
|
|
9
|
+
description: "Production-ready standards for Flutter apps with clean architecture, state management, and comprehensive testing"
|
|
10
|
+
|
|
11
|
+
# ----------------------------------------------------------------------------
|
|
12
|
+
# ARCHITECTURE
|
|
13
|
+
# ----------------------------------------------------------------------------
|
|
14
|
+
architecture:
|
|
15
|
+
type: clean
|
|
16
|
+
enforceLayerDependencies: true
|
|
17
|
+
layers:
|
|
18
|
+
- name: domain
|
|
19
|
+
description: "Core business logic. Pure Dart with no Flutter dependencies. Contains entities, use cases, and repository interfaces."
|
|
20
|
+
allowedDependencies: []
|
|
21
|
+
directories:
|
|
22
|
+
- "lib/domain"
|
|
23
|
+
- "lib/domain/entities"
|
|
24
|
+
- "lib/domain/repositories"
|
|
25
|
+
- "lib/domain/usecases"
|
|
26
|
+
- "lib/domain/failures"
|
|
27
|
+
|
|
28
|
+
- name: data
|
|
29
|
+
description: "Data layer. Implements repositories, data sources, and models."
|
|
30
|
+
allowedDependencies:
|
|
31
|
+
- domain
|
|
32
|
+
directories:
|
|
33
|
+
- "lib/data"
|
|
34
|
+
- "lib/data/repositories"
|
|
35
|
+
- "lib/data/datasources"
|
|
36
|
+
- "lib/data/models"
|
|
37
|
+
|
|
38
|
+
- name: presentation
|
|
39
|
+
description: "UI layer. Contains widgets, pages, and state management."
|
|
40
|
+
allowedDependencies:
|
|
41
|
+
- domain
|
|
42
|
+
directories:
|
|
43
|
+
- "lib/presentation"
|
|
44
|
+
- "lib/presentation/pages"
|
|
45
|
+
- "lib/presentation/widgets"
|
|
46
|
+
- "lib/presentation/bloc"
|
|
47
|
+
- "lib/presentation/providers"
|
|
48
|
+
|
|
49
|
+
# ----------------------------------------------------------------------------
|
|
50
|
+
# DART FEATURES
|
|
51
|
+
# ----------------------------------------------------------------------------
|
|
52
|
+
dartFeatures:
|
|
53
|
+
version: "3.0+"
|
|
54
|
+
|
|
55
|
+
nullSafety:
|
|
56
|
+
enabled: true
|
|
57
|
+
soundNullSafety: true
|
|
58
|
+
avoidLateUnnecessarily: true
|
|
59
|
+
useNullableTypes: true
|
|
60
|
+
examples:
|
|
61
|
+
- "Use ? for nullable types"
|
|
62
|
+
- "Use ! only when certain"
|
|
63
|
+
- "Prefer ?? for default values"
|
|
64
|
+
- "Use ?. for null-safe access"
|
|
65
|
+
|
|
66
|
+
records:
|
|
67
|
+
enabled: true
|
|
68
|
+
useForMultipleReturns: true
|
|
69
|
+
useForDTOs: true
|
|
70
|
+
example: "(String name, int age) getPerson() => ('John', 30);"
|
|
71
|
+
|
|
72
|
+
patterns:
|
|
73
|
+
enabled: true
|
|
74
|
+
switchExpressions: true
|
|
75
|
+
destructuring: true
|
|
76
|
+
guards: true
|
|
77
|
+
example: |
|
|
78
|
+
String describe(Object obj) => switch (obj) {
|
|
79
|
+
int n when n < 0 => 'negative',
|
|
80
|
+
int n => 'positive: $n',
|
|
81
|
+
String s => 'string: $s',
|
|
82
|
+
_ => 'unknown',
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
extensionTypes:
|
|
86
|
+
enabled: true
|
|
87
|
+
useForTypeAliases: true
|
|
88
|
+
|
|
89
|
+
sealed:
|
|
90
|
+
useForStates: true
|
|
91
|
+
useForEvents: true
|
|
92
|
+
example: |
|
|
93
|
+
sealed class AuthState {}
|
|
94
|
+
class AuthInitial extends AuthState {}
|
|
95
|
+
class AuthLoading extends AuthState {}
|
|
96
|
+
class AuthSuccess extends AuthState {
|
|
97
|
+
final User user;
|
|
98
|
+
AuthSuccess(this.user);
|
|
99
|
+
}
|
|
100
|
+
class AuthFailure extends AuthState {
|
|
101
|
+
final String message;
|
|
102
|
+
AuthFailure(this.message);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
# ----------------------------------------------------------------------------
|
|
106
|
+
# STATE MANAGEMENT
|
|
107
|
+
# ----------------------------------------------------------------------------
|
|
108
|
+
stateManagement:
|
|
109
|
+
preferred:
|
|
110
|
+
- name: "Riverpod"
|
|
111
|
+
version: "2.x"
|
|
112
|
+
useCase: "Recommended for most apps"
|
|
113
|
+
- name: "BLoC"
|
|
114
|
+
version: "8.x"
|
|
115
|
+
useCase: "Enterprise apps, strict separation"
|
|
116
|
+
|
|
117
|
+
riverpod:
|
|
118
|
+
enabled: true
|
|
119
|
+
patterns:
|
|
120
|
+
providers: true
|
|
121
|
+
stateNotifier: true
|
|
122
|
+
asyncNotifier: true
|
|
123
|
+
codeGeneration: true
|
|
124
|
+
example: |
|
|
125
|
+
@riverpod
|
|
126
|
+
class OrderNotifier extends _$OrderNotifier {
|
|
127
|
+
@override
|
|
128
|
+
FutureOr<List<Order>> build() async {
|
|
129
|
+
return ref.watch(orderRepositoryProvider).getOrders();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
Future<void> addOrder(Order order) async {
|
|
133
|
+
state = const AsyncLoading();
|
|
134
|
+
state = await AsyncValue.guard(() async {
|
|
135
|
+
await ref.read(orderRepositoryProvider).addOrder(order);
|
|
136
|
+
return ref.read(orderRepositoryProvider).getOrders();
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
bloc:
|
|
142
|
+
enabled: true
|
|
143
|
+
patterns:
|
|
144
|
+
events: true
|
|
145
|
+
states: true
|
|
146
|
+
cubits: true
|
|
147
|
+
freezed: true
|
|
148
|
+
example: |
|
|
149
|
+
@freezed
|
|
150
|
+
class OrderEvent with _$OrderEvent {
|
|
151
|
+
const factory OrderEvent.loadOrders() = LoadOrders;
|
|
152
|
+
const factory OrderEvent.addOrder(Order order) = AddOrder;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
@freezed
|
|
156
|
+
class OrderState with _$OrderState {
|
|
157
|
+
const factory OrderState.initial() = OrderInitial;
|
|
158
|
+
const factory OrderState.loading() = OrderLoading;
|
|
159
|
+
const factory OrderState.loaded(List<Order> orders) = OrderLoaded;
|
|
160
|
+
const factory OrderState.error(String message) = OrderError;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
# ----------------------------------------------------------------------------
|
|
164
|
+
# WIDGET PATTERNS
|
|
165
|
+
# ----------------------------------------------------------------------------
|
|
166
|
+
widgets:
|
|
167
|
+
principles:
|
|
168
|
+
composition: true
|
|
169
|
+
singleResponsibility: true
|
|
170
|
+
extractWidgets: true
|
|
171
|
+
constConstructors: true
|
|
172
|
+
|
|
173
|
+
structure:
|
|
174
|
+
maxBuildMethodLines: 50
|
|
175
|
+
extractLargeWidgets: true
|
|
176
|
+
usePrivateWidgets: true
|
|
177
|
+
example: |
|
|
178
|
+
class OrderListPage extends StatelessWidget {
|
|
179
|
+
const OrderListPage({super.key});
|
|
180
|
+
|
|
181
|
+
@override
|
|
182
|
+
Widget build(BuildContext context) {
|
|
183
|
+
return Scaffold(
|
|
184
|
+
appBar: const _OrderAppBar(),
|
|
185
|
+
body: const _OrderList(),
|
|
186
|
+
floatingActionButton: const _AddOrderFab(),
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
performance:
|
|
192
|
+
useConstConstructors: true
|
|
193
|
+
useConstWidgets: true
|
|
194
|
+
avoidRebuildingExpensiveWidgets: true
|
|
195
|
+
useSelectorsWithRiverpod: true
|
|
196
|
+
useBuilderWidgets: true
|
|
197
|
+
|
|
198
|
+
accessibility:
|
|
199
|
+
semanticsLabels: true
|
|
200
|
+
excludeSemantics: "when appropriate"
|
|
201
|
+
largeTextSupport: true
|
|
202
|
+
screenReaderSupport: true
|
|
203
|
+
|
|
204
|
+
# ----------------------------------------------------------------------------
|
|
205
|
+
# CODE QUALITY
|
|
206
|
+
# ----------------------------------------------------------------------------
|
|
207
|
+
codeQuality:
|
|
208
|
+
maxMethodLines: 30
|
|
209
|
+
maxClassLines: 200
|
|
210
|
+
maxFileLines: 400
|
|
211
|
+
maxMethodParameters: 4
|
|
212
|
+
maxCyclomaticComplexity: 10
|
|
213
|
+
requireDocumentation: true
|
|
214
|
+
requireTests: true
|
|
215
|
+
minimumTestCoverage: 70
|
|
216
|
+
|
|
217
|
+
principles:
|
|
218
|
+
- "Composition over inheritance"
|
|
219
|
+
- "Single responsibility for widgets"
|
|
220
|
+
- "Keep build methods small"
|
|
221
|
+
- "Use const constructors"
|
|
222
|
+
- "Prefer immutable state"
|
|
223
|
+
- "Separate business logic from UI"
|
|
224
|
+
|
|
225
|
+
linting:
|
|
226
|
+
package: "flutter_lints"
|
|
227
|
+
customRules:
|
|
228
|
+
- "prefer_const_constructors"
|
|
229
|
+
- "prefer_const_declarations"
|
|
230
|
+
- "avoid_print"
|
|
231
|
+
- "prefer_final_locals"
|
|
232
|
+
- "sort_constructors_first"
|
|
233
|
+
- "always_declare_return_types"
|
|
234
|
+
|
|
235
|
+
analysisOptions:
|
|
236
|
+
strictMode: true
|
|
237
|
+
example: |
|
|
238
|
+
analyzer:
|
|
239
|
+
language:
|
|
240
|
+
strict-casts: true
|
|
241
|
+
strict-inference: true
|
|
242
|
+
strict-raw-types: true
|
|
243
|
+
errors:
|
|
244
|
+
missing_return: error
|
|
245
|
+
dead_code: warning
|
|
246
|
+
|
|
247
|
+
# ----------------------------------------------------------------------------
|
|
248
|
+
# NAMING CONVENTIONS
|
|
249
|
+
# ----------------------------------------------------------------------------
|
|
250
|
+
naming:
|
|
251
|
+
general:
|
|
252
|
+
class: PascalCase
|
|
253
|
+
extension: PascalCase
|
|
254
|
+
mixin: PascalCase
|
|
255
|
+
function: camelCase
|
|
256
|
+
variable: camelCase
|
|
257
|
+
constant: camelCase
|
|
258
|
+
file: snake_case.dart
|
|
259
|
+
directory: snake_case
|
|
260
|
+
privateField: _camelCase
|
|
261
|
+
|
|
262
|
+
suffixes:
|
|
263
|
+
page: "Page"
|
|
264
|
+
widget: "Widget (optional)"
|
|
265
|
+
bloc: "Bloc"
|
|
266
|
+
cubit: "Cubit"
|
|
267
|
+
event: "Event"
|
|
268
|
+
state: "State"
|
|
269
|
+
provider: "Provider"
|
|
270
|
+
repository: "Repository"
|
|
271
|
+
dataSource: "DataSource"
|
|
272
|
+
model: "Model"
|
|
273
|
+
entity: "Entity"
|
|
274
|
+
useCase: "UseCase"
|
|
275
|
+
|
|
276
|
+
testing:
|
|
277
|
+
testFile: "*_test.dart"
|
|
278
|
+
testFunction: "should verb when condition"
|
|
279
|
+
group: "feature or class name"
|
|
280
|
+
|
|
281
|
+
# ----------------------------------------------------------------------------
|
|
282
|
+
# TESTING
|
|
283
|
+
# ----------------------------------------------------------------------------
|
|
284
|
+
testing:
|
|
285
|
+
framework: "flutter_test"
|
|
286
|
+
mockingLibrary: "mocktail"
|
|
287
|
+
goldenTesting: "golden_toolkit"
|
|
288
|
+
|
|
289
|
+
types:
|
|
290
|
+
unit:
|
|
291
|
+
location: "test/unit"
|
|
292
|
+
coverage: 80
|
|
293
|
+
patterns:
|
|
294
|
+
- "Given-When-Then"
|
|
295
|
+
- "Arrange-Act-Assert"
|
|
296
|
+
|
|
297
|
+
widget:
|
|
298
|
+
location: "test/widget"
|
|
299
|
+
coverage: 70
|
|
300
|
+
patterns:
|
|
301
|
+
- "pumpWidget"
|
|
302
|
+
- "find helpers"
|
|
303
|
+
- "expect matchers"
|
|
304
|
+
example: |
|
|
305
|
+
testWidgets('should display order list', (tester) async {
|
|
306
|
+
await tester.pumpWidget(
|
|
307
|
+
ProviderScope(
|
|
308
|
+
overrides: [orderProvider.overrideWith(() => mockNotifier)],
|
|
309
|
+
child: const MaterialApp(home: OrderListPage()),
|
|
310
|
+
),
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
expect(find.byType(OrderCard), findsNWidgets(3));
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
integration:
|
|
317
|
+
location: "integration_test"
|
|
318
|
+
patterns:
|
|
319
|
+
- "Integration test driver"
|
|
320
|
+
- "Full app testing"
|
|
321
|
+
|
|
322
|
+
golden:
|
|
323
|
+
enabled: true
|
|
324
|
+
location: "test/golden"
|
|
325
|
+
example: |
|
|
326
|
+
testGoldens('OrderCard should match golden', (tester) async {
|
|
327
|
+
await tester.pumpWidgetBuilder(
|
|
328
|
+
const OrderCard(order: mockOrder),
|
|
329
|
+
surfaceSize: const Size(400, 200),
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
await screenMatchesGolden(tester, 'order_card');
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
patterns:
|
|
336
|
+
mocktail: true
|
|
337
|
+
freezed: true
|
|
338
|
+
fixtures: true
|
|
339
|
+
example: |
|
|
340
|
+
@GenerateMocks([OrderRepository])
|
|
341
|
+
void main() {
|
|
342
|
+
late MockOrderRepository mockRepository;
|
|
343
|
+
late GetOrdersUseCase useCase;
|
|
344
|
+
|
|
345
|
+
setUp(() {
|
|
346
|
+
mockRepository = MockOrderRepository();
|
|
347
|
+
useCase = GetOrdersUseCase(mockRepository);
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
test('should return orders when repository succeeds', () async {
|
|
351
|
+
when(() => mockRepository.getOrders())
|
|
352
|
+
.thenAnswer((_) async => [testOrder]);
|
|
353
|
+
|
|
354
|
+
final result = await useCase();
|
|
355
|
+
|
|
356
|
+
expect(result, isA<Right<Failure, List<Order>>>());
|
|
357
|
+
verify(() => mockRepository.getOrders()).called(1);
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
# ----------------------------------------------------------------------------
|
|
362
|
+
# NAVIGATION
|
|
363
|
+
# ----------------------------------------------------------------------------
|
|
364
|
+
navigation:
|
|
365
|
+
preferred: "go_router"
|
|
366
|
+
|
|
367
|
+
patterns:
|
|
368
|
+
declarativeRouting: true
|
|
369
|
+
deepLinking: true
|
|
370
|
+
guards: true
|
|
371
|
+
shellRoutes: true
|
|
372
|
+
example: |
|
|
373
|
+
final router = GoRouter(
|
|
374
|
+
routes: [
|
|
375
|
+
GoRoute(
|
|
376
|
+
path: '/',
|
|
377
|
+
builder: (context, state) => const HomePage(),
|
|
378
|
+
routes: [
|
|
379
|
+
GoRoute(
|
|
380
|
+
path: 'orders/:id',
|
|
381
|
+
builder: (context, state) => OrderDetailPage(
|
|
382
|
+
orderId: state.pathParameters['id']!,
|
|
383
|
+
),
|
|
384
|
+
),
|
|
385
|
+
],
|
|
386
|
+
),
|
|
387
|
+
],
|
|
388
|
+
redirect: (context, state) {
|
|
389
|
+
final isLoggedIn = ref.read(authProvider).isLoggedIn;
|
|
390
|
+
if (!isLoggedIn && !state.matchedLocation.startsWith('/login')) {
|
|
391
|
+
return '/login';
|
|
392
|
+
}
|
|
393
|
+
return null;
|
|
394
|
+
},
|
|
395
|
+
);
|
|
396
|
+
|
|
397
|
+
# ----------------------------------------------------------------------------
|
|
398
|
+
# DEPENDENCY INJECTION
|
|
399
|
+
# ----------------------------------------------------------------------------
|
|
400
|
+
dependencyInjection:
|
|
401
|
+
preferred: "Riverpod"
|
|
402
|
+
alternatives:
|
|
403
|
+
- "get_it"
|
|
404
|
+
- "Injectable"
|
|
405
|
+
|
|
406
|
+
patterns:
|
|
407
|
+
providerScope: true
|
|
408
|
+
repositoryProviders: true
|
|
409
|
+
useCaseProviders: true
|
|
410
|
+
example: |
|
|
411
|
+
@riverpod
|
|
412
|
+
OrderRepository orderRepository(OrderRepositoryRef ref) {
|
|
413
|
+
return OrderRepositoryImpl(
|
|
414
|
+
remoteDataSource: ref.watch(orderRemoteDataSourceProvider),
|
|
415
|
+
localDataSource: ref.watch(orderLocalDataSourceProvider),
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
# ----------------------------------------------------------------------------
|
|
420
|
+
# NETWORKING
|
|
421
|
+
# ----------------------------------------------------------------------------
|
|
422
|
+
networking:
|
|
423
|
+
httpClient: "Dio"
|
|
424
|
+
|
|
425
|
+
patterns:
|
|
426
|
+
interceptors: true
|
|
427
|
+
errorHandling: true
|
|
428
|
+
caching: true
|
|
429
|
+
retries: true
|
|
430
|
+
example: |
|
|
431
|
+
@riverpod
|
|
432
|
+
Dio dio(DioRef ref) {
|
|
433
|
+
return Dio(BaseOptions(baseUrl: Environment.apiUrl))
|
|
434
|
+
..interceptors.addAll([
|
|
435
|
+
AuthInterceptor(ref.watch(authProvider)),
|
|
436
|
+
LoggingInterceptor(),
|
|
437
|
+
RetryInterceptor(),
|
|
438
|
+
]);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
errorHandling:
|
|
442
|
+
approach: "Either<Failure, T>"
|
|
443
|
+
library: "dartz or fpdart"
|
|
444
|
+
|
|
445
|
+
# ----------------------------------------------------------------------------
|
|
446
|
+
# LOCAL STORAGE
|
|
447
|
+
# ----------------------------------------------------------------------------
|
|
448
|
+
localStorage:
|
|
449
|
+
preferences: "shared_preferences"
|
|
450
|
+
database: "drift or isar"
|
|
451
|
+
secureStorage: "flutter_secure_storage"
|
|
452
|
+
caching: "hive"
|
|
453
|
+
|
|
454
|
+
patterns:
|
|
455
|
+
repositoryPattern: true
|
|
456
|
+
cacheFirst: true
|
|
457
|
+
offlineFirst: true
|
|
458
|
+
|
|
459
|
+
# ----------------------------------------------------------------------------
|
|
460
|
+
# PROJECT STRUCTURE
|
|
461
|
+
# ----------------------------------------------------------------------------
|
|
462
|
+
projectStructure:
|
|
463
|
+
approach: "Feature-first"
|
|
464
|
+
|
|
465
|
+
example: |
|
|
466
|
+
lib/
|
|
467
|
+
├── core/
|
|
468
|
+
│ ├── error/
|
|
469
|
+
│ ├── network/
|
|
470
|
+
│ ├── router/
|
|
471
|
+
│ └── theme/
|
|
472
|
+
├── features/
|
|
473
|
+
│ ├── auth/
|
|
474
|
+
│ │ ├── data/
|
|
475
|
+
│ │ ├── domain/
|
|
476
|
+
│ │ └── presentation/
|
|
477
|
+
│ └── orders/
|
|
478
|
+
│ ├── data/
|
|
479
|
+
│ │ ├── datasources/
|
|
480
|
+
│ │ ├── models/
|
|
481
|
+
│ │ └── repositories/
|
|
482
|
+
│ ├── domain/
|
|
483
|
+
│ │ ├── entities/
|
|
484
|
+
│ │ ├── repositories/
|
|
485
|
+
│ │ └── usecases/
|
|
486
|
+
│ └── presentation/
|
|
487
|
+
│ ├── bloc/
|
|
488
|
+
│ ├── pages/
|
|
489
|
+
│ └── widgets/
|
|
490
|
+
└── main.dart
|
|
491
|
+
|
|
492
|
+
# ----------------------------------------------------------------------------
|
|
493
|
+
# CODE GENERATION
|
|
494
|
+
# ----------------------------------------------------------------------------
|
|
495
|
+
codeGeneration:
|
|
496
|
+
tools:
|
|
497
|
+
- name: "freezed"
|
|
498
|
+
use: "Immutable classes, unions, copyWith"
|
|
499
|
+
- name: "json_serializable"
|
|
500
|
+
use: "JSON serialization"
|
|
501
|
+
- name: "riverpod_generator"
|
|
502
|
+
use: "Provider generation"
|
|
503
|
+
- name: "auto_route"
|
|
504
|
+
use: "Type-safe routing (alternative)"
|
|
505
|
+
- name: "mockgen"
|
|
506
|
+
use: "Mock generation"
|
|
507
|
+
|
|
508
|
+
buildRunner:
|
|
509
|
+
command: "dart run build_runner build --delete-conflicting-outputs"
|
|
510
|
+
watch: "dart run build_runner watch"
|
|
511
|
+
|
|
512
|
+
# ----------------------------------------------------------------------------
|
|
513
|
+
# TECHNOLOGIES
|
|
514
|
+
# ----------------------------------------------------------------------------
|
|
515
|
+
technologies:
|
|
516
|
+
- name: dart
|
|
517
|
+
version: "3.0+"
|
|
518
|
+
specificRules:
|
|
519
|
+
useSoundNullSafety: true
|
|
520
|
+
useRecords: true
|
|
521
|
+
usePatterns: true
|
|
522
|
+
useSealedClasses: true
|
|
523
|
+
preferFinal: true
|
|
524
|
+
|
|
525
|
+
- name: flutter
|
|
526
|
+
version: "3.16+"
|
|
527
|
+
specificRules:
|
|
528
|
+
useConstConstructors: true
|
|
529
|
+
extractWidgets: true
|
|
530
|
+
useThemeExtensions: true
|
|
531
|
+
supportMultiplePlatforms: true
|
|
532
|
+
|
|
533
|
+
- name: riverpod
|
|
534
|
+
version: "2.x"
|
|
535
|
+
specificRules:
|
|
536
|
+
useCodeGeneration: true
|
|
537
|
+
useAsyncNotifiers: true
|
|
538
|
+
useSelectors: true
|
|
539
|
+
disposeProviders: true
|
|
540
|
+
|
|
541
|
+
- name: testing
|
|
542
|
+
specificRules:
|
|
543
|
+
useMocktail: true
|
|
544
|
+
useGoldenTests: true
|
|
545
|
+
testWidgets: true
|
|
546
|
+
testUseCases: true
|
|
547
|
+
minimumCoverage: 70
|