@mrtdown/core 2.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +107 -0
- package/dist/constants.d.ts +10 -0
- package/dist/constants.js +11 -0
- package/dist/constants.js.map +1 -0
- package/dist/helpers/calculateDurationWithinServiceHours.d.ts +2 -0
- package/dist/helpers/calculateDurationWithinServiceHours.js +13 -0
- package/dist/helpers/calculateDurationWithinServiceHours.js.map +1 -0
- package/dist/helpers/calculateDurationWithinServiceHours.test.d.ts +1 -0
- package/dist/helpers/calculateDurationWithinServiceHours.test.js +83 -0
- package/dist/helpers/calculateDurationWithinServiceHours.test.js.map +1 -0
- package/dist/helpers/computeImpactFromEvidenceClaims.d.ts +21 -0
- package/dist/helpers/computeImpactFromEvidenceClaims.js +293 -0
- package/dist/helpers/computeImpactFromEvidenceClaims.js.map +1 -0
- package/dist/helpers/computeImpactFromEvidenceClaims.test.d.ts +1 -0
- package/dist/helpers/computeImpactFromEvidenceClaims.test.js +544 -0
- package/dist/helpers/computeImpactFromEvidenceClaims.test.js.map +1 -0
- package/dist/helpers/computeStartOfDaysWithinInterval.d.ts +2 -0
- package/dist/helpers/computeStartOfDaysWithinInterval.js +15 -0
- package/dist/helpers/computeStartOfDaysWithinInterval.js.map +1 -0
- package/dist/helpers/computeStartOfDaysWithinInterval.test.d.ts +1 -0
- package/dist/helpers/computeStartOfDaysWithinInterval.test.js +126 -0
- package/dist/helpers/computeStartOfDaysWithinInterval.test.js.map +1 -0
- package/dist/helpers/estimateOpenAICost.d.ts +40 -0
- package/dist/helpers/estimateOpenAICost.js +55 -0
- package/dist/helpers/estimateOpenAICost.js.map +1 -0
- package/dist/helpers/keyForAffectedEntity.d.ts +7 -0
- package/dist/helpers/keyForAffectedEntity.js +14 -0
- package/dist/helpers/keyForAffectedEntity.js.map +1 -0
- package/dist/helpers/normalizeRecurringPeriod.d.ts +7 -0
- package/dist/helpers/normalizeRecurringPeriod.js +118 -0
- package/dist/helpers/normalizeRecurringPeriod.js.map +1 -0
- package/dist/helpers/normalizeRecurringPeriod.test.d.ts +1 -0
- package/dist/helpers/normalizeRecurringPeriod.test.js +93 -0
- package/dist/helpers/normalizeRecurringPeriod.test.js.map +1 -0
- package/dist/helpers/resolvePeriods.d.ts +224 -0
- package/dist/helpers/resolvePeriods.js +207 -0
- package/dist/helpers/resolvePeriods.js.map +1 -0
- package/dist/helpers/resolvePeriods.test.d.ts +1 -0
- package/dist/helpers/resolvePeriods.test.js +239 -0
- package/dist/helpers/resolvePeriods.test.js.map +1 -0
- package/dist/helpers/splitIntervalByServiceHours.d.ts +2 -0
- package/dist/helpers/splitIntervalByServiceHours.js +30 -0
- package/dist/helpers/splitIntervalByServiceHours.js.map +1 -0
- package/dist/helpers/splitIntervalByServiceHours.test.d.ts +1 -0
- package/dist/helpers/splitIntervalByServiceHours.test.js +152 -0
- package/dist/helpers/splitIntervalByServiceHours.test.js.map +1 -0
- package/dist/helpers/sumIntervalDuration.d.ts +2 -0
- package/dist/helpers/sumIntervalDuration.js +9 -0
- package/dist/helpers/sumIntervalDuration.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/repo/MRTDownRepository.d.ts +23 -0
- package/dist/repo/MRTDownRepository.js +28 -0
- package/dist/repo/MRTDownRepository.js.map +1 -0
- package/dist/repo/common/FileStore.d.ts +12 -0
- package/dist/repo/common/FileStore.js +27 -0
- package/dist/repo/common/FileStore.js.map +1 -0
- package/dist/repo/common/StandardRepository.d.ts +32 -0
- package/dist/repo/common/StandardRepository.js +58 -0
- package/dist/repo/common/StandardRepository.js.map +1 -0
- package/dist/repo/common/store.d.ts +29 -0
- package/dist/repo/common/store.js +2 -0
- package/dist/repo/common/store.js.map +1 -0
- package/dist/repo/issue/IssueRepository.d.ts +36 -0
- package/dist/repo/issue/IssueRepository.js +177 -0
- package/dist/repo/issue/IssueRepository.js.map +1 -0
- package/dist/repo/issue/helpers/deriveCurrentState.d.ts +51 -0
- package/dist/repo/issue/helpers/deriveCurrentState.js +113 -0
- package/dist/repo/issue/helpers/deriveCurrentState.js.map +1 -0
- package/dist/repo/issue/helpers/deriveCurrentState.test.d.ts +1 -0
- package/dist/repo/issue/helpers/deriveCurrentState.test.js +477 -0
- package/dist/repo/issue/helpers/deriveCurrentState.test.js.map +1 -0
- package/dist/repo/landmark/LandmarkRepository.d.ts +7 -0
- package/dist/repo/landmark/LandmarkRepository.js +12 -0
- package/dist/repo/landmark/LandmarkRepository.js.map +1 -0
- package/dist/repo/line/LineRepository.d.ts +13 -0
- package/dist/repo/line/LineRepository.js +32 -0
- package/dist/repo/line/LineRepository.js.map +1 -0
- package/dist/repo/operator/OperatorRepository.d.ts +7 -0
- package/dist/repo/operator/OperatorRepository.js +12 -0
- package/dist/repo/operator/OperatorRepository.js.map +1 -0
- package/dist/repo/service/ServiceRepository.d.ts +19 -0
- package/dist/repo/service/ServiceRepository.js +39 -0
- package/dist/repo/service/ServiceRepository.js.map +1 -0
- package/dist/repo/station/StationRepository.d.ts +13 -0
- package/dist/repo/station/StationRepository.js +30 -0
- package/dist/repo/station/StationRepository.js.map +1 -0
- package/dist/repo/town/TownRepository.d.ts +7 -0
- package/dist/repo/town/TownRepository.js +12 -0
- package/dist/repo/town/TownRepository.js.map +1 -0
- package/dist/schema/Landmark.d.ts +11 -0
- package/dist/schema/Landmark.js +7 -0
- package/dist/schema/Landmark.js.map +1 -0
- package/dist/schema/Line.d.ts +58 -0
- package/dist/schema/Line.js +35 -0
- package/dist/schema/Line.js.map +1 -0
- package/dist/schema/Operator.d.ts +16 -0
- package/dist/schema/Operator.js +12 -0
- package/dist/schema/Operator.js.map +1 -0
- package/dist/schema/Service.d.ts +55 -0
- package/dist/schema/Service.js +24 -0
- package/dist/schema/Service.js.map +1 -0
- package/dist/schema/Station.d.ts +29 -0
- package/dist/schema/Station.js +25 -0
- package/dist/schema/Station.js.map +1 -0
- package/dist/schema/Town.d.ts +11 -0
- package/dist/schema/Town.js +7 -0
- package/dist/schema/Town.js.map +1 -0
- package/dist/schema/common.d.ts +24 -0
- package/dist/schema/common.js +23 -0
- package/dist/schema/common.js.map +1 -0
- package/dist/schema/issue/bundle.d.ts +239 -0
- package/dist/schema/issue/bundle.js +11 -0
- package/dist/schema/issue/bundle.js.map +1 -0
- package/dist/schema/issue/cause.d.ts +51 -0
- package/dist/schema/issue/cause.js +30 -0
- package/dist/schema/issue/cause.js.map +1 -0
- package/dist/schema/issue/claim.d.ts +149 -0
- package/dist/schema/issue/claim.js +36 -0
- package/dist/schema/issue/claim.js.map +1 -0
- package/dist/schema/issue/entity.d.ts +176 -0
- package/dist/schema/issue/entity.js +35 -0
- package/dist/schema/issue/entity.js.map +1 -0
- package/dist/schema/issue/evidence.d.ts +124 -0
- package/dist/schema/issue/evidence.js +30 -0
- package/dist/schema/issue/evidence.js.map +1 -0
- package/dist/schema/issue/facilityEffect.d.ts +15 -0
- package/dist/schema/issue/facilityEffect.js +12 -0
- package/dist/schema/issue/facilityEffect.js.map +1 -0
- package/dist/schema/issue/id.d.ts +3 -0
- package/dist/schema/issue/id.js +6 -0
- package/dist/schema/issue/id.js.map +1 -0
- package/dist/schema/issue/impactEvent.d.ts +373 -0
- package/dist/schema/issue/impactEvent.js +43 -0
- package/dist/schema/issue/impactEvent.js.map +1 -0
- package/dist/schema/issue/issue.d.ts +19 -0
- package/dist/schema/issue/issue.js +13 -0
- package/dist/schema/issue/issue.js.map +1 -0
- package/dist/schema/issue/issueType.d.ts +7 -0
- package/dist/schema/issue/issueType.js +3 -0
- package/dist/schema/issue/issueType.js.map +1 -0
- package/dist/schema/issue/period.d.ts +72 -0
- package/dist/schema/issue/period.js +32 -0
- package/dist/schema/issue/period.js.map +1 -0
- package/dist/schema/issue/serviceEffect.d.ts +29 -0
- package/dist/schema/issue/serviceEffect.js +21 -0
- package/dist/schema/issue/serviceEffect.js.map +1 -0
- package/dist/schema/issue/serviceScope.d.ts +38 -0
- package/dist/schema/issue/serviceScope.js +30 -0
- package/dist/schema/issue/serviceScope.js.map +1 -0
- package/dist/util/assert.d.ts +1 -0
- package/dist/util/assert.js +6 -0
- package/dist/util/assert.js.map +1 -0
- package/dist/util/ingestContent/helpers/getSlugDateTimeFromClaims.d.ts +7 -0
- package/dist/util/ingestContent/helpers/getSlugDateTimeFromClaims.js +24 -0
- package/dist/util/ingestContent/helpers/getSlugDateTimeFromClaims.js.map +1 -0
- package/dist/util/ingestContent/index.d.ts +12 -0
- package/dist/util/ingestContent/index.js +171 -0
- package/dist/util/ingestContent/index.js.map +1 -0
- package/dist/util/ingestContent/types.d.ts +32 -0
- package/dist/util/ingestContent/types.js +2 -0
- package/dist/util/ingestContent/types.js.map +1 -0
- package/dist/write/MRTDownWriter.d.ts +27 -0
- package/dist/write/MRTDownWriter.js +27 -0
- package/dist/write/MRTDownWriter.js.map +1 -0
- package/dist/write/common/FileWriteStore.d.ts +13 -0
- package/dist/write/common/FileWriteStore.js +31 -0
- package/dist/write/common/FileWriteStore.js.map +1 -0
- package/dist/write/common/StandardWriter.d.ts +14 -0
- package/dist/write/common/StandardWriter.js +17 -0
- package/dist/write/common/StandardWriter.js.map +1 -0
- package/dist/write/common/store.d.ts +32 -0
- package/dist/write/common/store.js +2 -0
- package/dist/write/common/store.js.map +1 -0
- package/dist/write/id/IdGenerator.d.ts +18 -0
- package/dist/write/id/IdGenerator.js +23 -0
- package/dist/write/id/IdGenerator.js.map +1 -0
- package/dist/write/issue/IssueWriter.d.ts +12 -0
- package/dist/write/issue/IssueWriter.js +33 -0
- package/dist/write/issue/IssueWriter.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import { resolvePeriods } from './resolvePeriods.js';
|
|
3
|
+
describe('resolvePeriods', () => {
|
|
4
|
+
const asOf = '2025-01-01T12:00:00+08:00';
|
|
5
|
+
const factEndedPeriod = [
|
|
6
|
+
{
|
|
7
|
+
kind: 'fixed',
|
|
8
|
+
startAt: '2025-01-01T08:00:00+08:00',
|
|
9
|
+
endAt: '2025-01-01T09:00:00+08:00',
|
|
10
|
+
},
|
|
11
|
+
];
|
|
12
|
+
test('keeps fact-ended period in all modes', () => {
|
|
13
|
+
const canonical = resolvePeriods({
|
|
14
|
+
periods: factEndedPeriod,
|
|
15
|
+
asOf,
|
|
16
|
+
mode: { kind: 'canonical' },
|
|
17
|
+
});
|
|
18
|
+
const operational = resolvePeriods({
|
|
19
|
+
periods: factEndedPeriod,
|
|
20
|
+
asOf,
|
|
21
|
+
mode: { kind: 'operational' },
|
|
22
|
+
});
|
|
23
|
+
expect(canonical[0]).toMatchObject({
|
|
24
|
+
startAt: '2025-01-01T08:00:00+08:00',
|
|
25
|
+
endAt: '2025-01-01T09:00:00+08:00',
|
|
26
|
+
endAtResolved: '2025-01-01T09:00:00+08:00',
|
|
27
|
+
endAtSource: 'fact',
|
|
28
|
+
});
|
|
29
|
+
expect(operational[0].endAtSource).toBe('fact');
|
|
30
|
+
});
|
|
31
|
+
test('open period with no evidence and no crowd remains open', () => {
|
|
32
|
+
const result = resolvePeriods({
|
|
33
|
+
periods: [
|
|
34
|
+
{
|
|
35
|
+
kind: 'fixed',
|
|
36
|
+
startAt: '2025-01-01T08:00:00+08:00',
|
|
37
|
+
endAt: null,
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
asOf,
|
|
41
|
+
mode: { kind: 'operational' },
|
|
42
|
+
});
|
|
43
|
+
expect(result[0]).toMatchObject({
|
|
44
|
+
endAt: null,
|
|
45
|
+
endAtResolved: null,
|
|
46
|
+
endAtSource: 'none',
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
test('open period infers end from evidence timeout only', () => {
|
|
50
|
+
const result = resolvePeriods({
|
|
51
|
+
periods: [
|
|
52
|
+
{
|
|
53
|
+
kind: 'fixed',
|
|
54
|
+
startAt: '2025-01-01T08:00:00+08:00',
|
|
55
|
+
endAt: null,
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
asOf: '2025-01-02T01:00:00+08:00', // Past inferred end-of-day (2025-01-02T00:00)
|
|
59
|
+
mode: {
|
|
60
|
+
kind: 'operational',
|
|
61
|
+
lastEvidenceAt: '2025-01-01T09:00:00+08:00',
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
expect(result[0]).toMatchObject({
|
|
65
|
+
endAtResolved: '2025-01-02T00:00:00.000+08:00',
|
|
66
|
+
endAtSource: 'inferred',
|
|
67
|
+
endAtReason: 'evidence_timeout',
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
test('crowd exited inference wins over evidence timeout', () => {
|
|
71
|
+
const result = resolvePeriods({
|
|
72
|
+
periods: [
|
|
73
|
+
{
|
|
74
|
+
kind: 'fixed',
|
|
75
|
+
startAt: '2025-01-01T08:00:00+08:00',
|
|
76
|
+
endAt: null,
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
asOf: '2025-01-02T01:00:00+08:00', // Past inferred end-of-day (2025-01-02T00:00)
|
|
80
|
+
mode: {
|
|
81
|
+
kind: 'operational',
|
|
82
|
+
lastEvidenceAt: '2025-01-01T09:00:00+08:00',
|
|
83
|
+
crowd: {
|
|
84
|
+
activeNow: false,
|
|
85
|
+
exitedAt: '2025-01-01T10:15:00+08:00',
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
expect(result[0]).toMatchObject({
|
|
90
|
+
endAtResolved: '2025-01-02T00:00:00.000+08:00',
|
|
91
|
+
endAtSource: 'inferred',
|
|
92
|
+
endAtReason: 'crowd_decay',
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
test('crowd.activeNow=true prevents crowd-based inference fallback', () => {
|
|
96
|
+
const result = resolvePeriods({
|
|
97
|
+
periods: [
|
|
98
|
+
{
|
|
99
|
+
kind: 'fixed',
|
|
100
|
+
startAt: '2025-01-01T08:00:00+08:00',
|
|
101
|
+
endAt: null,
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
asOf,
|
|
105
|
+
mode: {
|
|
106
|
+
kind: 'operational',
|
|
107
|
+
crowd: {
|
|
108
|
+
activeNow: true,
|
|
109
|
+
lastActiveAt: '2025-01-01T09:30:00+08:00',
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
expect(result[0]).toMatchObject({
|
|
114
|
+
endAtResolved: null,
|
|
115
|
+
endAtSource: 'none',
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
test('clamps inferred end to maxInferredDurationMinutes', () => {
|
|
119
|
+
const result = resolvePeriods({
|
|
120
|
+
periods: [
|
|
121
|
+
{
|
|
122
|
+
kind: 'fixed',
|
|
123
|
+
startAt: '2025-01-01T08:00:00+08:00',
|
|
124
|
+
endAt: null,
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
asOf: '2025-01-02T13:00:00+08:00',
|
|
128
|
+
mode: {
|
|
129
|
+
kind: 'operational',
|
|
130
|
+
lastEvidenceAt: '2025-01-02T10:00:00+08:00',
|
|
131
|
+
config: {
|
|
132
|
+
maxInferredDurationMinutes: 60,
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
expect(result[0]).toMatchObject({
|
|
137
|
+
endAtResolved: '2025-01-01T09:00:00.000+08:00',
|
|
138
|
+
endAtSource: 'inferred',
|
|
139
|
+
endAtReason: 'evidence_timeout',
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
test('does not close period when inferred end is later than asOf', () => {
|
|
143
|
+
const result = resolvePeriods({
|
|
144
|
+
periods: [
|
|
145
|
+
{
|
|
146
|
+
kind: 'fixed',
|
|
147
|
+
startAt: '2025-01-01T08:00:00+08:00',
|
|
148
|
+
endAt: null,
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
asOf: '2025-01-01T10:00:00+08:00',
|
|
152
|
+
mode: {
|
|
153
|
+
kind: 'operational',
|
|
154
|
+
lastEvidenceAt: '2025-01-01T09:30:00+08:00',
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
expect(result[0]).toMatchObject({
|
|
158
|
+
endAtResolved: null,
|
|
159
|
+
endAtSource: 'none',
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
test('expands recurring periods into fixed periods in canonical mode', () => {
|
|
163
|
+
const result = resolvePeriods({
|
|
164
|
+
periods: [
|
|
165
|
+
{
|
|
166
|
+
kind: 'recurring',
|
|
167
|
+
frequency: 'daily',
|
|
168
|
+
startAt: '2025-01-01T00:00:00+08:00',
|
|
169
|
+
endAt: '2025-01-03T23:59:59+08:00',
|
|
170
|
+
daysOfWeek: null,
|
|
171
|
+
timeWindow: {
|
|
172
|
+
startAt: '08:00:00',
|
|
173
|
+
endAt: '10:00:00',
|
|
174
|
+
},
|
|
175
|
+
timeZone: 'Asia/Singapore',
|
|
176
|
+
excludedDates: null,
|
|
177
|
+
},
|
|
178
|
+
],
|
|
179
|
+
asOf,
|
|
180
|
+
mode: { kind: 'canonical' },
|
|
181
|
+
});
|
|
182
|
+
expect(result).toEqual([
|
|
183
|
+
{
|
|
184
|
+
kind: 'fixed',
|
|
185
|
+
startAt: '2025-01-01T08:00:00.000+08:00',
|
|
186
|
+
endAt: '2025-01-01T10:00:00.000+08:00',
|
|
187
|
+
endAtResolved: '2025-01-01T10:00:00.000+08:00',
|
|
188
|
+
endAtSource: 'fact',
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
kind: 'fixed',
|
|
192
|
+
startAt: '2025-01-02T08:00:00.000+08:00',
|
|
193
|
+
endAt: '2025-01-02T10:00:00.000+08:00',
|
|
194
|
+
endAtResolved: '2025-01-02T10:00:00.000+08:00',
|
|
195
|
+
endAtSource: 'fact',
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
kind: 'fixed',
|
|
199
|
+
startAt: '2025-01-03T08:00:00.000+08:00',
|
|
200
|
+
endAt: '2025-01-03T10:00:00.000+08:00',
|
|
201
|
+
endAtResolved: '2025-01-03T10:00:00.000+08:00',
|
|
202
|
+
endAtSource: 'fact',
|
|
203
|
+
},
|
|
204
|
+
]);
|
|
205
|
+
});
|
|
206
|
+
test('sorts normalized recurring periods together with fixed periods', () => {
|
|
207
|
+
const result = resolvePeriods({
|
|
208
|
+
periods: [
|
|
209
|
+
{
|
|
210
|
+
kind: 'fixed',
|
|
211
|
+
startAt: '2025-01-01T07:00:00+08:00',
|
|
212
|
+
endAt: '2025-01-01T07:30:00+08:00',
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
kind: 'recurring',
|
|
216
|
+
frequency: 'daily',
|
|
217
|
+
startAt: '2025-01-01T00:00:00+08:00',
|
|
218
|
+
endAt: '2025-01-02T23:59:59+08:00',
|
|
219
|
+
daysOfWeek: null,
|
|
220
|
+
timeWindow: {
|
|
221
|
+
startAt: '08:00:00',
|
|
222
|
+
endAt: '09:00:00',
|
|
223
|
+
},
|
|
224
|
+
timeZone: 'Asia/Singapore',
|
|
225
|
+
excludedDates: null,
|
|
226
|
+
},
|
|
227
|
+
],
|
|
228
|
+
asOf,
|
|
229
|
+
mode: { kind: 'operational' },
|
|
230
|
+
});
|
|
231
|
+
expect(result.map((period) => period.startAt)).toEqual([
|
|
232
|
+
'2025-01-01T07:00:00+08:00',
|
|
233
|
+
'2025-01-01T08:00:00.000+08:00',
|
|
234
|
+
'2025-01-02T08:00:00.000+08:00',
|
|
235
|
+
]);
|
|
236
|
+
expect(result.every((period) => period.endAtSource === 'fact')).toBe(true);
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
//# sourceMappingURL=resolvePeriods.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolvePeriods.test.js","sourceRoot":"/","sources":["helpers/resolvePeriods.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, test } from 'vitest';\nimport type { Period } from '#schema/issue/period.js';\nimport { resolvePeriods } from './resolvePeriods.js';\n\ndescribe('resolvePeriods', () => {\n const asOf = '2025-01-01T12:00:00+08:00';\n const factEndedPeriod: Period[] = [\n {\n kind: 'fixed',\n startAt: '2025-01-01T08:00:00+08:00',\n endAt: '2025-01-01T09:00:00+08:00',\n },\n ];\n\n test('keeps fact-ended period in all modes', () => {\n const canonical = resolvePeriods({\n periods: factEndedPeriod,\n asOf,\n mode: { kind: 'canonical' },\n });\n const operational = resolvePeriods({\n periods: factEndedPeriod,\n asOf,\n mode: { kind: 'operational' },\n });\n\n expect(canonical[0]).toMatchObject({\n startAt: '2025-01-01T08:00:00+08:00',\n endAt: '2025-01-01T09:00:00+08:00',\n endAtResolved: '2025-01-01T09:00:00+08:00',\n endAtSource: 'fact',\n });\n expect(operational[0].endAtSource).toBe('fact');\n });\n\n test('open period with no evidence and no crowd remains open', () => {\n const result = resolvePeriods({\n periods: [\n {\n kind: 'fixed',\n startAt: '2025-01-01T08:00:00+08:00',\n endAt: null,\n },\n ],\n asOf,\n mode: { kind: 'operational' },\n });\n\n expect(result[0]).toMatchObject({\n endAt: null,\n endAtResolved: null,\n endAtSource: 'none',\n });\n });\n\n test('open period infers end from evidence timeout only', () => {\n const result = resolvePeriods({\n periods: [\n {\n kind: 'fixed',\n startAt: '2025-01-01T08:00:00+08:00',\n endAt: null,\n },\n ],\n asOf: '2025-01-02T01:00:00+08:00', // Past inferred end-of-day (2025-01-02T00:00)\n mode: {\n kind: 'operational',\n lastEvidenceAt: '2025-01-01T09:00:00+08:00',\n },\n });\n\n expect(result[0]).toMatchObject({\n endAtResolved: '2025-01-02T00:00:00.000+08:00',\n endAtSource: 'inferred',\n endAtReason: 'evidence_timeout',\n });\n });\n\n test('crowd exited inference wins over evidence timeout', () => {\n const result = resolvePeriods({\n periods: [\n {\n kind: 'fixed',\n startAt: '2025-01-01T08:00:00+08:00',\n endAt: null,\n },\n ],\n asOf: '2025-01-02T01:00:00+08:00', // Past inferred end-of-day (2025-01-02T00:00)\n mode: {\n kind: 'operational',\n lastEvidenceAt: '2025-01-01T09:00:00+08:00',\n crowd: {\n activeNow: false,\n exitedAt: '2025-01-01T10:15:00+08:00',\n },\n },\n });\n\n expect(result[0]).toMatchObject({\n endAtResolved: '2025-01-02T00:00:00.000+08:00',\n endAtSource: 'inferred',\n endAtReason: 'crowd_decay',\n });\n });\n\n test('crowd.activeNow=true prevents crowd-based inference fallback', () => {\n const result = resolvePeriods({\n periods: [\n {\n kind: 'fixed',\n startAt: '2025-01-01T08:00:00+08:00',\n endAt: null,\n },\n ],\n asOf,\n mode: {\n kind: 'operational',\n crowd: {\n activeNow: true,\n lastActiveAt: '2025-01-01T09:30:00+08:00',\n },\n },\n });\n\n expect(result[0]).toMatchObject({\n endAtResolved: null,\n endAtSource: 'none',\n });\n });\n\n test('clamps inferred end to maxInferredDurationMinutes', () => {\n const result = resolvePeriods({\n periods: [\n {\n kind: 'fixed',\n startAt: '2025-01-01T08:00:00+08:00',\n endAt: null,\n },\n ],\n asOf: '2025-01-02T13:00:00+08:00',\n mode: {\n kind: 'operational',\n lastEvidenceAt: '2025-01-02T10:00:00+08:00',\n config: {\n maxInferredDurationMinutes: 60,\n },\n },\n });\n\n expect(result[0]).toMatchObject({\n endAtResolved: '2025-01-01T09:00:00.000+08:00',\n endAtSource: 'inferred',\n endAtReason: 'evidence_timeout',\n });\n });\n\n test('does not close period when inferred end is later than asOf', () => {\n const result = resolvePeriods({\n periods: [\n {\n kind: 'fixed',\n startAt: '2025-01-01T08:00:00+08:00',\n endAt: null,\n },\n ],\n asOf: '2025-01-01T10:00:00+08:00',\n mode: {\n kind: 'operational',\n lastEvidenceAt: '2025-01-01T09:30:00+08:00',\n },\n });\n\n expect(result[0]).toMatchObject({\n endAtResolved: null,\n endAtSource: 'none',\n });\n });\n\n test('expands recurring periods into fixed periods in canonical mode', () => {\n const result = resolvePeriods({\n periods: [\n {\n kind: 'recurring',\n frequency: 'daily',\n startAt: '2025-01-01T00:00:00+08:00',\n endAt: '2025-01-03T23:59:59+08:00',\n daysOfWeek: null,\n timeWindow: {\n startAt: '08:00:00',\n endAt: '10:00:00',\n },\n timeZone: 'Asia/Singapore',\n excludedDates: null,\n },\n ],\n asOf,\n mode: { kind: 'canonical' },\n });\n\n expect(result).toEqual([\n {\n kind: 'fixed',\n startAt: '2025-01-01T08:00:00.000+08:00',\n endAt: '2025-01-01T10:00:00.000+08:00',\n endAtResolved: '2025-01-01T10:00:00.000+08:00',\n endAtSource: 'fact',\n },\n {\n kind: 'fixed',\n startAt: '2025-01-02T08:00:00.000+08:00',\n endAt: '2025-01-02T10:00:00.000+08:00',\n endAtResolved: '2025-01-02T10:00:00.000+08:00',\n endAtSource: 'fact',\n },\n {\n kind: 'fixed',\n startAt: '2025-01-03T08:00:00.000+08:00',\n endAt: '2025-01-03T10:00:00.000+08:00',\n endAtResolved: '2025-01-03T10:00:00.000+08:00',\n endAtSource: 'fact',\n },\n ]);\n });\n\n test('sorts normalized recurring periods together with fixed periods', () => {\n const result = resolvePeriods({\n periods: [\n {\n kind: 'fixed',\n startAt: '2025-01-01T07:00:00+08:00',\n endAt: '2025-01-01T07:30:00+08:00',\n },\n {\n kind: 'recurring',\n frequency: 'daily',\n startAt: '2025-01-01T00:00:00+08:00',\n endAt: '2025-01-02T23:59:59+08:00',\n daysOfWeek: null,\n timeWindow: {\n startAt: '08:00:00',\n endAt: '09:00:00',\n },\n timeZone: 'Asia/Singapore',\n excludedDates: null,\n },\n ],\n asOf,\n mode: { kind: 'operational' },\n });\n\n expect(result.map((period) => period.startAt)).toEqual([\n '2025-01-01T07:00:00+08:00',\n '2025-01-01T08:00:00.000+08:00',\n '2025-01-02T08:00:00.000+08:00',\n ]);\n expect(result.every((period) => period.endAtSource === 'fact')).toBe(true);\n });\n});\n"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { DateTime } from 'luxon';
|
|
2
|
+
import { computeStartOfDaysWithinInterval } from './computeStartOfDaysWithinInterval.js';
|
|
3
|
+
import { assert } from '../util/assert.js';
|
|
4
|
+
export function splitIntervalByServiceHours(interval) {
|
|
5
|
+
assert(interval.start != null);
|
|
6
|
+
assert(interval.end != null);
|
|
7
|
+
const startOfDaysWithinRange = computeStartOfDaysWithinInterval(interval.start, interval.end);
|
|
8
|
+
const segments = [];
|
|
9
|
+
for (const segment of interval.splitAt(...startOfDaysWithinRange)) {
|
|
10
|
+
const { start, end } = segment;
|
|
11
|
+
assert(start != null);
|
|
12
|
+
assert(end != null);
|
|
13
|
+
const segmentStart = DateTime.max(start, start.set({ hour: 5, minute: 30, second: 0, millisecond: 0 }));
|
|
14
|
+
const segmentEnd = DateTime.max(end, segmentStart);
|
|
15
|
+
const segmentDuration = segmentEnd.diff(segmentStart);
|
|
16
|
+
if (segmentDuration.as('milliseconds') <= 0) {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
const segmentUpdated = segment.set({
|
|
20
|
+
start: segmentStart,
|
|
21
|
+
end: segmentEnd,
|
|
22
|
+
});
|
|
23
|
+
if (!segmentUpdated.isValid) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
segments.push(segmentUpdated);
|
|
27
|
+
}
|
|
28
|
+
return segments;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=splitIntervalByServiceHours.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"splitIntervalByServiceHours.js","sourceRoot":"/","sources":["helpers/splitIntervalByServiceHours.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAiB,MAAM,OAAO,CAAC;AAChD,OAAO,EAAE,gCAAgC,EAAE,MAAM,uCAAuC,CAAC;AACzF,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,UAAU,2BAA2B,CAAC,QAAkB;IAC5D,MAAM,CAAC,QAAQ,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;IAC/B,MAAM,CAAC,QAAQ,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;IAE7B,MAAM,sBAAsB,GAAG,gCAAgC,CAC7D,QAAQ,CAAC,KAAK,EACd,QAAQ,CAAC,GAAG,CACb,CAAC;IAEF,MAAM,QAAQ,GAAe,EAAE,CAAC;IAEhC,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC,GAAG,sBAAsB,CAAC,EAAE,CAAC;QAClE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;QAC/B,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;QACtB,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;QAEpB,MAAM,YAAY,GAAG,QAAQ,CAAC,GAAG,CAC/B,KAAK,EACL,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,CAC9D,CAAC;QACF,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QACnD,MAAM,eAAe,GAAG,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAEtD,IAAI,eAAe,CAAC,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5C,SAAS;QACX,CAAC;QAED,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC;YACjC,KAAK,EAAE,YAAY;YACnB,GAAG,EAAE,UAAU;SAChB,CAAC,CAAC;QAEH,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC;YAC5B,SAAS;QACX,CAAC;QAED,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC","sourcesContent":["import { DateTime, type Interval } from 'luxon';\nimport { computeStartOfDaysWithinInterval } from './computeStartOfDaysWithinInterval.js';\nimport { assert } from '../util/assert.js';\n\nexport function splitIntervalByServiceHours(interval: Interval): Interval[] {\n assert(interval.start != null);\n assert(interval.end != null);\n\n const startOfDaysWithinRange = computeStartOfDaysWithinInterval(\n interval.start,\n interval.end,\n );\n\n const segments: Interval[] = [];\n\n for (const segment of interval.splitAt(...startOfDaysWithinRange)) {\n const { start, end } = segment;\n assert(start != null);\n assert(end != null);\n\n const segmentStart = DateTime.max(\n start,\n start.set({ hour: 5, minute: 30, second: 0, millisecond: 0 }), // Limit to start of general service hours\n );\n const segmentEnd = DateTime.max(end, segmentStart);\n const segmentDuration = segmentEnd.diff(segmentStart);\n\n if (segmentDuration.as('milliseconds') <= 0) {\n continue;\n }\n\n const segmentUpdated = segment.set({\n start: segmentStart,\n end: segmentEnd,\n });\n\n if (!segmentUpdated.isValid) {\n continue;\n }\n\n segments.push(segmentUpdated);\n }\n\n return segments;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import { DateTime, Interval } from 'luxon';
|
|
3
|
+
import { splitIntervalByServiceHours } from './splitIntervalByServiceHours.js';
|
|
4
|
+
describe('splitIntervalByServiceHours', () => {
|
|
5
|
+
test('single day, within service hours', () => {
|
|
6
|
+
expect(splitIntervalByServiceHours(Interval.fromDateTimes(DateTime.fromObject({
|
|
7
|
+
day: 1,
|
|
8
|
+
month: 4,
|
|
9
|
+
year: 2025,
|
|
10
|
+
hour: 8,
|
|
11
|
+
minute: 0,
|
|
12
|
+
}), DateTime.fromObject({
|
|
13
|
+
day: 1,
|
|
14
|
+
month: 4,
|
|
15
|
+
year: 2025,
|
|
16
|
+
hour: 12,
|
|
17
|
+
minute: 30,
|
|
18
|
+
})))).toEqual([
|
|
19
|
+
Interval.fromDateTimes(DateTime.fromObject({
|
|
20
|
+
day: 1,
|
|
21
|
+
month: 4,
|
|
22
|
+
year: 2025,
|
|
23
|
+
hour: 8,
|
|
24
|
+
minute: 0,
|
|
25
|
+
}), DateTime.fromObject({
|
|
26
|
+
day: 1,
|
|
27
|
+
month: 4,
|
|
28
|
+
year: 2025,
|
|
29
|
+
hour: 12,
|
|
30
|
+
minute: 30,
|
|
31
|
+
})),
|
|
32
|
+
]);
|
|
33
|
+
});
|
|
34
|
+
describe('transcends service hour boundaries', () => {
|
|
35
|
+
test('single day, starts before service hours', () => {
|
|
36
|
+
expect(splitIntervalByServiceHours(Interval.fromDateTimes(DateTime.fromObject({
|
|
37
|
+
day: 1,
|
|
38
|
+
month: 4,
|
|
39
|
+
year: 2025,
|
|
40
|
+
hour: 5,
|
|
41
|
+
minute: 0,
|
|
42
|
+
}), DateTime.fromObject({
|
|
43
|
+
day: 1,
|
|
44
|
+
month: 4,
|
|
45
|
+
year: 2025,
|
|
46
|
+
hour: 6,
|
|
47
|
+
minute: 0,
|
|
48
|
+
})))).toEqual([
|
|
49
|
+
Interval.fromDateTimes(DateTime.fromObject({
|
|
50
|
+
day: 1,
|
|
51
|
+
month: 4,
|
|
52
|
+
year: 2025,
|
|
53
|
+
hour: 5,
|
|
54
|
+
minute: 30,
|
|
55
|
+
}), DateTime.fromObject({
|
|
56
|
+
day: 1,
|
|
57
|
+
month: 4,
|
|
58
|
+
year: 2025,
|
|
59
|
+
hour: 6,
|
|
60
|
+
minute: 0,
|
|
61
|
+
})),
|
|
62
|
+
]);
|
|
63
|
+
});
|
|
64
|
+
test('single day, ends after service hours', () => {
|
|
65
|
+
expect(splitIntervalByServiceHours(Interval.fromDateTimes(DateTime.fromObject({
|
|
66
|
+
day: 1,
|
|
67
|
+
month: 4,
|
|
68
|
+
year: 2025,
|
|
69
|
+
hour: 18,
|
|
70
|
+
minute: 0,
|
|
71
|
+
}), DateTime.fromObject({
|
|
72
|
+
day: 2,
|
|
73
|
+
month: 4,
|
|
74
|
+
year: 2025,
|
|
75
|
+
hour: 1,
|
|
76
|
+
minute: 0,
|
|
77
|
+
})))).toEqual([
|
|
78
|
+
Interval.fromDateTimes(DateTime.fromObject({
|
|
79
|
+
day: 1,
|
|
80
|
+
month: 4,
|
|
81
|
+
year: 2025,
|
|
82
|
+
hour: 18,
|
|
83
|
+
minute: 0,
|
|
84
|
+
}), DateTime.fromObject({
|
|
85
|
+
day: 2,
|
|
86
|
+
month: 4,
|
|
87
|
+
year: 2025,
|
|
88
|
+
hour: 0,
|
|
89
|
+
minute: 0,
|
|
90
|
+
})),
|
|
91
|
+
]);
|
|
92
|
+
});
|
|
93
|
+
test('multiple days, transcends multiple service hours/non services hour ranges', () => {
|
|
94
|
+
expect(splitIntervalByServiceHours(Interval.fromDateTimes(DateTime.fromObject({
|
|
95
|
+
day: 1,
|
|
96
|
+
month: 4,
|
|
97
|
+
year: 2025,
|
|
98
|
+
hour: 18,
|
|
99
|
+
minute: 0,
|
|
100
|
+
}), DateTime.fromObject({
|
|
101
|
+
day: 2,
|
|
102
|
+
month: 4,
|
|
103
|
+
year: 2025,
|
|
104
|
+
hour: 18,
|
|
105
|
+
minute: 0,
|
|
106
|
+
})))).toEqual([
|
|
107
|
+
Interval.fromDateTimes(DateTime.fromObject({
|
|
108
|
+
day: 1,
|
|
109
|
+
month: 4,
|
|
110
|
+
year: 2025,
|
|
111
|
+
hour: 18,
|
|
112
|
+
minute: 0,
|
|
113
|
+
}), DateTime.fromObject({
|
|
114
|
+
day: 2,
|
|
115
|
+
month: 4,
|
|
116
|
+
year: 2025,
|
|
117
|
+
hour: 0,
|
|
118
|
+
minute: 0,
|
|
119
|
+
})),
|
|
120
|
+
Interval.fromDateTimes(DateTime.fromObject({
|
|
121
|
+
day: 2,
|
|
122
|
+
month: 4,
|
|
123
|
+
year: 2025,
|
|
124
|
+
hour: 5,
|
|
125
|
+
minute: 30,
|
|
126
|
+
}), DateTime.fromObject({
|
|
127
|
+
day: 2,
|
|
128
|
+
month: 4,
|
|
129
|
+
year: 2025,
|
|
130
|
+
hour: 18,
|
|
131
|
+
minute: 0,
|
|
132
|
+
})),
|
|
133
|
+
]);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
test('outside service hours', () => {
|
|
137
|
+
expect(splitIntervalByServiceHours(Interval.fromDateTimes(DateTime.fromObject({
|
|
138
|
+
day: 1,
|
|
139
|
+
month: 4,
|
|
140
|
+
year: 2025,
|
|
141
|
+
hour: 3,
|
|
142
|
+
minute: 0,
|
|
143
|
+
}), DateTime.fromObject({
|
|
144
|
+
day: 1,
|
|
145
|
+
month: 4,
|
|
146
|
+
year: 2025,
|
|
147
|
+
hour: 4,
|
|
148
|
+
minute: 30,
|
|
149
|
+
})))).toEqual([]);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
//# sourceMappingURL=splitIntervalByServiceHours.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"splitIntervalByServiceHours.test.js","sourceRoot":"/","sources":["helpers/splitIntervalByServiceHours.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, test } from 'vitest';\nimport { DateTime, Interval } from 'luxon';\nimport { splitIntervalByServiceHours } from './splitIntervalByServiceHours.js';\n\ndescribe('splitIntervalByServiceHours', () => {\n test('single day, within service hours', () => {\n expect(\n splitIntervalByServiceHours(\n Interval.fromDateTimes(\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 8,\n minute: 0,\n }),\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 12,\n minute: 30,\n }),\n ),\n ),\n ).toEqual([\n Interval.fromDateTimes(\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 8,\n minute: 0,\n }),\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 12,\n minute: 30,\n }),\n ),\n ] satisfies Interval[]);\n });\n describe('transcends service hour boundaries', () => {\n test('single day, starts before service hours', () => {\n expect(\n splitIntervalByServiceHours(\n Interval.fromDateTimes(\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 5,\n minute: 0,\n }),\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 6,\n minute: 0,\n }),\n ),\n ),\n ).toEqual([\n Interval.fromDateTimes(\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 5,\n minute: 30,\n }),\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 6,\n minute: 0,\n }),\n ),\n ] satisfies Interval[]);\n });\n test('single day, ends after service hours', () => {\n expect(\n splitIntervalByServiceHours(\n Interval.fromDateTimes(\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 18,\n minute: 0,\n }),\n DateTime.fromObject({\n day: 2,\n month: 4,\n year: 2025,\n hour: 1,\n minute: 0,\n }),\n ),\n ),\n ).toEqual([\n Interval.fromDateTimes(\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 18,\n minute: 0,\n }),\n DateTime.fromObject({\n day: 2,\n month: 4,\n year: 2025,\n hour: 0,\n minute: 0,\n }),\n ),\n ] satisfies Interval[]);\n });\n test('multiple days, transcends multiple service hours/non services hour ranges', () => {\n expect(\n splitIntervalByServiceHours(\n Interval.fromDateTimes(\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 18,\n minute: 0,\n }),\n DateTime.fromObject({\n day: 2,\n month: 4,\n year: 2025,\n hour: 18,\n minute: 0,\n }),\n ),\n ),\n ).toEqual([\n Interval.fromDateTimes(\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 18,\n minute: 0,\n }),\n DateTime.fromObject({\n day: 2,\n month: 4,\n year: 2025,\n hour: 0,\n minute: 0,\n }),\n ),\n Interval.fromDateTimes(\n DateTime.fromObject({\n day: 2,\n month: 4,\n year: 2025,\n hour: 5,\n minute: 30,\n }),\n DateTime.fromObject({\n day: 2,\n month: 4,\n year: 2025,\n hour: 18,\n minute: 0,\n }),\n ),\n ] satisfies Interval[]);\n });\n });\n test('outside service hours', () => {\n expect(\n splitIntervalByServiceHours(\n Interval.fromDateTimes(\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 3,\n minute: 0,\n }),\n DateTime.fromObject({\n day: 1,\n month: 4,\n year: 2025,\n hour: 4,\n minute: 30,\n }),\n ),\n ),\n ).toEqual([] satisfies Interval[]);\n });\n});\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Duration } from 'luxon';
|
|
2
|
+
export function sumIntervalDuration(intervals) {
|
|
3
|
+
let duration = Duration.fromObject({ milliseconds: 0 });
|
|
4
|
+
for (const segment of intervals) {
|
|
5
|
+
duration = duration.plus(segment.toDuration());
|
|
6
|
+
}
|
|
7
|
+
return duration;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=sumIntervalDuration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sumIntervalDuration.js","sourceRoot":"/","sources":["helpers/sumIntervalDuration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAiB,MAAM,OAAO,CAAC;AAEhD,MAAM,UAAU,mBAAmB,CAAC,SAAqB;IACvD,IAAI,QAAQ,GAAG,QAAQ,CAAC,UAAU,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC;IACxD,KAAK,MAAM,OAAO,IAAI,SAAS,EAAE,CAAC;QAChC,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC","sourcesContent":["import { Duration, type Interval } from 'luxon';\n\nexport function sumIntervalDuration(intervals: Interval[]) {\n let duration = Duration.fromObject({ milliseconds: 0 });\n for (const segment of intervals) {\n duration = duration.plus(segment.toDuration());\n }\n return duration;\n}\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { FileStore } from '#repo/common/FileStore.js';
|
|
2
|
+
export { MRTDownRepository } from '#repo/MRTDownRepository.js';
|
|
3
|
+
export { type IssueBundle, IssueBundleSchema, } from '#schema/issue/bundle.js';
|
|
4
|
+
export { type CauseDisruption, CauseDisruptionSchema, type CauseInfra, CauseInfraSchema, type CauseMaintenance, CauseMaintenanceSchema, type CauseSubtype, CauseSubtypeSchema, } from '#schema/issue/cause.js';
|
|
5
|
+
export { type AffectedEntity, type AffectedEntityFacility, AffectedEntityFacilitySchema, AffectedEntitySchema, type AffectedEntityService, AffectedEntityServiceSchema, type EntityImpactState, EntityImpactStateSchema, } from '#schema/issue/entity.js';
|
|
6
|
+
export { type Evidence, EvidenceSchema, } from '#schema/issue/evidence.js';
|
|
7
|
+
export { type FacilityEffect, FacilityEffectSchema, } from '#schema/issue/facilityEffect.js';
|
|
8
|
+
export { type ImpactEvent, ImpactEventSchema, } from '#schema/issue/impactEvent.js';
|
|
9
|
+
export { type Issue, IssueSchema } from '#schema/issue/issue.js';
|
|
10
|
+
export { type IssueType, IssueTypeSchema, } from '#schema/issue/issueType.js';
|
|
11
|
+
export { type Period, PeriodSchema, } from '#schema/issue/period.js';
|
|
12
|
+
export { type ServiceEffect, ServiceEffectSchema, } from '#schema/issue/serviceEffect.js';
|
|
13
|
+
export { type ServiceScope, ServiceScopeSchema, } from '#schema/issue/serviceScope.js';
|
|
14
|
+
export { FileWriteStore } from '#write/common/FileWriteStore.js';
|
|
15
|
+
export { IdGenerator } from '#write/id/IdGenerator.js';
|
|
16
|
+
export { MRTDownWriter } from '#write/MRTDownWriter.js';
|
|
17
|
+
export { normalizeRecurringPeriod } from './helpers/normalizeRecurringPeriod.js';
|
|
18
|
+
export { resolvePeriods } from './helpers/resolvePeriods.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export { FileStore } from '#repo/common/FileStore.js';
|
|
2
|
+
export { MRTDownRepository } from '#repo/MRTDownRepository.js';
|
|
3
|
+
export { IssueBundleSchema, } from '#schema/issue/bundle.js';
|
|
4
|
+
export { CauseDisruptionSchema, CauseInfraSchema, CauseMaintenanceSchema, CauseSubtypeSchema, } from '#schema/issue/cause.js';
|
|
5
|
+
export { AffectedEntityFacilitySchema, AffectedEntitySchema, AffectedEntityServiceSchema, EntityImpactStateSchema, } from '#schema/issue/entity.js';
|
|
6
|
+
export { EvidenceSchema, } from '#schema/issue/evidence.js';
|
|
7
|
+
export { FacilityEffectSchema, } from '#schema/issue/facilityEffect.js';
|
|
8
|
+
export { ImpactEventSchema, } from '#schema/issue/impactEvent.js';
|
|
9
|
+
export { IssueSchema } from '#schema/issue/issue.js';
|
|
10
|
+
export { IssueTypeSchema, } from '#schema/issue/issueType.js';
|
|
11
|
+
export { PeriodSchema, } from '#schema/issue/period.js';
|
|
12
|
+
export { ServiceEffectSchema, } from '#schema/issue/serviceEffect.js';
|
|
13
|
+
export { ServiceScopeSchema, } from '#schema/issue/serviceScope.js';
|
|
14
|
+
export { FileWriteStore } from '#write/common/FileWriteStore.js';
|
|
15
|
+
export { IdGenerator } from '#write/id/IdGenerator.js';
|
|
16
|
+
export { MRTDownWriter } from '#write/MRTDownWriter.js';
|
|
17
|
+
export { normalizeRecurringPeriod } from './helpers/normalizeRecurringPeriod.js';
|
|
18
|
+
export { resolvePeriods } from './helpers/resolvePeriods.js';
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"/","sources":["index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAEL,iBAAiB,GAClB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAEL,qBAAqB,EAErB,gBAAgB,EAEhB,sBAAsB,EAEtB,kBAAkB,GACnB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAGL,4BAA4B,EAC5B,oBAAoB,EAEpB,2BAA2B,EAE3B,uBAAuB,GACxB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAEL,cAAc,GACf,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAEL,oBAAoB,GACrB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAEL,iBAAiB,GAClB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAc,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAEL,eAAe,GAChB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAEL,YAAY,GACb,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAEL,mBAAmB,GACpB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAEL,kBAAkB,GACnB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,wBAAwB,EAAE,MAAM,uCAAuC,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC","sourcesContent":["export { FileStore } from '#repo/common/FileStore.js';\nexport { MRTDownRepository } from '#repo/MRTDownRepository.js';\nexport {\n type IssueBundle,\n IssueBundleSchema,\n} from '#schema/issue/bundle.js';\nexport {\n type CauseDisruption,\n CauseDisruptionSchema,\n type CauseInfra,\n CauseInfraSchema,\n type CauseMaintenance,\n CauseMaintenanceSchema,\n type CauseSubtype,\n CauseSubtypeSchema,\n} from '#schema/issue/cause.js';\nexport {\n type AffectedEntity,\n type AffectedEntityFacility,\n AffectedEntityFacilitySchema,\n AffectedEntitySchema,\n type AffectedEntityService,\n AffectedEntityServiceSchema,\n type EntityImpactState,\n EntityImpactStateSchema,\n} from '#schema/issue/entity.js';\nexport {\n type Evidence,\n EvidenceSchema,\n} from '#schema/issue/evidence.js';\nexport {\n type FacilityEffect,\n FacilityEffectSchema,\n} from '#schema/issue/facilityEffect.js';\nexport {\n type ImpactEvent,\n ImpactEventSchema,\n} from '#schema/issue/impactEvent.js';\nexport { type Issue, IssueSchema } from '#schema/issue/issue.js';\nexport {\n type IssueType,\n IssueTypeSchema,\n} from '#schema/issue/issueType.js';\nexport {\n type Period,\n PeriodSchema,\n} from '#schema/issue/period.js';\nexport {\n type ServiceEffect,\n ServiceEffectSchema,\n} from '#schema/issue/serviceEffect.js';\nexport {\n type ServiceScope,\n ServiceScopeSchema,\n} from '#schema/issue/serviceScope.js';\nexport { FileWriteStore } from '#write/common/FileWriteStore.js';\nexport { IdGenerator } from '#write/id/IdGenerator.js';\nexport { MRTDownWriter } from '#write/MRTDownWriter.js';\nexport { normalizeRecurringPeriod } from './helpers/normalizeRecurringPeriod.js';\nexport { resolvePeriods } from './helpers/resolvePeriods.js';\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { IStore } from './common/store.js';
|
|
2
|
+
import { IssueRepository } from './issue/IssueRepository.js';
|
|
3
|
+
import { LandmarkRepository } from './landmark/LandmarkRepository.js';
|
|
4
|
+
import { LineRepository } from './line/LineRepository.js';
|
|
5
|
+
import { OperatorRepository } from './operator/OperatorRepository.js';
|
|
6
|
+
import { ServiceRepository } from './service/ServiceRepository.js';
|
|
7
|
+
import { StationRepository } from './station/StationRepository.js';
|
|
8
|
+
import { TownRepository } from './town/TownRepository.js';
|
|
9
|
+
interface MRTDownRepositoryOptions {
|
|
10
|
+
store: IStore;
|
|
11
|
+
}
|
|
12
|
+
export declare class MRTDownRepository {
|
|
13
|
+
private readonly store;
|
|
14
|
+
readonly stations: StationRepository;
|
|
15
|
+
readonly towns: TownRepository;
|
|
16
|
+
readonly landmarks: LandmarkRepository;
|
|
17
|
+
readonly lines: LineRepository;
|
|
18
|
+
readonly operators: OperatorRepository;
|
|
19
|
+
readonly services: ServiceRepository;
|
|
20
|
+
readonly issues: IssueRepository;
|
|
21
|
+
constructor(options: MRTDownRepositoryOptions);
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { IssueRepository } from './issue/IssueRepository.js';
|
|
2
|
+
import { LandmarkRepository } from './landmark/LandmarkRepository.js';
|
|
3
|
+
import { LineRepository } from './line/LineRepository.js';
|
|
4
|
+
import { OperatorRepository } from './operator/OperatorRepository.js';
|
|
5
|
+
import { ServiceRepository } from './service/ServiceRepository.js';
|
|
6
|
+
import { StationRepository } from './station/StationRepository.js';
|
|
7
|
+
import { TownRepository } from './town/TownRepository.js';
|
|
8
|
+
export class MRTDownRepository {
|
|
9
|
+
store;
|
|
10
|
+
stations;
|
|
11
|
+
towns;
|
|
12
|
+
landmarks;
|
|
13
|
+
lines;
|
|
14
|
+
operators;
|
|
15
|
+
services;
|
|
16
|
+
issues;
|
|
17
|
+
constructor(options) {
|
|
18
|
+
this.store = options.store;
|
|
19
|
+
this.stations = new StationRepository(this.store);
|
|
20
|
+
this.towns = new TownRepository(this.store);
|
|
21
|
+
this.landmarks = new LandmarkRepository(this.store);
|
|
22
|
+
this.lines = new LineRepository(this.store);
|
|
23
|
+
this.operators = new OperatorRepository(this.store);
|
|
24
|
+
this.services = new ServiceRepository(this.store);
|
|
25
|
+
this.issues = new IssueRepository(this.store);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=MRTDownRepository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MRTDownRepository.js","sourceRoot":"/","sources":["repo/MRTDownRepository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAM1D,MAAM,OAAO,iBAAiB;IACX,KAAK,CAAS;IAEtB,QAAQ,CAAoB;IAC5B,KAAK,CAAiB;IACtB,SAAS,CAAqB;IAC9B,KAAK,CAAiB;IACtB,SAAS,CAAqB;IAC9B,QAAQ,CAAoB;IAC5B,MAAM,CAAkB;IAEjC,YAAY,OAAiC;QAC3C,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3B,IAAI,CAAC,QAAQ,GAAG,IAAI,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClD,IAAI,CAAC,KAAK,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5C,IAAI,CAAC,SAAS,GAAG,IAAI,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpD,IAAI,CAAC,KAAK,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5C,IAAI,CAAC,SAAS,GAAG,IAAI,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpD,IAAI,CAAC,QAAQ,GAAG,IAAI,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChD,CAAC;CACF","sourcesContent":["import type { IStore } from './common/store.js';\nimport { IssueRepository } from './issue/IssueRepository.js';\nimport { LandmarkRepository } from './landmark/LandmarkRepository.js';\nimport { LineRepository } from './line/LineRepository.js';\nimport { OperatorRepository } from './operator/OperatorRepository.js';\nimport { ServiceRepository } from './service/ServiceRepository.js';\nimport { StationRepository } from './station/StationRepository.js';\nimport { TownRepository } from './town/TownRepository.js';\n\ninterface MRTDownRepositoryOptions {\n store: IStore;\n}\n\nexport class MRTDownRepository {\n private readonly store: IStore;\n\n readonly stations: StationRepository;\n readonly towns: TownRepository;\n readonly landmarks: LandmarkRepository;\n readonly lines: LineRepository;\n readonly operators: OperatorRepository;\n readonly services: ServiceRepository;\n readonly issues: IssueRepository;\n\n constructor(options: MRTDownRepositoryOptions) {\n this.store = options.store;\n this.stations = new StationRepository(this.store);\n this.towns = new TownRepository(this.store);\n this.landmarks = new LandmarkRepository(this.store);\n this.lines = new LineRepository(this.store);\n this.operators = new OperatorRepository(this.store);\n this.services = new ServiceRepository(this.store);\n this.issues = new IssueRepository(this.store);\n }\n}\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IStore } from './store.js';
|
|
2
|
+
/**
|
|
3
|
+
* A store for reading and writing files.
|
|
4
|
+
*/
|
|
5
|
+
export declare class FileStore implements IStore {
|
|
6
|
+
private readonly rootDir;
|
|
7
|
+
constructor(rootDir: string);
|
|
8
|
+
readText(path: string): string;
|
|
9
|
+
readJson<T>(path: string): T;
|
|
10
|
+
listDir(path: string): string[];
|
|
11
|
+
exists(path: string): boolean;
|
|
12
|
+
}
|