@quranjs/api 1.6.0 → 1.7.1

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 (63) hide show
  1. package/dist/index.d.ts +553 -2
  2. package/dist/index.js +11 -6
  3. package/dist/index.js.map +1 -0
  4. package/dist/index.mjs +6 -0
  5. package/dist/index.mjs.map +1 -0
  6. package/package.json +24 -21
  7. package/src/sdk/utils.ts +18 -9
  8. package/src/sdk/v4/_fetcher.ts +63 -8
  9. package/src/sdk/v4/audio.ts +30 -50
  10. package/src/sdk/v4/chapters.ts +12 -15
  11. package/src/sdk/v4/juzs.ts +7 -2
  12. package/src/sdk/v4/resources.ts +27 -31
  13. package/src/sdk/v4/search.ts +14 -13
  14. package/src/sdk/v4/verses.ts +72 -50
  15. package/src/types/BaseApiOptions.ts +6 -0
  16. package/src/types/FetchFn.ts +1 -0
  17. package/src/types/index.ts +2 -0
  18. package/dist/api.cjs.development.js +0 -2754
  19. package/dist/api.cjs.development.js.map +0 -1
  20. package/dist/api.cjs.production.min.js +0 -2
  21. package/dist/api.cjs.production.min.js.map +0 -1
  22. package/dist/api.esm.js +0 -2746
  23. package/dist/api.esm.js.map +0 -1
  24. package/dist/sdk/index.d.ts +0 -195
  25. package/dist/sdk/utils.d.ts +0 -125
  26. package/dist/sdk/v4/_fetcher.d.ts +0 -3
  27. package/dist/sdk/v4/audio.d.ts +0 -52
  28. package/dist/sdk/v4/chapters.d.ts +0 -13
  29. package/dist/sdk/v4/index.d.ts +0 -185
  30. package/dist/sdk/v4/juzs.d.ts +0 -5
  31. package/dist/sdk/v4/resources.d.ts +0 -26
  32. package/dist/sdk/v4/search.d.ts +0 -22
  33. package/dist/sdk/v4/verses.d.ts +0 -76
  34. package/dist/types/ChapterId.d.ts +0 -4
  35. package/dist/types/HizbNumber.d.ts +0 -4
  36. package/dist/types/JuzNumber.d.ts +0 -4
  37. package/dist/types/PageNumber.d.ts +0 -4
  38. package/dist/types/RubNumber.d.ts +0 -4
  39. package/dist/types/VerseKey.d.ts +0 -2
  40. package/dist/types/api/ApiResponses.d.ts +0 -18
  41. package/dist/types/api/AudioData.d.ts +0 -17
  42. package/dist/types/api/AudioResponse.d.ts +0 -8
  43. package/dist/types/api/Chapter.d.ts +0 -14
  44. package/dist/types/api/ChapterInfo.d.ts +0 -8
  45. package/dist/types/api/Footnote.d.ts +0 -6
  46. package/dist/types/api/Juz.d.ts +0 -8
  47. package/dist/types/api/Pagination.d.ts +0 -7
  48. package/dist/types/api/Reciter.d.ts +0 -21
  49. package/dist/types/api/Resources.d.ts +0 -70
  50. package/dist/types/api/Segment.d.ts +0 -4
  51. package/dist/types/api/Tafsir.d.ts +0 -7
  52. package/dist/types/api/TafsirInfo.d.ts +0 -9
  53. package/dist/types/api/TranslatedName.d.ts +0 -4
  54. package/dist/types/api/Translation.d.ts +0 -17
  55. package/dist/types/api/Transliteration.d.ts +0 -4
  56. package/dist/types/api/Verse.d.ts +0 -32
  57. package/dist/types/api/Word.d.ts +0 -28
  58. package/dist/types/api/index.d.ts +0 -18
  59. package/dist/types/index.d.ts +0 -88
  60. package/dist/types/utils.d.ts +0 -5
  61. package/dist/utils/misc.d.ts +0 -1
  62. package/dist/utils/qs-stringify.d.ts +0 -21
  63. package/src/utils/qs-stringify.ts +0 -81
@@ -11,52 +11,26 @@ import {
11
11
  VerseKey,
12
12
  VerseRecitationField,
13
13
  } from '../../types';
14
- import { decamelize } from 'humps';
15
14
  import Utils from '../utils';
