Don't do duplicate work in getLastMensesStart
This commit is contained in:
+38
-55
@@ -26,70 +26,49 @@ export default function config(opts) {
|
||||
minCyclesForPrediction = opts.minCyclesForPrediction || 3
|
||||
}
|
||||
|
||||
function getLastMensesStart(targetDateString) {
|
||||
const targetDate = LocalDate.parse(targetDateString)
|
||||
const withWrappedDates = bleedingDaysSortedByDate
|
||||
.filter(day => !day.bleeding.exclude)
|
||||
.map(day => {
|
||||
day.wrappedDate = LocalDate.parse(day.date)
|
||||
return day
|
||||
})
|
||||
function findLatestMensesStart(bleedingDays) {
|
||||
if (!bleedingDays.length) return null
|
||||
|
||||
// the index of the first bleeding day before the target day
|
||||
const index = withWrappedDates.findIndex(day => {
|
||||
return (
|
||||
day.wrappedDate.isEqual(targetDate) ||
|
||||
day.wrappedDate.isBefore(targetDate)
|
||||
)
|
||||
})
|
||||
|
||||
if (index < 0) {
|
||||
withWrappedDates.forEach(day => delete day.wrappedDate)
|
||||
return null
|
||||
}
|
||||
|
||||
const prevBleedingDays = withWrappedDates.slice(index)
|
||||
|
||||
const lastMensesStart = prevBleedingDays.find((day, i) => {
|
||||
return noBleedingDayWithinThreshold(day, prevBleedingDays.slice(i + 1))
|
||||
// assumes bleeding days are ordered latest first, and
|
||||
// excluded values already removed
|
||||
const lastMensesStart = bleedingDays.find((day, i) => {
|
||||
return noBleedingDayWithinThreshold(day, bleedingDays.slice(i + 1))
|
||||
})
|
||||
|
||||
function noBleedingDayWithinThreshold(day, previousBleedingDays) {
|
||||
const periodThreshold = day.wrappedDate.minusDays(maxBreakInBleeding + 1)
|
||||
return !previousBleedingDays.some(({ wrappedDate }) => {
|
||||
return (
|
||||
wrappedDate.equals(periodThreshold) ||
|
||||
wrappedDate.isAfter(periodThreshold)
|
||||
)
|
||||
})
|
||||
const localDate = LocalDate.parse(day.date)
|
||||
const threshold = localDate.minusDays(maxBreakInBleeding + 1).toString()
|
||||
return !previousBleedingDays.some(({ date }) => date >= threshold)
|
||||
}
|
||||
|
||||
withWrappedDates.forEach(day => delete day.wrappedDate)
|
||||
return lastMensesStart
|
||||
}
|
||||
|
||||
function getFollowingMensesStart(targetDateString) {
|
||||
const targetDate = LocalDate.parse(targetDateString)
|
||||
const withWrappedDates = bleedingDaysSortedByDate
|
||||
function getLastMensesStartForDay(targetDateString) {
|
||||
// the index of the first bleeding day before the target day
|
||||
const index = bleedingDaysSortedByDate.findIndex(day => {
|
||||
return day.date <= targetDateString && !day.bleeding.exclude
|
||||
})
|
||||
|
||||
if (index < 0) return null
|
||||
|
||||
const prevBleedingDays = bleedingDaysSortedByDate.slice(index)
|
||||
return findLatestMensesStart(prevBleedingDays)
|
||||
}
|
||||
|
||||
function getFollowingMensesStartForDay(targetDateString) {
|
||||
const followingBleedingDays = bleedingDaysSortedByDate
|
||||
.filter(day => !day.bleeding.exclude)
|
||||
.map(day => {
|
||||
day.wrappedDate = LocalDate.parse(day.date)
|
||||
return day
|
||||
})
|
||||
|
||||
const firstBleedingDayAfterTargetDay = withWrappedDates
|
||||
.reverse()
|
||||
.find(day => {
|
||||
return day.wrappedDate.isAfter(targetDate)
|
||||
})
|
||||
|
||||
withWrappedDates.forEach(day => delete day.wrappedDate)
|
||||
const firstBleedingDayAfterTargetDay = followingBleedingDays
|
||||
.find(day => day.date > targetDateString)
|
||||
|
||||
return firstBleedingDayAfterTargetDay
|
||||
}
|
||||
|
||||
function getCycleDayNumber(targetDateString) {
|
||||
const lastMensesStart = getLastMensesStart(targetDateString)
|
||||
const lastMensesStart = getLastMensesStartForDay(targetDateString)
|
||||
if (!lastMensesStart) return null
|
||||
const targetDate = LocalDate.parse(targetDateString)
|
||||
const lastMensesLocalDate = LocalDate.parse(lastMensesStart.date)
|
||||
@@ -111,7 +90,7 @@ export default function config(opts) {
|
||||
}
|
||||
|
||||
function getPreviousCycle(dateString) {
|
||||
const startOfCycle = getLastMensesStart(dateString)
|
||||
const startOfCycle = getLastMensesStartForDay(dateString)
|
||||
if (!startOfCycle) return null
|
||||
const dateBeforeStartOfCycle = LocalDate
|
||||
.parse(startOfCycle.date)
|
||||
@@ -123,10 +102,10 @@ export default function config(opts) {
|
||||
|
||||
function getCycleForDay(dayOrDate) {
|
||||
const dateString = typeof dayOrDate === 'string' ? dayOrDate : dayOrDate.date
|
||||
const cycleStart = getLastMensesStart(dateString)
|
||||
const cycleStart = getLastMensesStartForDay(dateString)
|
||||
if (!cycleStart) return null
|
||||
const cycleStartIndex = cycleDaysSortedByDate.indexOf(cycleStart)
|
||||
const nextMensesStart = getFollowingMensesStart(dateString)
|
||||
const nextMensesStart = getFollowingMensesStartForDay(dateString)
|
||||
if (nextMensesStart) {
|
||||
return cycleDaysSortedByDate.slice(
|
||||
cycleDaysSortedByDate.indexOf(nextMensesStart) + 1,
|
||||
@@ -137,16 +116,20 @@ export default function config(opts) {
|
||||
}
|
||||
}
|
||||
|
||||
function getAllMensesStarts(day, collectedDates) {
|
||||
day = day || LocalDate.now().toString()
|
||||
function getAllMensesStarts(initialBleedingDays = bleedingDaysSortedByDate) {
|
||||
return recurse(initialBleedingDays.filter(d => !d.bleeding.exclude))
|
||||
|
||||
function recurse(bleedingDays, collectedDates) {
|
||||
collectedDates = collectedDates || []
|
||||
const lastStart = getLastMensesStart(day)
|
||||
const lastStart = findLatestMensesStart(bleedingDays)
|
||||
if (!lastStart) {
|
||||
return collectedDates
|
||||
} else {
|
||||
const newDay = LocalDate.parse(lastStart.date).minusDays(1).toString()
|
||||
collectedDates.push(lastStart.date)
|
||||
return getAllMensesStarts(newDay, collectedDates)
|
||||
const index = bleedingDays.indexOf(lastStart)
|
||||
const remainingDays = bleedingDays.slice(index + 1)
|
||||
return recurse(remainingDays, collectedDates)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -625,7 +625,8 @@ describe('getAllMensesStart', () => {
|
||||
const result = getAllMensesStarts()
|
||||
expect(result.length).to.eql(2)
|
||||
expect(result).to.eql(['2018-06-01', '2018-05-01'])
|
||||
}),
|
||||
})
|
||||
|
||||
it('works for two cycle starts with excluded data', () => {
|
||||
const cycleDaysSortedByDate = [
|
||||
{
|
||||
@@ -649,7 +650,8 @@ describe('getAllMensesStart', () => {
|
||||
const result = getAllMensesStarts()
|
||||
expect(result.length).to.eql(2)
|
||||
expect(result).to.eql(['2018-06-01', '2018-05-01'])
|
||||
}),
|
||||
})
|
||||
|
||||
it('returns an empty array if no bleeding days are given', () => {
|
||||
const cycleDaysSortedByDate = [ {} ]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user