UNPKG

is-mahram

Version:

A TypeScript library to determine if a person is a mahram based on Islamic jurisprudence.

299 lines (290 loc) 8.04 kB
var __defProp = Object.defineProperty; var __getOwnPropNames = Object.getOwnPropertyNames; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __hasOwnProp = Object.prototype.hasOwnProperty; var __moduleCache = /* @__PURE__ */ new WeakMap; var __toCommonJS = (from) => { var entry = __moduleCache.get(from), desc; if (entry) return entry; entry = __defProp({}, "__esModule", { value: true }); if (from && typeof from === "object" || typeof from === "function") __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable })); __moduleCache.set(from, entry); return entry; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true, configurable: true, set: (newValue) => all[name] = () => newValue }); }; // src/index.ts var exports_src = {}; __export(exports_src, { isMahram: () => isMahram, SucklingMotherMustBeFemaleError: () => SucklingMotherMustBeFemaleError, SpouseMustBeOppositeGenderError: () => SpouseMustBeOppositeGenderError, Person: () => Person, MotherMustBeFemaleError: () => MotherMustBeFemaleError, FatherMustBeMaleError: () => FatherMustBeMaleError }); module.exports = __toCommonJS(exports_src); // src/is-mahram.ts function isMahram(personA, personB) { if (personA.getId() === personB.getId()) { return true; } if (personA.getSpouses().has(personB)) { return true; } if (isBloodMahram(personA, personB)) { return true; } if (isMarriageMahram(personA, personB)) { return true; } if (isSucklingMahram(personA, personB)) { return true; } return false; } function isBloodMahram(personA, personB) { if (isAncestor(personA, personB) || isAncestor(personB, personA)) { return true; } if (isSibling(personA, personB)) { return true; } if (isAuntOrUncle(personA, personB) || isAuntOrUncle(personB, personA)) { return true; } return false; } function isMarriageMahram(personA, personB) { for (const spouse of personA.getSpouses()) { if (isAncestor(personB, spouse)) { return true; } } for (const spouse of personB.getSpouses()) { if (isAncestor(personA, spouse)) { return true; } } for (const spouse of personA.getSpouses()) { if (isDescendant(personB, spouse)) { return true; } } for (const spouse of personB.getSpouses()) { if (isDescendant(personA, spouse)) { return true; } } const { father: fatherA, mother: motherA } = personA.getParents(); const { father: fatherB, mother: motherB } = personB.getParents(); if (fatherA?.getSpouses().has(personB)) { return true; } if (motherA?.getSpouses().has(personB)) { return true; } if (fatherB?.getSpouses().has(personA)) { return true; } if (motherB?.getSpouses().has(personA)) { return true; } const childrenOfA = getChildren(personA); for (const child of childrenOfA) { if (child?.getSpouses().has(personB)) { return true; } } const childrenOfB = getChildren(personB); for (const child of childrenOfB) { if (child?.getSpouses().has(personA)) { return true; } } return false; } function isSucklingMahram(personA, personB) { const sucklingParentsA = getSucklingParents(personA); const sucklingParentsB = getSucklingParents(personB); if (!sucklingParentsA && !sucklingParentsB) return false; if (sucklingParentsB && sucklingParentsB.mother === personA || sucklingParentsB && sucklingParentsB.father === personA) { return true; } if (sucklingParentsA && sucklingParentsA.mother === personB || sucklingParentsA && sucklingParentsA.father === personB) { return true; } if (sucklingParentsA && sucklingParentsB && sucklingParentsA.mother === sucklingParentsB.mother) { return true; } const sucklingMotherA = personA.getSucklingMother(); const sucklingMotherB = personB.getSucklingMother(); if (sucklingMotherA && isBloodMahram(sucklingMotherA, personB)) { return true; } if (sucklingMotherB && isBloodMahram(sucklingMotherB, personA)) { return true; } return false; } function isAncestor(potentialAncestor, person) { const { father, mother } = person.getParents(); if (!father && !mother) { return false; } if (father === potentialAncestor || mother === potentialAncestor) { return true; } return !!(father && isAncestor(potentialAncestor, father) || mother && isAncestor(potentialAncestor, mother)); } function isDescendant(potentialDescendant, person) { return isAncestor(person, potentialDescendant); } function isSibling(personA, personB) { const { father: fatherA, mother: motherA } = personA.getParents(); const { father: fatherB, mother: motherB } = personB.getParents(); if (fatherA && motherA && fatherB && motherB) { return fatherA === fatherB || motherA === motherB; } return false; } function isAuntOrUncle(potentialAuntOrUncle, person) { const { father, mother } = person.getParents(); if (father && isSibling(potentialAuntOrUncle, father)) { return true; } if (mother && isSibling(potentialAuntOrUncle, mother)) { return true; } return false; } function getChildren(person) { return []; } function getSucklingParents(person) { const sucklingMother = person.getSucklingMother(); if (!sucklingMother) { return null; } return { mother: sucklingMother, father: Array.from(sucklingMother.getSpouses())[0] || null }; } // src/errors.ts class FatherMustBeMaleError extends Error { constructor() { super("Father must be male"); this.name = "FatherMustBeMaleError"; } } class MotherMustBeFemaleError extends Error { constructor() { super("Mother must be female"); this.name = "MotherMustBeFemaleError"; } } class SucklingMotherMustBeFemaleError extends Error { constructor() { super("Suckling mother must be femalre"); this.name = "SucklingMotherMustBeFemaleError"; } } class SpouseMustBeOppositeGenderError extends Error { constructor() { super("Spouse must be of opposite gender"); this.name = "SpouseMustBeOppositeGenderError"; } } // src/util.ts var generateId = () => { return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); }; // src/person.ts class Person { name; gender; id; parents = { father: null, mother: null }; spouses = new Set; sucklingMother = null; constructor(name, gender) { this.name = name; this.gender = gender; this.id = generateId(); } setName(name) { this.name = name; } setFather(father) { if (father.gender !== "Male") throw new FatherMustBeMaleError; this.parents.father = father; if (this.parents.mother && !this.parents.mother.getSpouses().has(father)) { this.parents.mother.addSpouse(father); } } setMother(mother) { if (mother.gender !== "Female") throw new MotherMustBeFemaleError; this.parents.mother = mother; if (this.parents.father && !this.parents.father.getSpouses().has(mother)) { this.parents.father.addSpouse(mother); } } addSpouse(spouse) { if (this.gender === spouse.gender) { throw new SpouseMustBeOppositeGenderError; } if (!this.spouses.has(spouse)) { this.spouses.add(spouse); spouse.spouses.add(this); } } setSucklingMother(wetNurse) { if (wetNurse.gender !== "Female") { throw new SucklingMotherMustBeFemaleError; } this.sucklingMother = wetNurse; } getId() { return this.id; } getName() { return this.name; } getGender() { return this.gender; } getParents() { return this.parents; } getFather() { return this.parents.father; } getMother() { return this.parents.mother; } getSpouses() { return this.spouses; } getSucklingMother() { return this.sucklingMother; } }