16
- import { fetcher } from './_fetcher';
15
+ import { fetcher, mergeApiOptions } from './_fetcher';
16
+ import { BaseApiOptions } from '../../types/BaseApiOptions';
17
17
 
18
- type GetChapterRecitationOptions = Partial<{
19
- language: Language;
20
- }>;
18
+ type GetChapterRecitationOptions = Partial<BaseApiOptions>;
21
19
 
22
20
  const defaultChapterRecitationsOptions: GetChapterRecitationOptions = {
23
21
  language: Language.ARABIC,
24
22
  };
25
23
 
26
- const getChapterRecitationsOptions = (
27
- options: GetChapterRecitationOptions = {}
28
- ) => {
29
- const final: any = { ...defaultChapterRecitationsOptions, ...options };
30
-
31
- return final;
32
- };
33
-
34
- type GetVerseRecitationOptions = Partial<{
35
- language: Language;
36
- fields: Partial<Record<VerseRecitationField, boolean>>;
37
- }>;
24
+ type GetVerseRecitationOptions = Partial<
25
+ BaseApiOptions & {
26
+ fields: Partial<Record<VerseRecitationField, boolean>>;
27
+ }
28
+ >;
38
29
 
39
30
  const defaultVerseRecitationsOptions: GetVerseRecitationOptions = {
40
31
  language: Language.ARABIC,
41
32
  };
42
33
 
