@royalschedule/maps 4.0.8 → 4.0.10
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/dist/PlanDigital/index.d.ts +21 -21
- package/dist/RS/to/input/collections.js +1 -1
- package/dist/RS/to/input/default.js +1 -1
- package/dist/RS/to/input/dynamic-locked-times.js +1 -1
- package/dist/RS/to/input/events.js +1 -1
- package/dist/RS/to/input/groups.js +1 -1
- package/dist/RS/to/input/intervals.js +28 -8
- package/dist/RS/to/input/intervals.js.map +1 -1
- package/dist/RS/to/input/teachers.js +1 -1
- package/dist/RS/to/input/util/parse-intervals.js +13 -17
- package/dist/RS/to/input/util/parse-intervals.js.map +1 -1
- package/dist/RS/to/input/util/util.js +0 -1
- package/dist/RS/to/input/util/util.js.map +1 -1
- package/package.json +1 -1
|
@@ -15,55 +15,55 @@ declare class PlanDigitalMap {
|
|
|
15
15
|
groups?: {
|
|
16
16
|
exceptions?: string[] | undefined;
|
|
17
17
|
lockedTimes?: string[] | undefined;
|
|
18
|
+
ids?: ID | undefined;
|
|
18
19
|
createdAt?: DateType | undefined;
|
|
19
20
|
updatedAt?: DateType | undefined;
|
|
20
21
|
lastModifiedBy?: unknown;
|
|
21
|
-
ids?: ID | undefined;
|
|
22
22
|
belongsTo?: string | undefined;
|
|
23
23
|
rank?: number | undefined;
|
|
24
|
-
days?: Day[] | undefined;
|
|
25
24
|
displayName?: string | undefined;
|
|
25
|
+
lunch?: string[] | undefined;
|
|
26
26
|
intervals?: AllowedInterval[] | undefined;
|
|
27
|
+
days?: Day[] | undefined;
|
|
27
28
|
minBreakLength?: BreakLength | undefined;
|
|
29
|
+
tags?: Tag[] | undefined;
|
|
28
30
|
maximumScheduleSpan?: MaximumScheduleSpan | undefined;
|
|
29
31
|
forbidOverlappingEvents?: boolean | undefined;
|
|
30
32
|
disableDayLengthPunishment?: boolean | undefined;
|
|
31
33
|
weight?: number | undefined;
|
|
34
|
+
rootInterval?: string | undefined;
|
|
35
|
+
maxNumWorkingHours?: number | boolean | undefined;
|
|
36
|
+
maxNumDailyWorkingHours?: number | number[] | boolean | undefined;
|
|
32
37
|
species?: "class" | undefined;
|
|
33
38
|
parentGroups?: string[] | undefined;
|
|
34
39
|
subGroups?: string[] | undefined;
|
|
35
|
-
lunch?: string[] | undefined;
|
|
36
40
|
members?: string[] | undefined;
|
|
37
|
-
rootInterval?: string | undefined;
|
|
38
|
-
tags?: Tag[] | undefined;
|
|
39
|
-
maxNumWorkingHours?: number | boolean | undefined;
|
|
40
|
-
maxNumDailyWorkingHours?: number | number[] | boolean | undefined;
|
|
41
41
|
}[];
|
|
42
42
|
teachers?: {
|
|
43
43
|
exceptions?: string[] | undefined;
|
|
44
44
|
lockedTimes?: string[] | undefined;
|
|
45
|
+
ids?: ID | undefined;
|
|
45
46
|
createdAt?: DateType | undefined;
|
|
46
47
|
updatedAt?: DateType | undefined;
|
|
47
48
|
lastModifiedBy?: unknown;
|
|
48
|
-
ids?: ID | undefined;
|
|
49
49
|
belongsTo?: string | undefined;
|
|
50
50
|
rank?: number | undefined;
|
|
51
|
-
days?: Day[] | undefined;
|
|
52
51
|
displayName?: string | undefined;
|
|
52
|
+
lunch?: string[] | undefined;
|
|
53
53
|
intervals?: AllowedInterval[] | undefined;
|
|
54
|
+
days?: Day[] | undefined;
|
|
54
55
|
minBreakLength?: BreakLength | undefined;
|
|
56
|
+
tags?: Tag[] | undefined;
|
|
57
|
+
plannedScheduledDuration?: PlannedScheduledDuration | undefined;
|
|
55
58
|
maximumScheduleSpan?: MaximumScheduleSpan | undefined;
|
|
56
59
|
forbidOverlappingEvents?: boolean | undefined;
|
|
57
60
|
disableDayLengthPunishment?: boolean | undefined;
|
|
58
61
|
weight?: number | undefined;
|
|
59
|
-
|
|
62
|
+
person?: string | undefined;
|
|
60
63
|
rootInterval?: string | undefined;
|
|
61
|
-
|
|
64
|
+
signature?: string | undefined;
|
|
62
65
|
maxNumWorkingHours?: number | boolean | undefined;
|
|
63
66
|
maxNumDailyWorkingHours?: number | number[] | boolean | undefined;
|
|
64
|
-
plannedScheduledDuration?: PlannedScheduledDuration | undefined;
|
|
65
|
-
person?: string | undefined;
|
|
66
|
-
signature?: string | undefined;
|
|
67
67
|
}[];
|
|
68
68
|
courses?: {
|
|
69
69
|
exceptions?: string[] | undefined;
|
|
@@ -72,26 +72,26 @@ declare class PlanDigitalMap {
|
|
|
72
72
|
locations?: AvailableLocation<string>[] | undefined;
|
|
73
73
|
events?: string[] | undefined;
|
|
74
74
|
lockedTimes?: string[] | undefined;
|
|
75
|
+
ids?: ID | undefined;
|
|
75
76
|
createdAt?: DateType | undefined;
|
|
76
77
|
updatedAt?: DateType | undefined;
|
|
77
78
|
lastModifiedBy?: unknown;
|
|
78
|
-
ids?: ID | undefined;
|
|
79
79
|
belongsTo?: string | undefined;
|
|
80
|
-
type?: string | undefined;
|
|
81
|
-
days?: Day[] | undefined;
|
|
82
|
-
weeks?: number[] | undefined;
|
|
83
80
|
displayName?: string | undefined;
|
|
84
|
-
period?: string | undefined;
|
|
85
81
|
intervals?: AllowedInterval[] | undefined;
|
|
82
|
+
days?: Day[] | undefined;
|
|
86
83
|
minBreakLength?: BreakLength | undefined;
|
|
87
|
-
weight?: number | undefined;
|
|
88
84
|
tags?: Tag[] | undefined;
|
|
89
|
-
|
|
85
|
+
weeks?: number[] | undefined;
|
|
86
|
+
weight?: number | undefined;
|
|
87
|
+
period?: string | undefined;
|
|
90
88
|
participants?: PersonReference<string>[] | undefined;
|
|
91
89
|
density?: number | undefined;
|
|
92
90
|
subject?: string | undefined;
|
|
91
|
+
color?: string | undefined;
|
|
93
92
|
eventDurationVariance?: number | undefined;
|
|
94
93
|
totalTime?: string | undefined;
|
|
94
|
+
type?: string | undefined;
|
|
95
95
|
comment?: string | undefined;
|
|
96
96
|
startDate?: DateType | undefined;
|
|
97
97
|
endDate?: DateType | undefined;
|
|
@@ -4,8 +4,8 @@ import { getPeriodIndex, idOf } from "./util/util.js";
|
|
|
4
4
|
import { attachLockedTimes } from "./util/attach-locked-times.js";
|
|
5
5
|
import { parseDays } from "./util/parse-days.js";
|
|
6
6
|
import { parseMinimumBreakLength } from "./util/parse-minimum-break-length.js";
|
|
7
|
-
import { parseIntervals } from "./util/parse-intervals.js";
|
|
8
7
|
import { getDefaultInterval } from "./intervals.js";
|
|
8
|
+
import { parseIntervals } from "./util/parse-intervals.js";
|
|
9
9
|
import { parseGroupReferences } from "./util/parse-group-references.js";
|
|
10
10
|
import { parseLocationReferences } from "./util/parse-location-references.js";
|
|
11
11
|
import { parseEvents } from "./events.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getPeriodIndex, min2hrs, toTimeFloat } from "./util/util.js";
|
|
2
|
-
import { parseIntervals } from "./util/parse-intervals.js";
|
|
3
2
|
import { computesDefaultIntervalId, getDefaultInterval } from "./intervals.js";
|
|
3
|
+
import { parseIntervals } from "./util/parse-intervals.js";
|
|
4
4
|
|
|
5
5
|
//#region src/RS/to/input/default.ts
|
|
6
6
|
function parseDefault(settings, periodsMap, options) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { getDayIndex, getVertexId } from "../../../core/util.js";
|
|
2
2
|
import { makeChainable } from "../../../common/make-chainable/index.js";
|
|
3
3
|
import { idOf } from "./util/util.js";
|
|
4
|
-
import { parseIntervals } from "./util/parse-intervals.js";
|
|
5
4
|
import { getDefaultInterval } from "./intervals.js";
|
|
5
|
+
import { parseIntervals } from "./util/parse-intervals.js";
|
|
6
6
|
import { parseGroupReferences } from "./util/parse-group-references.js";
|
|
7
7
|
import { toDayAndStart } from "./events.js";
|
|
8
8
|
import { groupBy, omitBy, uniq } from "lodash-es";
|
|
@@ -3,8 +3,8 @@ import { getPeriodIndex, idOf } from "./util/util.js";
|
|
|
3
3
|
import { attachLockedTimes } from "./util/attach-locked-times.js";
|
|
4
4
|
import { parseDays } from "./util/parse-days.js";
|
|
5
5
|
import { parseMinimumBreakLength } from "./util/parse-minimum-break-length.js";
|
|
6
|
-
import { parseIntervals } from "./util/parse-intervals.js";
|
|
7
6
|
import { getDefaultInterval } from "./intervals.js";
|
|
7
|
+
import { parseIntervals } from "./util/parse-intervals.js";
|
|
8
8
|
import { parseGroupReferences } from "./util/parse-group-references.js";
|
|
9
9
|
import { parseLocationReferences, parseSelectedLocations } from "./util/parse-location-references.js";
|
|
10
10
|
import { omitBy } from "lodash-es";
|
|
@@ -3,8 +3,8 @@ import { attachLockedTimes } from "./util/attach-locked-times.js";
|
|
|
3
3
|
import { parseDays } from "./util/parse-days.js";
|
|
4
4
|
import { parseMaxWorkingHours } from "./util/parse-max-working-hours.js";
|
|
5
5
|
import { parseMinimumBreakLength } from "./util/parse-minimum-break-length.js";
|
|
6
|
-
import { parseIntervals } from "./util/parse-intervals.js";
|
|
7
6
|
import { getDefaultInterval } from "./intervals.js";
|
|
7
|
+
import { parseIntervals } from "./util/parse-intervals.js";
|
|
8
8
|
import { omitBy } from "lodash-es";
|
|
9
9
|
|
|
10
10
|
//#region src/RS/to/input/groups.ts
|
|
@@ -6,13 +6,30 @@ import moment from "moment";
|
|
|
6
6
|
|
|
7
7
|
//#region src/RS/to/input/intervals.ts
|
|
8
8
|
/**
|
|
9
|
+
* Parses a date input into a moment object.
|
|
10
|
+
*
|
|
11
|
+
* Accepts an ISO date string, a string in 'HH:mm' format, or a DateType.
|
|
12
|
+
* - If the input is in 'HH:mm' format, it is parsed as a UTC time on the epoch date.
|
|
13
|
+
* - Otherwise, the input is parsed as a full UTC date.
|
|
14
|
+
*
|
|
15
|
+
* @param date - The date input to parse.
|
|
16
|
+
* @returns A moment object representing the parsed date and time.
|
|
17
|
+
*/
|
|
18
|
+
function parseIntervalDate(date) {
|
|
19
|
+
if (typeof date == "string") {
|
|
20
|
+
if (/^\d{1,2}:\d{2}$/.test(date)) return moment.utc(date, "HH:mm");
|
|
21
|
+
return moment.utc(date);
|
|
22
|
+
}
|
|
23
|
+
return moment.utc(date);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
9
26
|
* Removes the shorthand notation (a single day to represent all days)
|
|
10
27
|
*/
|
|
11
28
|
function standardizeIntervals(intervals, settings) {
|
|
12
29
|
if (intervals?.length == 1) {
|
|
13
30
|
const i = intervals[0];
|
|
14
|
-
const start =
|
|
15
|
-
const end =
|
|
31
|
+
const start = parseIntervalDate(i.start);
|
|
32
|
+
const end = parseIntervalDate(i.end);
|
|
16
33
|
return Array.from({ length: settings.numDays }, () => ({
|
|
17
34
|
start: start.clone(),
|
|
18
35
|
end: end.clone()
|
|
@@ -26,8 +43,8 @@ function standardizeIntervals(intervals, settings) {
|
|
|
26
43
|
function toFloatIntervals(intervals) {
|
|
27
44
|
return intervals?.map((i, day) => {
|
|
28
45
|
if (!i.start || !i.end) throw new Error(`(RS::To::convertIntervals) Interval missing start or end for day ${day}: ${JSON.stringify(i)}`);
|
|
29
|
-
const start = parseFloat(
|
|
30
|
-
const end = parseFloat(
|
|
46
|
+
const start = parseFloat(parseIntervalDate(i.start).format("HH.mm"));
|
|
47
|
+
const end = parseFloat(parseIntervalDate(i.end).format("HH.mm"));
|
|
31
48
|
return {
|
|
32
49
|
beg: start,
|
|
33
50
|
end
|
|
@@ -45,11 +62,14 @@ function combineAndMapIntervals(_intervals, rootInterval, settings) {
|
|
|
45
62
|
const limits = intervals.at(parseInt(day));
|
|
46
63
|
if (!limits) throw new Error(`(RS::To::Intervals) Day ${day} not found in dayStartAndEnds`);
|
|
47
64
|
return is.map((i) => ({
|
|
48
|
-
beg: parseFloat(
|
|
49
|
-
end: parseFloat(
|
|
65
|
+
beg: parseFloat(parseIntervalDate(i.start).format("HH.mm")),
|
|
66
|
+
end: parseFloat(parseIntervalDate(i.end).format("HH.mm")),
|
|
50
67
|
binary: true
|
|
51
68
|
})).filter((i) => i.beg >= limits.beg && i.end <= limits.end);
|
|
52
|
-
}))
|
|
69
|
+
}).reduce((acc, curr, index) => {
|
|
70
|
+
acc[index] = curr;
|
|
71
|
+
return acc;
|
|
72
|
+
}, Array.from({ length: settings.numDays }, () => []))).value;
|
|
53
73
|
}
|
|
54
74
|
if (intervals) return intervals.map((i) => [i]);
|
|
55
75
|
}
|
|
@@ -107,5 +127,5 @@ function extractUniqueIntervals(settings, groups, teachers, courses, events, loc
|
|
|
107
127
|
}
|
|
108
128
|
|
|
109
129
|
//#endregion
|
|
110
|
-
export { computesDefaultIntervalId, extractUniqueIntervals, getDefaultInterval };
|
|
130
|
+
export { computesDefaultIntervalId, extractUniqueIntervals, getDefaultInterval, parseIntervalDate };
|
|
111
131
|
//# sourceMappingURL=intervals.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intervals.js","names":["x"],"sources":["../../../../src/RS/to/input/intervals.ts"],"sourcesContent":["import moment from 'moment';\nimport { groupBy, uniqBy } from 'lodash-es';\nimport type { Types } from '../../types';\nimport type { ConnectedTypes } from '../../make-connected';\nimport type { AllowedInterval } from '../../../core/types/common/intervals';\nimport { idOf } from './util/util';\nimport { getDayIndex } from '../../../core/util';\nimport type { DateType } from '../../../common/types';\nimport type { RootInterval } from '../../../core/types/root-intervals';\nimport { makeChainable } from '../../../common/make-chainable';\n\n/**\n * Removes the shorthand notation (a single day to represent all days)\n */\nfunction standardizeIntervals (\n intervals: AllowedInterval[] | undefined,\n settings: ConnectedTypes.divisionSettings\n): AllowedInterval[] | undefined {\n if (intervals?.length == 1) {\n const i = intervals[0];\n const start =
|
|
1
|
+
{"version":3,"file":"intervals.js","names":["x"],"sources":["../../../../src/RS/to/input/intervals.ts"],"sourcesContent":["import moment from 'moment';\nimport { groupBy, uniqBy } from 'lodash-es';\nimport type { Types } from '../../types';\nimport type { ConnectedTypes } from '../../make-connected';\nimport type { AllowedInterval } from '../../../core/types/common/intervals';\nimport { idOf } from './util/util';\nimport { getDayIndex } from '../../../core/util';\nimport type { DateType } from '../../../common/types';\nimport type { RootInterval } from '../../../core/types/root-intervals';\nimport { makeChainable } from '../../../common/make-chainable';\n\n/**\n * Parses a date input into a moment object.\n *\n * Accepts an ISO date string, a string in 'HH:mm' format, or a DateType.\n * - If the input is in 'HH:mm' format, it is parsed as a UTC time on the epoch date.\n * - Otherwise, the input is parsed as a full UTC date.\n *\n * @param date - The date input to parse.\n * @returns A moment object representing the parsed date and time.\n */\nexport function parseIntervalDate (date: string | DateType): moment.Moment {\n if (typeof date == 'string') {\n // in case of HH:mm format, parse as UTC time on epoch date\n if (/^\\d{1,2}:\\d{2}$/.test(date)) {\n return moment.utc(date, 'HH:mm');\n }\n\n // otherwise parse as full date\n return moment.utc(date);\n }\n\n return moment.utc(date);\n}\n\n/**\n * Removes the shorthand notation (a single day to represent all days)\n */\nfunction standardizeIntervals (\n intervals: AllowedInterval[] | undefined,\n settings: ConnectedTypes.divisionSettings\n): AllowedInterval[] | undefined {\n if (intervals?.length == 1) {\n const i = intervals[0];\n const start = parseIntervalDate(i.start);\n const end = parseIntervalDate(i.end );\n return Array.from({ length: settings.numDays }, () => ({ start: start.clone(), end: end.clone() }));\n }\n\n return intervals;\n}\n\n/**\n * Converts the intervals to float type intervals\n */\nfunction toFloatIntervals (\n intervals: AllowedInterval[] | undefined\n): { beg: number, end: number }[] | undefined {\n return intervals?.map((i, day: number) => {\n if (!i.start || !i.end) throw new Error(`(RS::To::convertIntervals) Interval missing start or end for day ${day}: ${JSON.stringify(i)}`);\n const start = parseFloat(parseIntervalDate(i.start).format('HH.mm'));\n const end = parseFloat(parseIntervalDate(i.end ).format('HH.mm'));\n return { beg: start, end: end };\n });\n}\n\n/**\n * Converts\n */\nfunction combineAndMapIntervals (\n _intervals: AllowedInterval[] | undefined,\n rootInterval: ConnectedTypes.rootInterval | undefined,\n settings: ConnectedTypes.divisionSettings\n): Types.interval[][] | undefined {\n const intervals = toFloatIntervals(standardizeIntervals(_intervals, settings));\n\n if (rootInterval) {\n if (!intervals) throw new Error('(RS::To::parseIntervals) no accompanying intervals for rootInterval');\n return makeChainable(rootInterval.intervals)\n .chain(\n x => groupBy(x, i => getDayIndex(i.start)),\n x => Object.entries(x)\n .map(([day, is]) => {\n const limits = intervals.at(parseInt(day));\n if (!limits) throw new Error(`(RS::To::Intervals) Day ${day} not found in dayStartAndEnds`);\n\n // remove all block intervals that lay outside the day start and end\n return is\n .map(i => ({\n beg: parseFloat(parseIntervalDate(i.start).format('HH.mm')),\n end: parseFloat(parseIntervalDate(i.end ).format('HH.mm')),\n binary: true\n } satisfies Types.interval))\n .filter(i => i.beg >= limits.beg && i.end <= limits.end);\n })\n // ensure that all days are represented, even if empty\n .reduce<Types.interval[][]>((acc, curr, index) => {\n acc[index] = curr;\n return acc;\n }, Array.from({ length: settings.numDays }, () => []))\n )\n .value;\n }\n if (intervals) {\n return intervals.map(i => [i]);\n }\n return;\n};\n\n/**\n * extracts the default interval given the division settings\n */\nexport function getDefaultInterval (settings: ConnectedTypes.divisionSettings): AllowedInterval[] {\n const { dayStart, dayEnd } = settings;\n if (!dayStart) throw new Error('(RS::To::getDefaultInterval) \"settings.dayStart\" is falsy');\n if (!dayEnd ) throw new Error('(RS::To::getDefaultInterval) \"settings.dayEnd\" is falsy');\n return [{ start: dayStart, end: dayEnd }];\n}\n\n/**\n * Computes the default interval id given the division settings\n */\nexport function computesDefaultIntervalId (\n settings: ConnectedTypes.divisionSettings,\n options: Types.parsedToOptions\n): string {\n return idOf.intervalPairReference(getDefaultInterval(settings), undefined, options);\n}\n\n/**\n * Extracts all unique intervals and interval-root interval pairs used by the provided entities\n */\nexport function extractUniqueIntervals (\n settings: ConnectedTypes.divisionSettings,\n groups: ConnectedTypes.group[],\n teachers: ConnectedTypes.teacher[],\n courses: ConnectedTypes.course[],\n events: ConnectedTypes.event[],\n lockedTimes: ConnectedTypes.lockedTime[],\n options: Types.parsedToOptions\n): Types.rootInterval[] {\n const defaultInterval = getDefaultInterval(settings);\n\n type InheritedWithId = { id: string, data: [AllowedInterval<DateType>[] | undefined, RootInterval | undefined] };\n\n const withRootIntervals = [...groups, ...teachers]\n .map((item): InheritedWithId => {\n const intervals = item.intervals ?? defaultInterval;\n const rootInterval = item.rootInterval ?? settings.defaultRootInterval;\n\n return {\n id: idOf.intervalPairReference(intervals, rootInterval, options),\n data: [intervals, rootInterval]\n };\n });\n\n const withoutRootIntervals = [{ intervals: defaultInterval }, ...courses, ...events, ...lockedTimes]\n .map((item): InheritedWithId => {\n const interval = item.intervals ?? ('course' in item ? item.course?.intervals : undefined) ?? defaultInterval;\n\n return {\n id: idOf.intervalPairReference(interval, undefined, options),\n data: [interval, undefined]\n };\n });\n\n return makeChainable(withRootIntervals)\n .chain(\n x => x.concat(withoutRootIntervals),\n x => uniqBy(x, x => x.id),\n x => x\n .map(({ id, data: [_intervals, rootInterval] }) => {\n // compute the corresponding root interval for each interval pair\n const value = combineAndMapIntervals(_intervals, rootInterval, settings);\n if (!value) return;\n return { id, value } as Required<Types.rootInterval>;\n })\n .filter(x => x != null)\n )\n .value;\n};\n"],"mappings":"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"}
|
|
@@ -3,8 +3,8 @@ import { attachLockedTimes } from "./util/attach-locked-times.js";
|
|
|
3
3
|
import { parseDays } from "./util/parse-days.js";
|
|
4
4
|
import { parseMaxWorkingHours } from "./util/parse-max-working-hours.js";
|
|
5
5
|
import { parseMinimumBreakLength } from "./util/parse-minimum-break-length.js";
|
|
6
|
-
import { parseIntervals } from "./util/parse-intervals.js";
|
|
7
6
|
import { getDefaultInterval } from "./intervals.js";
|
|
7
|
+
import { parseIntervals } from "./util/parse-intervals.js";
|
|
8
8
|
import { omitBy } from "lodash-es";
|
|
9
9
|
|
|
10
10
|
//#region src/RS/to/input/teachers.ts
|
|
@@ -1,28 +1,21 @@
|
|
|
1
1
|
import { getDayIndex } from "../../../../core/util.js";
|
|
2
2
|
import { makeChainable } from "../../../../common/make-chainable/index.js";
|
|
3
|
+
import { parseIntervalDate } from "../intervals.js";
|
|
3
4
|
import { groupBy } from "lodash-es";
|
|
4
|
-
import moment from "moment";
|
|
5
5
|
|
|
6
6
|
//#region src/RS/to/input/util/parse-intervals.ts
|
|
7
|
-
function parseDate(date) {
|
|
8
|
-
if (typeof date == "string") {
|
|
9
|
-
if (/^\d{1,2}:\d{2}$/.test(date)) return moment.utc(date, "HH:mm");
|
|
10
|
-
return moment.utc(date);
|
|
11
|
-
}
|
|
12
|
-
return moment.utc(date);
|
|
13
|
-
}
|
|
14
7
|
function getDayLimits(intervals, settings) {
|
|
15
8
|
if (!intervals) {
|
|
16
|
-
const start =
|
|
17
|
-
const end =
|
|
9
|
+
const start = parseIntervalDate(settings.dayStart);
|
|
10
|
+
const end = parseIntervalDate(settings.dayEnd);
|
|
18
11
|
intervals = Array.from({ length: settings.numDays }, () => ({
|
|
19
12
|
start: start.clone(),
|
|
20
13
|
end: end.clone()
|
|
21
14
|
}));
|
|
22
15
|
} else if (intervals.length == 1) {
|
|
23
16
|
const i = intervals[0];
|
|
24
|
-
const start =
|
|
25
|
-
const end =
|
|
17
|
+
const start = parseIntervalDate(i.start);
|
|
18
|
+
const end = parseIntervalDate(i.end);
|
|
26
19
|
intervals = Array.from({ length: settings.numDays }, () => ({
|
|
27
20
|
start: start.clone(),
|
|
28
21
|
end: end.clone()
|
|
@@ -30,8 +23,8 @@ function getDayLimits(intervals, settings) {
|
|
|
30
23
|
} else if (intervals.length != settings.numDays) throw new Error(`(RS::To::Intervals) Intervals length ${intervals.length} does not match settings.numDays ${settings.numDays}`);
|
|
31
24
|
return intervals.map((i, day) => {
|
|
32
25
|
if (!i.start || !i.end) throw new Error(`(RS::To::Intervals) Interval missing start or end for day ${day}`);
|
|
33
|
-
const start = parseFloat(
|
|
34
|
-
const end = parseFloat(
|
|
26
|
+
const start = parseFloat(parseIntervalDate(i.start).format("HH.mm"));
|
|
27
|
+
const end = parseFloat(parseIntervalDate(i.end).format("HH.mm"));
|
|
35
28
|
return {
|
|
36
29
|
beg: start,
|
|
37
30
|
end
|
|
@@ -49,11 +42,14 @@ function parseIntervals(intervals, rootInterval, settings) {
|
|
|
49
42
|
const limit = dayLimits.at(parseInt(day));
|
|
50
43
|
if (!limit) throw new Error(`(RS::To::Intervals) Day ${day} not found in dayStartAndEnds`);
|
|
51
44
|
return xs.map((x$1) => ({
|
|
52
|
-
beg: parseFloat(
|
|
53
|
-
end: parseFloat(
|
|
45
|
+
beg: parseFloat(parseIntervalDate(x$1.start).format("HH.mm")),
|
|
46
|
+
end: parseFloat(parseIntervalDate(x$1.end).format("HH.mm")),
|
|
54
47
|
binary: true
|
|
55
48
|
})).filter((x$1) => x$1.beg >= limit.beg && x$1.end <= limit.end);
|
|
56
|
-
}))
|
|
49
|
+
}).reduce((acc, curr, index) => {
|
|
50
|
+
acc[index] = curr;
|
|
51
|
+
return acc;
|
|
52
|
+
}, Array.from({ length: settings.numDays }, () => []))).value;
|
|
57
53
|
}
|
|
58
54
|
}
|
|
59
55
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-intervals.js","names":["x"],"sources":["../../../../../src/RS/to/input/util/parse-intervals.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"parse-intervals.js","names":["x"],"sources":["../../../../../src/RS/to/input/util/parse-intervals.ts"],"sourcesContent":["import { groupBy } from 'lodash-es';\nimport type { ConnectedTypes } from '../../../make-connected';\nimport type { AllowedInterval } from '../../../../core/types/common/intervals';\nimport { getDayIndex } from '../../../../core/util';\nimport type { Types } from '../../../types';\nimport { makeChainable } from '../../../../common/make-chainable';\nimport { parseIntervalDate } from '../intervals';\n\nfunction getDayLimits (\n intervals: AllowedInterval[] | undefined,\n settings: ConnectedTypes.divisionSettings\n): { beg: number, end: number }[] {\n // remove short-hand notation (a single interval for all days)\n if (!intervals) {\n const start = parseIntervalDate(settings.dayStart);\n const end = parseIntervalDate(settings.dayEnd);\n intervals = Array.from({ length: settings.numDays }, () => ({ start: start.clone(), end: end.clone() }));\n }\n else if (intervals.length == 1) {\n const i = intervals[0];\n const start = parseIntervalDate(i.start);\n const end = parseIntervalDate(i.end);\n intervals = Array.from({ length: settings.numDays }, () => ({ start: start.clone(), end: end.clone() }));\n } else if (intervals.length != settings.numDays) {\n throw new Error(`(RS::To::Intervals) Intervals length ${intervals.length} does not match settings.numDays ${settings.numDays}`);\n }\n\n // the day start and end times of each day\n return intervals.map((i, day: number) => {\n if (!i.start || !i.end) throw new Error(`(RS::To::Intervals) Interval missing start or end for day ${day}`);\n const start = parseFloat(parseIntervalDate(i.start).format('HH.mm'));\n const end = parseFloat(parseIntervalDate(i.end ).format('HH.mm'));\n return { beg: start, end: end };\n });\n}\n\n\n/**\n * @deprecated The old way of parsing intervals\n */\nexport function parseIntervals (\n intervals: AllowedInterval[] | undefined,\n rootInterval: ConnectedTypes.rootInterval | undefined,\n settings: ConnectedTypes.divisionSettings\n): Types.interval[][] | undefined {\n // if only intervals are provided\n if (intervals && !rootInterval) return getDayLimits(intervals, settings).map(i => [i]);\n\n // if root intervals are present\n if (rootInterval) {\n const dayLimits = getDayLimits(intervals, settings);\n return makeChainable(rootInterval.intervals)\n .chain(\n x => groupBy(x, x => getDayIndex(x.start)),\n x => Object.entries(x)\n .map(([day, xs]) => {\n const limit = dayLimits.at(parseInt(day));\n if (!limit) throw new Error(`(RS::To::Intervals) Day ${day} not found in dayStartAndEnds`);\n\n // remove all block intervals that lay outside the day start and end\n return xs\n .map(x => ({\n beg: parseFloat(parseIntervalDate(x.start).format('HH.mm')),\n end: parseFloat(parseIntervalDate(x.end ).format('HH.mm')),\n binary: true\n } satisfies Types.interval))\n .filter(x => x.beg >= limit.beg && x.end <= limit.end);\n })\n // ensure that all days are represented, even if empty\n .reduce<Types.interval[][]>((acc, curr, index) => {\n acc[index] = curr;\n return acc;\n }, Array.from({ length: settings.numDays }, () => []))\n )\n .value;\n }\n\n // only remaining case here is \"!intervals && !rootInterval\"\n return;\n};\n"],"mappings":";;;;;;AAQA,SAAS,aACP,WACA,UACgC;AAEhC,KAAI,CAAC,WAAW;EACd,MAAM,QAAQ,kBAAkB,SAAS;EACzC,MAAM,MAAQ,kBAAkB,SAAS;AACzC,cAAY,MAAM,KAAK,EAAE,QAAQ,SAAS,kBAAkB;GAAE,OAAO,MAAM;GAAS,KAAK,IAAI;;YAEtF,UAAU,UAAU,GAAG;EAC9B,MAAM,IAAI,UAAU;EACpB,MAAM,QAAQ,kBAAkB,EAAE;EAClC,MAAM,MAAQ,kBAAkB,EAAE;AAClC,cAAY,MAAM,KAAK,EAAE,QAAQ,SAAS,kBAAkB;GAAE,OAAO,MAAM;GAAS,KAAK,IAAI;;YACpF,UAAU,UAAU,SAAS,QACtC,OAAM,IAAI,MAAM,wCAAwC,UAAU,OAAO,mCAAmC,SAAS;AAIvH,QAAO,UAAU,KAAK,GAAG,QAAgB;AACvC,MAAI,CAAC,EAAE,SAAS,CAAC,EAAE,IAAK,OAAM,IAAI,MAAM,6DAA6D;EACrG,MAAM,QAAQ,WAAW,kBAAkB,EAAE,OAAO,OAAO;EAC3D,MAAM,MAAQ,WAAW,kBAAkB,EAAE,KAAO,OAAO;AAC3D,SAAO;GAAE,KAAK;GAAY;;;;;;;AAQ9B,SAAgB,eACd,WACA,cACA,UACgC;AAEhC,KAAI,aAAa,CAAC,aAAc,QAAO,aAAa,WAAW,UAAU,KAAI,MAAK,CAAC;AAGnF,KAAI,cAAc;EAChB,MAAM,YAAY,aAAa,WAAW;AAC1C,SAAO,cAAc,aAAa,WAC/B,OACC,MAAK,QAAQ,IAAG,QAAK,YAAYA,IAAE,UACnC,MAAK,OAAO,QAAQ,GACjB,KAAK,CAAC,KAAK,QAAQ;GAClB,MAAM,QAAQ,UAAU,GAAG,SAAS;AACpC,OAAI,CAAC,MAAO,OAAM,IAAI,MAAM,2BAA2B,IAAI;AAG3D,UAAO,GACJ,KAAI,SAAM;IACT,KAAQ,WAAW,kBAAkBA,IAAE,OAAO,OAAO;IACrD,KAAQ,WAAW,kBAAkBA,IAAE,KAAO,OAAO;IACrD,QAAQ;OAET,QAAO,QAAKA,IAAE,OAAO,MAAM,OAAOA,IAAE,OAAO,MAAM;KAGrD,QAA4B,KAAK,MAAM,UAAU;AAChD,OAAI,SAAS;AACb,UAAO;KACN,MAAM,KAAK,EAAE,QAAQ,SAAS,iBAAiB,MAErD"}
|
|
@@ -53,7 +53,6 @@ let idOf;
|
|
|
53
53
|
if (interval === null) interval = void 0;
|
|
54
54
|
if (rootInterval === null) rootInterval = void 0;
|
|
55
55
|
if (interval && interval.length == 0) interval = void 0;
|
|
56
|
-
if (rootInterval && rootInterval.intervals.length == 0) rootInterval = void 0;
|
|
57
56
|
const out = (rootInterval ? getVertexId(rootInterval, options) + "&" : "") + JSON.stringify(interval);
|
|
58
57
|
return out;
|
|
59
58
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","names":["person","group","teacher","event","lockedTime"],"sources":["../../../../../src/RS/to/input/util/util.ts"],"sourcesContent":["import type { ConnectedTypes } from '../../../make-connected';\nimport type { Types } from '../../../types';\nimport type { Collection, GroupReference } from '../../../../core/types/common';\nimport { getVertexId } from '../../../../core/util';\nimport type { AllowedInterval } from '../../../../core/types/common/intervals';\n\nexport function min2hrs (min: number | undefined | null) {\n return min ? min / 60 : undefined;\n}\n\n/**\n * Converts a time string in the format \"HH:MM\" to a float representation, e.g., \"12:30\" becomes 12.3.\n */\nexport function toTimeFloat (str: string) {\n return parseFloat(str.replace(':', '.'));\n}\n\nexport function getPeriodIndex (\n period: ConnectedTypes.period | undefined | null,\n periodsMap: Map<string | undefined, number>,\n options: Types.parsedToOptions\n): number | undefined {\n const id = period ? getVertexId(period, options) : undefined;\n const periodIndex = periodsMap.get(id);\n if (periodIndex === undefined) throw new Error(`(RS::To::getPeriodIndex) Period \"${id}\" is not in periodsMap`);\n return periodIndex;\n}\n\nexport const COLLECTION_ID = {\n persons: 'persons',\n groups: 'groups',\n teachers: 'teachers',\n events: 'events',\n lockedTimes: 'lockedtimes',\n} satisfies Partial<Record<Collection, string>>;\n\n/**\n * returns a combined id for the vertex or edge by combining the type(s) and id(s).\n */\nexport namespace idOf {\n /** `persons.id` */\n export function person (\n person: ConnectedTypes.person | string,\n options: Types.parsedToOptions\n ): string {\n return `${COLLECTION_ID.persons}.${ getVertexId(person, options) }`;\n }\n\n /** `groups.id` */\n export function group (\n group: ConnectedTypes.group,\n options: Types.parsedToOptions\n ): string {\n return `${COLLECTION_ID.groups}.${ getVertexId(group, options) }`;\n }\n\n /** `teachers.id` */\n export function teacher (\n teacher: ConnectedTypes.teacher,\n options: Types.parsedToOptions\n ): string {\n return `${COLLECTION_ID.teachers}.${ getVertexId(teacher, options) }`;\n }\n\n /** `events.id` */\n export function event (\n event: ConnectedTypes.event,\n options: Types.parsedToOptions\n ): string {\n return `${COLLECTION_ID.events}.${ getVertexId(event, options) }`;\n }\n\n /** `lockedtimes.id` */\n export function lockedTime (\n lockedTime: ConnectedTypes.lockedTime,\n options: Types.parsedToOptions\n ): string {\n return `${COLLECTION_ID.lockedTimes}.${ getVertexId(lockedTime, options) }`;\n }\n\n /** `groups.id<.exclude.id1.id2...>` */\n export function groupReference (\n group: GroupReference<ConnectedTypes.group, ConnectedTypes.person>,\n options: Types.parsedToOptions\n ): string {\n return `${COLLECTION_ID.groups}.${ getVertexId(group.to, options) }`\n + (group.exclude?.length\n ? '.exclude.' + group.exclude\n .map(x => getVertexId(x, options))\n .sort()\n .join('.')\n : '');\n }\n\n /** `<rootIntervalsId&>JSON.stringify(intervals)>` */\n export function intervalPairReference (\n interval: AllowedInterval[] | undefined,\n rootInterval: ConnectedTypes.rootInterval | undefined,\n options: Types.parsedToOptions\n ): string {\n // replace null with undefined\n if (interval === null) interval = undefined;\n if (rootInterval === null) rootInterval = undefined;\n\n // replace empty intervals with undefined\n if (interval
|
|
1
|
+
{"version":3,"file":"util.js","names":["person","group","teacher","event","lockedTime"],"sources":["../../../../../src/RS/to/input/util/util.ts"],"sourcesContent":["import type { ConnectedTypes } from '../../../make-connected';\nimport type { Types } from '../../../types';\nimport type { Collection, GroupReference } from '../../../../core/types/common';\nimport { getVertexId } from '../../../../core/util';\nimport type { AllowedInterval } from '../../../../core/types/common/intervals';\n\nexport function min2hrs (min: number | undefined | null) {\n return min ? min / 60 : undefined;\n}\n\n/**\n * Converts a time string in the format \"HH:MM\" to a float representation, e.g., \"12:30\" becomes 12.3.\n */\nexport function toTimeFloat (str: string) {\n return parseFloat(str.replace(':', '.'));\n}\n\nexport function getPeriodIndex (\n period: ConnectedTypes.period | undefined | null,\n periodsMap: Map<string | undefined, number>,\n options: Types.parsedToOptions\n): number | undefined {\n const id = period ? getVertexId(period, options) : undefined;\n const periodIndex = periodsMap.get(id);\n if (periodIndex === undefined) throw new Error(`(RS::To::getPeriodIndex) Period \"${id}\" is not in periodsMap`);\n return periodIndex;\n}\n\nexport const COLLECTION_ID = {\n persons: 'persons',\n groups: 'groups',\n teachers: 'teachers',\n events: 'events',\n lockedTimes: 'lockedtimes',\n} satisfies Partial<Record<Collection, string>>;\n\n/**\n * returns a combined id for the vertex or edge by combining the type(s) and id(s).\n */\nexport namespace idOf {\n /** `persons.id` */\n export function person (\n person: ConnectedTypes.person | string,\n options: Types.parsedToOptions\n ): string {\n return `${COLLECTION_ID.persons}.${ getVertexId(person, options) }`;\n }\n\n /** `groups.id` */\n export function group (\n group: ConnectedTypes.group,\n options: Types.parsedToOptions\n ): string {\n return `${COLLECTION_ID.groups}.${ getVertexId(group, options) }`;\n }\n\n /** `teachers.id` */\n export function teacher (\n teacher: ConnectedTypes.teacher,\n options: Types.parsedToOptions\n ): string {\n return `${COLLECTION_ID.teachers}.${ getVertexId(teacher, options) }`;\n }\n\n /** `events.id` */\n export function event (\n event: ConnectedTypes.event,\n options: Types.parsedToOptions\n ): string {\n return `${COLLECTION_ID.events}.${ getVertexId(event, options) }`;\n }\n\n /** `lockedtimes.id` */\n export function lockedTime (\n lockedTime: ConnectedTypes.lockedTime,\n options: Types.parsedToOptions\n ): string {\n return `${COLLECTION_ID.lockedTimes}.${ getVertexId(lockedTime, options) }`;\n }\n\n /** `groups.id<.exclude.id1.id2...>` */\n export function groupReference (\n group: GroupReference<ConnectedTypes.group, ConnectedTypes.person>,\n options: Types.parsedToOptions\n ): string {\n return `${COLLECTION_ID.groups}.${ getVertexId(group.to, options) }`\n + (group.exclude?.length\n ? '.exclude.' + group.exclude\n .map(x => getVertexId(x, options))\n .sort()\n .join('.')\n : '');\n }\n\n /** `<rootIntervalsId&>JSON.stringify(intervals)>` */\n export function intervalPairReference (\n interval: AllowedInterval[] | undefined,\n rootInterval: ConnectedTypes.rootInterval | undefined,\n options: Types.parsedToOptions\n ): string {\n // replace null with undefined\n if (interval === null) interval = undefined;\n if (rootInterval === null) rootInterval = undefined;\n\n // replace empty intervals with undefined\n if (interval && interval.length == 0) interval = undefined;\n\n const out = (rootInterval ? getVertexId(rootInterval, options) + '&' : '') + JSON.stringify(interval);\n return out;\n }\n}\n"],"mappings":";;;AAMA,SAAgB,QAAS,KAAgC;AACvD,QAAO,MAAM,MAAM,KAAK;;;;;AAM1B,SAAgB,YAAa,KAAa;AACxC,QAAO,WAAW,IAAI,QAAQ,KAAK;;AAGrC,SAAgB,eACd,QACA,YACA,SACoB;CACpB,MAAM,KAAK,SAAS,YAAY,QAAQ,WAAW;CACnD,MAAM,cAAc,WAAW,IAAI;AACnC,KAAI,gBAAgB,OAAW,OAAM,IAAI,MAAM,oCAAoC,GAAG;AACtF,QAAO;;AAGT,MAAa,gBAAgB;CAC3B,SAAa;CACb,QAAa;CACb,UAAa;CACb,QAAa;CACb,aAAa;;;;CAQN,SAAS,OACd,UACA,SACQ;AACR,SAAO,GAAG,cAAc,QAAQ,GAAI,YAAYA,UAAQ;;;CAInD,SAAS,MACd,SACA,SACQ;AACR,SAAO,GAAG,cAAc,OAAO,GAAI,YAAYC,SAAO;;;CAIjD,SAAS,QACd,WACA,SACQ;AACR,SAAO,GAAG,cAAc,SAAS,GAAI,YAAYC,WAAS;;;CAIrD,SAAS,MACd,SACA,SACQ;AACR,SAAO,GAAG,cAAc,OAAO,GAAI,YAAYC,SAAO;;;CAIjD,SAAS,WACd,cACA,SACQ;AACR,SAAO,GAAG,cAAc,YAAY,GAAI,YAAYC,cAAY;;;CAI3D,SAAS,eACd,SACA,SACQ;AACR,SAAO,GAAG,cAAc,OAAO,GAAI,YAAYH,QAAM,IAAI,cACpDA,QAAM,SAAS,SACd,cAAcA,QAAM,QACnB,KAAI,MAAK,YAAY,GAAG,UACxB,OACA,KAAK,OACN;;;CAID,SAAS,sBACd,UACA,cACA,SACQ;AAER,MAAI,aAAiB,KAAM,YAAe;AAC1C,MAAI,iBAAiB,KAAM,gBAAe;AAG1C,MAAI,YAAY,SAAS,UAAU,EAAG,YAAW;EAEjD,MAAM,OAAO,eAAe,YAAY,cAAc,WAAW,MAAM,MAAM,KAAK,UAAU;AAC5F,SAAO"}
|