prpm-dbp 0.4.0 → 0.5.0

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/SKILL.md CHANGED
@@ -116,6 +116,34 @@ Ejaan yang disimpan begini ditandakan datang daripada pengguna, bukan daripada D
116
116
 
117
117
  Bagi nama berasal Arab, ejaan Jawinya memang ejaan Arab asal, jadi ia nampak seperti dikekalkan. Bagi nama bukan Arab ia ditransliterasi penuh: `Kuala Lumpur` menjadi `کوالا لومڤور`.
118
118
 
119
+ ## Peraturan Pedoman DBP
120
+
121
+ Satu fail sahaja dalam pakej ini **menjana** ejaan dan bukan mencarinya: `src/pedoman.js`. Ia dibenarkan kerana setiap peraturan di dalamnya datang daripada *Pedoman Umum Ejaan Jawi Bahasa Melayu* terbitan DBP, dan dirujuk pada seksyennya.
122
+
123
+ **§14.1 — kata sendi `di` dan `ke` ditulis sebagai satu kata dengan kata yang mengikutinya.**
124
+
125
+ ```
126
+ di Mekah -> دمکة bukan د مکة
127
+ ke sekolah -> کسکوله bukan ک سکوله
128
+ ```
129
+
130
+ Nota seksyen yang sama: jika kata berikutnya bermula dengan alif, hamzah dibubuh di atas alif itu. `di Asrama` menjadi `دأسراما`, bukan `داسراما`.
131
+
132
+ Kodpoint hamzah (U+0623) disahkan secara empirik daripada dataset, bukan diandaikan: `abai` bermula `ا` U+0627, `diabaikan` bermula `د` + `أ` U+0623. Corak sama pada `diambil`, `diajar`, `diurus`.
133
+
134
+ Bentuk bercantum tidak wujud sebagai entri kamus, jadi pembacaan songsang memisahkannya semula dan memulihkan hamzah kepada alif. Peraturan ini simetri.
135
+
136
+ Kata sendi **tidak** dicantum apabila kata berikutnya belum disahkan, kerana hasilnya akan menjadi Jawi bercantum dengan teks Rumi bertanda.
137
+
138
+ **§11 — kata serapan Arab, dua peringkat:**
139
+
140
+ | Seksyen | Jenis | Cara eja | Contoh |
141
+ |---|---|---|---|
142
+ | §11.1 | istilah khusus | ikut ejaan asal Arab | `wuduk`, `Qur'an`, `sunah`, `hadis`, `tayamum` |
143
+ | §11.2 | kata umum yang sudah terserap | ikut kaedah kata jati Melayu | `sabun` |
144
+
145
+ Pakej tidak perlu memilih antara dua ini. DBP sudah memilih, dan pilihan itu terkandung dalam ejaan yang dipulangkan PRPM. Ia didokumenkan supaya tiada siapa "membetulkan" `صلاة` kepada ejaan fonetik Melayu kemudian hari.
146
+
119
147
  ## Rantai kepercayaan
120
148
 