43
- const getVerseRecitationsOptions = (
44
- options: GetVerseRecitationOptions = {}
45
- ) => {
46
- const initial = { ...defaultVerseRecitationsOptions, ...options };
47
- const final: any = { language: initial.language };
48
-
49
- if (initial.fields) {
50
- const fields: string[] = [];
51
- for (const [key, value] of Object.entries(initial.fields)) {
52
- if (value) fields.push(decamelize(key));
53
- }
54
- final.fields = fields.join(',');
55
- }
56
-
57
- return final;
58
- };
59
-
60
34
  /**
61
35
  * Get all chapter recitations for specific reciter
62
36
  * @description https://quran.api-docs.io/v4/audio-recitations/list-of-all-surah-audio-files-for-specific-reciter
@@ -69,10 +43,11 @@ const findAllChapterRecitations = async (
69
43
  reciterId: string,
70
44
  options?: GetChapterRecitationOptions
71
45
  ) => {
72
- const params = getChapterRecitationsOptions(options);
46
+ const params = mergeApiOptions(options, defaultChapterRecitationsOptions);
73
47
  const { audioFiles } = await fetcher<{ audioFiles: ChapterRecitation[] }>(
74
48
  `/chapter_recitations/${reciterId}`,
75
- params
49
+ params,
50
+ options?.fetchFn
76
51
  );
77
52
  return audioFiles;
78
53
  };
@@ -93,10 +68,11 @@ const findChapterRecitationById = async (
93
68
  ) => {
94
69
  if (!Utils.isValidChapterId(chapterId)) throw new Error('Invalid chapter id');
95
70
 
96
- const params = getChapterRecitationsOptions(options);
71
+ const params = mergeApiOptions(options, defaultChapterRecitationsOptions);
97
72
  const { audioFile } = await fetcher<{ audioFile: ChapterRecitation }>(
98
73
  `/chapter_recitations/${reciterId}/${chapterId}`,
99
- params
74
+ params,
75
+ options?.fetchFn
100
76
  );
101
77
 
102
78
  return audioFile;
@@ -118,11 +94,15 @@ const findVerseRecitationsByChapter = async (
118
94
  ) => {
119
95
  if (!Utils.isValidChapterId(chapterId)) throw new Error('Invalid chapter id');
120
96
 
121
- const params = getVerseRecitationsOptions(options);
97
+ const params = mergeApiOptions(options, defaultVerseRecitationsOptions);
122
98
  const data = await fetcher<{
123
99
  audioFiles: VerseRecitation[];
124
100
  pagination: Pagination;
125
- }>(`/recitations/${recitationId}/by_chapter/${chapterId}`, params);
101
+ }>(
102
+ `/recitations/${recitationId}/by_chapter/${chapterId}`,
103
+ params,
104
+ options?.fetchFn
105
+ );
126
106
 
127
107
  return data;
128
108
  };
@@ -143,11 +123,11 @@ const findVerseRecitationsByJuz = async (
143
123
  ) => {
144
124
  if (!Utils.isValidJuz(juz)) throw new Error('Invalid juz');
145
125
 
146
- const params = getVerseRecitationsOptions(options);
126
+ const params = mergeApiOptions(options, defaultVerseRecitationsOptions);
147
127
  const data = await fetcher<{
148
128
  audioFiles: VerseRecitation[];
149
129
  pagination: Pagination;
150
- }>(`/recitations/${recitationId}/by_juz/${juz}`, params);
130
+ }>(`/recitations/${recitationId}/by_juz/${juz}`, params, options?.fetchFn);
151
131
 
152
132
  return data;
153
133
  };
@@ -168,11 +148,11 @@ const findVerseRecitationsByPage = async (
168
148
  ) => {
169
149
  if (!Utils.isValidQuranPage(page)) throw new Error('Invalid page');
170
150
 
171
- const params = getVerseRecitationsOptions(options);
151
+ const params = mergeApiOptions(options, defaultVerseRecitationsOptions);
172
152
  const data = await fetcher<{
173
153
  audioFiles: VerseRecitation[];
174
154
  pagination: Pagination;
175
- }>(`/recitations/${recitationId}/by_page/${page}`, params);
155
+ }>(`/recitations/${recitationId}/by_page/${page}`, params, options?.fetchFn);
176
156
 
177
157
  return data;
178
158
  };
@@ -193,11 +173,11 @@ const findVerseRecitationsByRub = async (
193
173
  ) => {
194
174
  if (!Utils.isValidRub(rub)) throw new Error('Invalid rub');
195
175
 
196
- const params = getVerseRecitationsOptions(options);
176
+ const params = mergeApiOptions(options, defaultVerseRecitationsOptions);
197
177
  const data = await fetcher<{
198
178
  audioFiles: VerseRecitation[];
199
179
  pagination: Pagination;
200
- }>(`/recitations/${recitationId}/by_rub/${rub}`, params);
180
+ }>(`/recitations/${recitationId}/by_rub/${rub}`, params, options?.fetchFn);
201
181
 
202
182
  return data;
203
183
  };
@@ -218,11 +198,11 @@ const findVerseRecitationsByHizb = async (
218
198
  ) => {
219
199
  if (!Utils.isValidHizb(hizb)) throw new Error('Invalid hizb');
220
200
 
221
- const params = getVerseRecitationsOptions(options);
201
+ const params = mergeApiOptions(options, defaultVerseRecitationsOptions);
222
202
  const data = await fetcher<{
223
203
  audioFiles: VerseRecitation[];
224
204
  pagination: Pagination;
225
- }>(`/recitations/${recitationId}/by_hizb/${hizb}`, params);
205
+ }>(`/recitations/${recitationId}/by_hizb/${hizb}`, params, options?.fetchFn);
226
206
 
227
207
  return data;
228
208
  };
@@ -243,11 +223,11 @@ const findVerseRecitationsByKey = async (
243
223
  ) => {
244
224
  if (!Utils.isValidVerseKey(key)) throw new Error('Invalid verse key');
245
225
 
246
- const params = getVerseRecitationsOptions(options);
226
+ const params = mergeApiOptions(options, defaultVerseRecitationsOptions);
247
227
  const data = await fetcher<{
248
228
  audioFiles: VerseRecitation[];
249
229
  pagination: Pagination;
250
- }>(`/recitations/${recitationId}/by_ayah/${key}`, params);
230
+ }>(`/recitations/${recitationId}/by_ayah/${key}`, params, options?.fetchFn);
251
231
 
252
232
  return data;
253
233
  };
@@ -1,20 +1,14 @@
1
1
  import { Chapter, ChapterId, ChapterInfo, Language } from '../../types';
2
- import { fetcher } from './_fetcher';
2
+ import { fetcher, mergeApiOptions } from './_fetcher';
3
3
  import Utils from '../utils';
4
+ import { BaseApiOptions } from '../../types/BaseApiOptions';
4
5
 
5
- type GetChapterOptions = Partial<{
6
- language: Language;
7
- }>;
6
+ type GetChapterOptions = Partial<BaseApiOptions>;
8
7
 
9
8
  const defaultOptions: GetChapterOptions = {
10
9
  language: Language.ARABIC,
11
10
  };
12
11
 
13
- const getChapterOptions = (options: GetChapterOptions = {}) => {
14
- const final: any = { ...defaultOptions, ...options };
15
- return final;
16
- };
17
-
18
12
  /**
19
13
  * Get all chapters.
20
14
  * @description https://quran.api-docs.io/v4/chapters/list-chapters
@@ -23,10 +17,11 @@ const getChapterOptions = (options: GetChapterOptions = {}) => {
23
17
  * quran.v4.chapters.findAll()
24
18
  */
