@el-j/magic-helix-plugins 4.0.0-beta.6 → 4.0.0-beta.7

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.
@@ -0,0 +1,340 @@
1
+ # Flutter Development Guidelines
2
+
3
+ ## Architecture & Structure
4
+
5
+ ### Project Organization
6
+ ```
7
+ lib/
8
+ ├── main.dart
9
+ ├── app.dart
10
+ ├── core/
11
+ │ ├── constants/
12
+ │ ├── theme/
13
+ │ └── utils/
14
+ ├── features/
15
+ │ ├── auth/
16
+ │ │ ├── data/
17
+ │ │ ├── domain/
18
+ │ │ └── presentation/
19
+ │ └── home/
20
+ └── shared/
21
+ ├── widgets/
22
+ └── models/
23
+ ```
24
+
25
+ ## Widget Best Practices
26
+
27
+ ### StatelessWidget
28
+ ```dart
29
+ class UserCard extends StatelessWidget {
30
+ const UserCard({
31
+ super.key,
32
+ required this.user,
33
+ this.onTap,
34
+ });
35
+
36
+ final User user;
37
+ final VoidCallback? onTap;
38
+
39
+ @override
40
+ Widget build(BuildContext context) {
41
+ return Card(
42
+ child: ListTile(
43
+ title: Text(user.name),
44
+ subtitle: Text(user.email),
45
+ onTap: onTap,
46
+ ),
47
+ );
48
+ }
49
+ }
50
+ ```
51
+
52
+ ### StatefulWidget
53
+ ```dart
54
+ class Counter extends StatefulWidget {
55
+ const Counter({super.key});
56
+
57
+ @override
58
+ State<Counter> createState() => _CounterState();
59
+ }
60
+
61
+ class _CounterState extends State<Counter> {
62
+ int _count = 0;
63
+
64
+ @override
65
+ void dispose() {
66
+ // Clean up resources
67
+ super.dispose();
68
+ }
69
+
70
+ @override
71
+ Widget build(BuildContext context) {
72
+ return Column(
73
+ children: [
74
+ Text('Count: $_count'),
75
+ ElevatedButton(
76
+ onPressed: () => setState(() => _count++),
77
+ child: const Text('Increment'),
78
+ ),
79
+ ],
80
+ );
81
+ }
82
+ }
83
+ ```
84
+
85
+ ## State Management
86
+
87
+ ### Riverpod (Recommended)
88
+ ```dart
89
+ final userProvider = StateNotifierProvider<UserNotifier, AsyncValue<User>>((ref) {
90
+ return UserNotifier();
91
+ });
92
+
93
+ class UserNotifier extends StateNotifier<AsyncValue<User>> {
94
+ UserNotifier() : super(const AsyncValue.loading());
95
+
96
+ Future<void> fetchUser(String id) async {
97
+ state = const AsyncValue.loading();
98
+ state = await AsyncValue.guard(() => api.getUser(id));
99
+ }
100
+ }
101
+
102
+ // Usage in widget
103
+ class UserProfile extends ConsumerWidget {
104
+ @override
105
+ Widget build(BuildContext context, WidgetRef ref) {
106
+ final userState = ref.watch(userProvider);
107
+
108
+ return userState.when(
109
+ data: (user) => Text(user.name),
110
+ loading: () => CircularProgressIndicator(),
111
+ error: (err, stack) => Text('Error: $err'),
112
+ );
113
+ }
114
+ }
115
+ ```
116
+
117
+ ### Bloc Pattern
118
+ ```dart
119
+ class UserBloc extends Bloc<UserEvent, UserState> {
120
+ UserBloc() : super(UserInitial()) {
121
+ on<LoadUser>(_onLoadUser);
122
+ }
123
+
124
+ Future<void> _onLoadUser(LoadUser event, Emitter<UserState> emit) async {
125
+ emit(UserLoading());
126
+ try {
127
+ final user = await repository.getUser(event.id);
128
+ emit(UserLoaded(user));
129
+ } catch (e) {
130
+ emit(UserError(e.toString()));
131
+ }
132
+ }
133
+ }
134
+ ```
135
+
136
+ ## Navigation
137
+
138
+ ### Named Routes
139
+ ```dart
140
+ // Define routes
141
+ final routes = {
142
+ '/': (context) => HomeScreen(),
143
+ '/profile': (context) => ProfileScreen(),
144
+ '/settings': (context) => SettingsScreen(),
145
+ };
146
+
147
+ // Navigate
148
+ Navigator.pushNamed(context, '/profile');
149
+
150
+ // With arguments
151
+ Navigator.pushNamed(
152
+ context,
153
+ '/profile',
154
+ arguments: {'userId': '123'},
155
+ );
156
+ ```
157
+
158
+ ### Go Router (Modern)
159
+ ```dart
160
+ final router = GoRouter(
161
+ routes: [
162
+ GoRoute(
163
+ path: '/',
164
+ builder: (context, state) => HomeScreen(),
165
+ ),
166
+ GoRoute(
167
+ path: '/profile/:id',
168
+ builder: (context, state) {
169
+ final id = state.pathParameters['id']!;
170
+ return ProfileScreen(userId: id);
171
+ },
172
+ ),
173
+ ],
174
+ );
175
+
176
+ // Navigate
177
+ context.go('/profile/123');
178
+ context.push('/settings');
179
+ ```
180
+
181
+ ## Performance Optimization
182
+
183
+ ### const Constructors
184
+ ```dart
185
+ // Use const wherever possible
186
+ const Text('Hello');
187
+ const Padding(padding: EdgeInsets.all(8.0));
188
+ const SizedBox(height: 16);
189
+ ```
190
+
191
+ ### ListView.builder
192
+ ```dart
193
+ // For large lists, use builder
194
+ ListView.builder(
195
+ itemCount: items.length,
196
+ itemBuilder: (context, index) {
197
+ return ListTile(title: Text(items[index]));
198
+ },
199
+ );
200
+ ```
201
+
202
+ ### Keys
203
+ ```dart
204
+ // Use keys for widgets that need to preserve state
205
+ ListView(
206
+ children: items.map((item) =>
207
+ ListTile(
208
+ key: ValueKey(item.id),
209
+ title: Text(item.name),
210
+ )
211
+ ).toList(),
212
+ );
213
+ ```
214
+
215
+ ## Responsive Design
216
+
217
+ ### MediaQuery
218
+ ```dart
219
+ final size = MediaQuery.of(context).size;
220
+ final isPortrait = size.height > size.width;
221
+
222
+ if (size.width > 600) {
223
+ // Tablet layout
224
+ } else {
225
+ // Mobile layout
226
+ }
227
+ ```
228
+
229
+ ### LayoutBuilder
230
+ ```dart
231
+ LayoutBuilder(
232
+ builder: (context, constraints) {
233
+ if (constraints.maxWidth > 600) {
234
+ return WideLayout();
235
+ }
236
+ return NarrowLayout();
237
+ },
238
+ );
239
+ ```
240
+
241
+ ## Testing
242
+
243
+ ### Widget Tests
244
+ ```dart
245
+ testWidgets('Counter increments', (tester) async {
246
+ await tester.pumpWidget(
247
+ MaterialApp(home: Counter()),
248
+ );
249
+
250
+ expect(find.text('0'), findsOneWidget);
251
+
252
+ await tester.tap(find.byType(ElevatedButton));
253
+ await tester.pump();
254
+
255
+ expect(find.text('1'), findsOneWidget);
256
+ });
257
+ ```
258
+
259
+ ### Integration Tests
260
+ ```dart
261
+ void main() {
262
+ IntegrationTestWidgetsFlutterBinding.ensureInitialized();
263
+
264
+ testWidgets('Complete user flow', (tester) async {
265
+ await tester.pumpWidget(MyApp());
266
+
267
+ // Login
268
+ await tester.enterText(find.byKey(Key('email')), 'test@test.com');
269
+ await tester.tap(find.byKey(Key('login')));
270
+ await tester.pumpAndSettle();
271
+
272
+ // Verify home screen
273
+ expect(find.text('Welcome'), findsOneWidget);
274
+ });
275
+ }
276
+ ```
277
+
278
+ ## Best Practices
279
+
280
+ ### Widget Composition
281
+ - Break large widgets into smaller, reusable components
282
+ - Extract complex logic into separate methods or classes
283
+ - Use const constructors to improve performance
284
+
285
+ ### Error Handling
286
+ - Use ErrorWidget.builder for custom error widgets
287
+ - Wrap risky operations in try-catch
288
+ - Provide meaningful error messages to users
289
+
290
+ ### Asset Management
291
+ ```yaml
292
+ # pubspec.yaml
293
+ flutter:
294
+ assets:
295
+ - assets/images/
296
+ - assets/icons/
297
+ fonts:
298
+ - family: Roboto
299
+ fonts:
300
+ - asset: fonts/Roboto-Regular.ttf
301
+ ```
302
+
303
+ ### Platform-Specific Code
304
+ ```dart
305
+ import 'dart:io' show Platform;
306
+
307
+ if (Platform.isAndroid) {
308
+ // Android-specific
309
+ } else if (Platform.isIOS) {
310
+ // iOS-specific
311
+ }
312
+ ```
313
+
314
+ ## Common Patterns
315
+
316
+ ### Dependency Injection
317
+ ```dart
318
+ class MyApp extends StatelessWidget {
319
+ final ApiService apiService;
320
+ final AuthService authService;
321
+
322
+ const MyApp({
323
+ required this.apiService,
324
+ required this.authService,
325
+ });
326
+ }
327
+ ```
328
+
329
+ ### Service Locator
330
+ ```dart
331
+ final getIt = GetIt.instance;
332
+
333
+ void setupLocator() {
334
+ getIt.registerSingleton<ApiService>(ApiService());
335
+ getIt.registerLazySingleton<AuthService>(() => AuthService());
336
+ }
337
+
338
+ // Usage
339
+ final api = getIt<ApiService>();
340
+ ```
@@ -0,0 +1,233 @@
1
+ # Dart Development Guidelines
2
+
3
+ ## Language Overview
4
+ Dart is a client-optimized language for fast apps on any platform. It's the programming language behind Flutter and supports strong typing with null safety.
5
+
6
+ ## Code Style & Conventions
7
+
8
+ ### Naming
9
+ - **Classes/Enums/Typedefs**: PascalCase (`UserModel`, `ColorState`)
10
+ - **Functions/Variables**: camelCase (`getUserData`, `userName`)
11
+ - **Constants**: lowerCamelCase (`defaultTimeout`, `maxRetries`)
12
+ - **Private members**: Prefix with underscore (`_privateMethod`, `_internalState`)
13
+
14
+ ### Null Safety
15
+ ```dart
16
+ // Non-nullable by default
17
+ String name; // Must be initialized
18
+ String? optionalName; // Can be null
19
+
20
+ // Null-aware operators
21
+ String? maybeValue;
22
+ final length = maybeValue?.length ?? 0; // Default value
23
+ final value = maybeValue!; // Null assertion (use carefully)
24
+ ```
25
+
26
+ ### Collections
27
+ ```dart
28
+ // Use const for immutable collections
29
+ const colors = ['red', 'green', 'blue'];
30
+
31
+ // Type-safe collections
32
+ final List<User> users = [];
33
+ final Map<String, int> scores = {};
34
+ final Set<String> uniqueNames = {};
35
+
36
+ // Collection operators
37
+ final adults = users.where((u) => u.age >= 18).toList();
38
+ final names = users.map((u) => u.name).toList();
39
+ ```
40
+
41
+ ## Object-Oriented Programming
42
+
43
+ ### Classes
44
+ ```dart
45
+ class User {
46
+ final String id;
47
+ final String name;
48
+ final int age;
49
+
50
+ // Constructor with named parameters
51
+ const User({
52
+ required this.id,
53
+ required this.name,
54
+ required this.age,
55
+ });
56
+
57
+ // Named constructor
58
+ User.guest() : this(id: 'guest', name: 'Guest', age: 0);
59
+
60
+ // Factory constructor
61
+ factory User.fromJson(Map<String, dynamic> json) {
62
+ return User(
63
+ id: json['id'],
64
+ name: json['name'],
65
+ age: json['age'],
66
+ );
67
+ }
68
+
69
+ // Copyhold
70
+ User copyWith({String? name, int? age}) {
71
+ return User(
72
+ id: id,
73
+ name: name ?? this.name,
74
+ age: age ?? this.age,
75
+ );
76
+ }
77
+ }
78
+ ```
79
+
80
+ ### Mixins
81
+ ```dart
82
+ mixin LoggerMixin {
83
+ void log(String message) {
84
+ print('[${DateTime.now()}] $message');
85
+ }
86
+ }
87
+
88
+ class MyService with LoggerMixin {
89
+ void doSomething() {
90
+ log('Doing something');
91
+ }
92
+ }
93
+ ```
94
+
95
+ ## Async Programming
96
+
97
+ ### Futures
98
+ ```dart
99
+ Future<User> fetchUser(String id) async {
100
+ final response = await http.get(Uri.parse('/users/$id'));
101
+ return User.fromJson(json.decode(response.body));
102
+ }
103
+
104
+ // Error handling
105
+ try {
106
+ final user = await fetchUser('123');
107
+ } catch (e) {
108
+ print('Error: $e');
109
+ }
110
+ ```
111
+
112
+ ### Streams
113
+ ```dart
114
+ Stream<int> countStream(int max) async* {
115
+ for (int i = 1; i <= max; i++) {
116
+ await Future.delayed(Duration(seconds: 1));
117
+ yield i;
118
+ }
119
+ }
120
+
121
+ // Usage
122
+ await for (final count in countStream(5)) {
123
+ print(count);
124
+ }
125
+ ```
126
+
127
+ ## Testing
128
+
129
+ ### Unit Tests
130
+ ```dart
131
+ import 'package:test/test.dart';
132
+
133
+ void main() {
134
+ group('User', () {
135
+ test('creates from JSON', () {
136
+ final json = {'id': '1', 'name': 'John', 'age': 30};
137
+ final user = User.fromJson(json);
138
+
139
+ expect(user.id, '1');
140
+ expect(user.name, 'John');
141
+ expect(user.age, 30);
142
+ });
143
+
144
+ test('copyWith preserves unchanged fields', () {
145
+ final user = User(id: '1', name: 'John', age: 30);
146
+ final updated = user.copyWith(name: 'Jane');
147
+
148
+ expect(updated.id, user.id);
149
+ expect(updated.name, 'Jane');
150
+ expect(updated.age, user.age);
151
+ });
152
+ });
153
+ }
154
+ ```
155
+
156
+ ## Best Practices
157
+
158
+ ### Performance
159
+ - Use `const` constructors when possible
160
+ - Prefer `final` over `var` for immutability
161
+ - Use collection literals instead of constructors
162
+ - Avoid unnecessary rebuilds
163
+
164
+ ### Code Organization
165
+ - One class per file (generally)
166
+ - Group related files in directories
167
+ - Use barrel files (index.dart) for clean exports
168
+ - Separate models, services, and utilities
169
+
170
+ ### Error Handling
171
+ - Use exceptions for exceptional cases
172
+ - Return `Result<T, E>` types for expected failures
173
+ - Validate input early
174
+ - Provide meaningful error messages
175
+
176
+ ## Common Patterns
177
+
178
+ ### Singleton
179
+ ```dart
180
+ class ApiService {
181
+ static final ApiService _instance = ApiService._internal();
182
+ factory ApiService() => _instance;
183
+ ApiService._internal();
184
+ }
185
+ ```
186
+
187
+ ### Factory Pattern
188
+ ```dart
189
+ abstract class Shape {
190
+ factory Shape(String type) {
191
+ switch (type) {
192
+ case 'circle':
193
+ return Circle();
194
+ case 'square':
195
+ return Square();
196
+ default:
197
+ throw ArgumentError('Unknown shape: $type');
198
+ }
199
+ }
200
+ }
201
+ ```
202
+
203
+ ### Repository Pattern
204
+ ```dart
205
+ abstract class UserRepository {
206
+ Future<User> getUser(String id);
207
+ Future<void> saveUser(User user);
208
+ }
209
+
210
+ class ApiUserRepository implements UserRepository {
211
+ @override
212
+ Future<User> getUser(String id) async {
213
+ // Implementation
214
+ }
215
+ }
216
+ ```
217
+
218
+ ## Tools & Commands
219
+ ```bash
220
+ # Format code
221
+ dart format .
222
+
223
+ # Analyze code
224
+ dart analyze
225
+
226
+ # Run tests
227
+ dart test
228
+
229
+ # Pub commands
230
+ dart pub get
231
+ dart pub upgrade
232
+ dart pub outdated
233
+ ```
@@ -0,0 +1,147 @@
1
+ # Elixir Development Guidelines
2
+
3
+ ## Language Overview
4
+ Elixir is a functional, concurrent programming language built on the Erlang VM (BEAM). It's designed for building scalable, maintainable applications with excellent support for distributed systems.
5
+
6
+ ## Code Style & Conventions
7
+
8
+ ### Naming
9
+ - **Modules**: PascalCase (`MyApp.UserController`)
10
+ - **Functions/Variables**: snake_case (`create_user`, `user_id`)
11
+ - **Atoms**: snake_case (`:ok`, `:error`, `:user_not_found`)
12
+ - **Constants**: snake_case module attributes (`@default_timeout`)
13
+
14
+ ### Pattern Matching
15
+ ```elixir
16
+ # Use pattern matching extensively
17
+ def process({:ok, result}), do: result
18
+ def process({:error, reason}), do: Logger.error(reason)
19
+
20
+ # Guards for additional constraints
21
+ def divide(a, b) when b != 0, do: {:ok, a / b}
22
+ def divide(_, 0), do: {:error, :division_by_zero}
23
+ ```
24
+
25
+ ### Pipe Operator
26
+ ```elixir
27
+ # Chain operations with |>
28
+ user
29
+ |> validate_user()
30
+ |> create_record()
31
+ |> send_welcome_email()
32
+ ```
33
+
34
+ ## OTP Patterns
35
+
36
+ ### GenServer
37
+ ```elixir
38
+ defmodule MyApp.Worker do
39
+ use GenServer
40
+
41
+ def start_link(opts) do
42
+ GenServer.start_link(__MODULE__, opts, name: __MODULE__)
43
+ end
44
+
45
+ def init(state) do
46
+ {:ok, state}
47
+ end
48
+
49
+ def handle_call({:get, key}, _from, state) do
50
+ {:reply, Map.get(state, key), state}
51
+ end
52
+ end
53
+ ```
54
+
55
+ ### Supervision
56
+ ```elixir
57
+ children = [
58
+ {MyApp.Repo, []},
59
+ {MyApp.Worker, []},
60
+ {Phoenix.PubSub, name: MyApp.PubSub}
61
+ ]
62
+
63
+ Supervisor.start_link(children, strategy: :one_for_one)
64
+ ```
65
+
66
+ ## Phoenix Framework
67
+
68
+ ### Controllers
69
+ ```elixir
70
+ defmodule MyAppWeb.UserController do
71
+ use MyAppWeb, :controller
72
+
73
+ def create(conn, %{"user" => user_params}) do
74
+ case Accounts.create_user(user_params) do
75
+ {:ok, user} ->
76
+ conn
77
+ |> put_status(:created)
78
+ |> render("show.json", user: user)
79
+
80
+ {:error, changeset} ->
81
+ conn
82
+ |> put_status(:unprocessable_entity)
83
+ |> render("error.json", changeset: changeset)
84
+ end
85
+ end
86
+ end
87
+ ```
88
+
89
+ ### Contexts
90
+ - Group related functionality in contexts
91
+ - Keep controllers thin, business logic in contexts
92
+ - Use Ecto changesets for validation
93
+
94
+ ## Ecto Database
95
+
96
+ ### Schemas
97
+ ```elixir
98
+ defmodule MyApp.User do
99
+ use Ecto.Schema
100
+ import Ecto.Changeset
101
+
102
+ schema "users" do
103
+ field :email, :string
104
+ field :name, :string
105
+ has_many :posts, MyApp.Post
106
+
107
+ timestamps()
108
+ end
109
+
110
+ def changeset(user, attrs) do
111
+ user
112
+ |> cast(attrs, [:email, :name])
113
+ |> validate_required([:email])
114
+ |> validate_format(:email, ~r/@/)
115
+ |> unique_constraint(:email)
116
+ end
117
+ end
118
+ ```
119
+
120
+ ## Testing
121
+
122
+ ### ExUnit
123
+ ```elixir
124
+ defmodule MyApp.UserTest do
125
+ use MyApp.DataCase
126
+
127
+ test "creates user with valid attrs" do
128
+ attrs = %{email: "test@example.com", name: "Test"}
129
+ assert {:ok, user} = Accounts.create_user(attrs)
130
+ assert user.email == "test@example.com"
131
+ end
132
+ end
133
+ ```
134
+
135
+ ## Error Handling
136
+ - Use tagged tuples: `{:ok, result}`, `{:error, reason}`
137
+ - Pattern match on results
138
+ - Use `with` for complex error handling
139
+ - Leverage supervisor restart strategies
140
+
141
+ ## Best Practices
142
+ - Keep functions pure when possible
143
+ - Use immutable data structures
144
+ - Leverage concurrency with Task and GenServer
145
+ - Follow "let it crash" philosophy
146
+ - Use telemetry for observability
147
+ - Run `mix format` before committing