sunnah 1.3.6 → 1.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/CHANGELOG.md +19 -0
- package/README.md +258 -254
- package/bin/index.js +1022 -1604
- package/books/jami-al-tirmidhi/README.md +201 -0
- package/books/jami-al-tirmidhi/bin/index.js +165 -0
- package/books/jami-al-tirmidhi/examples/express/server.js +7 -0
- package/books/jami-al-tirmidhi/examples/node-commonjs/example.js +7 -0
- package/books/jami-al-tirmidhi/examples/node-esm/example.mjs +6 -0
- package/books/jami-al-tirmidhi/examples/react/HadithExample.jsx +17 -0
- package/books/jami-al-tirmidhi/package.json +58 -0
- package/books/jami-al-tirmidhi/src/index.cjs +52 -0
- package/books/jami-al-tirmidhi/src/index.js +35 -0
- package/books/jami-al-tirmidhi/src/index.node.js +18 -0
- package/books/jami-al-tirmidhi/types/index.d.ts +28 -0
- package/books/sahih-al-bukhari/LICENSE +661 -0
- package/books/sahih-al-bukhari/README.md +551 -0
- package/books/sahih-al-bukhari/bin/index.js +306 -0
- package/books/sahih-al-bukhari/data/bukhari.json.gz +0 -0
- package/books/sahih-al-bukhari/examples/express/server.js +49 -0
- package/books/sahih-al-bukhari/examples/node-commonjs/example.js +21 -0
- package/books/sahih-al-bukhari/examples/node-esm/example.mjs +24 -0
- package/books/sahih-al-bukhari/examples/react/HadithExample.jsx +73 -0
- package/books/sahih-al-bukhari/package.json +54 -0
- package/books/sahih-al-bukhari/src/index.cjs +55 -0
- package/books/sahih-al-bukhari/src/index.js +35 -0
- package/books/sahih-al-bukhari/src/index.node.js +21 -0
- package/books/sahih-al-bukhari/types/index.d.ts +35 -0
- package/books/sahih-muslim/LICENSE +661 -0
- package/books/sahih-muslim/README.md +547 -0
- package/books/sahih-muslim/bin/index.js +183 -0
- package/books/sahih-muslim/data/muslim.json.gz +0 -0
- package/books/sahih-muslim/examples/express/server.js +16 -0
- package/books/sahih-muslim/examples/node-commonjs/example.js +11 -0
- package/books/sahih-muslim/examples/node-esm/example.mjs +9 -0
- package/books/sahih-muslim/examples/react/HadithExample.jsx +28 -0
- package/books/sahih-muslim/package.json +58 -0
- package/books/sahih-muslim/src/index.cjs +52 -0
- package/books/sahih-muslim/src/index.js +35 -0
- package/books/sahih-muslim/src/index.node.js +18 -0
- package/books/sahih-muslim/types/index.d.ts +28 -0
- package/books/sunan-abi-dawud/LICENSE +661 -0
- package/books/sunan-abi-dawud/README.md +149 -0
- package/books/sunan-abi-dawud/bin/index.js +183 -0
- package/books/sunan-abi-dawud/data/dawud.json.gz +0 -0
- package/books/sunan-abi-dawud/examples/express/server.js +7 -0
- package/books/sunan-abi-dawud/examples/node-commonjs/example.js +7 -0
- package/books/sunan-abi-dawud/examples/node-esm/example.mjs +6 -0
- package/books/sunan-abi-dawud/examples/react/HadithExample.jsx +17 -0
- package/books/sunan-abi-dawud/package.json +58 -0
- package/books/sunan-abi-dawud/src/index.cjs +52 -0
- package/books/sunan-abi-dawud/src/index.js +35 -0
- package/books/sunan-abi-dawud/src/index.node.js +18 -0
- package/books/sunan-abi-dawud/types/index.d.ts +28 -0
- package/books/sunan-ibn-majah/README.md +198 -0
- package/books/sunan-ibn-majah/bin/index.js +138 -0
- package/books/sunan-ibn-majah/examples/express/server.js +8 -0
- package/books/sunan-ibn-majah/examples/node-commonjs/example.js +7 -0
- package/books/sunan-ibn-majah/examples/node-esm/example.mjs +6 -0
- package/books/sunan-ibn-majah/examples/react/HadithExample.jsx +17 -0
- package/books/sunan-ibn-majah/package.json +58 -0
- package/books/sunan-ibn-majah/src/index.cjs +52 -0
- package/books/sunan-ibn-majah/src/index.js +35 -0
- package/books/sunan-ibn-majah/src/index.node.js +18 -0
- package/books/sunan-ibn-majah/types/index.d.ts +28 -0
- package/package.json +39 -27
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<h1>
|
|
4
|
+
<img src="https://em-content.zobj.net/source/apple/391/mosque_1f54c.png" width="36" />
|
|
5
|
+
sahih-muslim
|
|
6
|
+
</h1>
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
<strong>The complete Sahih Muslim — 7,563 hadiths, full Arabic & English.</strong><br />
|
|
10
|
+
One repo · one dataset · published on both <strong>npm</strong> and <strong>PyPI</strong>.
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
<br />
|
|
14
|
+
|
|
15
|
+
<!-- Row 1: version badges -->
|
|
16
|
+
<p>
|
|
17
|
+
<a href="https://www.npmjs.com/package/sahih-muslim" text-decoration="none">
|
|
18
|
+
<img src="https://img.shields.io/npm/v/sahih-muslim?style=for-the-badge&logo=npm&logoColor=white&color=CB3837&labelColor=1a1a1a" alt="npm version" />
|
|
19
|
+
</a><a href="https://pypi.org/project/sahih-muslim/" text-decoration="none">
|
|
20
|
+
<img src="https://img.shields.io/pypi/v/sahih-muslim?style=for-the-badge&logo=pypi&logoColor=white&color=3775A9&labelColor=1a1a1a" alt="PyPI version" />
|
|
21
|
+
</a><a href="https://github.com/SENODROOM/sahih-muslim/blob/main/LICENSE" text-decoration="none">
|
|
22
|
+
<img src="https://img.shields.io/github/license/SENODROOM/sahih-muslim?style=for-the-badge&logo=gnu&logoColor=white&color=A42E2B&labelColor=1a1a1a" alt="License: AGPL-3.0" />
|
|
23
|
+
</a>
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
<!-- Row 2: stats -->
|
|
27
|
+
<p>
|
|
28
|
+
<a href="https://www.npmjs.com/package/sahih-muslim" text-decoration="none">
|
|
29
|
+
<img src="https://img.shields.io/npm/dt/sahih-muslim?style=for-the-badge&logo=npm&logoColor=white&color=CB3837&labelColor=1a1a1a" alt="npm downloads" />
|
|
30
|
+
</a><a href="https://pypi.org/project/sahih-muslim/" text-decoration="none">
|
|
31
|
+
<img src="https://img.shields.io/pypi/dm/sahih-muslim?style=for-the-badge&logo=pypi&logoColor=white&color=3775A9&labelColor=1a1a1a" alt="PyPI monthly downloads" />
|
|
32
|
+
</a>
|
|
33
|
+
</p>
|
|
34
|
+
|
|
35
|
+
<!-- Row 3: repo stats -->
|
|
36
|
+
<p>
|
|
37
|
+
<a href="https://github.com/SENODROOM/sahih-muslim/stargazers" text-decoration="none">
|
|
38
|
+
<img src="https://img.shields.io/github/stars/SENODROOM/sahih-muslim?style=for-the-badge&logo=github&logoColor=white&color=f0c040&labelColor=1a1a1a" alt="GitHub stars" />
|
|
39
|
+
</a><a href="https://github.com/SENODROOM/sahih-muslim/issues" text-decoration="none">
|
|
40
|
+
<img src="https://img.shields.io/github/issues/SENODROOM/sahih-muslim?style=for-the-badge&logo=github&logoColor=white&color=238636&labelColor=1a1a1a" alt="GitHub issues" />
|
|
41
|
+
</a><a href="https://github.com/SENODROOM/sahih-muslim/commits/main" text-decoration="none">
|
|
42
|
+
<img src="https://img.shields.io/github/last-commit/SENODROOM/sahih-muslim?style=for-the-badge&logo=github&logoColor=white&color=8957e5&labelColor=1a1a1a" alt="Last commit" />
|
|
43
|
+
</a>
|
|
44
|
+
</p>
|
|
45
|
+
|
|
46
|
+
<!-- Row 4: tech -->
|
|
47
|
+
<p>
|
|
48
|
+
<img src="https://img.shields.io/badge/Node.js-%3E%3D14-339933?style=for-the-badge&logo=node.js&logoColor=white&labelColor=1a1a1a" alt="Node.js" /><img src="https://img.shields.io/badge/Python-%3E%3D3.8-3776AB?style=for-the-badge&logo=python&logoColor=white&labelColor=1a1a1a" alt="Python" /><img src="https://img.shields.io/badge/TypeScript-Typed-3178C6?style=for-the-badge&logo=typescript&logoColor=white&labelColor=1a1a1a" alt="TypeScript" /><img src="https://img.shields.io/badge/Zero-Dependencies-00C853?style=for-the-badge&logoColor=white&labelColor=1a1a1a" alt="Zero dependencies" />
|
|
49
|
+
</p>
|
|
50
|
+
|
|
51
|
+
<br />
|
|
52
|
+
|
|
53
|
+
[](https://nodei.co/npm/sahih-muslim/)
|
|
54
|
+
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## ✨ Features at a Glance
|
|
60
|
+
|
|
61
|
+
| | Feature | Details |
|
|
62
|
+
| --- | ----------------------- | ------------------------------------------------------- |
|
|
63
|
+
| 📚 | **Complete Collection** | All 7,563 authentic hadiths from Sahih Muslim |
|
|
64
|
+
| 🌐 | **Bilingual** | Full Arabic text + English translation for every hadith |
|
|
65
|
+
| 📝 | **Chapters** | 2,200+ chapters with Arabic & English names |
|
|
66
|
+
| ⚡ | **Tiny Install** | ~3KB package — data loaded from CDN on demand |
|
|
67
|
+
| 🔍 | **Full-text Search** | Search English text and narrator names instantly |
|
|
68
|
+
| 🖥️ | **CLI** | Terminal access with Arabic/English/both flags |
|
|
69
|
+
| ⚛️ | **React Hook** | One command generates `useMuslim()` in your project |
|
|
70
|
+
| 🐍 | **Python** | Identical API — same method names as the npm package |
|
|
71
|
+
| 📘 | **TypeScript** | Full type definitions, zero `@types` package needed |
|
|
72
|
+
| 🔧 | **Zero Config** | Works out of the box everywhere |
|
|
73
|
+
| 🗄️ | **One Dataset** | `bin/muslim.json` shared by both JS and Python |
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 🚀 Installation
|
|
78
|
+
|
|
79
|
+
<table>
|
|
80
|
+
<tr>
|
|
81
|
+
<td><strong>JavaScript / Node.js</strong></td>
|
|
82
|
+
<td><strong>Python</strong></td>
|
|
83
|
+
</tr>
|
|
84
|
+
<tr>
|
|
85
|
+
<td>
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# local (for projects)
|
|
89
|
+
npm install sahih-muslim
|
|
90
|
+
|
|
91
|
+
# global (for CLI)
|
|
92
|
+
npm install -g sahih-muslim
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
</td>
|
|
96
|
+
<td>
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# local (for projects)
|
|
100
|
+
pip install sahih-muslim
|
|
101
|
+
|
|
102
|
+
# global CLI is included automatically
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
</td>
|
|
106
|
+
</tr>
|
|
107
|
+
</table>
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 🟨 JavaScript / Node.js
|
|
112
|
+
|
|
113
|
+
### CommonJS & ESM
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
// CommonJS — require()
|
|
117
|
+
const muslim = require("sahih-muslim");
|
|
118
|
+
|
|
119
|
+
// ESM — import
|
|
120
|
+
import muslim from "sahih-muslim";
|
|
121
|
+
|
|
122
|
+
// Get by ID
|
|
123
|
+
muslim.get(1); // → Hadith
|
|
124
|
+
|
|
125
|
+
// Get by chapter
|
|
126
|
+
muslim.getByChapter(1); // → Hadith[]
|
|
127
|
+
|
|
128
|
+
// Full-text search
|
|
129
|
+
muslim.search("prayer"); // → Hadith[]
|
|
130
|
+
|
|
131
|
+
// Random
|
|
132
|
+
muslim.getRandom(); // → Hadith
|
|
133
|
+
|
|
134
|
+
// Index access
|
|
135
|
+
muslim[0]; // → Hadith (first)
|
|
136
|
+
muslim.length; // → 7563
|
|
137
|
+
|
|
138
|
+
// Metadata
|
|
139
|
+
muslim.metadata; // → { title, author, ... }
|
|
140
|
+
muslim.chapters; // → Chapter[]
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Hadith object shape
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
{
|
|
147
|
+
id: 1,
|
|
148
|
+
chapterId: 1,
|
|
149
|
+
arabic: "حَدَّثَنِي يَحْيَى بْنُ يَحْيَى...",
|
|
150
|
+
english: {
|
|
151
|
+
narrator: "Yahya bin Yahya",
|
|
152
|
+
text: "It is narrated on the authority of Amir al-Mu'minin..."
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Native array methods — all work
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
muslim.find((h) => h.id === 23);
|
|
161
|
+
muslim.filter((h) => h.chapterId === 1);
|
|
162
|
+
muslim.map((h) => h.english.narrator);
|
|
163
|
+
muslim.forEach((h) => console.log(h.id));
|
|
164
|
+
muslim.slice(0, 10);
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## ⚛️ React / Vue / Vite
|
|
170
|
+
|
|
171
|
+
Run this **once** inside your React project:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
cd my-react-app
|
|
175
|
+
muslim --react
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
This auto-generates `src/hooks/useMuslim.js`. Then use it anywhere:
|
|
179
|
+
|
|
180
|
+
```jsx
|
|
181
|
+
import { useMuslim } from "../hooks/useMuslim";
|
|
182
|
+
|
|
183
|
+
function HadithOfTheDay() {
|
|
184
|
+
const muslim = useMuslim();
|
|
185
|
+
if (!muslim) return <p>Loading...</p>;
|
|
186
|
+
|
|
187
|
+
const h = muslim.getRandom();
|
|
188
|
+
return (
|
|
189
|
+
<div>
|
|
190
|
+
<p>
|
|
191
|
+
<strong>{h.english.narrator}</strong>
|
|
192
|
+
</p>
|
|
193
|
+
<p>{h.english.text}</p>
|
|
194
|
+
</div>
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
```jsx
|
|
200
|
+
// Search example
|
|
201
|
+
function HadithSearch() {
|
|
202
|
+
const muslim = useMuslim();
|
|
203
|
+
const [results, setResults] = useState([]);
|
|
204
|
+
if (!muslim) return <p>Loading...</p>;
|
|
205
|
+
|
|
206
|
+
return (
|
|
207
|
+
<>
|
|
208
|
+
<input
|
|
209
|
+
placeholder="Search hadiths..."
|
|
210
|
+
onChange={(e) => setResults(muslim.search(e.target.value, 10))}
|
|
211
|
+
/>
|
|
212
|
+
{results.map((h) => (
|
|
213
|
+
<p key={h.id}>{h.english.text}</p>
|
|
214
|
+
))}
|
|
215
|
+
</>
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
> Data is fetched from jsDelivr CDN once and cached globally. All components share the same request — no duplicates.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## 🐍 Python
|
|
225
|
+
|
|
226
|
+
The Python API is **identical** to the npm package — same camelCase method names, same behaviour.
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
from sahih_muslim import Muslim
|
|
230
|
+
|
|
231
|
+
muslim = Muslim() # reads bin/muslim.json if in repo, else fetches from CDN
|
|
232
|
+
|
|
233
|
+
# Exact same API as JS
|
|
234
|
+
muslim.get(1) # Hadith | None
|
|
235
|
+
muslim.getByChapter(1) # list[Hadith]
|
|
236
|
+
muslim.search("prayer") # list[Hadith]
|
|
237
|
+
muslim.search("prayer", limit=5) # list[Hadith] — top 5
|
|
238
|
+
muslim.getRandom() # Hadith
|
|
239
|
+
|
|
240
|
+
# Index access & iteration
|
|
241
|
+
muslim[0] # first hadith
|
|
242
|
+
muslim.length # 7563
|
|
243
|
+
len(muslim) # 7563
|
|
244
|
+
for h in muslim: print(h.id)
|
|
245
|
+
|
|
246
|
+
# Array-style methods (matches JS prototype)
|
|
247
|
+
muslim.find(lambda h: h.id == 23)
|
|
248
|
+
muslim.filter(lambda h: h.chapterId == 1)
|
|
249
|
+
muslim.map(lambda h: h.narrator)
|
|
250
|
+
muslim.slice(0, 10)
|
|
251
|
+
|
|
252
|
+
# Metadata
|
|
253
|
+
muslim.metadata.english # {"title": ..., "author": ...}
|
|
254
|
+
muslim.chapters # list[Chapter]
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Custom data path
|
|
258
|
+
|
|
259
|
+
```python
|
|
260
|
+
# Use your own muslim.json at any path
|
|
261
|
+
muslim = Muslim(data_path="/absolute/path/to/muslim.json")
|
|
262
|
+
muslim = Muslim(data_path=Path(__file__).parent / "muslim.json")
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Flask API example
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
from flask import Flask, jsonify, request
|
|
269
|
+
from sahih_muslim import Muslim
|
|
270
|
+
|
|
271
|
+
app = Flask(__name__)
|
|
272
|
+
muslim = Muslim()
|
|
273
|
+
|
|
274
|
+
@app.get("/api/hadith/<int:hadith_id>")
|
|
275
|
+
def get_hadith(hadith_id):
|
|
276
|
+
h = muslim.get(hadith_id)
|
|
277
|
+
return jsonify(h.to_dict()) if h else ("Not found", 404)
|
|
278
|
+
|
|
279
|
+
@app.get("/api/search")
|
|
280
|
+
def search():
|
|
281
|
+
return jsonify([h.to_dict() for h in muslim.search(request.args.get("q", ""), limit=20)])
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## 🖥️ CLI
|
|
287
|
+
|
|
288
|
+
The same `muslim` command works whether installed via **npm** or **pip**.
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
# By ID
|
|
292
|
+
muslim 1
|
|
293
|
+
muslim 2345
|
|
294
|
+
|
|
295
|
+
# Within a chapter
|
|
296
|
+
muslim 23 34
|
|
297
|
+
|
|
298
|
+
# Language flags
|
|
299
|
+
muslim 2345 # English only (default)
|
|
300
|
+
muslim 2345 -a # Arabic only
|
|
301
|
+
muslim 2345 --arabic # Arabic only
|
|
302
|
+
muslim 2345 -b # Arabic + English
|
|
303
|
+
muslim 2345 --both # Arabic + English
|
|
304
|
+
|
|
305
|
+
# Search
|
|
306
|
+
muslim --search "prayer"
|
|
307
|
+
muslim --search "fasting" --all # show all results (default: top 5)
|
|
308
|
+
|
|
309
|
+
# Chapter listing
|
|
310
|
+
muslim --chapter 5
|
|
311
|
+
|
|
312
|
+
# Random
|
|
313
|
+
muslim --random
|
|
314
|
+
muslim --random -b
|
|
315
|
+
|
|
316
|
+
# React hook generator (JS only — run inside your React project)
|
|
317
|
+
muslim --react
|
|
318
|
+
|
|
319
|
+
# Info
|
|
320
|
+
muslim --version
|
|
321
|
+
muslim --help
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Example output
|
|
325
|
+
|
|
326
|
+
```
|
|
327
|
+
════════════════════════════════════════════════════════════
|
|
328
|
+
Hadith #1 | Chapter: 1 — Faith
|
|
329
|
+
════════════════════════════════════════════════════════════
|
|
330
|
+
Narrator: Yahya bin Yahya
|
|
331
|
+
|
|
332
|
+
It is narrated on the authority of Amir al-Mu'minin, Abu Hafs
|
|
333
|
+
Umar ibn al-Khattab, who said: I heard the Messenger of Allah
|
|
334
|
+
(ﷺ) say: "Actions are judged by intentions..."
|
|
335
|
+
════════════════════════════════════════════════════════════
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## 🗄️ Monorepo Structure
|
|
341
|
+
|
|
342
|
+
```
|
|
343
|
+
sahih-muslim/
|
|
344
|
+
│
|
|
345
|
+
├── bin/
|
|
346
|
+
│ ├── muslim.json ← 🔑 SHARED — single source of truth for JS + Python
|
|
347
|
+
│ └── index.js ← JS CLI entry
|
|
348
|
+
│
|
|
349
|
+
├── chapters/ ← 🔑 SHARED — generated by `node build.mjs`
|
|
350
|
+
│ ├── meta.json used by CDN loader (JS browser) + Python CDN fallback
|
|
351
|
+
│ ├── 1.json
|
|
352
|
+
│ └── ...
|
|
353
|
+
│
|
|
354
|
+
├── sahih_muslim/ ← Python package
|
|
355
|
+
│ ├── __init__.py
|
|
356
|
+
│ ├── muslim.py ← auto-reads bin/muslim.json
|
|
357
|
+
│ └── cli.py
|
|
358
|
+
│
|
|
359
|
+
├── index.js ← JS ESM (browser-safe)
|
|
360
|
+
├── index.cjs ← JS CommonJS
|
|
361
|
+
├── index.node.js ← JS Node ESM
|
|
362
|
+
├── index.browser.js ← JS browser / CDN (auto-generated)
|
|
363
|
+
├── index.d.ts ← TypeScript definitions
|
|
364
|
+
├── build.mjs ← generates chapters/ from bin/muslim.json
|
|
365
|
+
│
|
|
366
|
+
├── package.json ← npm config
|
|
367
|
+
├── pyproject.toml ← Python / Poetry config
|
|
368
|
+
├── MANIFEST.in ← Python sdist: include data, exclude JS
|
|
369
|
+
└── .npmignore ← npm publish: exclude Python files
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### Shared data — how it works
|
|
373
|
+
|
|
374
|
+
| File | Used by |
|
|
375
|
+
| ----------------- | ----------------------------------------------------------- |
|
|
376
|
+
| `bin/muslim.json` | JS Node (CJS + ESM) · Python (auto-detected from repo root) |
|
|
377
|
+
| `chapters/` | JS browser CDN fetch · Python CDN fallback |
|
|
378
|
+
|
|
379
|
+
**You never duplicate data.** Both packages read the exact same file.
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## 📊 API Reference
|
|
384
|
+
|
|
385
|
+
### Methods
|
|
386
|
+
|
|
387
|
+
| Method | JS | Python | Returns |
|
|
388
|
+
| ----------------------- | --- | ------ | -------------------------- |
|
|
389
|
+
| `get(id)` | ✅ | ✅ | `Hadith \| undefined/None` |
|
|
390
|
+
| `getByChapter(id)` | ✅ | ✅ | `Hadith[]` |
|
|
391
|
+
| `search(query, limit?)` | ✅ | ✅ | `Hadith[]` |
|
|
392
|
+
| `getRandom()` | ✅ | ✅ | `Hadith` |
|
|
393
|
+
| `find(predicate)` | ✅ | ✅ | `Hadith \| undefined/None` |
|
|
394
|
+
| `filter(predicate)` | ✅ | ✅ | `Hadith[]` |
|
|
395
|
+
| `map(fn)` | ✅ | ✅ | `any[]` |
|
|
396
|
+
| `forEach(fn)` | ✅ | ✅ | `void/None` |
|
|
397
|
+
| `slice(start, end)` | ✅ | ✅ | `Hadith[]` |
|
|
398
|
+
|
|
399
|
+
### Properties
|
|
400
|
+
|
|
401
|
+
| Property | Type | Description |
|
|
402
|
+
| ---------- | -------------- | --------------------------- |
|
|
403
|
+
| `length` | `number / int` | Total hadiths — 7,563 |
|
|
404
|
+
| `metadata` | `Metadata` | Title, author, introduction |
|
|
405
|
+
| `chapters` | `Chapter[]` | All chapters |
|
|
406
|
+
|
|
407
|
+
---
|
|
408
|
+
|
|
409
|
+
## 💡 Examples
|
|
410
|
+
|
|
411
|
+
<details>
|
|
412
|
+
<summary><strong>Seed a MongoDB database (Node.js)</strong></summary>
|
|
413
|
+
|
|
414
|
+
```javascript
|
|
415
|
+
import { MongoClient } from "mongodb";
|
|
416
|
+
import muslim from "sahih-muslim";
|
|
417
|
+
|
|
418
|
+
const client = new MongoClient(process.env.MONGO_URI);
|
|
419
|
+
await client.connect();
|
|
420
|
+
await client
|
|
421
|
+
.db("islam")
|
|
422
|
+
.collection("hadiths")
|
|
423
|
+
.insertMany([...muslim]);
|
|
424
|
+
await client.close();
|
|
425
|
+
console.log("Seeded", muslim.length, "hadiths");
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
</details>
|
|
429
|
+
|
|
430
|
+
<details>
|
|
431
|
+
<summary><strong>Seed a database (Python)</strong></summary>
|
|
432
|
+
|
|
433
|
+
```python
|
|
434
|
+
from sahih_muslim import Muslim
|
|
435
|
+
|
|
436
|
+
muslim = Muslim()
|
|
437
|
+
records = [h.to_dict() for h in muslim]
|
|
438
|
+
# Insert into any DB
|
|
439
|
+
print(f"Seeded {len(records)} hadiths")
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
</details>
|
|
443
|
+
|
|
444
|
+
<details>
|
|
445
|
+
<summary><strong>Thematic search</strong></summary>
|
|
446
|
+
|
|
447
|
+
```python
|
|
448
|
+
from sahih_muslim import Muslim
|
|
449
|
+
|
|
450
|
+
muslim = Muslim()
|
|
451
|
+
topics = ["prayer", "charity", "fasting", "knowledge", "patience"]
|
|
452
|
+
for topic in topics:
|
|
453
|
+
count = len(muslim.search(topic))
|
|
454
|
+
print(f"{topic:12} → {count} hadiths")
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
</details>
|
|
458
|
+
|
|
459
|
+
<details>
|
|
460
|
+
<summary><strong>Express.js REST API</strong></summary>
|
|
461
|
+
|
|
462
|
+
```javascript
|
|
463
|
+
import express from "express";
|
|
464
|
+
import muslim from "sahih-muslim";
|
|
465
|
+
|
|
466
|
+
const app = express();
|
|
467
|
+
|
|
468
|
+
app.get("/api/hadith/random", (_, res) => res.json(muslim.getRandom()));
|
|
469
|
+
app.get("/api/hadith/:id", (req, res) => {
|
|
470
|
+
const h = muslim.get(parseInt(req.params.id));
|
|
471
|
+
h ? res.json(h) : res.status(404).json({ error: "Not found" });
|
|
472
|
+
});
|
|
473
|
+
app.get("/api/search", (req, res) =>
|
|
474
|
+
res.json(muslim.search(req.query.q || "")),
|
|
475
|
+
);
|
|
476
|
+
app.get("/api/chapter/:id", (req, res) =>
|
|
477
|
+
res.json(muslim.getByChapter(parseInt(req.params.id))),
|
|
478
|
+
);
|
|
479
|
+
|
|
480
|
+
app.listen(3000, () => console.log("Running on :3000"));
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
</details>
|
|
484
|
+
|
|
485
|
+
---
|
|
486
|
+
|
|
487
|
+
## 🔧 Development
|
|
488
|
+
|
|
489
|
+
```bash
|
|
490
|
+
git clone https://github.com/SENODROOM/sahih-muslim.git
|
|
491
|
+
cd sahih-muslim
|
|
492
|
+
npm install
|
|
493
|
+
|
|
494
|
+
# Regenerate chapters/ from bin/muslim.json
|
|
495
|
+
node build.mjs
|
|
496
|
+
|
|
497
|
+
# Publish to npm
|
|
498
|
+
npm publish
|
|
499
|
+
|
|
500
|
+
# Publish to PyPI
|
|
501
|
+
pip install build twine
|
|
502
|
+
python -m build
|
|
503
|
+
python -m twine upload dist/*
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
---
|
|
507
|
+
|
|
508
|
+
## 🤝 Contributing
|
|
509
|
+
|
|
510
|
+
Contributions are welcome!
|
|
511
|
+
|
|
512
|
+
1. Fork the repository
|
|
513
|
+
2. Create a branch: `git checkout -b feature/my-feature`
|
|
514
|
+
3. Commit: `git commit -m 'Add my feature'`
|
|
515
|
+
4. Push: `git push origin feature/my-feature`
|
|
516
|
+
5. Open a Pull Request
|
|
517
|
+
|
|
518
|
+
---
|
|
519
|
+
|
|
520
|
+
## 📄 License
|
|
521
|
+
|
|
522
|
+
Licensed under the **GNU Affero General Public License v3.0 (AGPL-3.0)** — see [LICENSE](LICENSE) for details.
|
|
523
|
+
|
|
524
|
+
---
|
|
525
|
+
|
|
526
|
+
## 🙏 Acknowledgments
|
|
527
|
+
|
|
528
|
+
- **📖 Source** — Sahih Muslim, one of the most authentic hadith collections in Islam
|
|
529
|
+
- **👨🏫 Translations** — By reputable Islamic scholars
|
|
530
|
+
- **💚 Inspiration** — The global Muslim community seeking knowledge
|
|
531
|
+
|
|
532
|
+
---
|
|
533
|
+
|
|
534
|
+
<div align="center">
|
|
535
|
+
|
|
536
|
+
### 🌟 If this project helped you, please give it a star!
|
|
537
|
+
|
|
538
|
+
[](https://github.com/SENODROOM/sahih-muslim/stargazers)
|
|
539
|
+
[](https://github.com/SENODROOM/sahih-muslim/fork)
|
|
540
|
+
|
|
541
|
+
<br />
|
|
542
|
+
|
|
543
|
+
**Made with ❤️ for the Muslim community · Seeking knowledge together**
|
|
544
|
+
|
|
545
|
+
[📖 Docs](https://github.com/SENODROOM/sahih-muslim#readme) · [🐛 Issues](https://github.com/SENODROOM/sahih-muslim/issues) · [💬 Discussions](https://github.com/SENODROOM/sahih-muslim/discussions)
|
|
546
|
+
|
|
547
|
+
</div>
|