prpm-dbp 0.10.0 → 0.11.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/README.md +2 -0
- package/SKILL.md +27 -3
- package/bin/cli.js +9 -2
- package/package.json +1 -1
- package/src/prpm.js +15 -1
- package/src/tukar.js +38 -10
package/README.md
CHANGED
|
@@ -134,6 +134,8 @@ Pengguna kemudian menarik versi baharu dengan `npx skills update`.
|
|
|
134
134
|
|
|
135
135
|
Pilihan: `--refresh`, `--had <n>`, `--delay <ms>`, `--json`, `--cepat`, `--pedoman`.
|
|
136
136
|
|
|
137
|
+
`--luar-talian` tidak pernah menyentuh rangkaian. Wajib untuk laluan permintaan aplikasi: dokumen penuh dari cache mengambil 0.19 saat, manakala satu perkataan baharu daripada PRPM mengambil beberapa saat.
|
|
138
|
+
|
|
137
139
|
`--pedoman` membenarkan penjanaan imbuhan menurut peraturan DBP apabila kamus tiada jawapan. Ketepatannya diukur 88-98% terhadap 66,000 perkataan sebenar, jadi ia mati secara lalai dan hasilnya sentiasa ditanda.
|
|
138
140
|
|
|
139
141
|
## Guna sebagai library
|
package/SKILL.md
CHANGED
|
@@ -69,6 +69,10 @@ Contoh kedua: `dipelajari` ialah terbitan sah daripada `ajar`. Alat ini **tidak*
|
|
|
69
69
|
|
|
70
70
|
**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
71
|
|
|
72
|
+
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.
|
|
73
|
+
|
|
74
|
+
Isyaratnya mestilah tanda `®` itu, **bukan** kehadiran ejaan Jawi. `pada` tiada ejaan Jawi dalam PRPM manakala `pad` (pinjaman Inggeris) ada. Mengutamakan "yang ada Jawi" akan menukar setiap `pada` menjadi `pad`.
|
|
75
|
+
|
|
72
76
|
Jawi Melayu menulis vokal dengan alif, wau dan ya, tidak seperti Arab. Kerana itu kekaburan jarang berlaku, tetapi ia tetap wujud.
|
|
73
77
|
|
|
74
78
|
`rumi` bekerja dari cache sahaja dan tidak menyentuh rangkaian. Perkataan yang belum pernah disemak dalam arah Rumi ke Jawi tidak akan dikenali. Jalankan `warm` atau `audit` dahulu pada kosa kata yang berkaitan.
|
|
@@ -215,12 +219,12 @@ Diuji terhadap 406 perkataan pelajaran Pendidikan Islam Tingkatan 4 sebenar, dit
|
|
|
215
219
|
|
|
216
220
|
```
|
|
217
221
|
token asal 336 -> token pusing balik 336
|
|
218
|
-
padan tepat
|
|
219
|
-
padan antara calon
|
|
222
|
+
padan tepat 314 (93%)
|
|
223
|
+
padan antara calon 22 (7%)
|
|
220
224
|
TIDAK padan 0 (0%)
|
|
221
225
|
```
|
|
222
226
|
|
|
223
|
-
Dua puluh
|
|
227
|
+
Dua puluh dua kes kabur yang tinggal itu sah: `قلقله` boleh dibaca `qalqalah` atau `kalkalah`, dua ejaan Rumi yang sama-sama betul bagi istilah Arab yang sama. Alat melaporkan kedua-duanya dan tidak memilih.
|
|
224
228
|
|
|
225
229
|
**Sifar perkataan hilang atau rosak.**
|
|
226
230
|
|
|
@@ -233,6 +237,26 @@ Dua puluh tujuh kes kabur itu sah: `قلقله` boleh dibaca `qalqalah` atau `ka
|
|
|
233
237
|
| §12 serapan Inggeris | Kamus sudah meliputinya; tiada penjanaan diperlukan. |
|
|
234
238
|
| §16.2, §18 | Tidak memerlukan kod: perbezaannya sudah dikodkan dalam jarak teks Rumi. Ada ujian yang mengunci tingkah laku ini. |
|
|
235
239
|
|
|
240
|
+
## Menyambung ke aplikasi
|
|
241
|
+
|
|
242
|
+
Kelajuan diukur pada 406 perkataan:
|
|
243
|
+
|
|
244
|
+
| Keadaan | Masa |
|
|
245
|
+
|---|---|
|
|
246
|
+
| Semua dari cache | **0.19 saat** |
|
|
247
|
+
| Dua perkataan baharu (perlu rangkaian) | **30.7 saat** |
|
|
248
|
+
|
|
249
|
+
Perbezaan itu menentukan cara ia disambung. **Dalam laluan permintaan aplikasi, gunakan `--luar-talian` sentiasa.** Mod itu tidak pernah menyentuh rangkaian: perkataan yang tiada dalam cache dilaporkan belum disahkan, bukan diambil secara segerak sambil pengguna menunggu.
|
|
250
|
+
|
|
251
|
+
Urutan yang disyorkan:
|
|
252
|
+
|
|
253
|
+
1. **Panaskan cache di luar talian** daripada kosa kata projek anda: `npx prpm-dbp warm senarai.txt`
|
|
254
|
+
2. **Hantar cache itu bersama aplikasi** (salin `~/.cache/prpm-dbp/cache.json`, atau tetapkan `PRPM_CACHE`)
|
|
255
|
+
3. **Jalankan dengan `--luar-talian`** dalam laluan permintaan
|
|
256
|
+
4. **Kumpul medan `belumDisahkan`** dan panaskan cache secara berkala di luar talian
|
|
257
|
+
|
|
258
|
+
Dengan cara ini pengguna tidak pernah menunggu PRPM, dan PRPM tidak pernah menerima trafik daripada aplikasi anda.
|
|
259
|
+
|
|
236
260
|
## Rantai kepercayaan
|
|
237
261
|
|
|
238
262
|
Setiap ejaan Jawi yang dikeluarkan membawa asal-usulnya. Jangan runtuhkan lapisan ini.
|
package/bin/cli.js
CHANGED
|
@@ -34,7 +34,8 @@ const BANTUAN = `prpm-dbp — semak Bahasa Melayu dan Jawi terhadap PRPM DBP
|
|
|
34
34
|
npx prpm-dbp install [--link] pasang sebagai Claude Code skill
|
|
35
35
|
|
|
36
36
|
Pilihan: --refresh --had <n> --delay <ms> --json --cepat
|
|
37
|
-
--pedoman
|
|
37
|
+
--pedoman jana imbuhan ikut peraturan DBP (88-98% tepat, hasil ditanda)
|
|
38
|
+
--luar-talian jangan sentuh rangkaian langsung (wajib untuk laluan permintaan app)
|
|
38
39
|
|
|
39
40
|
Cache: ${CACHE_PATH}
|
|
40
41
|
`
|
|
@@ -49,6 +50,7 @@ function huraiArgs(argv) {
|
|
|
49
50
|
else if (a === '--link') pilihan.link = true
|
|
50
51
|
else if (a === '--cepat') pilihan.cepat = true
|
|
51
52
|
else if (a === '--pedoman') pilihan.pedoman = true
|
|
53
|
+
else if (a === '--luar-talian') pilihan.luarTalian = true
|
|
52
54
|
else if (a === '--jenis') pilihan.jenis = argv[++i]
|
|
53
55
|
else if (a === '--had') pilihan.had = Number(argv[++i])
|
|
54
56
|
else if (a === '--delay') pilihan.delay = Number(argv[++i])
|
|
@@ -79,7 +81,12 @@ async function main() {
|
|
|
79
81
|
}
|
|
80
82
|
|
|
81
83
|
const cache = await loadCache()
|
|
82
|
-
const opts = {
|
|
84
|
+
const opts = {
|
|
85
|
+
refresh: pilihan.refresh,
|
|
86
|
+
delay: pilihan.delay,
|
|
87
|
+
onProgress: progres,
|
|
88
|
+
luarTalian: pilihan.luarTalian,
|
|
89
|
+
}
|
|
83
90
|
|
|
84
91
|
switch (perintah) {
|
|
85
92
|
case 'lookup': {
|
package/package.json
CHANGED
package/src/prpm.js
CHANGED
|
@@ -130,11 +130,25 @@ export async function fetchPage(kata, { timeout = 20000 } = {}) {
|
|
|
130
130
|
|
|
131
131
|
const tidur = (ms) => new Promise((r) => setTimeout(r, ms))
|
|
132
132
|
|
|
133
|
-
export async function lookup(
|
|
133
|
+
export async function lookup(
|
|
134
|
+
kata,
|
|
135
|
+
cache,
|
|
136
|
+
{ refresh = false, delay = 400, perluPenuh = false, luarTalian = false } = {},
|
|
137
|
+
) {
|
|
134
138
|
const key = String(kata).trim().toLowerCase()
|
|
135
139
|
if (!key) return null
|
|
136
140
|
|
|
137
141
|
const simpanan = cache[key]
|
|
142
|
+
|
|
143
|
+
// Mod luar talian TIDAK PERNAH menyentuh rangkaian. Ini wajib untuk
|
|
144
|
+
// laluan permintaan aplikasi: satu perkataan yang belum dicache mengambil
|
|
145
|
+
// beberapa saat, manakala keseluruhan dokumen dari cache mengambil 0.2
|
|
146
|
+
// saat. Perkataan yang tiada dalam cache dilaporkan belum disahkan,
|
|
147
|
+
// bukan diambil secara segerak sambil pengguna menunggu.
|
|
148
|
+
if (luarTalian) {
|
|
149
|
+
if (simpanan) return { ...simpanan, dariCache: true }
|
|
150
|
+
return { kata: key, dijumpai: false, jawi: null, jawiVarian: [], entri: [], nota: 'tiada dalam cache (mod luar talian)', url: `${BASE_URL}?keyword=${encodeURIComponent(key)}` }
|
|
151
|
+
}
|
|
138
152
|
// Rekod benih membawa ejaan sahaja, tanpa definisi, supaya pakej kekal
|
|
139
153
|
// kecil. Bila pemanggil betul-betul perlukan definisi, ambil semula.
|
|
140
154
|
const cukup = simpanan && !(perluPenuh && simpanan.ringkas)
|
package/src/tukar.js
CHANGED
|
@@ -159,13 +159,28 @@ export function petaSongsang(cache, dataset = null) {
|
|
|
159
159
|
const peta = new Map()
|
|
160
160
|
let maxKata = 1
|
|
161
161
|
|
|
162
|
-
|
|
162
|
+
// DBP menandakan bentuk varian dengan rujukan silang: definisi `kalkalah`
|
|
163
|
+
// ialah "®qalqalah.", bukan definisi sebenar. Varian begitu dinyahutamakan
|
|
164
|
+
// supaya قلقله dibaca qalqalah dan bukan dilaporkan kabur.
|
|
165
|
+
//
|
|
166
|
+
// Isyaratnya mestilah tanda ® itu, BUKAN kehadiran ejaan Jawi. `pada`
|
|
167
|
+
// tiada Jawi dalam PRPM manakala `pad` (pinjaman Inggeris) ada, jadi
|
|
168
|
+
// mengutamakan "yang ada Jawi" akan menukar setiap `pada` menjadi `pad`.
|
|
169
|
+
const rujukanSilang = new Set()
|
|
170
|
+
for (const [kata, rec] of Object.entries(cache)) {
|
|
171
|
+
const def = rec?.entri?.[0]?.definisi ?? ''
|
|
172
|
+
if (/^®/.test(def.trim())) rujukanSilang.add(kata)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const tambah = (jawi, rumi, sumber) => {
|
|
163
176
|
const kunci = normalisasiJawi(jawi)
|
|
164
177
|
if (!kunci) return
|
|
165
178
|
const bilangan = kunci.split(/\s+/).length
|
|
166
179
|
if (bilangan > maxKata) maxKata = bilangan
|
|
167
|
-
if (!peta.has(kunci)) peta.set(kunci, [])
|
|
168
|
-
|
|
180
|
+
if (!peta.has(kunci)) peta.set(kunci, { utama: [], rujukan: [] })
|
|
181
|
+
const jenis = rujukanSilang.has(rumi) ? 'rujukan' : 'utama'
|
|
182
|
+
const slot = peta.get(kunci)[jenis]
|
|
183
|
+
if (!slot.includes(rumi)) slot.push(rumi)
|
|
169
184
|
}
|
|
170
185
|
|
|
171
186
|
for (const rec of Object.values(cache)) {
|
|
@@ -179,6 +194,19 @@ export function petaSongsang(cache, dataset = null) {
|
|
|
179
194
|
return peta
|
|
180
195
|
}
|
|
181
196
|
|
|
197
|
+
/**
|
|
198
|
+
* Pilih calon songsang. Bentuk yang DBP sendiri tandakan sebagai rujukan
|
|
199
|
+
* silang (®) hanya digunakan apabila tiada bentuk utama. Selain itu semua
|
|
200
|
+
* calon dilayan sama rata, dan kekaburan sebenar dilaporkan sepenuhnya.
|
|
201
|
+
*/
|
|
202
|
+
export function pilihCalon(masuk) {
|
|
203
|
+
if (!masuk) return null
|
|
204
|
+
if (Array.isArray(masuk)) return { calon: masuk, sumber: 'campur' }
|
|
205
|
+
if (masuk.utama.length) return { calon: masuk.utama, sumber: 'utama' }
|
|
206
|
+
if (masuk.rujukan.length) return { calon: masuk.rujukan, sumber: 'rujukan' }
|
|
207
|
+
return null
|
|
208
|
+
}
|
|
209
|
+
|
|
182
210
|
/**
|
|
183
211
|
* Rumi -> Jawi. Pemisah, tanda baca dan baris baru dikekalkan.
|
|
184
212
|
* Perkataan yang tidak disahkan dibalut penanda, tidak pernah direka.
|
|
@@ -360,17 +388,17 @@ export function keRumi(teksJawi, cache, { penanda = ['«', '»'], dataset = null
|
|
|
360
388
|
}
|
|
361
389
|
if (!bolehGabung) continue
|
|
362
390
|
const frasa = bahagian.slice(i, akhir + 1).join(' ').replace(/\s+/g, ' ')
|
|
363
|
-
const jumpa = peta.get(normalisasiJawi(frasa))
|
|
364
|
-
if (jumpa) { padanan = jumpa; hujung = akhir; break }
|
|
391
|
+
const jumpa = pilihCalon(peta.get(normalisasiJawi(frasa)))
|
|
392
|
+
if (jumpa) { padanan = jumpa.calon; hujung = akhir; break }
|
|
365
393
|
}
|
|
366
394
|
|
|
367
395
|
if (!padanan) {
|
|
368
396
|
// Pedoman DBP §17.1 songsang: kata dasar + ٢ menjadi kata berulang.
|
|
369
397
|
const dasarUlang = pisahUlangJawi(bahagian[i])
|
|
370
398
|
if (dasarUlang) {
|
|
371
|
-
const jumpaUlang = peta.get(normalisasiJawi(dasarUlang))
|
|
372
|
-
if (jumpaUlang?.length === 1) {
|
|
373
|
-
keluar.push(jumpaUlang[0] + '-' + jumpaUlang[0])
|
|
399
|
+
const jumpaUlang = pilihCalon(peta.get(normalisasiJawi(dasarUlang)))
|
|
400
|
+
if (jumpaUlang?.calon.length === 1) {
|
|
401
|
+
keluar.push(jumpaUlang.calon[0] + '-' + jumpaUlang.calon[0])
|
|
374
402
|
continue
|
|
375
403
|
}
|
|
376
404
|
}
|
|
@@ -379,8 +407,8 @@ export function keRumi(teksJawi, cache, { penanda = ['«', '»'], dataset = null
|
|
|
379
407
|
// dalam kamus, jadi cuba pisahkan kata sendi di hadapan.
|
|
380
408
|
let dipisah = null
|
|
381
409
|
for (const calon of pisahSendi(bahagian[i])) {
|
|
382
|
-
const jumpa = peta.get(normalisasiJawi(calon.baki))
|
|
383
|
-
if (jumpa?.length === 1) { dipisah = calon.sendi + ' ' + jumpa[0]; break }
|
|
410
|
+
const jumpa = pilihCalon(peta.get(normalisasiJawi(calon.baki)))
|
|
411
|
+
if (jumpa?.calon.length === 1) { dipisah = calon.sendi + ' ' + jumpa.calon[0]; break }
|
|
384
412
|
}
|
|
385
413
|
if (dipisah) { keluar.push(dipisah); sendiDipisah.push(bahagian[i]); continue }
|
|
386
414
|
|