UNPKG

is-mahram

Version:

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

267 lines (260 loc) 6.8 kB
// 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; } } export { isMahram, SucklingMotherMustBeFemaleError, SpouseMustBeOppositeGenderError, Person, MotherMustBeFemaleError, FatherMustBeMaleError };