Flutter Linter Kuralları Bölüm 1: Hata Kuralları 💫 🌌 ✨
Gülsen Keskin
Posted on February 19, 2022
“Where there are rules, there’s law“
Linting Nedir?
Linting , programatik, stilistik hatalar ve biçimlendirilmemiş kod için kaynak kodunu kontrol etme işlemidir. Mantıksal hatalar, kullanılmayan değişkenler, boş if-else ifadeleri gibi kodlama sırasında yapılan bazı yaygın ve yaygın olmayan hataları belirlemede yardımcı olur.
Linting'in amacı, kod kalitesini iyileştirebilecek gizli hatayı veya uygulamayı çalıştırırken sorunlara neden olabilecek hataları belirleme konusunda gerçek zamanlı öneriler almaktır.
Linter kuralları 3 gruba ayrılır. Bunlar:
- Hatalar: Olası kodlama hataları.
- Stil
- Bar: Pub paketi kurulumuyla ilgili olası sorunlar .
Her kuralın ayrıca bir olgunluk düzeyi vardır.
Kuralların olgunluk düzeyleri de 3'e ayrılır. Bunlar:
Kararlı-Stable
Bu kuralların kullanımı güvenlidir ve Dart dilinin en son sürümleriyle işlevsel oldukları doğrulanmıştır. Deneysel olarak işaretlenmedikçe veya kullanımdan kaldırılmadıkça tüm kurallar kararlı olarak kabul edilir.
Deneysel-Experimental
Bu kurallar halen değerlendirme aşamasındadır ve hiçbir zaman istikrara kavuşturulamayabilir. Bunları dikkatli kullanmanız gerekir.
Kullanımdan kaldırıldı-Deprecated
Bu kurallar artık kullanım için önerilmemektedir ve gelecekteki bir linter yayınında kaldırılabilir.
Hata kuralları
Hata kuralları, kodunuzdaki olası hataları ve diğer hataları tanımlar.
Always_use_package_imports
lib/. içindeki dosyalar için relative imports'dan (göreli içe aktarmalardan) kaçının.
Aynı üyeyi iki farklı şekilde içe aktarmaktan kaçınmak için lib/dizindeki dosyalar için mutlak içe aktarmayı (absolute imports) kullandığınızdan emin olun.
Doğru kullanım:
import 'package:foo/bar.dart';
import 'package:foo/baz.dart';
import 'package:foo/src/baz.dart';
Yanlış kullanım:
import 'baz.dart';
import 'src/bag.dart'
import '../lib/baz.dart';
avoid_dynamic_calls
"dynamic" bir hedefte method çağrılarından veya property erişimlerinden kaçının.
Açıkça veya dolaylı olarak statik olarak yazılan dynamic bir obje üzerindeki method çağrılarından veya özellik(propertie) erişimlerinden kaçının. Dinamik çağrılar, her çalışma zamanı ortamında ve derleyicide biraz farklı olarak ele alınır, ancak çoğu üretim modu (ve hatta bazı geliştirme modları), dinamik çağrılarla ilişkili hem derleme boyutu hem de çalışma zamanı performans sorunlarına sahiptir.
Ek olarak, "dynamic" yazılan hedefler, çoğu statik analizi devre dışı bırakır.
Yanlış kullanım:
void explicitDynamicType(dynamic object) {
print(object.foo());
}
void implicitDynamicType(object) {
print(object.foo());
}
abstract class SomeWrapper {
T doSomething<T>();
}
void inferredDynamicType(SomeWrapper wrapper) {
var object = wrapper.doSomething();
print(object.foo());
}
void callDynamic(dynamic function) {
function();
}
void functionType(Function function) {
function();
}
Doğru kullanım:
void explicitType(Fooable object) {
object.foo();
}
void castedType(dynamic object) {
(object as Fooable).foo();
}
abstract class SomeWrapper {
T doSomething<T>();
}
void inferredType(SomeWrapper wrapper) {
var object = wrapper.doSomething<Fooable>();
object.foo();
}
void functionTypeWithParameters(Function() function) {
function();
}
avoid_empty_else
Boş else ifadelerinden kaçının.
Yanlış kullanım:
if (x > y)
print("1");
else ;
print("2");
avoid_print
Üretim kodunda "print" çağrılarından kaçının.
void f(int x) {
print('debug: $x');
...
}
avoid_returning_null_for_future
Future için null döndürmekten kaçının.
avoid_slow_async_io
Yavaş asenkron dart:io
yöntemlerinden kaçının.
Aşağıdaki asenkron I/O methodlarını kullanmaktan kaçının, çünkü bunlar senkron emsallerine göre çok daha yavaştır.
• Directory.exists
• Directory.stat
• File.lastModified
• File.exists
• File.stat
• FileSystemEntity.isDirectory
• FileSystemEntity.isFile
• FileSystemEntity.isLink
• FileSystemEntity.type
Yanlış kullanım:
import 'dart:io';
Future<Null> someFunction() async {
var file = File('/path/to/my/file');
var now = DateTime.now();
if ((await file.lastModified()).isBefore(now)) print('before'); // LINT
}
Doğru kullanım:
import 'dart:io';
Future<Null> someFunction() async {
var file = File('/path/to/my/file');
var now = DateTime.now();
if (file.lastModifiedSync().isBefore(now)) print('before'); // OK
}
avoid_type_to_string
Sonuçlar küçültülebileceğinden üretim kodunda ".toString()" kullanmaktan kaçının.
Yanlış kullanım:
void bar(Object other) {
if (other.runtimeType.toString() == 'Bar') {
doThing();
}
}
Object baz(Thing myThing) {
return getThingFromDatabase(key: myThing.runtimeType.toString());
}
Doğru kullanım:
void bar(Object other) {
if (other is Bar) {
doThing();
}
}
class Thing {
String get thingTypeKey => ...
}
Object baz(Thing myThing) {
return getThingFromDatabase(key: myThing.thingTypeKey);
}
avoid_types_as_parameter_names
Tipleri paremetre adı olarak kullanmaktan kaçının.
Yanlış kullanım: m(f(int));
Doğru kullanım: m(f(int v));
avoid_web_libraries_in_flutter
Flutter web plugin paketleri dışında yalnızca web kitaplıkları kullanmaktan kaçının.
Web eklentileri olmayan Flutter paketlerinde web kitaplıkları, dart:html, dart:js ve dart:js_util kullanmaktan kaçının. Bu kitaplıklar bir web context dışında desteklenmez; bunlara bağlı olan işlevsellik Flutter mobil runtime da başarısız olur ve Flutter web'de kullanılmaları genellikle önerilmez.
Web kitaplığı erişimine şu durumlarda izin verilir:
• web'i desteklenen bir context olarak bildiren plugin paketleri
aksi takdirde, dart:html, dart:js ve dart:js_util'in import edilmesine izin verilmez.
cancel_subscriptions
dart.async.StreamSubscription örneklerini iptal edin.
StreamSubscription örneklerinin (instance) iptal edilmesi, bellek sızıntılarını ve beklenmeyen davranışları (unexpected behavior) önler.
Yanlış Kullanım:
class A {
StreamSubscription _subscriptionA; // LINT
void init(Stream stream) {
_subscriptionA = stream.listen((_) {});
}
}
Yanlış kullanım:
void someFunction() {
StreamSubscription _subscriptionF; // LINT
}
Doğru kullanım:
class B {
StreamSubscription _subscriptionB; // OK
void init(Stream stream) {
_subscriptionB = stream.listen((_) {});
}
void dispose(filename) {
_subscriptionB.cancel();
}
}
Doğru kullanım:
void someFunctionOK() {
StreamSubscription _subscriptionB; // OK
_subscriptionB.cancel();
}
close_sinks
Sink örneklerini kapatmak, bellek sızıntılarını(memory leaks) ve beklenmeyen davranışları(unexpected behavior) önler.
Yanlış kullanım:
class A {
IOSink _sinkA;
void init(filename) {
_sinkA = File(filename).openWrite(); // LINT
}
}
Yanlış kullanım:
void someFunction() {
IOSink _sinkF; // LINT
}
Doğru kullanım:
class B {
IOSink _sinkB;
void init(filename) {
_sinkB = File(filename).openWrite(); // OK
}
void dispose(filename) {
_sinkB.close();
}
}
Doğru kullanım:
void someFunctionOK() {
IOSink _sinkFOK; // OK
_sinkFOK.close();
}
comment_references
Yalnızca belge yorumlarındaki kapsam tanımlayıcılarına (scope identifiers) başvurun.
Değişken, method veya köşeli parantez içinde adlar yazarsanız, dartdoc adı arar ve belgelerine bağlanır. Tüm bunların işe yaraması için, parantez içine alınmış belgelerdeki tüm tanımlayıcıların kapsam içinde olduğundan emin olun.
Örneğin:
Doğru kullanım:
/// [a] veya [b]'den büyük olanı döndürün.
int max_int(int a, int b) { ... }
Öte yandan, outOfScopeId'in kapsam dışı olduğunu varsayarsak:
Yanlış kullanım:
/// [value], [outOfScopeId] değerinden büyükse true değerini döndürün.
bool isOutOfRange(int value) { ... }
Köşeli parantez yorum biçiminin, açıklamaların oldukça doğal bir biçim kullanarak bildirimlere başvurmasına izin verecek şekilde tasarlandığını, ancak keyfi ifadelere izin vermediğini unutmayın. Özellikle, köşeli parantez içindeki kod referansları, aşağıdakilerden herhangi birini içerebilir:
• Tanımlayıcının comment kapsamındaki herhangi bir tanımlayıcı(identifier) olduğu tek bir tanımlayıcı (doküman yorumlarında kapsamda ne olduğuna ilişkin spesifikasyona bakın),
• ilk tanımlayıcının kapsamdaki bir sınıfın adı ve ikincisinin sınıfta bildirilen bir üyenin adı olduğu bir nokta ile ayrılmış iki tanımlayıcı,
• tek bir tanımlayıcı ve ardından bir parantez çifti, burada tanımlayıcı kapsamdaki bir sınıfın adıdır (sınıfın adsız constructor'ına atıfta bulunmak için kullanılır),
• veya bir nokta ile ayrılmış ve ardından bir çift parantez ile ayrılmış iki tanımlayıcı; burada ilk tanımlayıcı kapsamdaki bir sınıfın adı ve ikincisi adlandırılmış bir constructor'ın adıdır (kesinlikle gerekli değildir, ancak tutarlılık için izin verilir).
control_flow_in_finally
Son bloklarda kontrol akışı kullanmaktan kaçının.
Son bloklarda kontrol akışının kullanılması, kaçınılmaz olarak, hata ayıklaması zor olan beklenmeyen davranışlara neden olacaktır.
Doğru kullanım:
class Ok {
double compliantMethod() {
var i = 5;
try {
i = 1 / 0;
} catch (e) {
print(e); // OK
}
return i;
}
}
Yanlış kullanım:
class BadReturn {
double nonCompliantMethod() {
try {
return 1 / 0;
} catch (e) {
print(e);
} finally {
return 1.0; // LINT
}
}
}
Yanlış kullanım:
class BadContinue {
double nonCompliantMethod() {
for (var o in [1, 2]) {
try {
print(o / 0);
} catch (e) {
print(e);
} finally {
continue; // LINT
}
}
return 1.0;
}
}
Yanlış kullanım:
class BadBreak {
double nonCompliantMethod() {
for (var o in [1, 2]) {
try {
print(o / 0);
} catch (e) {
print(e);
} finally {
break; // LINT
}
}
return 1.0;
}
}
diagnostic_describe_all_properties
Debug methodlarında tüm public property'leri implemente edin.
Diagnosticable'ın uygulayıcıları, çalışma zamanında hata ayıklanabilirliğini iyileştirmek için bir debugFillProperties(...) veya debugDescribeChildren(...) methodu tüm public özelliklere başvurmalıdır.
Yanlış kullanım:
class Absorber extends Widget {
bool get absorbing => _absorbing;
bool _absorbing;
bool get ignoringSemantics => _ignoringSemantics;
bool _ignoringSemantics;
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<bool>('absorbing', absorbing));
// Missing reference to ignoringSemantics
}
}
Doğru kullanım:
class Absorber extends Widget {
bool get absorbing => _absorbing;
bool _absorbing;
bool get ignoringSemantics => _ignoringSemantics;
bool _ignoringSemantics;
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<bool>('absorbing', absorbing));
properties.add(DiagnosticsProperty<bool>('ignoringSemantics', ignoringSemantics));
}
}
empty_statements
Boş ifadelerden kaçının.
Boş ifadeler genellikle bir hatayı gösterir.
Örneğin,
Yanlış kullanım:
if (complicated.expression.foo());
bar();
Dart formatı ile biçimlendirilen hata bariz hale gelir:
if (complicated.expression.foo()) ;
bar();
Doğru kullanım:
if (complicated.expression.foo())
bar();
invariant_booleans
Koşullu ifadeler koşulsuz olarak true veya false olarak değerlendirilmemelidir.
Bu kural şu anda deneyseldir. (experimental)
Derleme zamanında çıkarılabilecek koşulları test etmeyin veya aynı koşulu iki kez test etmeyin.
False'dan başka bir şey olamayacak bir koşul kullanan koşullu ifadeler, kod bloklarını işlevsiz hale getirme etkisine sahiptir. Koşul, true dışında hiçbir şeyi değerlendiremezse, koşullu ifade tamamen gereksizdir ve kodu daha az okunabilir hale getirir. Kodun programcının amacı ile uyuşmaması oldukça olasıdır. Ya koşul kaldırılmalı ya da her zaman true veya false olarak değerlendirilmemesi ve gereksiz testler yapmaması için güncellenmelidir.
Yanlış kullanım:
// foo aynı ifadede bara hem eşitdir hem de eşit olamaz
if(foo == bar && something && foo != bar) {...}
Yanlış kullanım:
void compute(int foo) {
if (foo == 4) {
doSomething();
// bu noktada foo'nun 4'e eşit olduğunu biliyoruz, bu nedenle sonraki koşul her zaman false
if (foo > 4) {...}
...
}
...
}
Yanlış kullanım:
void compute(bool foo) {
if (foo) {
return;
}
doSomething();
// burada foo'nun değeri her zaman false'dır
if (foo){...}
...
}
Doğru kullanım:
void nestedOK() {
if (foo == bar) {
foo = baz;
if (foo != bar) {...}
}
}
Doğru kullanım:
void nestedOk2() {
if (foo == bar) {
return;
}
foo = baz;
if (foo == bar) {...} // OK
}
Doğru kullanım:
void nestedOk5() {
if (foo != null) {
if (bar != null) {
return;
}
}
if (bar != null) {...} // OK
}
iterable_contains_unrelated_type
İlişkisiz(unrelated) türlerin referanslarıyla Iterable.contains çağrısı.
Yanlış kullanım:
void someFunction() {
var list = <int>[];
if (list.contains('1')) print('someFunction'); // LINT
}
Yanlış kullanım:
void someFunction3() {
List<int> list = <int>[];
if (list.contains('1')) print('someFunction3'); // LINT
}
Yanlış kullanım:
void someFunction8() {
List<DerivedClass2> list = <DerivedClass2>[];
DerivedClass3 instance;
if (list.contains(instance)) print('someFunction8'); // LINT
}
Yanlış kullanım:
abstract class SomeIterable<E> implements Iterable<E> {}
abstract class MyClass implements SomeIterable<int> {
bool badMethod(String thing) => this.contains(thing); // LINT
}
Doğru kullanım:
void someFunction10() {
var list = [];
if (list.contains(1)) print('someFunction10'); // OK
}
Doğru kullanım:
void someFunction1() {
var list = <int>[];
if (list.contains(1)) print('someFunction1'); // OK
}
Doğru kullanım:
void someFunction4() {
List<int> list = <int>[];
if (list.contains(1)) print('someFunction4'); // OK
}
Doğru kullanım:
void someFunction5() {
List<ClassBase> list = <ClassBase>[];
DerivedClass1 instance;
if (list.contains(instance)) print('someFunction5'); // OK
}
abstract class ClassBase {}
class DerivedClass1 extends ClassBase {}
Doğru kullanım:
void someFunction6() {
List<Mixin> list = <Mixin>[];
DerivedClass2 instance;
if (list.contains(instance)) print('someFunction6'); // OK
}
abstract class ClassBase {}
abstract class Mixin {}
class DerivedClass2 extends ClassBase with Mixin {}
Doğru kullanım:
void someFunction7() {
List<Mixin> list = <Mixin>[];
DerivedClass3 instance;
if (list.contains(instance)) print('someFunction7'); // OK
}
abstract class ClassBase {}
abstract class Mixin {}
class DerivedClass3 extends ClassBase implements Mixin {}
list_remove_unrelated_type
İlişkisiz türlerin referanslarıyla remove
çağrısı.
Parametre türünden farklı türde bir örnekle(instance) listede remove yöntemini çağırmayın.
Bunu yapmak, liste elemanları üzerinde == öğesini çağırır ve büyük olasılıkla false döndürür.
Yanlış kullanım:
void someFunction() {
var list = <int>[];
if (list.remove('1')) print('someFunction'); // LINT
}
Yanlış kullanım:
void someFunction3() {
List<int> list = <int>[];
if (list.remove('1')) print('someFunction3'); // LINT
}
Yanlış kullanım:
void someFunction8() {
List<DerivedClass2> list = <DerivedClass2>[];
DerivedClass3 instance;
if (list.remove(instance)) print('someFunction8'); // LINT
}
Yanlış kullanım:
abstract class SomeList<E> implements List<E> {}
abstract class MyClass implements SomeList<int> {
bool badMethod(String thing) => this.remove(thing); // LINT
}
Doğru kullanım:
void someFunction10() {
var list = [];
if (list.remove(1)) print('someFunction10'); // OK
}
Doğru kullanım:
void someFunction1() {
var list = <int>[];
if (list.remove(1)) print('someFunction1'); // OK
}
Doğru kullanım:
void someFunction4() {
List<int> list = <int>[];
if (list.remove(1)) print('someFunction4'); // OK
}
Doğru kullanım:
void someFunction5() {
List<ClassBase> list = <ClassBase>[];
DerivedClass1 instance;
if (list.remove(instance)) print('someFunction5'); // OK
}
abstract class ClassBase {}
class DerivedClass1 extends ClassBase {}
Doğru kullanım:
void someFunction6() {
List<Mixin> list = <Mixin>[];
DerivedClass2 instance;
if (list.remove(instance)) print('someFunction6'); // OK
}
abstract class ClassBase {}
abstract class Mixin {}
class DerivedClass2 extends ClassBase with Mixin {}
Doğru kullanım:
void someFunction7() {
List<Mixin> list = <Mixin>[];
DerivedClass3 instance;
if (list.remove(instance)) print('someFunction7'); // OK
}
abstract class ClassBase {}
abstract class Mixin {}
class DerivedClass3 extends ClassBase implements Mixin {}
literal_only_boolean_expressions
Boole ifadesi yalnızca literal'lerden oluşur.
False'dan başka bir şey olamayacak bir koşulu kullanan koşullu ifadeler (conditional statements), kod bloklarını işlevsiz hale getirme etkisine sahiptir. Koşul, true dışında hiçbir şeyi değerlendiremezse, koşullu ifade tamamen gereksizdir ve kodu daha az okunabilir hale getirir. Kodun programcının amacı ile uyuşmaması oldukça olasıdır. Ya koşul kaldırılmalı ya da her zaman true veya false olarak değerlendirilmemesi için güncellenmelidir.
Yanlış kullanım:
void bad() {
if (true) {} // LINT
}
Yanlış kullanım:
void bad() {
if (true && 1 != 0) {} // LINT
}
Yanlış kullanım:
void bad() {
if (1 != 0 && true) {} // LINT
}
Yanlış kullanım:
void bad() {
if (1 < 0 && true) {} // LINT
}
Yanlış kullanım:
void bad() {
if (true && false) {} // LINT
}
Yanlış kullanım:
void bad() {
if (1 != 0) {} // LINT
}
Yanlış kullanım:
void bad() {
if (true && 1 != 0 || 3 < 4) {} // LINT
}
Yanlış kullanım:
void bad() {
if (1 != 0 || 3 < 4 && true) {} // LINT
}
NOT: (;;) eşdeğerine tercih edilen while (true) { } deyimi için bir istisna yapılmıştır.
Doğru kullanım:
void good() {
while (true) {
// Do stuff.
}
}
no_adjacent_strings_in_list
Listede bitişik stringleri kullanmayın.
Doğru kullanım:
List<String> list = <String>[
'a' +
'b',
'c',
];
Yanlış kullanım:
List<String> list = <String>[
'a'
'b',
'c',
];
no_duplicate_case_values
Aynı değerde birden fazla case kullanmayın.
Bu genellikle bir yazım hatası veya constant'ın değiştirilmiş değeridir.
Doğru kullanım:
const int A = 1;
switch (v) {
case A:
case 2:
}
Yanlış kullanım:
const int A = 1;
switch (v) {
case 1:
case 2:
case A:
case 2:
}
no_logic_in_create_state
"createState" içine herhangi bir mantık koymayın.
createState() uygulamaları, bir state nesnesinin yeni bir örneğini (instance) döndürmeli ve başka bir şey yapmamalıdır. Widget alanı aracılığıyla durum erişimi tercih edildiğinden, verilerin özel constructor parametreleri kullanılarak state nesnelerine iletilmesinden de kaçınılmalıdır ve , state constructor'ına hiçbir argüman iletilmemelidir.
Yanlış kullanım:
MyState global;
class MyStateful extends StatefulWidget {
@override
MyState createState() {
global = MyState();
return global;
}
}
class MyStateful extends StatefulWidget {
@override
MyState createState() => MyState()..field = 42;
}
class MyStateful extends StatefulWidget {
@override
MyState createState() => MyState(42);
}
Doğru kullanım:
class MyStateful extends StatefulWidget {
@override
MyState createState() {
return MyState();
}
}
prefer_relative_imports
lib/ altındaki dosyalar için relative import'u tercih edin.
Relative(göreceli) ve absolute(mutlak) içe aktarmaların her ikisini birden kullanırken aynı üyenin iki farklı şekilde içe aktarıldığı bir durumla karşılaşılması mümkündür.
Bundan kaçınmak için lib/ klasöründeki dosyalar için sürekli olarak relative importları (göreceli içe aktarmaları) kullandığınızdan emin olun.
Doğru kullanım: import 'bar.dart';
Yanlış kullanım: import 'package:my_package/bar.dart';
prefer_void_to_null
Void'in çalışacağı yerlerde Null türünü kullanmayın.
Yanlış kullanım:
Null f() {}
Future<Null> f() {}
Stream<Null> f() {}
f(Null x) {}
Doğru kullanım:
void f() {}
Future<void> f() {}
Stream<void> f() {}
f(void x) {}
Bazı istisnalar, özel işlev türlerinin formüle edilmesini içerir:
Null Function(Null, Null);
ve herhangi bir map veya list türü için read-only konumlara geçmek için güvenli olan empty literal'ler (değişmezler) yapmak için:
<Null>[];
<int, Null>{};
test_types_in_equals
Türlerin test edilmemesi, sınıfınızın tüketicileri için beklenmeyen null pointer (boş işaretçi) istisnalarına (exceptions) neden olabilir.
Doğru kullanım:
class Field {
}
class Good {
final Field someField;
Good(this.someField);
@override
bool operator ==(Object other) {
if (identical(this, other)) {
return true;
}
return other is Good &&
this.someField == other.someField;
}
@override
int get hashCode {
return someField.hashCode;
}
}
Yanlış kullanım:
class Field {
}
class Bad {
final Field someField;
Bad(this.someField);
@override
bool operator ==(Object other) {
Bad otherBad = other as Bad; // LINT
bool areEqual = otherBad != null && otherBad.someField == someField;
return areEqual;
}
@override
int get hashCode {
return someField.hashCode;
}
}
throw_in_finally
Son bloklarda istisna(exceptions) atmaktan kaçının.
Nihai bloklarda istisnalar atmak, hata ayıklaması zor olan beklenmeyen davranışlara(unexpected behavior) neden olacaktır.
Doğru kullanım:
class Ok {
double compliantMethod() {
var i = 5;
try {
i = 1 / 0;
} catch (e) {
print(e); // OK
}
return i;
}
}
Yanlış kullanım:
class BadThrow {
double nonCompliantMethod() {
try {
print('hello world! ${1 / 0}');
} catch (e) {
print(e);
} finally {
throw 'Find the hidden error :P'; // LINT
}
}
}
unnecessary_statements
Gereksiz ifadeler kullanmaktan kaçının.
Açık bir etkisi olmayan ifadeler genellikle gereksizdir veya bölünmelidir.
Örneğin,
Yanlış kullanım:
myvar;
list.clear;
1 + 2;
methodOne() + methodTwo();
foo ? bar : baz;
Bunun gibi kodlar eksik bir düşünceyi gösterir ve bir hatadır.
Doğru kullanım:
some.method();
const SomeClass();
methodOne();
methodTwo();
foo ? bar() : baz();
return myvar;
unrelated_type_equality_checks
Eşitlik operatörünü ilişkisiz türlerin referanslarını karşılaştırırken kullanmayın.
Hiçbirinin diğerinin alt türü olmadığı bir türün referanslarını karşılaştırmak, büyük olasılıkla false döndürür ve programcının amacını yansıtmayabilir.
package:fixnum'daki Int64 ve Int32, int2in sağ tarafta olması koşuluyla int ile karşılaştırmaya izin verir. Lint, buna özel bir durum olarak izin verir.
Yanlış kullanım:
void someFunction() {
var x = '1';
if (x == 1) print('someFunction'); // LINT
}
Yanlış kullanım:
void someFunction1() {
String x = '1';
if (x == 1) print('someFunction1'); // LINT
}
Yanlış kullanım:
void someFunction13(DerivedClass2 instance) {
var other = DerivedClass3();
if (other == instance) print('someFunction13'); // LINT
}
class ClassBase {}
class DerivedClass1 extends ClassBase {}
abstract class Mixin {}
class DerivedClass2 extends ClassBase with Mixin {}
class DerivedClass3 extends ClassBase implements Mixin {}
Doğru kullanım:
void someFunction2() {
var x = '1';
var y = '2';
if (x == y) print(someFunction2); // OK
}
Doğru kullanım:
void someFunction3() {
for (var i = 0; i < 10; i++) {
if (i == 0) print(someFunction3); // OK
}
}
Doğru kullanım:
void someFunction4() {
var x = '1';
if (x == null) print(someFunction4); // OK
}
Doğru kullanım:
void someFunction7() {
List someList;
if (someList.length == 0) print('someFunction7'); // OK
}
Doğru kullanım:
void someFunction8(ClassBase instance) {
DerivedClass1 other;
if (other == instance) print('someFunction8'); // OK
}
Doğru kullanım:
void someFunction10(unknown) {
var what = unknown - 1;
for (var index = 0; index < unknown; index++) {
if (what == index) print('someFunction10'); // OK
}
}
Doğru kullanım:
void someFunction11(Mixin instance) {
var other = DerivedClass2();
if (other == instance) print('someFunction11'); // OK
if (other != instance) print('!someFunction11'); // OK
}
class ClassBase {}
abstract class Mixin {}
class DerivedClass2 extends ClassBase with Mixin {}
unsafe_html
Güvenli olmayan HTML API'lerinden kaçının.
• Bir AnchorElement öğesinin href alanına doğrudan atama
• Bir EmbedElement, IFrameElement, ImageElement veya ScriptElement • öğesinin src alanına doğrudan atama
• Bir IFrameElement öğesinin srcdoc alanına doğrudan atama
• Element'in createFragment yöntemini çağırma
• Window open methodunu çağırma
• Element'in setInnerHtml yöntemini çağırma
• Element.html constructor'ını çağırma
• DocumentFragment.html constructor'ını çağırma
Yanlış kullanım:
var script = ScriptElement()..src = 'foo.js';
use_build_context_synchronously
Asenkron boşluklarda BuildContexts kullanmayın.
BuildContext'i daha sonra kullanmak üzere saklamak, teşhis edilmesi zor çökmelere yol açabilir. Asenkron boşluklar örtük olarak BuildContext'i depolar ve kod yazarken gözden kaçırılır.
Bir StatefulWidget'tan bir BuildContext kullanıldığında, asenkron bir boşluktan sonra mounted property kontrol edilmelidir.
Doğru kullanım:
void onButtonTapped(BuildContext context) {
Navigator.of(context).pop();
}
Yanlış kullanım:
void onButtonTapped(BuildContext context) async {
await Future.delayed(const Duration(seconds: 1));
Navigator.of(context).pop();
}
Doğru kullanım:
class _MyWidgetState extends State<MyWidget> {
...
void onButtonTapped() async {
await Future.delayed(const Duration(seconds: 1));
if (!mounted) return;
Navigator.of(context).pop();
}
}
use_key_in_widget_constructors
Widget constructor'larında key kullanın.
Public widget'lar oluştururken key kullanmak iyi bir yoldur.
Yanlış kullanım:
class MyPublicWidget extends StatelessWidget {}
Doğru kullanım:
class MyPublicWidget extends StatelessWidget {
MyPublicWidget({Key? key}) : super(key: key);
}
valid_regexps
Geçerli bir regular expression syntax'ı kullanın.
Regular expression (normal ifade örnekleri) oluştururken geçerli regular expression söz dizimini kullanın.
Geçersiz syntax ile oluşturulan düzenli ifadeler, çalışma zamanında bir FormatException oluşturacaktır, bu nedenle bunlardan kaçınılmalıdır.
Yanlış kullanım: print(RegExp(r'(').hasMatch('foo()'));
Doğru kullanım: print(RegExp(r'\(').hasMatch('foo()'));
Bu yazıda Linter kurallarının ilk grubu olan error kurallarını inceledik. Bir sonraki yazıda stil kurallarını inceleyeceğiz.
References:
https://medium.com/podiihq/setting-up-lint-rules-in-dart-flutter-1ebbed0418a6
https://medium.flutterdevs.com/lint-rules-in-flutter-efbcf05daeb5
https://dart.dev/tools/linter-rules#directives_ordering
https://dart-lang.github.io/linter/lints/
https://sourcelevel.io/blog/what-is-a-linter-and-why-your-team-should-use-it
Posted on February 19, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.