dart format dan dart fix

dart format untuk tata letak kode dengan satu gaya resmi dan dart fix untuk migrasi otomatis.

Daftar isi

dart format menyusun ulang tata letak kode dengan satu gaya resmi, sedangkan dart fix menerapkan perbaikan otomatis pada pola penulisan yang sudah usang. Topik ini membahas keduanya pada proyek konversi suhu sederhana yang dibangun dari nol, mulai dari memformat berkas yang berantakan sampai melakukan migrasi kecil secara otomatis. Setelah membacanya, kedua perintah dapat dijalankan pada proyek mana pun, dan keluaran yang dihasilkannya dapat dibaca dengan tepat.

Formatter dengan satu gaya resmi#

dart format adalah formatter bawaan toolchain Dart, yaitu program yang menulis ulang teks kode tanpa mengubah maknanya. Perubahan yang diterapkan hanya menyentuh susunan baris, indentasi, dan spasi, sehingga struktur program tetap sama persis. Perintahnya dapat dijalankan pada satu berkas, sejumlah berkas, atau seluruh folder proyek, dan hasilnya langsung ditulis ke berkas yang sama.

Gaya yang dihasilkan bersifat tunggal dan tidak dapat dinegosiasikan (opinionated). Tidak ada berkas konfigurasi gaya yang dibaca dart format, tidak ada pilihan kedalaman indentasi, dan tidak ada perdebatan panjang tentang penempatan tanda kurung. Keputusan gaya ditetapkan satu kali oleh tim Dart, kemudian diterapkan sama pada semua proyek. Konsekuensinya menguntungkan tim pengembang, karena kode yang ditulis oleh orang berbeda di folder berbeda tetap seragam.

Sejak Dart 3.7, gaya tersebut dikenal sebagai tall style, yang menata argumen dan elemen koleksi secara bertingkat apabila satu baris tidak muat dalam batas lebar baris. Pada proyek kecil, perbedaannya jarang terasa, tetapi konsistensinya tetap berlaku sama. Detail gaya tidak perlu dihafal karena alat inilah yang memutuskan susunannya.

Memformat berkas berantakan#

Proyek latihan dibuat dari nol sebagai package konversi suhu tanpa dependensi. Berkas pertamanya sengaja ditulis berantakan, yaitu indentasi yang tidak konsisten di antara fungsi, operator tanpa spasi, dan badan perulangan yang menempel di kiri. Blok berikut membuat proyek beserta berkas pertamanya.

bash
# buat proyek konversi suhu dari nol
rm -rf ~/contoh/alat-dan-kualitas/dart-format-dan-dart-fix/konversi_suhu
mkdir -p ~/contoh/alat-dan-kualitas/dart-format-dan-dart-fix/konversi_suhu/lib
cd ~/contoh/alat-dan-kualitas/dart-format-dan-dart-fix/konversi_suhu
export PATH=/home/kal/dart-sdk/bin:$PATH
cat > pubspec.yaml <<'EOF'
name: konversi_suhu
description: Konversi suhu untuk latihan dart format dan dart fix.
version: 1.0.0
environment:
  sdk: ^3.13.0
EOF
cat > lib/konversi_suhu.dart <<'EOF'
double celsiusKeFahrenheit(double celsius){
    return celsius*9/5+32;
}

double fahrenheitKeCelsius(double fahrenheit) {
  return (fahrenheit-32)*5/9;
}

void main() {
final derajat = [0.0, 36.6, 100.0];
for (var nilai in derajat) {
print('${celsiusKeFahrenheit(nilai).toStringAsFixed(1)} F dari ${nilai} C');
}
}
EOF

Isi awal berkasnya diamati terlebih dahulu, karena blok berikutnya akan menulis ulang berkas itu.

bash
# tampilkan isi berkas yang masih berantakan
cat lib/konversi_suhu.dart
text Keluaran
double celsiusKeFahrenheit(double celsius){
    return celsius*9/5+32;
}