121
149
  Setiap ejaan Jawi yang dikeluarkan membawa asal-usulnya. Jangan runtuhkan lapisan ini.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prpm-dbp",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
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/pedoman.js ADDED
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Peraturan daripada Pedoman Umum Ejaan Jawi Bahasa Melayu (DBP).
3
+ *
4
+ * Ini satu-satunya tempat dalam pakej yang MENJANA ejaan dan bukan sekadar
5
+ * mencarinya. Ia dibenarkan kerana setiap peraturan di sini datang daripada
6
+ * dokumen rasmi DBP dan dirujuk pada seksyennya, bukan direka.
7
+ *
8
+ * Sumber: Pedoman Umum Ejaan Jawi Bahasa Melayu, Dewan Bahasa dan Pustaka.
9
+ * Berasaskan Pedoman Ejaan Jawi yang Disempurnakan (1986, ed. 3 1993),
10
+ * hasil Konvensyen Tulisan Jawi Peringkat Kebangsaan 1984, diselaraskan
11
+ * 1991 dan 1993, disahkan Jawatankuasa Teknikal Ejaan Jawi 1993-1994.
12
+ */
13
+
14
+ const ALIF = 'ا' // ا
15
+ const ALIF_HAMZAH = 'أ' // أ
16
+
17
+ /**
18
+ * §14.1 — Kata sendi nama `di` dan `ke` ditulis sebagai SATU KATA dengan
19
+ * kata yang mengikutinya.
20
+ *
21
+ * Nota §14.1: jika kata yang mengikutinya bermula dengan huruf alif, huruf
22
+ * hamzah dibubuh di atas alif itu.
23
+ *
24
+ * Kodpoint hamzah disahkan secara empirik daripada dataset, bukan diandaikan:
25
+ * abai ا U+0627 ...
26
+ * diabaikan د + أ U+0623 ...
27
+ * Corak sama pada diambil, diajar, diurus.
28
+ */
29
+ export const KATA_SENDI = new Map([
30
+ ['di', 'د'], // د
31
+ ['ke', 'ک'], // ک
32
+ ])
33
+
34
+ export function bolehCantumSendi(kata) {
35
+ return KATA_SENDI.has(String(kata).toLowerCase())
36
+ }
37
+
38
+ /**
39
+ * Cantumkan kata sendi dengan ejaan Jawi kata yang mengikutinya.
40
+ * Pulangkan null jika kata itu bukan kata sendi yang dicakupi.
41
+ */
42
+ export function cantumSendi(kataSendi, jawiSelepas) {
43
+ const awalan = KATA_SENDI.get(String(kataSendi).toLowerCase())
44
+ if (!awalan || !jawiSelepas) return null
45
+
46
+ const selepas = jawiSelepas.startsWith(ALIF)
47
+ ? ALIF_HAMZAH + jawiSelepas.slice(ALIF.length)
48
+ : jawiSelepas
49
+
50
+ return { jawi: awalan + selepas, rujukan: 'Pedoman DBP §14.1' }
51
+ }
52
+
53
+ /**
54
+ * §11 — Kata serapan Arab dieja dalam dua cara berbeza:
55
+ * §11.1 istilah khusus -> ikut ejaan asal bahasa Arab (wuduk, Qur'an,
56
+ * sunah, hadis, tayamum, wuquf, reda)
57
+ * §11.2 kata umum yang -> ikut cara mengeja kata jati Melayu (sabun)
58
+ * sudah terserap
59
+ *
60
+ * Pakej ini tidak perlu memilih antara dua ini: DBP sudah memilih, dan
61
+ * pilihan itu terkandung dalam ejaan yang dipulangkan PRPM. Peraturan ini
62
+ * didokumenkan di sini supaya tiada siapa "membetulkan" صلاة kepada ejaan
63
+ * fonetik Melayu kemudian hari.
64
+ */
65
+ export const NOTA_SERAPAN_ARAB = 'Pedoman DBP §11.1 dan §11.2'
66
+
67
+ /**
68
+ * Songsangan §14.1: pisahkan kata sendi yang bercantum.
69
+ *
70
+ * Bentuk bercantum seperti دمکة tidak wujud sebagai entri kamus, jadi
71
+ * pembacaan songsang mesti mencubanya sendiri. Hamzah dipulihkan kepada
72
+ * alif kerana hamzah itu ditambah oleh peraturan, bukan sebahagian ejaan
73
+ * kata dasar.
74
+ */
75
+ export function pisahSendi(jawi) {
76
+ const calon = []
77
+ for (const [rumi, awalan] of KATA_SENDI) {
78
+ if (!jawi.startsWith(awalan) || jawi.length <= awalan.length) continue
79
+ let baki = jawi.slice(awalan.length)
80
+ if (baki.startsWith(ALIF_HAMZAH)) baki = ALIF + baki.slice(ALIF_HAMZAH.length)
81
+ calon.push({ sendi: rumi, baki, rujukan: 'Pedoman DBP §14.1' })
82
+ }
83
+ return calon
84
+ }
package/src/tukar.js CHANGED
@@ -12,6 +12,7 @@ import { lookup } from './prpm.js'
12
12
  import { normalisasiJawi } from './kamus.js'
