prpm-dbp 0.13.0 → 0.13.2

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.
Files changed (3) hide show
  1. package/SKILL.md +11 -1
  2. package/package.json +1 -1
  3. package/src/tukar.js +33 -12
package/SKILL.md CHANGED
@@ -11,6 +11,8 @@ Model boleh hasilkan Jawi yang nampak betul tetapi salah, dan pembaca tidak dapa
11
11
 
12
12
  ## Peraturan
13
13
 
14
+ 0. **Semak ejaan ikut DBP, bukan ikut ingatan.** Ini peraturan pertama kerana ia yang paling kerap dilanggar. Perkataan yang anda "tahu" ejaannya masih perlu disemak. Contoh sebenar daripada penggunaan: `sunah` ialah `سنة` tetapi `sunat` ialah `سونت`; `bena` langsung tiada ejaan Jawi dalam PRPM walaupun ia perkataan yang sah; `salat` hanyalah rujukan silang kepada `solat`. Tiada satu pun daripada perbezaan ini boleh diteka daripada bentuk Rumi. Jalankan `lookup` atau `jawi`, jangan tulis daripada ingatan.
15
+
14
16
  1. **Jangan hantar Jawi yang belum disemak.** Setiap perkataan Jawi dalam output mesti datang dari PRPM atau ditanda belum disahkan.
15
17
  2. **Tanda, jangan sekat.** Kalau satu perkataan tiada dalam PRPM, hantar kerja itu dan senaraikan perkataan berkenaan di hujung. Jangan tahan seluruh dokumen sebab satu nama khas.
16
18
  3. **Sebut sumber.** PRPM ada beberapa kamus. Bila petik definisi, sebut kamus mana (Kamus Dewan Edisi Keempat, Kamus Pelajar Edisi Kedua, dan lain-lain).
@@ -67,6 +69,10 @@ Tanda baca, baris baru dan jarak dikekalkan, jadi susun atur dokumen tidak rosak
67
69
 
68
70
  Contoh kedua: `dipelajari` ialah terbitan sah daripada `ajar`. Alat ini **tidak** akan menulis Jawi bagi `ajar` di tempatnya. Itu perkataan lain, dan ejaannya berbeza.
69
71
 
72
+ **Calon pembacaan songsang diisih ikut rantai kepercayaan.** Perkataan hanya layak menjadi pembacaan bagi sesuatu ejaan Jawi jika PRPM memberikannya ejaan Jawi **sendiri**. Kata yang PRPM catatkan tanpa ejaan Jawi (`bena`), atau yang definisinya rujukan silang (`salat` → `® solat`), dibuang daripada senarai calon walaupun dataset komuniti memetakannya kepada ejaan yang sama.
73
+
74
+ Perkataan yang **belum diketahui** statusnya, iaitu tiada dalam cache, tidak pernah dibuang. Ketiadaan bukan bukti kegagalan. Ia kekal sebagai calon dan sumbernya dilabel `dataset`. Kerana itu memanaskan cache mengurangkan kekaburan: bukan kerana peraturan berubah, tetapi kerana bukti bertambah.
75
+
70
76
  **Bila `rumi` jumpa kekaburan**, satu ejaan Jawi memetakan kepada beberapa perkataan Rumi. Semua calon dipaparkan dipisah `|`. Pilih ikut konteks ayat, jangan ambil yang pertama secara membuta.
71
77
 
72
78
  Sebahagian kekaburan itu palsu dan diselesaikan sendiri. DBP menandakan bentuk varian dengan **rujukan silang**: definisi `kalkalah` ialah `®qalqalah.`, bukan definisi sebenar. Varian begitu dinyahutamakan, jadi `قلقله` dibaca `qalqalah` terus.
@@ -288,7 +294,11 @@ Panduan DBP membahagikannya kepada dua:
288
294
 
289
295
  Jenis kedua ialah Pedoman §8.17 (juga Klinik Jawi Siri ke-35): alif melambangkan [a] di suku kata tertutup untuk membezakannya daripada pepet yang tidak dilambangkan. **Ejaan DBP sudah mengandungi peraturan ini**, jadi pakej tidak perlu menjananya. Sembilan pasangan rujukan diuji, kesemuanya dibezakan dengan betul.
290
296
 
291
- Jenis pertama pula tidak boleh diselesaikan oleh mana-mana peraturan. Itulah sebab `rumi` melaporkan semua calon dan enggan memilih: bagi homograf hakiki, DBP sendiri menyatakan kekaburan itu dibenarkan dan hanya konteks ayat boleh menyelesaikannya.
297
+ **Istilah "hakiki" dan "tidak hakiki" tidak digunakan dalam pakej ini.** Sumber pengajaran bercanggah tentang mana satu bermaksud apa: satu panduan menyatakan hakiki bermaksud tidak dibezakan dan dibenarkan kekal, satu lagi menyatakan hakiki bermaksud boleh diselesaikan dengan huruf saksi. Pakej melaporkan fakta yang boleh diperhatikan, iaitu ejaan Jawi ini dikongsi oleh perkataan-perkataan berikut, dan membiarkan pengelasan itu kepada guru.
298
+
299
+ Sebahagian homograf ejaan lama telah diselesaikan oleh ejaan baharu dengan menambah huruf vokal: `tulang` تولڠ dan `tolong` تولوڠ, `tujuh` توجوه dan `tujah` توجه. Pembezaan itu ada dalam ejaan yang kita ambil dan dikunci dengan ujian.
300
+
301
+ Jenis yang tinggal pula tidak boleh diselesaikan oleh mana-mana peraturan. Itulah sebab `rumi` melaporkan semua calon dan enggan memilih: bagi homograf hakiki, DBP sendiri menyatakan kekaburan itu dibenarkan dan hanya konteks ayat boleh menyelesaikannya.
292
302
 