double fahrenheitKeCelsius(double fahrenheit) {
  return (fahrenheit-32)*5/9;
}

void main() {
final derajat = [0.0, 36.6, 100.0];
for (var nilai in derajat) {
print('${celsiusKeFahrenheit(nilai).toStringAsFixed(1)} F dari ${nilai} C');
}
}

Pemformatan dijalankan dengan menyebut jalur berkasnya secara eksplisit.

bash
# rapikan satu berkas dengan dart format
dart format lib/konversi_suhu.dart
text Keluaran
Formatted lib/konversi_suhu.dart
Formatted 1 file (1 changed) in 0.00 seconds.

Keluaran memuat dua baris. Baris pertama menyebut berkas yang ditulis ulang, sedangkan baris kedua merangkum pemeriksaannya, yaitu satu berkas diperiksa dan satu berubah. Berkas yang telah rapi ditunjukkan di bawah ini.

dart konversi_suhu.dart
double celsiusKeFahrenheit(double celsius) {
  return celsius * 9 / 5 + 32;
}

double fahrenheitKeCelsius(double fahrenheit) {
  return (fahrenheit - 32) * 5 / 9;
}

void main() {
  final derajat = [0.0, 36.6, 100.0];
  for (var nilai in derajat) {
    print('${celsiusKeFahrenheit(nilai).toStringAsFixed(1)} F dari ${nilai} C');
  }
}

Dibandingkan dengan versi awal pada Keluaran sebelumnya, badan setiap fungsi kini menjorok dua spasi dari deklarasi fungsinya, operator aritmetika diberi spasi di kedua sisinya, dan badan perulangan for tidak lagi menempel di kiri. Yang tidak berubah adalah nama, tipe, urutan pernyataan, dan nilai yang dihitung. Perbandingan semacam ini biasanya dilakukan melalui alat pengelola versi, yang menampilkan hasil formatter sebagai baris-baris kecil yang mudah ditinjau.

Perubahan yang diterapkan formatter#

Format yang dihasilkan mengikuti aturan tetap. Indentasi bertambah dua spasi untuk setiap tingkat sarang, spasi mengapit operator seperti * dan /, dan baris kosong di antara deklarasi dipertahankan satu. Batas lebar baris ditetapkan 80 karakter, dan argumen yang tidak muat ditata bertingkat sesuai tall style.

Klaim bahwa formatter tidak mengubah perilaku dapat diuji langsung dengan menjalankan programnya. Program konversi suhu mencetak hasil konversi tiga nilai Celsius ke Fahrenheit, dan keluaran pada blok berikut berasal dari program yang sudah diformat.

bash
# jalankan program yang sudah diformat
dart run lib/konversi_suhu.dart
text Keluaran
32.0 F dari 0.0 C
97.9 F dari 36.6 C
212.0 F dari 100.0 C

Tiga konversi tercetak dengan nilai yang sesuai perhitungannya, yaitu 32.0, 97.9, dan 212.0 Fahrenheit. Nilai 36.6 derajat menghasilkan 97.9 Fahrenheit setelah pembulatan satu desimal melalui toStringAsFixed. Karena hanya teks yang disusun ulang, keluaran ini sama dengan yang dicetak program sebelum format, tanpa memerlukan pengujian ulang.

Memperbaiki pola lama dengan dart fix#

dart fix menerapkan perbaikan otomatis atas pola penulisan yang sudah usang. Sumber perbaikannya adalah diagnostik yang aktif pada proyek, termasuk aturan linter yang diaktifkan melalui analysis_options.yaml. Berkas konfigurasi analysis_options.yaml yang diperkenalkan pada topik dart analyze digunakan kembali di sini, kali ini berisi aturan yang menjadi dasar perbaikan otomatis.