13
13
  import { cariDataset, muatDataset } from './dataset.js'
14
14
  import { cariNama, mungkinNamaKhas } from './nama.js'
15
+ import { bolehCantumSendi, cantumSendi, pisahSendi } from './pedoman.js'
15
16
 
16
17
  // Baris tanda vokal Arab (fathah, kasrah, dammah, sukun, syaddah, tanwin,
17
18
  // alef superscript). Jawi Melayu TIDAK menggunakannya; teks al-Quran dan
@@ -185,8 +186,27 @@ export async function keJawi(teks, cache, opts = {}) {
185
186
  keluar.push(penanda[0] + cebis + penanda[1])
186
187
  }
187
188
 
189
+ // Pedoman DBP §14.1: kata sendi di dan ke bercantum dengan kata berikutnya.
190
+ // Dibuat sebagai lulusan kedua supaya logik carian di atas kekal mudah.
191
+ const sendiDicantum = []
192
+ for (let k = 1; k < keluar.length - 2; k += 2) {
193
+ const asal = bahagian[k]
194
+ if (!bolehCantumSendi(asal)) continue
195
+ if (!/^\s+$/.test(keluar[k + 1])) continue
196
+ const seterusnya = keluar[k + 2]
197
+ // Hanya cantum bila kata berikutnya benar-benar bertukar, bukan ditanda.
198
+ if (!seterusnya || seterusnya.startsWith(penanda[0])) continue
199
+ const gabung = cantumSendi(asal, seterusnya)
200
+ if (!gabung) continue
201
+ sendiDicantum.push({ sendi: asal, jawi: gabung.jawi, rujukan: gabung.rujukan })
202
+ keluar[k] = gabung.jawi
203
+ keluar[k + 1] = ''
204
+ keluar[k + 2] = ''
205
+ }
206
+
188
207
  return {
189
208
  teks: keluar.join(''),
209
+ sendiDicantum,
190
210
  disahkanDbp: dbp.length,
191
211
  dariDataset,
192
212
  dariNama,
@@ -212,6 +232,7 @@ export function keRumi(teksJawi, cache, { penanda = ['«', '»'], dataset = null
212
232
  const tidakDikenali = []
213
233
  const kabur = []
214
234
  const arab = []
235
+ const sendiDipisah = []
215
236
  const bahagian = teksJawi.split(PECAH_JAWI)
216
237
  const keluar = []
217
238
 
@@ -249,6 +270,15 @@ export function keRumi(teksJawi, cache, { penanda = ['«', '»'], dataset = null
249
270
  }
250
271
 
251
272
  if (!padanan) {
273
+ // Pedoman DBP §14.1 songsang: bentuk bercantum seperti دمکة tiada
274
+ // dalam kamus, jadi cuba pisahkan kata sendi di hadapan.
275
+ let dipisah = null
276
+ for (const calon of pisahSendi(bahagian[i])) {
277
+ const jumpa = peta.get(normalisasiJawi(calon.baki))
278
+ if (jumpa?.length === 1) { dipisah = calon.sendi + ' ' + jumpa[0]; break }
279
+ }
280
+ if (dipisah) { keluar.push(dipisah); sendiDipisah.push(bahagian[i]); continue }
281
+
252
282
  tidakDikenali.push(bahagian[i])
253
283
  keluar.push(penanda[0] + bahagian[i] + penanda[1])
254
284
  continue
@@ -267,6 +297,7 @@ export function keRumi(teksJawi, cache, { penanda = ['«', '»'], dataset = null
267
297
  tidakDikenali: [...new Set(tidakDikenali)],
268
298
  kabur,
269
299
  arab: [...new Set(arab)],
300
+ sendiDipisah,
270
301
  saizPeta: peta.size,
271
302
  lengkap: tidakDikenali.length === 0,
272
303
  }