Sort spouses by marriage date (#10)

This commit is contained in:
Przemek Wiech
2020-02-13 14:33:43 +01:00
parent 21eba112d5
commit d3ea1705f4
3 changed files with 151 additions and 26 deletions

70
src/gedcom_util.spec.ts Normal file
View File

@@ -0,0 +1,70 @@
import {normalizeGedcom} from './gedcom_util';
describe('normalizeGedcom()', () => {
it('sorts children', () => {
const data = {
indis: [
{
id: 'I3',
birth: {date: {year: 1901}},
famc: 'F1',
},
{
id: 'I2',
birth: {date: {year: 1902, month: 7}},
famc: 'F1',
},
{
id: 'I1',
birth: {date: {year: 1902, month: 8}},
famc: 'F1',
},
],
fams: [
{
id: 'F1',
children: ['I1', 'I2', 'I3'],
},
],
};
const normalized = normalizeGedcom(data);
expect(normalized.fams[0].children).toEqual(['I3', 'I2', 'I1']);
});
it('sorts spouses', () => {
const data = {
indis: [
{id: 'I1', fams: ['F1']},
{id: 'I2', fams: ['F2']},
{id: 'I3', fams: ['F3']},
{id: 'I4', fams: ['F1', 'F2', 'F3']},
],
fams: [
{
id: 'F3',
marriage: {date: {year: 1901}},
husband: 'I4',
wife: 'I3',
},
{
id: 'F2',
marriage: {date: {year: 1902, month: 7}},
husband: 'I4',
wife: 'I2',
},
{
id: 'F1',
marriage: {date: {year: 1902, month: 8}},
husband: 'I4',
wife: 'I1',
},
],
};
const normalized = normalizeGedcom(data);
expect(normalized.indis.find((i) => i.id === 'I4')!.fams).toEqual([
'F3',
'F2',
'F1',
]);
});
});

View File

@@ -4,6 +4,7 @@ import {
JsonIndi, JsonIndi,
gedcomEntriesToJson, gedcomEntriesToJson,
JsonImage, JsonImage,
JsonEvent,
} from 'topola'; } from 'topola';
import {GedcomEntry, parse as parseGedcom} from 'parse-gedcom'; import {GedcomEntry, parse as parseGedcom} from 'parse-gedcom';
@@ -58,6 +59,33 @@ function strcmp(a: string, b: string) {
return 0; return 0;
} }
/** Compares dates of the given events. */
function compareDates(
event1: JsonEvent | undefined,
event2: JsonEvent | undefined,
): number {
const date1 =
event1 && (event1.date || (event1.dateRange && event1.dateRange.from));
const date2 =
event2 && (event2.date || (event2.dateRange && event2.dateRange.from));
if (!date1 || !date1.year || !date2 || !date2.year) {
return 0;
}
if (date1.year !== date2.year) {
return date1.year - date2.year;
}
if (!date1.month || !date2.month) {
return 0;
}
if (date1.month !== date2.month) {
return date1.month - date2.month;
}
if (date1.day && date2.day && date1.day !== date2.day) {
return date1.month - date2.month;
}
return 0;
}
/** Birth date comparator for individuals. */ /** Birth date comparator for individuals. */
function birthDatesComparator(gedcom: JsonGedcomData) { function birthDatesComparator(gedcom: JsonGedcomData) {
const idToIndiMap = new Map<string, JsonIndi>(); const idToIndiMap = new Map<string, JsonIndi>();
@@ -66,31 +94,29 @@ function birthDatesComparator(gedcom: JsonGedcomData) {
}); });
return (indiId1: string, indiId2: string) => { return (indiId1: string, indiId2: string) => {
const idComparison = strcmp(indiId1, indiId2);
const indi1: JsonIndi = idToIndiMap[indiId1]; const indi1: JsonIndi = idToIndiMap[indiId1];
const indi2: JsonIndi = idToIndiMap[indiId2]; const indi2: JsonIndi = idToIndiMap[indiId2];
const birth1 = indi1 && indi1.birth; return (
const birth2 = indi2 && indi2.birth; compareDates(indi1 && indi1.birth, indi2 && indi2.birth) ||
const date1 = strcmp(indiId1, indiId2)
birth1 && (birth1.date || (birth1.dateRange && birth1.dateRange.from)); );
const date2 = };
birth2 && (birth2.date || (birth2.dateRange && birth2.dateRange.from)); }
if (!date1 || !date1.year || !date2 || !date2.year) {
return idComparison; /** Marriage date comparator for families. */
} function marriageDatesComparator(gedcom: JsonGedcomData) {
if (date1.year !== date2.year) { const idToFamMap = new Map<string, JsonFam>();
return date1.year - date2.year; gedcom.fams.forEach((fam) => {
} idToFamMap[fam.id] = fam;
if (!date1.month || !date2.month) { });
return idComparison;
} return (famId1: string, famId2: string) => {
if (date1.month !== date2.month) { const fam1: JsonFam = idToFamMap[famId1];
return date1.month - date2.month; const fam2: JsonFam = idToFamMap[famId2];
} return (
if (date1.day && date2.day && date1.day !== date2.day) { compareDates(fam1 && fam1.marriage, fam2 && fam2.marriage) ||
return date1.month - date2.month; strcmp(famId1, famId2)
} );
return idComparison;
}; };
} }
@@ -119,6 +145,34 @@ function sortChildren(gedcom: JsonGedcomData): JsonGedcomData {
return Object.assign({}, gedcom, {fams: newFams}); return Object.assign({}, gedcom, {fams: newFams});
} }
/**
* Sorts spouses by marriage date.
* Does not modify the input objects.
*/
function sortIndiSpouses(
indi: JsonIndi,
comparator: (id1: string, id2: string) => number,
): JsonFam {
if (!indi.fams) {
return indi;
}
const newFams = indi.fams.sort(comparator);
return Object.assign({}, indi, {fams: newFams});
}
function sortSpouses(gedcom: JsonGedcomData): JsonGedcomData {
const comparator = marriageDatesComparator(gedcom);
const newIndis = gedcom.indis.map((indi) =>
sortIndiSpouses(indi, comparator),
);
return Object.assign({}, gedcom, {indis: newIndis});
}
/** Sorts children and spouses. */
export function normalizeGedcom(gedcom: JsonGedcomData): JsonGedcomData {
return sortSpouses(sortChildren(gedcom));
}
const IMAGE_EXTENSIONS = ['.jpg', '.png', '.gif']; const IMAGE_EXTENSIONS = ['.jpg', '.png', '.gif'];
/** Returns true if the given file name has a known image extension. */ /** Returns true if the given file name has a known image extension. */
@@ -185,7 +239,7 @@ export function convertGedcom(
} }
return { return {
chartData: filterImages(sortChildren(json), images), chartData: filterImages(normalizeGedcom(json), images),
gedcom: prepareGedcom(entries), gedcom: prepareGedcom(entries),
}; };
} }

View File

@@ -1,6 +1,6 @@
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import {Date, JsonFam, JsonIndi} from 'topola'; import {Date, JsonFam, JsonIndi} from 'topola';
import {GedcomData, TopolaData} from './gedcom_util'; import {GedcomData, TopolaData, normalizeGedcom} from './gedcom_util';
import {GedcomEntry} from 'parse-gedcom'; import {GedcomEntry} from 'parse-gedcom';
/** WikiTree API getAncestors request. */ /** WikiTree API getAncestors request. */
@@ -286,8 +286,9 @@ export async function loadWikiTree(
return fam; return fam;
}); });
const chartData = normalizeGedcom({indis, fams});
const gedcom = buildGedcom(indis); const gedcom = buildGedcom(indis);
return {chartData: {indis, fams}, gedcom}; return {chartData, gedcom};
} }
/** Creates a family identifier given 2 spouse identifiers. */ /** Creates a family identifier given 2 spouse identifiers. */