Berkas kedua pada proyek latihan sengaja ditulis dengan dua pola lama. Kata kunci new sebelum nama kelas merupakan keharusan di Dart 1 dan sudah tidak diperlukan sejak Dart 2, tetapi penulisannya masih sah sampai sekarang. Pembuatan objek Skala('F') belum diawali const padahal konstruktor Skala adalah konstruktor const, sehingga objeknya dapat dibuat sebagai konstanta pada waktu kompilasi. Dua aturan linter dipilih untuk menandai keduanya, yaitu unnecessary_new dan prefer_const_constructors.

yaml analysis_options.yaml
linter:
  rules:
    - unnecessary_new
    - prefer_const_constructors

Berkas konversi_lama.dart ditulis ke folder lib menggunakan heredoc, dan isi awalnya ditampilkan untuk perbandingan.

bash
# tulis aturan linter dan berkas dengan pola lama, lalu tampilkan isinya
cat > analysis_options.yaml <<'EOF'
linter:
  rules:
    - unnecessary_new
    - prefer_const_constructors
EOF
cat > lib/konversi_lama.dart <<'EOF'
class Skala {
  final String satuan;
  const Skala(this.satuan);
}

class Termometer {
  double suhu;
  Termometer(double suhuAwal) : suhu = suhuAwal;
}

void main() {
  var t = new Termometer(97.9);
  var label = Skala('F');
  print('${t.suhu} ${label.satuan}');
}
EOF
cat lib/konversi_lama.dart
text Keluaran
class Skala {
  final String satuan;
  const Skala(this.satuan);
}

class Termometer {
  double suhu;
  Termometer(double suhuAwal) : suhu = suhuAwal;
}

void main() {
  var t = new Termometer(97.9);
  var label = Skala('F');
  print('${t.suhu} ${label.satuan}');
}

Perbaikan diperiksa dahulu dengan mode uji coba (dry-run) agar rencananya terlihat tanpa mengubah berkas apa pun.

bash
# pratinjau perbaikan tanpa menerapkannya
dart fix --dry-run
text Keluaran
Computing fixes in konversi_suhu (dry run)...

2 proposed fixes in 1 file.

lib/konversi_lama.dart
  prefer_const_constructors - 1 fix
  unnecessary_new - 1 fix

To fix an individual diagnostic, run one of:
  dart fix --apply --code=prefer_const_constructors
  dart fix --apply --code=unnecessary_new

To fix all diagnostics, run:
  dart fix --apply

Keluaran menyatakan ada dua perbaikan yang diusulkan pada satu berkas, lalu merinci kodenya per berkas, yaitu prefer_const_constructors dan unnecessary_new. Bagian akhirnya menyediakan perintah yang siap disalin untuk menerapkan satu kode tertentu atau semuanya. Mode dry-run tidak menulis apa pun ke berkas, sehingga aman dijalankan berkala.

Perbaikan diterapkan dengan dart fix --apply.

bash
# terapkan seluruh perbaikan yang diusulkan
dart fix --apply
text Keluaran
Computing fixes in konversi_suhu...
Applying fixes...

lib/konversi_lama.dart
  prefer_const_constructors - 1 fix
  unnecessary_new - 1 fix

2 fixes made in 1 file.

Keluaran memuat tiga bagian, yaitu penghitungan perbaikan, daftar perbaikan per berkas, dan ringkasan bahwa dua perbaikan diterapkan pada satu berkas. Isi berkas setelah dart fix ditunjukkan berikut ini.

dart konversi_lama.dart
class Skala {
  final String satuan;
  const Skala(this.satuan);
}

class Termometer {
  double suhu;
  Termometer(double suhuAwal) : suhu = suhuAwal;
}

void main() {
  var t = Termometer(97.9);
  var label = const Skala('F');
  print('${t.suhu} ${label.satuan}');
}

Kata kunci new pada pembuatan Termometer telah dihapus, dan pembuatan Skala('F') kini diawali const. Perubahan semacam ini merupakan migrasi kecil, yaitu penggantian pola lama dengan pola baku Dart 3 tanpa mengubah perilaku. Ujiannya sederhana, yaitu menjalankan berkas hasil perbaikan.

