-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
133 lines (114 loc) · 4.88 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
const getTemperatureShift = require('./temperature')
const getMucusShift = require('./mucus')
const getCervixShift = require('./cervix')
const { LocalDate } = require('js-joda')
const assert = require('assert')
module.exports = function getSymptoThermalStatus(cycleInfo) {
const {
cycle,
previousCycle,
earlierCycles = [],
secondarySymptom = 'mucus',
excludePreOvu
} = cycleInfo
throwIfArgsAreNotInRequiredFormat([cycle, ...earlierCycles])
const status = {
phases: {}
}
// if there was no first higher measurement in the previous cycle,
// no infertile pre-ovulatory phase may be assumed
if (!excludePreOvu && previousCycle) {
const getPreOvulatoryPhase = require('./pre-ovulatory')
const statusForLast = getSymptoThermalStatus({
cycle: previousCycle,
secondarySymptom: secondarySymptom
})
if (statusForLast.temperatureShift) {
const preOvuPhase = getPreOvulatoryPhase(
cycle,
[previousCycle, ...earlierCycles],
secondarySymptom
)
if (preOvuPhase) {
status.phases.preOvulatory = preOvuPhase
if (status.phases.preOvulatory.cycleDays.length === cycle.length) {
return status
}
}
}
}
// TODO maybe add indicator if there was no preovuphase?
status.phases.periOvulatory = {
start: { date: null },
cycleDays: []
}
const periPhase = status.phases.periOvulatory
if (status.phases.preOvulatory) {
const prePhase = status.phases.preOvulatory
const startDate = LocalDate.parse(prePhase.end.date).plusDays(1).toString()
periPhase.start.date = startDate
const lastPreDay = prePhase.cycleDays[prePhase.cycleDays.length - 1]
periPhase.cycleDays = cycle.slice(cycle.indexOf(lastPreDay) + 1)
} else {
periPhase.start.date = cycle[0].date
periPhase.cycleDays = [...cycle]
}
const temperatureShift = getTemperatureShift(cycle)
if (!temperatureShift.detected) return status
const tempEvalEndIndex = cycle.indexOf(temperatureShift.evaluationCompleteDay)
let secondaryShift
if (secondarySymptom === 'mucus') {
secondaryShift = getMucusShift(cycle, tempEvalEndIndex)
} else if (secondarySymptom === 'cervix') {
secondaryShift = getCervixShift(cycle, tempEvalEndIndex)
}
if (!secondaryShift.detected) return status
let periOvulatoryEnd
const tempOver = temperatureShift.evaluationCompleteDay.date
const secondarySymptomOver = secondaryShift.evaluationCompleteDay.date
if (tempOver >= secondarySymptomOver) {
periOvulatoryEnd = temperatureShift.evaluationCompleteDay
} else if (secondarySymptom > tempOver) {
periOvulatoryEnd = secondaryShift.evaluationCompleteDay
}
const previousPeriDays = periPhase.cycleDays
const previousPeriEndIndex = previousPeriDays.indexOf(periOvulatoryEnd)
status.phases.postOvulatory = {
start: {
date: periOvulatoryEnd.date,
time: '18:00'
},
cycleDays: previousPeriDays.slice(previousPeriEndIndex)
}
periPhase.cycleDays = previousPeriDays.slice(0, previousPeriEndIndex + 1)
periPhase.end = status.phases.postOvulatory.start
if (secondarySymptom === 'mucus') {
status.mucusShift = secondaryShift
} else if (secondarySymptom === 'cervix') {
status.cervixShift = secondaryShift
}
status.temperatureShift = temperatureShift
return status
}
function throwIfArgsAreNotInRequiredFormat(cycles) {
cycles.forEach(cycle => {
assert.ok(Array.isArray(cycle), "Cycles must be arrays.")
assert.ok(cycle.length > 0, "Cycle must not be empty.")
assert.equal(typeof cycle[0].bleeding, 'number', "First cycle day should have bleeding.")
cycle.forEach(day => {
assert.equal(typeof day.date, 'string', "Date must be given as a string.")
assert.doesNotThrow(() => LocalDate.parse(day.date), "Date must be given in right string format.")
if (day.temperature) assert.equal(typeof day.temperature, 'number', "Temperature value must be a number.")
if (day.mucus) assert.equal(typeof day.mucus, 'number', "Mucus value must be a number.")
if (day.cervix) assert.equal(typeof day.cervix.opening, 'number', "Cervix opening value must be a number.")
if (day.cervix) assert.equal(typeof day.cervix.firmness, 'number', "Cervix firmness value must be a number.")
if (day.mucus) assert.ok(day.mucus >= 0, "Mucus value must greater or equal to 0.")
if (day.mucus) assert.ok(day.mucus <= 4, "Mucus value must be below 5.")
if (day.cervix) assert.ok(day.cervix.opening >= 0, "Cervix opening value must be 0 or bigger")
if (day.cervix) assert.ok(day.cervix.opening <= 2, "Cervix opening value must be 2 or smaller")
if (day.cervix) assert.ok(day.cervix.firmness >= 0, "Cervix firmness value must be 0 or bigger")
if (day.cervix) assert.ok(day.cervix.firmness <= 1, "Cervix firmness value must be 1 or smaller")
assert.equal(typeof cycle[0].bleeding, 'number', "Bleeding value must be a number")
})
})
}