mcp-probe-kit 3.0.15 → 3.0.16
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 +17 -11
- package/build/lib/skill-bridge.d.ts +31 -0
- package/build/lib/skill-bridge.js +100 -0
- package/build/resources/ui-ux-data/charts.json +302 -0
- package/build/resources/ui-ux-data/colors.json +1058 -0
- package/build/resources/ui-ux-data/icons.json +1102 -0
- package/build/resources/ui-ux-data/landing.json +262 -0
- package/build/resources/ui-ux-data/metadata.json +6 -0
- package/build/resources/ui-ux-data/products.json +1058 -0
- package/build/resources/ui-ux-data/react-performance.json +574 -0
- package/build/resources/ui-ux-data/stacks/astro.json +266 -0
- package/build/resources/ui-ux-data/stacks/flutter.json +626 -0
- package/build/resources/ui-ux-data/stacks/html-tailwind.json +662 -0
- package/build/resources/ui-ux-data/stacks/jetpack-compose.json +626 -0
- package/build/resources/ui-ux-data/stacks/nextjs.json +218 -0
- package/build/resources/ui-ux-data/stacks/nuxt-ui.json +14 -0
- package/build/resources/ui-ux-data/stacks/nuxtjs.json +182 -0
- package/build/resources/ui-ux-data/stacks/react-native.json +350 -0
- package/build/resources/ui-ux-data/stacks/react.json +530 -0
- package/build/resources/ui-ux-data/stacks/shadcn.json +566 -0
- package/build/resources/ui-ux-data/stacks/svelte.json +134 -0
- package/build/resources/ui-ux-data/stacks/swiftui.json +26 -0
- package/build/resources/ui-ux-data/stacks/vue.json +170 -0
- package/build/resources/ui-ux-data/styles.json +1610 -0
- package/build/resources/ui-ux-data/typography.json +743 -0
- package/build/resources/ui-ux-data/ui-reasoning.json +1431 -0
- package/build/resources/ui-ux-data/ux-guidelines.json +1190 -0
- package/build/resources/ui-ux-data/web-interface.json +389 -0
- package/build/schemas/ui-ux-schemas.js +1 -1
- package/build/tools/start_product.js +8 -1
- package/build/tools/start_ui.js +14 -3
- package/build/tools/ui-ux-tools.js +21 -17
- package/build/utils/ui-data-loader.d.ts +18 -2
- package/build/utils/ui-data-loader.js +74 -12
- package/docs/i18n/en.json +2 -2
- package/docs/i18n/ja.json +2 -2
- package/docs/i18n/ko.json +2 -2
- package/docs/i18n/zh-CN.json +2 -2
- package/package.json +2 -1
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"No": "1",
|
|
4
|
+
"Category": "Widgets",
|
|
5
|
+
"Guideline": "Use StatelessWidget when possible",
|
|
6
|
+
"Description": "Immutable widgets are simpler",
|
|
7
|
+
"Do": "StatelessWidget for static UI",
|
|
8
|
+
"Don't": "StatefulWidget for everything",
|
|
9
|
+
"Code Good": "class MyWidget extends StatelessWidget",
|
|
10
|
+
"Code Bad": "class MyWidget extends StatefulWidget (static)",
|
|
11
|
+
"Severity": "Medium",
|
|
12
|
+
"Docs URL": "https://api.flutter.dev/flutter/widgets/StatelessWidget-class.html"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"No": "2",
|
|
16
|
+
"Category": "Widgets",
|
|
17
|
+
"Guideline": "Keep widgets small",
|
|
18
|
+
"Description": "Single responsibility principle",
|
|
19
|
+
"Do": "Extract widgets into smaller pieces",
|
|
20
|
+
"Don't": "Large build methods",
|
|
21
|
+
"Code Good": "Column(children: [Header() Content()])",
|
|
22
|
+
"Code Bad": "500+ line build method",
|
|
23
|
+
"Severity": "Medium",
|
|
24
|
+
"Docs URL": ""
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"No": "3",
|
|
28
|
+
"Category": "Widgets",
|
|
29
|
+
"Guideline": "Use const constructors",
|
|
30
|
+
"Description": "Compile-time constants for performance",
|
|
31
|
+
"Do": "const MyWidget() when possible",
|
|
32
|
+
"Don't": "Non-const for static widgets",
|
|
33
|
+
"Code Good": "const Text('Hello')",
|
|
34
|
+
"Code Bad": "Text('Hello') for literals",
|
|
35
|
+
"Severity": "High",
|
|
36
|
+
"Docs URL": "https://dart.dev/guides/language/language-tour#constant-constructors"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"No": "4",
|
|
40
|
+
"Category": "Widgets",
|
|
41
|
+
"Guideline": "Prefer composition over inheritance",
|
|
42
|
+
"Description": "Combine widgets using children",
|
|
43
|
+
"Do": "Compose widgets",
|
|
44
|
+
"Don't": "Extend widget classes",
|
|
45
|
+
"Code Good": "Container(child: MyContent())",
|
|
46
|
+
"Code Bad": "class MyContainer extends Container",
|
|
47
|
+
"Severity": "Medium",
|
|
48
|
+
"Docs URL": ""
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"No": "5",
|
|
52
|
+
"Category": "State",
|
|
53
|
+
"Guideline": "Use setState correctly",
|
|
54
|
+
"Description": "Minimal state in StatefulWidget",
|
|
55
|
+
"Do": "setState for UI state changes",
|
|
56
|
+
"Don't": "setState for business logic",
|
|
57
|
+
"Code Good": "setState(() { _counter++; })",
|
|
58
|
+
"Code Bad": "Complex logic in setState",
|
|
59
|
+
"Severity": "Medium",
|
|
60
|
+
"Docs URL": "https://api.flutter.dev/flutter/widgets/State/setState.html"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"No": "6",
|
|
64
|
+
"Category": "State",
|
|
65
|
+
"Guideline": "Avoid setState in build",
|
|
66
|
+
"Description": "Never call setState during build",
|
|
67
|
+
"Do": "setState in callbacks only",
|
|
68
|
+
"Don't": "setState in build method",
|
|
69
|
+
"Code Good": "onPressed: () => setState(() {})",
|
|
70
|
+
"Code Bad": "build() { setState(); }",
|
|
71
|
+
"Severity": "High",
|
|
72
|
+
"Docs URL": ""
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"No": "7",
|
|
76
|
+
"Category": "State",
|
|
77
|
+
"Guideline": "Use state management for complex apps",
|
|
78
|
+
"Description": "Provider Riverpod BLoC",
|
|
79
|
+
"Do": "State management for shared state",
|
|
80
|
+
"Don't": "setState for global state",
|
|
81
|
+
"Code Good": "Provider.of<MyState>(context)",
|
|
82
|
+
"Code Bad": "Global setState calls",
|
|
83
|
+
"Severity": "Medium",
|
|
84
|
+
"Docs URL": ""
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"No": "8",
|
|
88
|
+
"Category": "State",
|
|
89
|
+
"Guideline": "Prefer Riverpod or Provider",
|
|
90
|
+
"Description": "Recommended state solutions",
|
|
91
|
+
"Do": "Riverpod for new projects",
|
|
92
|
+
"Don't": "InheritedWidget manually",
|
|
93
|
+
"Code Good": "ref.watch(myProvider)",
|
|
94
|
+
"Code Bad": "Custom InheritedWidget",
|
|
95
|
+
"Severity": "Medium",
|
|
96
|
+
"Docs URL": "https://riverpod.dev/"
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"No": "9",
|
|
100
|
+
"Category": "State",
|
|
101
|
+
"Guideline": "Dispose resources",
|
|
102
|
+
"Description": "Clean up controllers and subscriptions",
|
|
103
|
+
"Do": "dispose() for cleanup",
|
|
104
|
+
"Don't": "Memory leaks from subscriptions",
|
|
105
|
+
"Code Good": "@override void dispose() { controller.dispose(); }",
|
|
106
|
+
"Code Bad": "No dispose implementation",
|
|
107
|
+
"Severity": "High",
|
|
108
|
+
"Docs URL": ""
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"No": "10",
|
|
112
|
+
"Category": "Layout",
|
|
113
|
+
"Guideline": "Use Column and Row",
|
|
114
|
+
"Description": "Basic layout widgets",
|
|
115
|
+
"Do": "Column Row for linear layouts",
|
|
116
|
+
"Don't": "Stack for simple layouts",
|
|
117
|
+
"Code Good": "Column(children: [Text(), Button()])",
|
|
118
|
+
"Code Bad": "Stack for vertical list",
|
|
119
|
+
"Severity": "Medium",
|
|
120
|
+
"Docs URL": "https://api.flutter.dev/flutter/widgets/Column-class.html"
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"No": "11",
|
|
124
|
+
"Category": "Layout",
|
|
125
|
+
"Guideline": "Use Expanded and Flexible",
|
|
126
|
+
"Description": "Control flex behavior",
|
|
127
|
+
"Do": "Expanded to fill space",
|
|
128
|
+
"Don't": "Fixed sizes in flex containers",
|
|
129
|
+
"Code Good": "Expanded(child: Container())",
|
|
130
|
+
"Code Bad": "Container(width: 200) in Row",
|
|
131
|
+
"Severity": "Medium",
|
|
132
|
+
"Docs URL": ""
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"No": "12",
|
|
136
|
+
"Category": "Layout",
|
|
137
|
+
"Guideline": "Use SizedBox for spacing",
|
|
138
|
+
"Description": "Consistent spacing",
|
|
139
|
+
"Do": "SizedBox for gaps",
|
|
140
|
+
"Don't": "Container for spacing only",
|
|
141
|
+
"Code Good": "SizedBox(height: 16)",
|
|
142
|
+
"Code Bad": "Container(height: 16)",
|
|
143
|
+
"Severity": "Low",
|
|
144
|
+
"Docs URL": ""
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"No": "13",
|
|
148
|
+
"Category": "Layout",
|
|
149
|
+
"Guideline": "Use LayoutBuilder for responsive",
|
|
150
|
+
"Description": "Respond to constraints",
|
|
151
|
+
"Do": "LayoutBuilder for adaptive layouts",
|
|
152
|
+
"Don't": "Fixed sizes for responsive",
|
|
153
|
+
"Code Good": "LayoutBuilder(builder: (context constraints) {})",
|
|
154
|
+
"Code Bad": "Container(width: 375)",
|
|
155
|
+
"Severity": "Medium",
|
|
156
|
+
"Docs URL": "https://api.flutter.dev/flutter/widgets/LayoutBuilder-class.html"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"No": "14",
|
|
160
|
+
"Category": "Layout",
|
|
161
|
+
"Guideline": "Avoid deep nesting",
|
|
162
|
+
"Description": "Keep widget tree shallow",
|
|
163
|
+
"Do": "Extract deeply nested widgets",
|
|
164
|
+
"Don't": "10+ levels of nesting",
|
|
165
|
+
"Code Good": "Extract widget to method or class",
|
|
166
|
+
"Code Bad": "Column(Row(Column(Row(...))))",
|
|
167
|
+
"Severity": "Medium",
|
|
168
|
+
"Docs URL": ""
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"No": "15",
|
|
172
|
+
"Category": "Lists",
|
|
173
|
+
"Guideline": "Use ListView.builder",
|
|
174
|
+
"Description": "Lazy list building",
|
|
175
|
+
"Do": "ListView.builder for long lists",
|
|
176
|
+
"Don't": "ListView with children for large lists",
|
|
177
|
+
"Code Good": "ListView.builder(itemCount: 100, itemBuilder: ...)",
|
|
178
|
+
"Code Bad": "ListView(children: items.map(...).toList())",
|
|
179
|
+
"Severity": "High",
|
|
180
|
+
"Docs URL": "https://api.flutter.dev/flutter/widgets/ListView-class.html"
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"No": "16",
|
|
184
|
+
"Category": "Lists",
|
|
185
|
+
"Guideline": "Provide itemExtent when known",
|
|
186
|
+
"Description": "Skip measurement",
|
|
187
|
+
"Do": "itemExtent for fixed height items",
|
|
188
|
+
"Don't": "No itemExtent for uniform lists",
|
|
189
|
+
"Code Good": "ListView.builder(itemExtent: 50)",
|
|
190
|
+
"Code Bad": "ListView.builder without itemExtent",
|
|
191
|
+
"Severity": "Medium",
|
|
192
|
+
"Docs URL": ""
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
"No": "17",
|
|
196
|
+
"Category": "Lists",
|
|
197
|
+
"Guideline": "Use keys for stateful items",
|
|
198
|
+
"Description": "Preserve widget state",
|
|
199
|
+
"Do": "Key for stateful list items",
|
|
200
|
+
"Don't": "No key for dynamic lists",
|
|
201
|
+
"Code Good": "ListTile(key: ValueKey(item.id))",
|
|
202
|
+
"Code Bad": "ListTile without key",
|
|
203
|
+
"Severity": "High",
|
|
204
|
+
"Docs URL": ""
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"No": "18",
|
|
208
|
+
"Category": "Lists",
|
|
209
|
+
"Guideline": "Use SliverList for custom scroll",
|
|
210
|
+
"Description": "Custom scroll effects",
|
|
211
|
+
"Do": "CustomScrollView with Slivers",
|
|
212
|
+
"Don't": "Nested ListViews",
|
|
213
|
+
"Code Good": "CustomScrollView(slivers: [SliverList()])",
|
|
214
|
+
"Code Bad": "ListView inside ListView",
|
|
215
|
+
"Severity": "Medium",
|
|
216
|
+
"Docs URL": "https://api.flutter.dev/flutter/widgets/SliverList-class.html"
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
"No": "19",
|
|
220
|
+
"Category": "Navigation",
|
|
221
|
+
"Guideline": "Use Navigator 2.0 or GoRouter",
|
|
222
|
+
"Description": "Declarative routing",
|
|
223
|
+
"Do": "go_router for navigation",
|
|
224
|
+
"Don't": "Navigator.push for complex apps",
|
|
225
|
+
"Code Good": "GoRouter(routes: [...])",
|
|
226
|
+
"Code Bad": "Navigator.push everywhere",
|
|
227
|
+
"Severity": "Medium",
|
|
228
|
+
"Docs URL": "https://pub.dev/packages/go_router"
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"No": "20",
|
|
232
|
+
"Category": "Navigation",
|
|
233
|
+
"Guideline": "Use named routes",
|
|
234
|
+
"Description": "Organized navigation",
|
|
235
|
+
"Do": "Named routes for clarity",
|
|
236
|
+
"Don't": "Anonymous routes",
|
|
237
|
+
"Code Good": "Navigator.pushNamed(context '/home')",
|
|
238
|
+
"Code Bad": "Navigator.push(context MaterialPageRoute())",
|
|
239
|
+
"Severity": "Low",
|
|
240
|
+
"Docs URL": ""
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"No": "21",
|
|
244
|
+
"Category": "Navigation",
|
|
245
|
+
"Guideline": "Handle back button (PopScope)",
|
|
246
|
+
"Description": "Android back behavior and predictive back (Android 14+)",
|
|
247
|
+
"Do": "Use PopScope widget (WillPopScope is deprecated)",
|
|
248
|
+
"Don't": "Use WillPopScope",
|
|
249
|
+
"Code Good": "PopScope(canPop: false, onPopInvoked: (didPop) => ...)",
|
|
250
|
+
"Code Bad": "WillPopScope(onWillPop: ...)",
|
|
251
|
+
"Severity": "High",
|
|
252
|
+
"Docs URL": "https://api.flutter.dev/flutter/widgets/PopScope-class.html"
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
"No": "22",
|
|
256
|
+
"Category": "Navigation",
|
|
257
|
+
"Guideline": "Pass typed arguments",
|
|
258
|
+
"Description": "Type-safe route arguments",
|
|
259
|
+
"Do": "Typed route arguments",
|
|
260
|
+
"Don't": "Dynamic arguments",
|
|
261
|
+
"Code Good": "MyRoute(id: '123')",
|
|
262
|
+
"Code Bad": "arguments: {'id': '123'}",
|
|
263
|
+
"Severity": "Medium",
|
|
264
|
+
"Docs URL": ""
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"No": "23",
|
|
268
|
+
"Category": "Async",
|
|
269
|
+
"Guideline": "Use FutureBuilder",
|
|
270
|
+
"Description": "Async UI building",
|
|
271
|
+
"Do": "FutureBuilder for async data",
|
|
272
|
+
"Don't": "setState for async",
|
|
273
|
+
"Code Good": "FutureBuilder(future: fetchData())",
|
|
274
|
+
"Code Bad": "fetchData().then((d) => setState())",
|
|
275
|
+
"Severity": "Medium",
|
|
276
|
+
"Docs URL": "https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html"
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"No": "24",
|
|
280
|
+
"Category": "Async",
|
|
281
|
+
"Guideline": "Use StreamBuilder",
|
|
282
|
+
"Description": "Stream UI building",
|
|
283
|
+
"Do": "StreamBuilder for streams",
|
|
284
|
+
"Don't": "Manual stream subscription",
|
|
285
|
+
"Code Good": "StreamBuilder(stream: myStream)",
|
|
286
|
+
"Code Bad": "stream.listen in initState",
|
|
287
|
+
"Severity": "Medium",
|
|
288
|
+
"Docs URL": "https://api.flutter.dev/flutter/widgets/StreamBuilder-class.html"
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
"No": "25",
|
|
292
|
+
"Category": "Async",
|
|
293
|
+
"Guideline": "Handle loading and error states",
|
|
294
|
+
"Description": "Complete async UI states",
|
|
295
|
+
"Do": "ConnectionState checks",
|
|
296
|
+
"Don't": "Only success state",
|
|
297
|
+
"Code Good": "if (snapshot.connectionState == ConnectionState.waiting)",
|
|
298
|
+
"Code Bad": "No loading indicator",
|
|
299
|
+
"Severity": "High",
|
|
300
|
+
"Docs URL": ""
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
"No": "26",
|
|
304
|
+
"Category": "Async",
|
|
305
|
+
"Guideline": "Cancel subscriptions",
|
|
306
|
+
"Description": "Clean up stream subscriptions",
|
|
307
|
+
"Do": "Cancel in dispose",
|
|
308
|
+
"Don't": "Memory leaks",
|
|
309
|
+
"Code Good": "subscription.cancel() in dispose",
|
|
310
|
+
"Code Bad": "No subscription cleanup",
|
|
311
|
+
"Severity": "High",
|
|
312
|
+
"Docs URL": ""
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
"No": "27",
|
|
316
|
+
"Category": "Theming",
|
|
317
|
+
"Guideline": "Use ThemeData",
|
|
318
|
+
"Description": "Consistent theming",
|
|
319
|
+
"Do": "ThemeData for app theme",
|
|
320
|
+
"Don't": "Hardcoded colors",
|
|
321
|
+
"Code Good": "Theme.of(context).primaryColor",
|
|
322
|
+
"Code Bad": "Color(0xFF123456) everywhere",
|
|
323
|
+
"Severity": "Medium",
|
|
324
|
+
"Docs URL": "https://api.flutter.dev/flutter/material/ThemeData-class.html"
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
"No": "28",
|
|
328
|
+
"Category": "Theming",
|
|
329
|
+
"Guideline": "Use ColorScheme",
|
|
330
|
+
"Description": "Material 3 color system",
|
|
331
|
+
"Do": "ColorScheme for colors",
|
|
332
|
+
"Don't": "Individual color properties",
|
|
333
|
+
"Code Good": "colorScheme: ColorScheme.fromSeed()",
|
|
334
|
+
"Code Bad": "primaryColor: Colors.blue",
|
|
335
|
+
"Severity": "Medium",
|
|
336
|
+
"Docs URL": ""
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
"No": "29",
|
|
340
|
+
"Category": "Theming",
|
|
341
|
+
"Guideline": "Access theme via context",
|
|
342
|
+
"Description": "Dynamic theme access",
|
|
343
|
+
"Do": "Theme.of(context)",
|
|
344
|
+
"Don't": "Static theme reference",
|
|
345
|
+
"Code Good": "Theme.of(context).textTheme.bodyLarge",
|
|
346
|
+
"Code Bad": "TextStyle(fontSize: 16)",
|
|
347
|
+
"Severity": "Medium",
|
|
348
|
+
"Docs URL": ""
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
"No": "30",
|
|
352
|
+
"Category": "Theming",
|
|
353
|
+
"Guideline": "Support dark mode",
|
|
354
|
+
"Description": "Respect system theme",
|
|
355
|
+
"Do": "darkTheme in MaterialApp",
|
|
356
|
+
"Don't": "Light theme only",
|
|
357
|
+
"Code Good": "MaterialApp(theme: light, darkTheme: dark)",
|
|
358
|
+
"Code Bad": "MaterialApp(theme: light)",
|
|
359
|
+
"Severity": "Medium",
|
|
360
|
+
"Docs URL": ""
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
"No": "31",
|
|
364
|
+
"Category": "Animation",
|
|
365
|
+
"Guideline": "Use implicit animations",
|
|
366
|
+
"Description": "Simple animations",
|
|
367
|
+
"Do": "AnimatedContainer AnimatedOpacity",
|
|
368
|
+
"Don't": "Explicit for simple transitions",
|
|
369
|
+
"Code Good": "AnimatedContainer(duration: Duration())",
|
|
370
|
+
"Code Bad": "AnimationController for fade",
|
|
371
|
+
"Severity": "Low",
|
|
372
|
+
"Docs URL": "https://api.flutter.dev/flutter/widgets/AnimatedContainer-class.html"
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
"No": "32",
|
|
376
|
+
"Category": "Animation",
|
|
377
|
+
"Guideline": "Use AnimationController for complex",
|
|
378
|
+
"Description": "Fine-grained control",
|
|
379
|
+
"Do": "AnimationController with Ticker",
|
|
380
|
+
"Don't": "Implicit for complex sequences",
|
|
381
|
+
"Code Good": "AnimationController(vsync: this)",
|
|
382
|
+
"Code Bad": "AnimatedContainer for staggered",
|
|
383
|
+
"Severity": "Medium",
|
|
384
|
+
"Docs URL": ""
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
"No": "33",
|
|
388
|
+
"Category": "Animation",
|
|
389
|
+
"Guideline": "Dispose AnimationControllers",
|
|
390
|
+
"Description": "Clean up animation resources",
|
|
391
|
+
"Do": "dispose() for controllers",
|
|
392
|
+
"Don't": "Memory leaks",
|
|
393
|
+
"Code Good": "controller.dispose() in dispose",
|
|
394
|
+
"Code Bad": "No controller disposal",
|
|
395
|
+
"Severity": "High",
|
|
396
|
+
"Docs URL": ""
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
"No": "34",
|
|
400
|
+
"Category": "Animation",
|
|
401
|
+
"Guideline": "Use Hero for transitions",
|
|
402
|
+
"Description": "Shared element transitions",
|
|
403
|
+
"Do": "Hero for navigation animations",
|
|
404
|
+
"Don't": "Manual shared element",
|
|
405
|
+
"Code Good": "Hero(tag: 'image' child: Image())",
|
|
406
|
+
"Code Bad": "Custom shared element animation",
|
|
407
|
+
"Severity": "Low",
|
|
408
|
+
"Docs URL": "https://api.flutter.dev/flutter/widgets/Hero-class.html"
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
"No": "35",
|
|
412
|
+
"Category": "Forms",
|
|
413
|
+
"Guideline": "Use Form widget",
|
|
414
|
+
"Description": "Form validation",
|
|
415
|
+
"Do": "Form with GlobalKey",
|
|
416
|
+
"Don't": "Individual validation",
|
|
417
|
+
"Code Good": "Form(key: _formKey child: ...)",
|
|
418
|
+
"Code Bad": "TextField without Form",
|
|
419
|
+
"Severity": "Medium",
|
|
420
|
+
"Docs URL": "https://api.flutter.dev/flutter/widgets/Form-class.html"
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
"No": "36",
|
|
424
|
+
"Category": "Forms",
|
|
425
|
+
"Guideline": "Use TextEditingController",
|
|
426
|
+
"Description": "Control text input",
|
|
427
|
+
"Do": "Controller for text fields",
|
|
428
|
+
"Don't": "onChanged for all text",
|
|
429
|
+
"Code Good": "final controller = TextEditingController()",
|
|
430
|
+
"Code Bad": "onChanged: (v) => setState()",
|
|
431
|
+
"Severity": "Medium",
|
|
432
|
+
"Docs URL": ""
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
"No": "37",
|
|
436
|
+
"Category": "Forms",
|
|
437
|
+
"Guideline": "Validate on submit",
|
|
438
|
+
"Description": "Form validation flow",
|
|
439
|
+
"Do": "_formKey.currentState!.validate()",
|
|
440
|
+
"Don't": "Skip validation",
|
|
441
|
+
"Code Good": "if (_formKey.currentState!.validate())",
|
|
442
|
+
"Code Bad": "Submit without validation",
|
|
443
|
+
"Severity": "High",
|
|
444
|
+
"Docs URL": ""
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
"No": "38",
|
|
448
|
+
"Category": "Forms",
|
|
449
|
+
"Guideline": "Dispose controllers",
|
|
450
|
+
"Description": "Clean up text controllers",
|
|
451
|
+
"Do": "dispose() for controllers",
|
|
452
|
+
"Don't": "Memory leaks",
|
|
453
|
+
"Code Good": "controller.dispose() in dispose",
|
|
454
|
+
"Code Bad": "No controller disposal",
|
|
455
|
+
"Severity": "High",
|
|
456
|
+
"Docs URL": ""
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
"No": "39",
|
|
460
|
+
"Category": "Performance",
|
|
461
|
+
"Guideline": "Use const widgets",
|
|
462
|
+
"Description": "Reduce rebuilds",
|
|
463
|
+
"Do": "const for static widgets",
|
|
464
|
+
"Don't": "No const for literals",
|
|
465
|
+
"Code Good": "const Icon(Icons.add)",
|
|
466
|
+
"Code Bad": "Icon(Icons.add)",
|
|
467
|
+
"Severity": "High",
|
|
468
|
+
"Docs URL": ""
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
"No": "40",
|
|
472
|
+
"Category": "Performance",
|
|
473
|
+
"Guideline": "Avoid rebuilding entire tree",
|
|
474
|
+
"Description": "Minimal rebuild scope",
|
|
475
|
+
"Do": "Isolate changing widgets",
|
|
476
|
+
"Don't": "setState on parent",
|
|
477
|
+
"Code Good": "Consumer only around changing widget",
|
|
478
|
+
"Code Bad": "setState on root widget",
|
|
479
|
+
"Severity": "High",
|
|
480
|
+
"Docs URL": ""
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
"No": "41",
|
|
484
|
+
"Category": "Performance",
|
|
485
|
+
"Guideline": "Use RepaintBoundary",
|
|
486
|
+
"Description": "Isolate repaints",
|
|
487
|
+
"Do": "RepaintBoundary for animations",
|
|
488
|
+
"Don't": "Full screen repaints",
|
|
489
|
+
"Code Good": "RepaintBoundary(child: AnimatedWidget())",
|
|
490
|
+
"Code Bad": "Animation without boundary",
|
|
491
|
+
"Severity": "Medium",
|
|
492
|
+
"Docs URL": "https://api.flutter.dev/flutter/widgets/RepaintBoundary-class.html"
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
"No": "42",
|
|
496
|
+
"Category": "Performance",
|
|
497
|
+
"Guideline": "Profile with DevTools",
|
|
498
|
+
"Description": "Measure before optimizing",
|
|
499
|
+
"Do": "Flutter DevTools profiling",
|
|
500
|
+
"Don't": "Guess at performance",
|
|
501
|
+
"Code Good": "DevTools performance tab",
|
|
502
|
+
"Code Bad": "Optimize without measuring",
|
|
503
|
+
"Severity": "Medium",
|
|
504
|
+
"Docs URL": "https://docs.flutter.dev/tools/devtools"
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
"No": "43",
|
|
508
|
+
"Category": "Accessibility",
|
|
509
|
+
"Guideline": "Use Semantics widget",
|
|
510
|
+
"Description": "Screen reader support",
|
|
511
|
+
"Do": "Semantics for accessibility",
|
|
512
|
+
"Don't": "Missing accessibility info",
|
|
513
|
+
"Code Good": "Semantics(label: 'Submit button')",
|
|
514
|
+
"Code Bad": "GestureDetector without semantics",
|
|
515
|
+
"Severity": "High",
|
|
516
|
+
"Docs URL": "https://api.flutter.dev/flutter/widgets/Semantics-class.html"
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
"No": "44",
|
|
520
|
+
"Category": "Accessibility",
|
|
521
|
+
"Guideline": "Support large fonts",
|
|
522
|
+
"Description": "MediaQuery text scaling",
|
|
523
|
+
"Do": "MediaQuery.textScaleFactor",
|
|
524
|
+
"Don't": "Fixed font sizes",
|
|
525
|
+
"Code Good": "style: Theme.of(context).textTheme",
|
|
526
|
+
"Code Bad": "TextStyle(fontSize: 14)",
|
|
527
|
+
"Severity": "High",
|
|
528
|
+
"Docs URL": ""
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
"No": "45",
|
|
532
|
+
"Category": "Accessibility",
|
|
533
|
+
"Guideline": "Test with screen readers",
|
|
534
|
+
"Description": "TalkBack and VoiceOver",
|
|
535
|
+
"Do": "Test accessibility regularly",
|
|
536
|
+
"Don't": "Skip accessibility testing",
|
|
537
|
+
"Code Good": "Regular TalkBack testing",
|
|
538
|
+
"Code Bad": "No screen reader testing",
|
|
539
|
+
"Severity": "High",
|
|
540
|
+
"Docs URL": ""
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
"No": "46",
|
|
544
|
+
"Category": "Testing",
|
|
545
|
+
"Guideline": "Use widget tests",
|
|
546
|
+
"Description": "Test widget behavior",
|
|
547
|
+
"Do": "WidgetTester for UI tests",
|
|
548
|
+
"Don't": "Unit tests only",
|
|
549
|
+
"Code Good": "testWidgets('...' (tester) async {})",
|
|
550
|
+
"Code Bad": "Only test() for UI",
|
|
551
|
+
"Severity": "Medium",
|
|
552
|
+
"Docs URL": "https://docs.flutter.dev/testing"
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
"No": "47",
|
|
556
|
+
"Category": "Testing",
|
|
557
|
+
"Guideline": "Use integration tests",
|
|
558
|
+
"Description": "Full app testing",
|
|
559
|
+
"Do": "integration_test package",
|
|
560
|
+
"Don't": "Manual testing only",
|
|
561
|
+
"Code Good": "IntegrationTestWidgetsFlutterBinding",
|
|
562
|
+
"Code Bad": "Manual E2E testing",
|
|
563
|
+
"Severity": "Medium",
|
|
564
|
+
"Docs URL": ""
|
|
565
|
+
},
|
|
566
|
+
{
|
|
567
|
+
"No": "48",
|
|
568
|
+
"Category": "Testing",
|
|
569
|
+
"Guideline": "Mock dependencies",
|
|
570
|
+
"Description": "Isolate tests",
|
|
571
|
+
"Do": "Mockito or mocktail",
|
|
572
|
+
"Don't": "Real dependencies in tests",
|
|
573
|
+
"Code Good": "when(mock.method()).thenReturn()",
|
|
574
|
+
"Code Bad": "Real API calls in tests",
|
|
575
|
+
"Severity": "Medium",
|
|
576
|
+
"Docs URL": ""
|
|
577
|
+
},
|
|
578
|
+
{
|
|
579
|
+
"No": "49",
|
|
580
|
+
"Category": "Platform",
|
|
581
|
+
"Guideline": "Use Platform checks",
|
|
582
|
+
"Description": "Platform-specific code",
|
|
583
|
+
"Do": "Platform.isIOS Platform.isAndroid",
|
|
584
|
+
"Don't": "Same code for all platforms",
|
|
585
|
+
"Code Good": "if (Platform.isIOS) {}",
|
|
586
|
+
"Code Bad": "Hardcoded iOS behavior",
|
|
587
|
+
"Severity": "Medium",
|
|
588
|
+
"Docs URL": ""
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
"No": "50",
|
|
592
|
+
"Category": "Platform",
|
|
593
|
+
"Guideline": "Use kIsWeb for web",
|
|
594
|
+
"Description": "Web platform detection",
|
|
595
|
+
"Do": "kIsWeb for web checks",
|
|
596
|
+
"Don't": "Platform for web",
|
|
597
|
+
"Code Good": "if (kIsWeb) {}",
|
|
598
|
+
"Code Bad": "Platform.isWeb (doesn't exist)",
|
|
599
|
+
"Severity": "Medium",
|
|
600
|
+
"Docs URL": ""
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
"No": "51",
|
|
604
|
+
"Category": "Packages",
|
|
605
|
+
"Guideline": "Use pub.dev packages",
|
|
606
|
+
"Description": "Community packages",
|
|
607
|
+
"Do": "Popular maintained packages",
|
|
608
|
+
"Don't": "Custom implementations",
|
|
609
|
+
"Code Good": "cached_network_image",
|
|
610
|
+
"Code Bad": "Custom image cache",
|
|
611
|
+
"Severity": "Medium",
|
|
612
|
+
"Docs URL": "https://pub.dev/"
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
"No": "52",
|
|
616
|
+
"Category": "Packages",
|
|
617
|
+
"Guideline": "Check package quality",
|
|
618
|
+
"Description": "Quality before adding",
|
|
619
|
+
"Do": "Pub points and popularity",
|
|
620
|
+
"Don't": "Any package without review",
|
|
621
|
+
"Code Good": "100+ pub points",
|
|
622
|
+
"Code Bad": "Unmaintained packages",
|
|
623
|
+
"Severity": "Medium",
|
|
624
|
+
"Docs URL": ""
|
|
625
|
+
}
|
|
626
|
+
]
|