25
19
  const findAll = async (options?: GetChapterOptions) => {
26
- const params = getChapterOptions(options);
20
+ const params = mergeApiOptions(options, defaultOptions);
27
21
  const { chapters } = await fetcher<{ chapters: Chapter[] }>(
28
22
  '/chapters',
29
- params
23
+ params,
24
+ options?.fetchFn
30
25
  );
31
26
 
32
27
  return chapters;
@@ -44,10 +39,11 @@ const findAll = async (options?: GetChapterOptions) => {
44
39
  const findById = async (id: ChapterId, options?: GetChapterOptions) => {
45
40
  if (!Utils.isValidChapterId(id)) throw new Error('Invalid chapter id');
46
41
 
47
- const params = getChapterOptions(options);
42
+ const params = mergeApiOptions(options, defaultOptions);
48
43
  const { chapter } = await fetcher<{ chapter: Chapter }>(
49
44
  `/chapters/${id}`,
50
- params
45
+ params,
46
+ options?.fetchFn
51
47
  );
52
48
 
53
49
  return chapter;
@@ -65,10 +61,11 @@ const findById = async (id: ChapterId, options?: GetChapterOptions) => {
65
61
  const findInfoById = async (id: ChapterId, options?: GetChapterOptions) => {
66
62
  if (!Utils.isValidChapterId(id)) throw new Error('Invalid chapter id');
67
63
 
68
- const params = getChapterOptions(options);
64
+ const params = mergeApiOptions(options, defaultOptions);
69
65
  const { chapterInfo } = await fetcher<{ chapterInfo: ChapterInfo }>(
70
66
  `/chapters/${id}/info`,
71
- params
67
+ params,
68
+ options?.fetchFn
72
69
  );
73
70
 
74
71
  return chapterInfo;
@@ -1,4 +1,5 @@
1
1
  import { Juz } from '../../types';
2
+ import { BaseApiOptions } from '../../types/BaseApiOptions';
2
3
  import { fetcher } from './_fetcher';
3
4
 
4
5
  /**
@@ -7,8 +8,12 @@ import { fetcher } from './_fetcher';
7
8
  * @example
8
9
  * quran.v4.juzs.findAll()
9
10
  */
10
- const findAll = async () => {
11
- const { juzs } = await fetcher<{ juzs: Juz[] }>('/juzs');
11
+ const findAll = async (options?: Omit<BaseApiOptions, 'language'>) => {
12
+ const { juzs } = await fetcher<{ juzs: Juz[] }>(
13
+ '/juzs',
14
+ undefined,
15
+ options?.fetchFn
16
+ );
12
17
  return juzs;
13
18
  };
14
19
 
@@ -12,21 +12,15 @@ import {
12
12
  TranslationResource,
13
13
  VerseMediaResource,
14
14
  } from '../../types';
15
- import { fetcher } from './_fetcher';
15
+ import { BaseApiOptions } from '../../types/BaseApiOptions';
16
+ import { fetcher, mergeApiOptions } from './_fetcher';
16
17
 
17
- type GetResourceOptions = Partial<{
18
- language: Language;
19
- }>;
18
+ type GetResourceOptions = Partial<BaseApiOptions>;
20
19
 
21
20
  const defaultOptions: GetResourceOptions = {
22
21
  language: Language.ARABIC,
23
22
  };
24
23
 
25
- const getResourcesOptions = (options: GetResourceOptions = {}) => {
26
- const final: any = { ...defaultOptions, ...options };
27
- return final;
28
- };
29
-
30
24
  /**
31
25
  * Get all recitations.
32
26
  * @description https://quran.api-docs.io/v4/resources/recitations
@@ -35,10 +29,10 @@ const getResourcesOptions = (options: GetResourceOptions = {}) => {
35
29
  * quran.v4.resources.findAllRecitations()
36
30
  */
37
31
  const findAllRecitations = async (options?: GetResourceOptions) => {
38
- const params = getResourcesOptions(options);
32
+ const params = mergeApiOptions(options);
39
33
  const { recitations } = await fetcher<{
40
34
  recitations: RecitationResource[];
41
- }>('/resources/recitations', params);
35
+ }>('/resources/recitations', params, options?.fetchFn);
42
36
 
43
37
  return recitations;
44
38
  };
@@ -53,10 +47,10 @@ const findAllRecitations = async (options?: GetResourceOptions) => {
53
47
  * quran.v4.resources.findRecitationInfo('1')
54
48
  */
55
49
  // const findRecitationInfo = async (id: string, options?: GetResourceOptions) => {
56
- // const params = getResourcesOptions(options);
50
+ // const params = mergeApiOptions(options, defaultOptions);
57
51
  // const { info } = await fetcher<{
58
52
  // info: RecitationInfoResource;
59
- // }>(`/resources/recitations/${id}/info`, params);
53
+ // }>(`/resources/recitations/${id}/info`, params, options?.fetchFn);
60
54
 
61
55
  // return info;
62
56
  // };
@@ -69,10 +63,10 @@ const findAllRecitations = async (options?: GetResourceOptions) => {
69
63
  * quran.v4.resources.findAllTranslations()
70
64
  */
71
65
  const findAllTranslations = async (options?: GetResourceOptions) => {
72
- const params = getResourcesOptions(options);
66
+ const params = mergeApiOptions(options, defaultOptions);
73
67
  const { translations } = await fetcher<{
74
68
  translations: TranslationResource[];
75
- }>('/resources/translations', params);
69
+ }>('/resources/translations', params, options?.fetchFn);
76
70
 
77
71
  return translations;
78
72
  };
@@ -87,10 +81,10 @@ const findAllTranslations = async (options?: GetResourceOptions) => {
87
81
  * quran.v4.resources.findTranslationInfo('169')
88
82
  */
89
83
  // const findTranslationInfo = async (id: string, options?: GetResourceOptions) => {
90
- // const params = getResourcesOptions(options);
84
+ // const params = mergeApiOptions(options, defaultOptions);
91
85
  // const { info } = await fetcher<{
92
86
  // info: TranslationInfoResource;
93
- // }>(`/resources/translations/${id}/info`, params);
87
+ // }>(`/resources/translations/${id}/info`, params, options?.fetchFn);
94
88
 
95
89
  // return info;
96
90
  // };
@@ -103,10 +97,10 @@ const findAllTranslations = async (options?: GetResourceOptions) => {
103
97
  * quran.v4.resources.findAllTafsirs()
104
98
  */
105
99
  const findAllTafsirs = async (options?: GetResourceOptions) => {
106
- const params = getResourcesOptions(options);
100
+ const params = mergeApiOptions(options, defaultOptions);
107
101
  const { tafsirs } = await fetcher<{
108
102
  tafsirs: TafsirResource[];
109
- }>('/resources/tafsirs', params);
103
+ }>('/resources/tafsirs', params, options?.fetchFn);
110
104
 
111
105
  return tafsirs;
112
106
  };
@@ -121,10 +115,10 @@ const findAllTafsirs = async (options?: GetResourceOptions) => {
121
115
  * quran.v4.resources.findTranslationInfo('1')
122
116
  */
123
117
  // const findTafsirInfo = async (id: string, options?: GetResourceOptions) => {
124
- // const params = getResourcesOptions(options);
118
+ // const params = mergeApiOptions(options, defaultOptions);
125
119
  // const { info } = await fetcher<{
126
120
  // info: TafsirInfoResource;
127
- // }>(`/resources/tafsirs/${id}/info`, params);
121
+ // }>(`/resources/tafsirs/${id}/info`, params, options?.fetchFn);
128
122
 
129
123
  // return info;
130
124
  // };
@@ -135,10 +129,12 @@ const findAllTafsirs = async (options?: GetResourceOptions) => {
135
129
  * @example
136
130
  * quran.v4.resources.findAllRecitationStyles()
137
131
  */
138
- const findAllRecitationStyles = async () => {
132
+ const findAllRecitationStyles = async (
133
+ options?: Omit<BaseApiOptions, 'language'>
134
+ ) => {
139
135
  const { recitationStyles } = await fetcher<{
140
136
  recitationStyles: RecitationStylesResource;
141
- }>('/resources/recitation_styles');
137
+ }>('/resources/recitation_styles', undefined, options?.fetchFn);
142
138
 
143
139
  return recitationStyles;
144
140
  };
@@ -151,10 +147,10 @@ const findAllRecitationStyles = async () => {
151
147
  * quran.v4.resources.findAllLanguages()
152
148
  */
153
149
  const findAllLanguages = async (options?: GetResourceOptions) => {
154
- const params = getResourcesOptions(options);
150
+ const params = mergeApiOptions(options, defaultOptions);
155
151
  const { languages } = await fetcher<{
156
152
  languages: LanguageResource[];
157
- }>('/resources/languages', params);
153
+ }>('/resources/languages', params, options?.fetchFn);
158
154
 
159
155
  return languages;
160
156
  };
@@ -167,10 +163,10 @@ const findAllLanguages = async (options?: GetResourceOptions) => {
167
163
  * quran.v4.resources.findAllChapterInfos()
168
164
  */
169
165
  const findAllChapterInfos = async (options?: GetResourceOptions) => {
170
- const params = getResourcesOptions(options);
166
+ const params = mergeApiOptions(options, defaultOptions);
171
167
  const { chapterInfos } = await fetcher<{
172
168
  chapterInfos: ChapterInfoResource[];
173
- }>('/resources/chapter_infos', params);
169
+ }>('/resources/chapter_infos', params, options?.fetchFn);
174
170
 
175
171
  return chapterInfos;
176
172
  };
@@ -183,10 +179,10 @@ const findAllChapterInfos = async (options?: GetResourceOptions) => {
183
179
  * quran.v4.resources.findVerseMedia()
184
180
  */
185
181
  const findVerseMedia = async (options?: GetResourceOptions) => {
186
- const params = getResourcesOptions(options);
182
+ const params = mergeApiOptions(options, defaultOptions);
187
183
  const { verseMedia } = await fetcher<{
188
184
  verseMedia: VerseMediaResource;
189
- }>(`/resources/verse_media`, params);
185
+ }>(`/resources/verse_media`, params, options?.fetchFn);
190
186
 
191
187
  return verseMedia;
192
188
  };
@@ -199,10 +195,10 @@ const findVerseMedia = async (options?: GetResourceOptions) => {
199
195
  * quran.v4.resources.findAllChapterReciters()
200
196
  */
201
197
  const findAllChapterReciters = async (options?: GetResourceOptions) => {
202
- const params = getResourcesOptions(options);
198
+ const params = mergeApiOptions(options, defaultOptions);
203
199
  const { reciters } = await fetcher<{
204
200
  reciters: ChapterReciterResource[];
205
- }>(`/resources/chapter_reciters`, params);
201
+ }>(`/resources/chapter_reciters`, params, options?.fetchFn);
206
202
 
207
203
  return reciters;
208
204
  };
@@ -1,22 +1,19 @@
1
1
  import { Language, SearchResponse } from '../../types';
2
- import { fetcher } from './_fetcher';
2
+ import { BaseApiOptions } from '../../types/BaseApiOptions';
3
+ import { fetcher, mergeApiOptions } from './_fetcher';
3
4
 
4
- type SearchOptions = Partial<{
5
- language: Language;
6
- size: number;
7
- page: number;
8
- }>;
5
+ type SearchOptions = Partial<
6
+ BaseApiOptions & {
7
+ size: number;
8
+ page: number;
9
+ }
10
+ >;
9
11
 
10
12
  const defaultSearchOptions: SearchOptions = {
11
13
  language: Language.ARABIC,
12
14
  size: 30,
13
15
  };
14
16
 
15
- const getSearchOptions = (q: string, options: SearchOptions = {}) => {
16
- const all = { ...defaultSearchOptions, ...options, q };
17
- return all;
18
- };
19
-
20
17
  /**
21
18
  * Search
22
19
  * @description https://quran.api-docs.io/v4/search/KfCmk4KQYbtyK9adj
@@ -29,8 +26,12 @@ const getSearchOptions = (q: string, options: SearchOptions = {}) => {
29
26
  * quran.v4.search.search('نور', { language: Language.ENGLISH, page: 2 })
30
27
  */
31
28
  const search = async (q: string, options?: SearchOptions) => {
32
- const params = getSearchOptions(q, options);
33
- const { search } = await fetcher<SearchResponse>('/search', params);
29
+ const params = mergeApiOptions({ q, ...options }, defaultSearchOptions);
30
+ const { search } = await fetcher<SearchResponse>(
31
+ '/search',
32
+ params,
33
+ options?.fetchFn
34
+ );
34
35
 
35
36
  return search;
36
37
  };
@@ -13,61 +13,59 @@ import {
13
13
  } from '../../types';
14
14
  import { decamelize } from 'humps';
15
15
  import Utils from '../utils';
16
- import { fetcher } from './_fetcher';
17
-
18
- type GetVerseOptions = Partial<{
19
- language: Language;
20
- reciter: string | number;
21
- words: boolean;
22
- translations: string[] | number[];
23
- tafsirs: string[] | number[];
24
- wordFields: Partial<Record<WordField, boolean>>;
25
- translationFields: Partial<Record<TranslationField, boolean>>;
26
- fields: Partial<Record<VerseField, boolean>>;
27
- page: number;
28
- perPage: number;
29
- }>;
16
+ import { fetcher, mergeApiOptions } from './_fetcher';
17
+ import { BaseApiOptions } from '../../types/BaseApiOptions';
18
+
19
+ type GetVerseOptions = Partial<
20
+ BaseApiOptions & {
21
+ reciter: string | number;
22
+ words: boolean;
23
+ translations: string[] | number[];
24
+ tafsirs: string[] | number[];
25
+ wordFields: Partial<Record<WordField, boolean>>;
26
+ translationFields: Partial<Record<TranslationField, boolean>>;
27
+ fields: Partial<Record<VerseField, boolean>>;
28
+ page: number;
29
+ perPage: number;
30
+ }
31
+ >;
30
32
 
31
33
  const defaultOptions: GetVerseOptions = {
32
34
  language: Language.ARABIC,
33
35
  perPage: 50,
36
+ words: false,
34
37
  };
35
38
 
36
- const getVerseOptions = (options: GetVerseOptions = {}) => {
37
- const initial = { ...defaultOptions, ...options };
38
- const result: any = { language: initial.language, perPage: initial.perPage };
39
-
40
- if (initial.page) result.page = initial.page;
41
- if (initial.words !== undefined) result.words = initial.words;
42
- if (initial.translations)
43
- result.translations = initial.translations.join(',');
44
- if (initial.tafsirs) result.tafsirs = initial.tafsirs.join(',');
45
-
46
- if (initial.fields) {
47
- const fields: string[] = [];
48
- for (const [key, value] of Object.entries(initial.fields)) {
49
- if (value) fields.push(decamelize(key));
50
- }
51
- result.fields = fields.join(',');
52
- }
39
+ const mergeVerseOptions = (options: GetVerseOptions = {}) => {
40
+ const result = mergeApiOptions(options, defaultOptions);
41
+
42
+ // @ts-expect-error - we accept an array of strings, however, the API expects a comma separated string
43
+ if (result.translations) result.translations = result.translations.join(',');
53
44
 
54
- if (initial.wordFields) {
45
+ // @ts-expect-error - we accept an array of strings, however, the API expects a comma separated string
46
+ if (result.tafsirs) result.tafsirs = result.tafsirs.join(',');
47
+
48
+ if (result.wordFields) {
55
49
  const wordFields: string[] = [];
56
- for (const [key, value] of Object.entries(initial.wordFields)) {
50
+ Object.entries(result.wordFields).forEach(([key, value]) => {
57
51
  if (value) wordFields.push(decamelize(key));
58
- }
52
+ });
59
53
  result.wordFields = wordFields.join(',');
60
54
  }
61
55
 
62
- if (initial.translationFields) {
56
+ if (result.translationFields) {
63
57
  const translationFields: string[] = [];
64
- for (const [key, value] of Object.entries(initial.translationFields)) {
58
+ Object.entries(result.translationFields).forEach(([key, value]) => {
65
59
  if (value) translationFields.push(decamelize(key));
66
- }
60
+ });
67
61
  result.translationFields = translationFields.join(',');
68
62
  }
69
63
 
70
- if (initial.reciter) result.audio = initial.reciter;
64
+ // rename `reciter` to `audio` because the API expects `audio`
65
+ if (result.reciter) {
66
+ result.audio = result.reciter;
67
+ result.reciter = undefined;
68
+ }
71
69
 
72
70
  return result;
73
71
  };
@@ -83,9 +81,13 @@ const getVerseOptions = (options: GetVerseOptions = {}) => {
83
81
  */
84
82
  const findByKey = async (key: VerseKey, options?: GetVerseOptions) => {
85
83
  if (!Utils.isValidVerseKey(key)) throw new Error('Invalid verse key');
86
- const params = getVerseOptions(options);
84
+ const params = mergeVerseOptions(options);
87
85
  const url = `/verses/by_key/${key}`;
88
- const { verse } = await fetcher<{ verse: Verse }>(url, params);
86
+ const { verse } = await fetcher<{ verse: Verse }>(
87
+ url,
88
+ params,
89
+ options?.fetchFn
90
+ );
89
91
 
90
92
  return verse;
91
93
  };
@@ -101,9 +103,13 @@ const findByKey = async (key: VerseKey, options?: GetVerseOptions) => {
101
103
  */
102
104
  const findByChapter = async (id: ChapterId, options?: GetVerseOptions) => {
103
105
  if (!Utils.isValidChapterId(id)) throw new Error('Invalid chapter id');
104
- const params = getVerseOptions(options);
106
+ const params = mergeVerseOptions(options);
105
107
  const url = `/verses/by_chapter/${id}`;
106
- const { verses } = await fetcher<{ verses: Verse[] }>(url, params);
108
+ const { verses } = await fetcher<{ verses: Verse[] }>(
109
+ url,
110
+ params,
111
+ options?.fetchFn
112
+ );
107
113
 
108
114
  return verses;
109
115
  };
@@ -120,9 +126,13 @@ const findByChapter = async (id: ChapterId, options?: GetVerseOptions) => {
120
126
  const findByPage = async (page: PageNumber, options?: GetVerseOptions) => {
121
127
  if (!Utils.isValidQuranPage(page)) throw new Error('Invalid page');
122
128
 
123
- const params = getVerseOptions(options);
129
+ const params = mergeVerseOptions(options);
124
130
  const url = `/verses/by_page/${page}`;
125
- const { verses } = await fetcher<{ verses: Verse[] }>(url, params);
131
+ const { verses } = await fetcher<{ verses: Verse[] }>(
132
+ url,
133
+ params,
134
+ options?.fetchFn
135
+ );
126
136
 
127
137
  return verses;
128
138
  };
@@ -139,9 +149,13 @@ const findByPage = async (page: PageNumber, options?: GetVerseOptions) => {
139
149
  const findByJuz = async (juz: JuzNumber, options?: GetVerseOptions) => {
140
150
  if (!Utils.isValidJuz(juz)) throw new Error('Invalid juz');
141
151
 
142
- const params = getVerseOptions(options);
152
+ const params = mergeVerseOptions(options);
143
153
  const url = `/verses/by_juz/${juz}`;
144
- const { verses } = await fetcher<{ verses: Verse[] }>(url, params);
154
+ const { verses } = await fetcher<{ verses: Verse[] }>(
155
+ url,
156
+ params,
157
+ options?.fetchFn
158
+ );
145
159
 
146
160
  return verses;
147
161
  };
@@ -158,9 +172,13 @@ const findByJuz = async (juz: JuzNumber, options?: GetVerseOptions) => {
158
172
  const findByHizb = async (hizb: HizbNumber, options?: GetVerseOptions) => {
159
173
  if (!Utils.isValidHizb(hizb)) throw new Error('Invalid hizb');
160
174
 
161
- const params = getVerseOptions(options);
175
+ const params = mergeVerseOptions(options);
162
176
  const url = `/verses/by_hizb/${hizb}`;
163
- const { verses } = await fetcher<{ verses: Verse[] }>(url, params);
177
+ const { verses } = await fetcher<{ verses: Verse[] }>(
178
+ url,
179
+ params,
180
+ options?.fetchFn
181
+ );
164
182
 
165
183
  return verses;
166
184
  };
@@ -193,8 +211,12 @@ const findByHizb = async (hizb: HizbNumber, options?: GetVerseOptions) => {
193
211
  * quran.v4.verses.findRandom()
194
212
  */
195
213
  const findRandom = async (options?: GetVerseOptions) => {
196
- const params = getVerseOptions(options);
197
- const { verse } = await fetcher<{ verse: Verse }>('/verses/random', params);
214
+ const params = mergeVerseOptions(options);
215
+ const { verse } = await fetcher<{ verse: Verse }>(
216
+ '/verses/random',
217
+ params,
218
+ options?.fetchFn
219
+ );
198
220
 
199
221
  return verse;
200
222
  };
@@ -0,0 +1,6 @@
1
+ import { FetchFn, Language } from '.';
2
+
3
+ export interface BaseApiOptions {
4
+ language: Language;
5
+ fetchFn?: FetchFn;
6
+ }
@@ -0,0 +1 @@
1
+ export type FetchFn = (url: string) => Promise<Record<string, unknown>>;