diff --git a/.changeset/verse-field-types.md b/.changeset/verse-field-types.md new file mode 100644 index 0000000..814aac5 --- /dev/null +++ b/.changeset/verse-field-types.md @@ -0,0 +1,5 @@ +--- +"@quranjs/api": patch +--- + +Add the documented field names that the verse field-selection types were missing, so they can be requested without a cast, and type the properties they return. `VerseField` gains `textQpcHafs`, `textQpcNastaleeqHafs`, `textQpcNastaleeq` and `pageNumber`. `WordField` gains `textIndopakNastaleeq`, `textUthmaniTajweed`, `textQpcHafs`, `textImlaeiSimple`, `textUthmaniSimple`, `verseId`, `chapterId`, `lineNumber`, `lineV1` and `lineV2`. `TranslationField` gains `rubElHizbNumber`, `rukuNumber`, `manzilNumber` and `id`. `Verse`, `Word` and `Translation` declare the matching response properties. `TranslationField` `"rubNumber"` is sent as `rub_number`, which the API does not recognize, and `Translation.rubNumber` is never set: use `rubElHizbNumber`. diff --git a/packages/api/src/types/api/Translation.ts b/packages/api/src/types/api/Translation.ts index cdfc6dc..0095c8a 100644 --- a/packages/api/src/types/api/Translation.ts +++ b/packages/api/src/types/api/Translation.ts @@ -16,6 +16,10 @@ export interface Translation { verseNumber?: number; juzNumber?: number; hizbNumber?: number; + /** @deprecated Never set. The API returns this number as `rubElHizbNumber`. */ rubNumber?: number; pageNumber?: number; + rubElHizbNumber?: number; + rukuNumber?: number; + manzilNumber?: number; } diff --git a/packages/api/src/types/api/Verse.ts b/packages/api/src/types/api/Verse.ts index d2addd3..1e47bff 100644 --- a/packages/api/src/types/api/Verse.ts +++ b/packages/api/src/types/api/Verse.ts @@ -22,6 +22,9 @@ export interface Verse { textImlaeiSimple?: string; textIndopak?: string; textIndopakNastaleeq?: string; + textQpcHafs?: string; + textQpcNastaleeqHafs?: string; + textQpcNastaleeq?: string; sajdahNumber: null; // sajdahType: null; imageUrl?: string; diff --git a/packages/api/src/types/api/Word.ts b/packages/api/src/types/api/Word.ts index 20e654a..beaef86 100644 --- a/packages/api/src/types/api/Word.ts +++ b/packages/api/src/types/api/Word.ts @@ -27,4 +27,15 @@ export interface Word { transliteration: Transliteration; location?: string; // chapter:verse:word verseKey?: VerseKey; + verseId?: number; + chapterId?: number; + textIndopakNastaleeq?: string | null; + textImlaeiSimple?: string; + textUthmaniSimple?: string; + textUthmaniTajweed?: string; + textQpcHafs?: string; + v1Page?: number; + v2Page?: number; + lineV1?: number; + lineV2?: number; } diff --git a/packages/api/src/types/index.ts b/packages/api/src/types/index.ts index 7f00df2..f877732 100644 --- a/packages/api/src/types/index.ts +++ b/packages/api/src/types/index.ts @@ -87,7 +87,11 @@ export type VerseField = | "codeV1" | "codeV2" | "v1Page" - | "v2Page"; + | "v2Page" + | "textQpcHafs" + | "textQpcNastaleeqHafs" + | "textQpcNastaleeq" + | "pageNumber"; export type WordField = | "v1Page" @@ -98,7 +102,17 @@ export type WordField = | "verseKey" | "location" | "codeV1" - | "codeV2"; + | "codeV2" + | "verseId" + | "chapterId" + | "textIndopakNastaleeq" + | "textImlaeiSimple" + | "textUthmaniSimple" + | "textUthmaniTajweed" + | "textQpcHafs" + | "lineNumber" + | "lineV1" + | "lineV2"; export type TranslationField = | "resourceName" @@ -110,8 +124,13 @@ export type TranslationField = | "verseNumber" | "juzNumber" | "hizbNumber" + // Not a field the API knows: it is sent as `rub_number`. Use `rubElHizbNumber`. | "rubNumber" - | "pageNumber"; + | "pageNumber" + | "rubElHizbNumber" + | "rukuNumber" + | "manzilNumber" + | "id"; export type VerseRecitationField = "id" | "chapterId" | "segments" | "format"; diff --git a/packages/api/test/verse-fields.test.ts b/packages/api/test/verse-fields.test.ts new file mode 100644 index 0000000..a266d5d --- /dev/null +++ b/packages/api/test/verse-fields.test.ts @@ -0,0 +1,123 @@ +import { http, HttpResponse } from "msw"; +import { describe, expect, it } from "vitest"; + +import { server } from "../mocks/server"; +import { testClient } from "./test-client"; + +const BY_KEY_URL = + "https://apis.quran.foundation/content/api/v4/verses/by_key/:verse_key"; + +describe("Verse field selections", () => { + it("requests the documented field names and types what they return", async () => { + let requestUrl: URL | null = null; + server.use( + http.get(BY_KEY_URL, ({ request }) => { + requestUrl = new URL(request.url); + + return HttpResponse.json({ + verse: { + id: 2, + verse_number: 2, + verse_key: "1:2", + page_number: 1, + juz_number: 1, + hizb_number: 1, + rub_el_hizb_number: 1, + sajdah_number: null, + text_qpc_hafs: "verse-qpc-hafs", + text_qpc_nastaleeq: "verse-qpc-nastaleeq", + text_qpc_nastaleeq_hafs: "verse-qpc-nastaleeq-hafs", + translations: [ + { + id: 96493, + manzil_number: 1, + resource_id: 20, + rub_el_hizb_number: 1, + ruku_number: 1, + text: "[All] praise is [due] to Allāh, Lord of the worlds -", + }, + ], + words: [ + { + audio_url: "wbw/001_002_001.mp3", + chapter_id: 1, + char_type_name: "word", + id: 1130, + line_v1: 3, + line_v2: 3, + position: 1, + text_indopak_nastaleeq: "word-indopak-nastaleeq", + text_qpc_hafs: "word-qpc-hafs", + text_uthmani_tajweed: "word-uthmani-tajweed", + translation: { + language_name: "english", + text: "All praises and thanks", + }, + transliteration: { language_name: "english", text: "al-ḥamdu" }, + verse_id: 2, + }, + ], + }, + }); + }), + ); + + const verse = await testClient.verses.findByKey("1:2", { + fields: { + pageNumber: true, + textQpcHafs: true, + textQpcNastaleeq: true, + textQpcNastaleeqHafs: true, + }, + translationFields: { + id: true, + manzilNumber: true, + rubElHizbNumber: true, + rukuNumber: true, + }, + translations: [20], + wordFields: { + chapterId: true, + lineNumber: true, + lineV1: true, + lineV2: true, + textImlaeiSimple: true, + textIndopakNastaleeq: true, + textQpcHafs: true, + textUthmaniSimple: true, + textUthmaniTajweed: true, + verseId: true, + }, + words: true, + }); + + const params = requestUrl!.searchParams; + expect(params.get("fields")).toBe( + "page_number,text_qpc_hafs,text_qpc_nastaleeq,text_qpc_nastaleeq_hafs", + ); + expect(params.get("translation_fields")).toBe( + "id,manzil_number,rub_el_hizb_number,ruku_number", + ); + expect(params.get("word_fields")).toBe( + "chapter_id,line_number,line_v1,line_v2,text_imlaei_simple,text_indopak_nastaleeq,text_qpc_hafs,text_uthmani_simple,text_uthmani_tajweed,verse_id", + ); + + expect(verse.textQpcHafs).toBe("verse-qpc-hafs"); + expect(verse.textQpcNastaleeq).toBe("verse-qpc-nastaleeq"); + expect(verse.textQpcNastaleeqHafs).toBe("verse-qpc-nastaleeq-hafs"); + + const word = verse.words?.[0]; + expect(word?.verseId).toBe(2); + expect(word?.chapterId).toBe(1); + expect(word?.lineV1).toBe(3); + expect(word?.lineV2).toBe(3); + expect(word?.textIndopakNastaleeq).toBe("word-indopak-nastaleeq"); + expect(word?.textQpcHafs).toBe("word-qpc-hafs"); + expect(word?.textUthmaniTajweed).toBe("word-uthmani-tajweed"); + + const translation = verse.translations?.[0]; + expect(translation?.rubElHizbNumber).toBe(1); + expect(translation?.rukuNumber).toBe(1); + expect(translation?.manzilNumber).toBe(1); + }); +});