@quran.ws/text 0.1.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/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@quran.ws/text",
3
+ "version": "0.1.0",
4
+ "description": "Read the quran-text dataset: the Qurʾān in seven riwāyāt with pages, lines, āyāt, waqf marks and one shared word numbering.",
5
+ "type": "module",
6
+ "main": "./quran-text.js",
7
+ "types": "./quran-text.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./quran-text.d.ts",
11
+ "default": "./quran-text.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "quran-text.js",
16
+ "quran-text.d.ts",
17
+ "data/hafs.json",
18
+ "data/UthmanicHafs-v-3.0.ttf",
19
+ "README.md"
20
+ ],
21
+ "scripts": {
22
+ "test": "node --test"
23
+ },
24
+ "license": "CC-BY-4.0",
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "repository": "github:quran-ws/quran-text",
29
+ "keywords": [
30
+ "quran",
31
+ "mushaf",
32
+ "hafs",
33
+ "warsh",
34
+ "qalun",
35
+ "riwayahs",
36
+ "arabic"
37
+ ],
38
+ "homepage": "https://quran.ws",
39
+ "bugs": {
40
+ "url": "https://github.com/quran-ws/quran-text/issues"
41
+ },
42
+ "author": "quran-ws <service@quran.ws>",
43
+ "engines": {
44
+ "node": ">=18"
45
+ }
46
+ }
@@ -0,0 +1,302 @@
1
+ /** quran-text — read the muṣḥaf files of the quran-text dataset. */
2
+
3
+ export type Layer = "surahs" | "ayahs" | "pages" | "lines" | "juz" | "marks" | "rasm_imlai";
4
+ export type MarkKind = "waqf" | "division" | "sajdah" | "sajdah_line" | "sah" | "raised_dot";
5
+ export type Relation = "same" | "merged" | "split" | "shifted" | "unnumbered";
6
+
7
+ export interface RenderOptions {
8
+ /** `true` for every sign, or the kinds you want. Default: none. */
9
+ marks?: boolean | MarkKind[];
10
+ /** Append ۝ with the āyah number after each āyah that ends inside the span. */
11
+ ayahMarks?: boolean;
12
+ /** Break the text where the printed lines break. */
13
+ lines?: boolean;
14
+ }
15
+
16
+ export const AYAH_MARK: string;
17
+ /** The end-of-āyah sign with its number, as the muṣḥaf prints it: ۝٢٥٥ */
18
+ export function ayahMark(number: number): string;
19
+ /** Plain letters for matching: no harakah, one alif, one yāʾ. Not a spelling. */
20
+ export function fold(text: string): string;
21
+
22
+ export class Mark {
23
+ readonly kind: MarkKind;
24
+ readonly side: "before" | "after";
25
+ readonly sign: string;
26
+ }
27
+
28
+ export class Word {
29
+ readonly position: number;
30
+ readonly text: string;
31
+ /** Plain modern spelling, Ḥafṣ only; null elsewhere. */
32
+ readonly rasm_imlai: string | null;
33
+ readonly surah: Surah;
34
+ /** null for the unnumbered basmalah. */
35
+ readonly ayah: Ayah | null;
36
+ /** 1-based position within the āyah; null when unnumbered. */
37
+ readonly index: number | null;
38
+ readonly page: Page;
39
+ readonly line: Line | null;
40
+ readonly juz: Juz | null;
41
+ /** The shared number: the same word in every riwāyah. */
42
+ readonly number: number;
43
+ readonly numberLast: number;
44
+ readonly marks: Mark[];
45
+ hasMark(kind: MarkKind): boolean;
46
+ /** The same word in another riwāyah; null where it does not read it. */
47
+ to(other: Mushaf): Word | null;
48
+ /** The word with its signs: ۞ before, waqf and ۩ after. */
49
+ render(marks?: boolean | MarkKind[]): string;
50
+ toString(): string;
51
+ }
52
+
53
+ export class Span implements Iterable<Word> {
54
+ readonly start: number;
55
+ readonly end: number;
56
+ readonly mushaf: Mushaf;
57
+ readonly length: number;
58
+ readonly words: string[];
59
+ readonly wordList: Word[];
60
+ /** The words joined with spaces, without any sign. */
61
+ readonly text: string;
62
+ render(options?: RenderOptions): string;
63
+ /** Every numbered āyah with at least one word in the span. */
64
+ readonly ayahs: Ayah[];
65
+ readonly firstAyah: Ayah | null;
66
+ readonly lastAyah: Ayah | null;
67
+ readonly surahs: Surah[];
68
+ readonly pages: Page[];
69
+ /** The page the span starts on. */
70
+ readonly page: Page;
71
+ readonly juz: Juz | null;
72
+ readonly marks: { word: Word; mark: Mark }[];
73
+ /** The index-th word of the span, 1-based. */
74
+ word(index: number): Word;
75
+ [Symbol.iterator](): Iterator<Word>;
76
+ }
77
+
78
+ /** Where an āyah falls in another riwāyah. */
79
+ export class AyahMatch {
80
+ readonly ayahs: Ayah[];
81
+ readonly relation: Relation | "missing";
82
+ readonly first: Ayah | null;
83
+ readonly last: Ayah | null;
84
+ /** "2:253-254" */
85
+ readonly key: string;
86
+ }
87
+
88
+ export class Ayah extends Span {
89
+ /** The shared numbers of this āyah's words. */
90
+ readonly numbers: Set<number>;
91
+ /** This āyah in another riwāyah, from the shared numbering. */
92
+ to(other: Mushaf): AyahMatch;
93
+ readonly surah: Surah;
94
+ /** In this edition's own count. */
95
+ readonly number: number;
96
+ /** "2:255" */
97
+ readonly key: string;
98
+ /** 0-based ordinal of the āyah in the muṣḥaf. */
99
+ readonly index: number;
100
+ readonly line: Line | null;
101
+ readonly lines: Line[];
102
+ readonly rasm_imlai: (string | null)[] | null;
103
+ readonly hasSajdah: boolean;
104
+ /** ۝٢٥٥ */
105
+ readonly marker: string;
106
+ next(): Ayah | null;
107
+ previous(): Ayah | null;
108
+ equals(other: unknown): boolean;
109
+ }
110
+
111
+ export class Surah extends Span {
112
+ readonly number: number;
113
+ readonly nameAr: string;
114
+ readonly nameEn: string;
115
+ readonly revelation: "makki" | "madani";
116
+ readonly hasBasmalah: boolean;
117
+ readonly ayahCount: number;
118
+ readonly ayahs: Ayah[];
119
+ ayah(number: number): Ayah;
120
+ /** The unnumbered basmalah before āyah 1, where the edition prints it so. */
121
+ readonly basmalah: Span | null;
122
+ readonly firstPage: Page;
123
+ readonly lastPage: Page;
124
+ }
125
+
126
+ export class Page extends Span {
127
+ readonly number: number;
128
+ readonly lines: Line[];
129
+ line(number: number): Line;
130
+ next(): Page | null;
131
+ previous(): Page | null;
132
+ }
133
+
134
+ /** One printed line. Reconstructed, not read: see layers.derived.line. */
135
+ export class Line extends Span {
136
+ readonly page: Page;
137
+ /** Within the page, 1-based. */
138
+ readonly number: number;
139
+ /** Within the muṣḥaf, 0-based. */
140
+ readonly index: number;
141
+ }
142
+
143
+ export class Juz extends Span {
144
+ readonly number: number;
145
+ }
146
+
147
+ export interface Font {
148
+ /** e.g. "KFGQPC HAFS Uthmanic Script" — the name to use in CSS or a Typeface. */
149
+ family: string;
150
+ /** The file name; the copy lives under data/fonts/ in the dataset. */
151
+ file: string;
152
+ sha256: string;
153
+ publisher: string;
154
+ /** The font file when the package bundles it (Ḥafṣ); null otherwise. */
155
+ url: string | null;
156
+ }
157
+
158
+ export class Mushaf {
159
+ constructor(doc: object);
160
+ /** The KFGQPC font this text is set in; ship it with the text. */
161
+ readonly font: Font;
162
+ /** A CSS @font-face rule for this muṣḥaf's font. */
163
+ fontFace(url?: string): string;
164
+ /** Ḥafṣ, bundled with the package. */
165
+ static hafs(): Promise<Mushaf>;
166
+ /** Any of the seven riwāyāt, Node only. In the browser: `Mushaf.fromJson(await res.json())`. */
167
+ static load(path: string): Promise<Mushaf>;
168
+ static fromJson(data: string | object): Mushaf;
169
+
170
+ readonly words: string[];
171
+ readonly key: string;
172
+ readonly nameEn: string;
173
+ readonly nameAr: string;
174
+ readonly qiraahEn: string | null;
175
+ readonly qiraahAr: string | null;
176
+ readonly countingSystem: string;
177
+ /**
178
+ * The counting system this muṣḥaf's qāriʾ is associated with. Compare with
179
+ * {@link Mushaf.countingSystem}, the system this edition measures onto: for
180
+ * Dūrī and Sūsī they differ.
181
+ */
182
+ readonly countingSystemAssociatedWithQari: string;
183
+ readonly basmalahCounted: boolean;
184
+ readonly surahs: Surah[];
185
+
186
+ readonly layers: Layer[];
187
+ has(layer: Layer): boolean;
188
+ readonly counting: Record<string, unknown>;
189
+ readonly provenance: Record<string, unknown>;
190
+ /** Where {@link Mushaf.checkForUpdate} looks by default. */
191
+ static VERSION_URL: string;
192
+ /**
193
+ * Ask whether a newer build of this riwāyah exists. Never called for you,
194
+ * never rejects: resolves to `null` when the check could not be made.
195
+ */
196
+ checkForUpdate(url?: string, timeoutMs?: number): Promise<UpdateStatus | null>;
197
+ readonly wordCount: number;
198
+ readonly ayahCount: number;
199
+ readonly pageCount: number;
200
+ readonly lineCount: number;
201
+ readonly juzCount: number;
202
+
203
+ surah(number: number): Surah;
204
+ /** Āyah `number` of `surah` in this edition's own count. */
205
+ ayah(surah: number, number: number): Ayah;
206
+ page(number: number): Page;
207
+ juz(number: number): Juz;
208
+ line(page: number, number: number): Line;
209
+ /** Word `index` (1-based) of an āyah. */
210
+ word(surah: number, ayah: number, index: number): Word;
211
+ span(start: number, end: number): Span;
212
+ readonly all: Span;
213
+ readonly ayahs: Ayah[];
214
+ readonly pages: Page[];
215
+ readonly ajza: Juz[];
216
+
217
+ wordAt(position: number): Word;
218
+ ayahAt(position: number): Ayah | null;
219
+ surahAt(position: number): Surah;
220
+ pageAt(position: number): Page;
221
+ lineAt(position: number): Line | null;
222
+ juzAt(position: number): Juz | null;
223
+
224
+ /** The shared number of the word at `position`. */
225
+ numberAt(position: number): number;
226
+ /** null where this muṣḥaf does not read the number. */
227
+ wordByNumber(number: number): Word | null;
228
+ readonly missingNumbers: Set<number>;
229
+
230
+ /** Every āyah printed with ۩. */
231
+ sajdat(): Ayah[];
232
+ /** Every word printed with ۞ before it. */
233
+ divisionMarks(): Word[];
234
+ /** Every place the words of `text` occur in sequence, matched on fold(). */
235
+ search(text: string): Span[];
236
+ }
237
+
238
+ export class MappedAyah {
239
+ readonly surah: number;
240
+ readonly ayah: number;
241
+ readonly relation: Relation;
242
+ readonly ayahLast: number | null;
243
+ /** "2:253-254" */
244
+ readonly key: string;
245
+ }
246
+
247
+ export class AyahMap {
248
+ constructor(doc: object);
249
+ static load(path: string): Promise<AyahMap>;
250
+ static fromJson(data: string | object): AyahMap;
251
+ readonly editions: string[];
252
+ /** convert(2, 255, "warsh") → { surah: 2, ayah: 253, ayahLast: 254, relation: "split" } */
253
+ convert(surah: number, ayah: number, to: string): MappedAyah;
254
+ all(surah: number, ayah: number): Record<string, MappedAyah>;
255
+ }
256
+
257
+ export interface HafsCoordinates { surah: number; ayah: number; position: number; }
258
+
259
+ export class IndexedWord {
260
+ readonly number: number;
261
+ readonly surah: number;
262
+ readonly index: number;
263
+ readonly key: string;
264
+ readonly rasm_uthmani: string;
265
+ readonly plain: string;
266
+ readonly rasm: string;
267
+ readonly pointed: string;
268
+ readonly status: "identical" | "diacritic_variant" | "dotting_variant" | "alif_variant" | "rasm_variant" | "word_boundary" | "partial";
269
+ readonly hafs: HafsCoordinates | null;
270
+ readonly ayah: Record<string, number>;
271
+ readonly forms: Record<string, string>;
272
+ readonly groups: { text: string; riwayahs: string[] }[];
273
+ readonly missing: string[];
274
+ readonly writtenJoined: string[];
275
+ form(riwayah: string): string | null;
276
+ readonly raw: Record<string, unknown>;
277
+ }
278
+
279
+ export class WordIndex implements Iterable<IndexedWord> {
280
+ constructor(doc: object);
281
+ static load(path: string): Promise<WordIndex>;
282
+ static fromJson(data: string | object): WordIndex;
283
+ readonly mushafs: string[];
284
+ readonly total: number;
285
+ readonly length: number;
286
+ word(number: number): IndexedWord;
287
+ /** By Ḥafṣ coordinates: sūrah, āyah in the Kūfī count, 1-based word. */
288
+ find(surah: number, ayah: number, index: number): IndexedWord | null;
289
+ search(text: string): IndexedWord[];
290
+ differing(): IndexedWord[];
291
+ [Symbol.iterator](): Iterator<IndexedWord>;
292
+ }
293
+
294
+ /** What {@link Mushaf.checkForUpdate} found. */
295
+ export interface UpdateStatus {
296
+ edition: string;
297
+ upToDate: boolean;
298
+ localSource: string | null;
299
+ latestSource: string | null;
300
+ dataset: string | null;
301
+ downloadUrl: string;
302
+ }