bash
# jalankan berkas hasil perbaikan
dart run lib/konversi_lama.dart
text Keluaran
97.9 F

Keluaran 97.9 F sama seperti yang dicetak versi lama, sehingga perbaikan otomatis terbukti tidak mengubah perilaku. Proses serupa dapat diulang untuk pola lama lain selama aturan linter yang sesuai aktif. Kombinasi dart analyze yang menemukan, dart fix yang menerapkan, dan dart format yang menata membuat pemutakhiran kode berjalan dengan campur tangan manual yang minimal.

Kesalahan umum#

Kesalahan pertama terjadi saat dart format dijalankan tanpa argumen jalur. Tanpa jalur, dart format tidak memeriksa folder proyek, tetapi membaca kode dari masukan standar (stdin) dan mencetak hasilnya ke keluaran standar. Di terminal, perintah tampak diam karena menunggu ketikan dari keyboard. Perilaku ini justru berguna untuk memformat potongan kode yang dikirim melalui pipa shell, seperti pada blok berikut.

bash
# dart format tanpa jalur membaca dari stdin
echo 'void  main(){}' | dart format
text Keluaran
void main() {}

Satu baris kode masuk berantakan dan keluar rapi, tanpa berkas mana pun yang disentuh. Untuk pekerjaan biasa, sertakan selalu jalur berkas atau folder, misalnya dart format lib, agar hasilnya ditulis ulang langsung ke berkasnya.

Kesalahan kedua adalah mengharapkan dart fix menemukan pola lama tanpa mengaktifkan aturan linter. Apabila analysis_options.yaml dipindahkan sementara dari proyek, pemeriksaan pada berkas konversi_lama.dart tidak menemukan satu perbaikan pun, lalu menemukan keduanya setelah berkas konfigurasi dikembalikan. Blok berikut memperagakan urutan tersebut secara utuh.

bash
# tulis ulang berkas lama, lalu pindahkan analysis_options.yaml sementara
cat > lib/konversi_lama.dart <<'EOF'
class Skala {
  final String satuan;
  const Skala(this.satuan);
}

class Termometer {
  double suhu;
  Termometer(double suhuAwal) : suhu = suhuAwal;
}

void main() {
  var t = new Termometer(97.9);
  var label = Skala('F');
  print('${t.suhu} ${label.satuan}');
}
EOF
mv analysis_options.yaml analysis_options.bak
dart fix --dry-run
# pulihkan berkas konfigurasi lalu terapkan perbaikan
mv analysis_options.bak analysis_options.yaml
dart fix --apply
text Keluaran
Computing fixes in konversi_suhu (dry run)...
Nothing to fix!
Computing fixes in konversi_suhu...
Applying fixes...

lib/konversi_lama.dart
  prefer_const_constructors - 1 fix
  unnecessary_new - 1 fix

2 fixes made in 1 file.

Pesan Nothing to fix! pada keluaran bukan tanda berkas sudah bersih, melainkan tanda tidak ada diagnostik aktif yang menyediakan perbaikan. Pastikan analysis_options.yaml berada di akar proyek dan aturannya memang menyasar pola yang dicari. Daftar aturan lengkap beserta penjelasannya terdapat pada halaman Linter rules dart.dev yang dirujuk di bagian Referensi.

Ringkasan#

  • dart format menyusun ulang tata letak kode dengan satu gaya resmi, menulis ulang berkas di tempat, dan merangkum hasilnya pada baris seperti Formatted 1 file (1 changed).
  • Formatter tidak mengubah perilaku program, sehingga keluaran dart run sebelum dan sesudah format sama persis.
  • dart fix menerapkan perbaikan otomatis dari diagnostik aktif, dengan dart fix --dry-run untuk pratinjau dan dart fix --apply untuk penerapan.
  • Aturan linter seperti unnecessary_new dan prefer_const_constructors diaktifkan lebih dahulu melalui analysis_options.yaml sebelum dart fix dapat menemukan polanya.

Referensi#