293
303
  `--homograf` menandakan perkataan yang ejaan Jawinya dikongsi, supaya penulis tahu sebelum menghantar bahawa pembaca akan bergantung pada konteks:
294
304
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prpm-dbp",
3
- "version": "0.13.0",
3
+ "version": "0.13.2",
4
4
  "description": "Semak ejaan Bahasa Melayu dan Jawi terhadap PRPM Dewan Bahasa dan Pustaka. CLI dan skill untuk AI agent.",
5
5
  "keywords": [
6
6
  "bahasa-melayu",
package/src/tukar.js CHANGED
@@ -172,10 +172,26 @@ export function petaSongsang(cache, dataset = null) {
172
172
  // Isyaratnya mestilah tanda ® itu, BUKAN kehadiran ejaan Jawi. `pada`
173
173
  // tiada Jawi dalam PRPM manakala `pad` (pinjaman Inggeris) ada, jadi
174
174
  // mengutamakan "yang ada Jawi" akan menukar setiap `pada` menjadi `pad`.
175
- const rujukanSilang = new Set()
176
- for (const [kata, rec] of Object.entries(cache)) {
177
- const def = rec?.entri?.[0]?.definisi ?? ''
178
- if (/^®/.test(def.trim())) rujukanSilang.add(kata)
175
+ // Calon dikelaskan kepada TIGA peringkat, bukan dua.
176
+ //
177
+ // layak : PRPM ada entri DAN ada ejaan Jawi sendiri. Ini lapisan 1.
178
+ // tolak : PRPM ada entri tetapi TIADA ejaan Jawi, atau definisinya
179
+ // rujukan silang (®). Kata begini tidak boleh menjadi
180
+ // pembacaan bagi mana-mana ejaan Jawi.
181
+ // entah : tiada dalam cache langsung. Ketiadaan BUKAN bukti kegagalan,
182
+ // jadi ia tidak boleh dibuang. Ia kekal sebagai calon lapisan 3.
183
+ //
184
+ // Perbezaan antara `tolak` dan `entah` itulah pembetulannya. Versi lama
185
+ // hanya memeriksa rujukan silang, dan hanya bagi calon yang datang dari
186
+ // cache, jadi calon dataset seperti salat dan bena lolos sepenuhnya.
187
+ const darjat = (rumi) => {
188
+ const rec = cache[rumi]
189
+ if (!rec) return 'entah'
190
+ const def = (rec.entri?.[0]?.definisi ?? '').trim()
191
+ if (/^®/.test(def)) return 'tolak'
192
+ if (rec.dijumpai && !rec.jawi) return 'tolak'
193
+ if (rec.jawi) return 'layak'
194
+ return 'entah'
179
195
  }
180
196
 
181
197
  const tambah = (jawi, rumi, sumber) => {
@@ -183,9 +199,8 @@ export function petaSongsang(cache, dataset = null) {
183
199
  if (!kunci) return
184
200
  const bilangan = kunci.split(/\s+/).length
185
201
  if (bilangan > maxKata) maxKata = bilangan
186
- if (!peta.has(kunci)) peta.set(kunci, { utama: [], rujukan: [] })
187
- const jenis = rujukanSilang.has(rumi) ? 'rujukan' : 'utama'
188
- const slot = peta.get(kunci)[jenis]
202
+ if (!peta.has(kunci)) peta.set(kunci, { layak: [], entah: [], tolak: [] })
203
+ const slot = peta.get(kunci)[darjat(rumi)]
189
204
  if (!slot.includes(rumi)) slot.push(rumi)
190
205
  }
191
206
 
@@ -201,15 +216,21 @@ export function petaSongsang(cache, dataset = null) {
201
216
  }
202
217
 
203
218
  /**
204
- * Pilih calon songsang. Bentuk yang DBP sendiri tandakan sebagai rujukan
205
- * silang (®) hanya digunakan apabila tiada bentuk utama. Selain itu semua
206
- * calon dilayan sama rata, dan kekaburan sebenar dilaporkan sepenuhnya.
219
+ * Pilih calon songsang mengikut rantai kepercayaan.
220
+ *
221
+ * Calon lapisan 1 (ada entri PRPM dengan ejaan Jawi sendiri) menang mutlak.
222
+ * Kekaburan dilaporkan HANYA apabila dua calon lapisan 1 berkongsi ejaan,
223
+ * iaitu homograf tulen seperti sunah dan sanat yang kedua-duanya سنة.
224
+ *
225
+ * Apabila tiada calon lapisan 1, calon yang belum diketahui digunakan dan
226
+ * sumbernya dilabel, tidak dipulangkan secara senyap.
207
227
  */
208
228
  export function pilihCalon(masuk) {
209
229
  if (!masuk) return null
210
230
  if (Array.isArray(masuk)) return { calon: masuk, sumber: 'campur' }
211
- if (masuk.utama.length) return { calon: masuk.utama, sumber: 'utama' }
212
- if (masuk.rujukan.length) return { calon: masuk.rujukan, sumber: 'rujukan' }
231
+ if (masuk.layak?.length) return { calon: masuk.layak, sumber: 'dbp' }
232
+ if (masuk.entah?.length) return { calon: masuk.entah, sumber: 'dataset' }
233
+ if (masuk.tolak?.length) return { calon: masuk.tolak, sumber: 'rujukan' }
213
234
  return null
214
235
  }
215
236