@royalschedule/maps 4.0.18 → 4.0.21
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/RS/to/input/events.js +1 -1
- package/dist/RS/to/input/events.js.map +1 -1
- package/dist/RS/to/schedules.js +4 -1
- package/dist/RS/to/schedules.js.map +1 -1
- package/dist/RS/types/algorithm-parameters.d.ts +13 -1
- package/dist/RS/types/to.d.ts +3 -4
- package/dist/RS/types/to.js.map +1 -1
- package/dist/Skola24/txt/from/schedules.js +32 -26
- package/dist/Skola24/txt/from/schedules.js.map +1 -1
- package/dist/core/from/schedules.js +2 -1
- package/dist/core/from/schedules.js.map +1 -1
- package/dist/core/from/settings.js +21 -0
- package/dist/core/from/settings.js.map +1 -0
- package/dist/core/interfaces/vertices/util/custom-vertex-export/assert-no-invalid-expand-keys.d.ts +16 -0
- package/dist/core/interfaces/vertices/util/custom-vertex-export/index.d.ts +5 -3
- package/dist/core/interfaces/vertices/util/custom-vertex-export/util.d.ts +4 -2
- package/dist/core/interfaces/vertices/util/index.d.ts +1 -0
- package/dist/core/interfaces/vertices/util/util.d.ts +5 -1
- package/dist/core/interfaces/vertices/util/vertex-query/index.d.ts +4 -2
- package/dist/core/interfaces/vertices/vertex-query.d.ts +21 -18
- package/dist/core/interfaces/vertices/vertex-query.js +8 -0
- package/dist/core/interfaces/vertices/vertex-query.js.map +1 -1
- package/package.json +2 -2
|
@@ -25,7 +25,7 @@ function parseEvents(events, settings, options, periodsMap) {
|
|
|
25
25
|
const duration = event.preferredDuration;
|
|
26
26
|
if (!duration) throw new Error(`(RS::To::Events) Event "${id}" has no duration`);
|
|
27
27
|
const forcedOverlapId = event.overlapSpecies?.species?.find(({ to }) => to == event)?.id;
|
|
28
|
-
const maxLengthVariance = forcedOverlapId
|
|
28
|
+
const maxLengthVariance = forcedOverlapId == null ? event.durationVariance : 0;
|
|
29
29
|
const doc = {
|
|
30
30
|
id: idOf.event(event, options),
|
|
31
31
|
length: duration,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","names":["doc: Types.event","id"],"sources":["../../../../src/RS/to/input/events.ts"],"sourcesContent":["import moment from 'moment';\nimport { omitBy } from 'lodash-es';\nimport { parseMinimumBreakLength } from './util/parse-minimum-break-length';\nimport { attachLockedTimes } from './util/attach-locked-times';\nimport type { Types } from '../../types';\nimport { parseGroupReferences } from './util/parse-group-references';\nimport { parseLocationReferences, parseSelectedLocations } from './util/parse-location-references';\nimport type { ConnectedTypes } from '../../make-connected';\nimport { getDayIndex, getVertexId } from '../../../core/util';\nimport { getPeriodIndex, idOf } from './util/util';\nimport { parseDays } from './util/parse-days';\nimport type { DateType } from '../../../common/types';\nimport { parseIntervals } from './util/parse-intervals';\nimport { getDefaultInterval } from './intervals';\n\nexport function toDayAndStart (start: DateType) {\n return {\n start: parseFloat(moment.utc(start).format('HH.mm')),\n day: getDayIndex(start)\n };\n}\n\nexport function parseEvents (\n events: ConnectedTypes.event[] | undefined,\n settings: ConnectedTypes.divisionSettings,\n options: Types.parsedToOptions,\n periodsMap: Map<string | undefined, number>\n): Types.event[] {\n const defaultInterval = getDefaultInterval(settings);\n\n return (events ?? [])\n .map((event): Types.event | undefined => {\n const id = getVertexId(event, options);\n const intervals = event.intervals ?? event.course?.intervals ?? defaultInterval;\n\n const duration = event.preferredDuration;\n if (!duration) throw new Error(`(RS::To::Events) Event \"${id}\" has no duration`);\n\n const forcedOverlapId = event.overlapSpecies?.species?.find(({ to }) => to == event)?.id;\n\n // if the event
|
|
1
|
+
{"version":3,"file":"events.js","names":["doc: Types.event","id"],"sources":["../../../../src/RS/to/input/events.ts"],"sourcesContent":["import moment from 'moment';\nimport { omitBy } from 'lodash-es';\nimport { parseMinimumBreakLength } from './util/parse-minimum-break-length';\nimport { attachLockedTimes } from './util/attach-locked-times';\nimport type { Types } from '../../types';\nimport { parseGroupReferences } from './util/parse-group-references';\nimport { parseLocationReferences, parseSelectedLocations } from './util/parse-location-references';\nimport type { ConnectedTypes } from '../../make-connected';\nimport { getDayIndex, getVertexId } from '../../../core/util';\nimport { getPeriodIndex, idOf } from './util/util';\nimport { parseDays } from './util/parse-days';\nimport type { DateType } from '../../../common/types';\nimport { parseIntervals } from './util/parse-intervals';\nimport { getDefaultInterval } from './intervals';\n\nexport function toDayAndStart (start: DateType) {\n return {\n start: parseFloat(moment.utc(start).format('HH.mm')),\n day: getDayIndex(start)\n };\n}\n\nexport function parseEvents (\n events: ConnectedTypes.event[] | undefined,\n settings: ConnectedTypes.divisionSettings,\n options: Types.parsedToOptions,\n periodsMap: Map<string | undefined, number>\n): Types.event[] {\n const defaultInterval = getDefaultInterval(settings);\n\n return (events ?? [])\n .map((event): Types.event | undefined => {\n const id = getVertexId(event, options);\n const intervals = event.intervals ?? event.course?.intervals ?? defaultInterval;\n\n const duration = event.preferredDuration;\n if (!duration) throw new Error(`(RS::To::Events) Event \"${id}\" has no duration`);\n\n const forcedOverlapId = event.overlapSpecies?.species?.find(({ to }) => to == event)?.id;\n\n // allow duration variance only if the event isn't linked\n const maxLengthVariance = forcedOverlapId == null\n ? event.durationVariance\n : 0;\n\n const doc: Types.event = {\n id: idOf.event(event, options),\n length: duration,\n maxLengthVariance: maxLengthVariance,\n weight: event.weight,\n density: event.density,\n potentialCenter: event.centerOfAttraction ? parseFloat(event.centerOfAttraction.replace(':', '.')) : undefined,\n forcedOverlapId: forcedOverlapId,\n period: getPeriodIndex (event.period, periodsMap, options),\n _period: event.period ? getVertexId(event.period, options) : undefined,\n days: parseDays (event.days, settings),\n dependencies: parseLocationReferences (event.locations, options),\n groups: parseGroupReferences ({ type: 'event', item: event }, options),\n intervals: options.oldFormat\n ? parseIntervals(intervals, undefined, settings)\n : idOf.intervalPairReference(intervals, undefined, options),\n lockedTimes: attachLockedTimes (event.lockedTimes, options),\n minBreakLength: parseMinimumBreakLength (event.minBreakLength),\n };\n\n // if the event has a fixed day and start\n if (event.fixedStart && event.start) {\n Object.assign(doc, toDayAndStart(event.start));\n }\n\n if (options.includeEntityMeta) {\n doc.meta = omitBy({\n name: event.displayName,\n ids: event.ids,\n parked: event.parked,\n visible: event.visible,\n start: event.start ? moment.utc(event.start) : undefined,\n end: event.end ? moment.utc(event.start) : undefined,\n course: event.course ? getVertexId(event.course, options) : undefined,\n inLocations: event.inLocations ? parseSelectedLocations(event, options) : undefined\n }, x => x == null);\n }\n\n ////\n //// filter events based on partialScheduleOptions\n ////\n if (options.partialScheduleOptions) {\n const { includedEvents, omittedEventsHandling } = options.partialScheduleOptions;\n if (includedEvents && !includedEvents.has(doc.id)) { // collection.id => take into account dynamic locked times too!\n\n if (omittedEventsHandling == 'ignore') return;\n\n if (omittedEventsHandling == 'freeze') {\n // must not be parked and have a start and duration to be frozen, otherwise it's ignored\n if (event.parked || !event.start || !event.duration) return;\n\n // fix day, start and end\n Object.assign(doc, toDayAndStart(event.start));\n doc.length = event.duration;\n doc.maxLengthVariance = 0;\n\n // override intervals and days to not cause conflicts\n const numDays = settings.numDays ?? 5;\n doc.days = Array.from({ length: numDays }, (_, i) => i);\n doc.intervals = Array.from({ length: numDays }, () => [{ beg: 0, end: 23.55 }]);\n\n // fix locations\n doc.dependencies = (event.inLocations ?? [])\n .filter((x): x is NonNullable<typeof x> => !!x)\n .map(x => {\n const id = getVertexId(x, options);\n\n // filter location references based on partial schedule options\n const includedLocations = options.partialScheduleOptions?.includedLocations;\n if (includedLocations && !includedLocations.has(id)) return;\n\n return [{ dependency: id }] as Types.availableDependency[];\n })\n .filter(x => x != null);\n }\n\n }\n }\n\n return omitBy(doc, x => x == null) as Types.event;\n })\n .filter((x): x is NonNullable<typeof x> => !!x);\n}"],"mappings":"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"}
|
package/dist/RS/to/schedules.js
CHANGED
|
@@ -29,7 +29,10 @@ function schedules(data, _options = {}) {
|
|
|
29
29
|
structure,
|
|
30
30
|
division: pick(connectedData.division, "displayName", "start", "end")
|
|
31
31
|
},
|
|
32
|
-
algorithmParameters: {
|
|
32
|
+
algorithmParameters: {
|
|
33
|
+
weights: options.algorithmWeightParameters,
|
|
34
|
+
computeTimeMultiplier: options.computeTimeMultiplier
|
|
35
|
+
},
|
|
33
36
|
input: parseInput(connectedData, options),
|
|
34
37
|
...options.appendCoreData && { coreData: CoreMap.to.schedules(data) },
|
|
35
38
|
...options.appendOutput && { output: initialConfiguration(connectedData.events, connectedData.lockedTimes, options) }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schedules.js","names":["partialScheduleOptions: Types.parsedToOptions['partialScheduleOptions']"],"sources":["../../../src/RS/to/schedules.ts"],"sourcesContent":["import { pick } from 'lodash-es';\nimport { parseInput } from './input/input';\nimport { makeConnected } from '../make-connected';\nimport { initialConfiguration } from './initial-configuration';\nimport type { Types } from '../types';\nimport { CoreMap } from '../../core';\nimport { structure } from '../types/to';\n\nexport function schedules (\n data: Types.toInput,\n _options: Types.toOptions = {}\n): Types.toOutput {\n ////\n //// parse the options\n ////\n const options = ((): Types.parsedToOptions => {\n const x = _options.partialScheduleOptions;\n const partialScheduleOptions: Types.parsedToOptions['partialScheduleOptions'] = x\n ? {\n includedEvents: x.includedEvents ? new Set(x.includedEvents) : undefined,\n includedLocations: x.includedLocations ? new Set(x.includedLocations) : undefined,\n omittedEventsHandling: x.omittedEventsHandling\n }\n : undefined;\n\n return { ..._options, partialScheduleOptions };\n })();\n\n ////\n //// for backward compatibility: add default collection to included events set\n ////\n if (options.partialScheduleOptions?.includedEvents?.size) {\n options.partialScheduleOptions.includedEvents = new Set(\n [...options.partialScheduleOptions.includedEvents]\n .map(x => {\n // should start with 'events.' or 'lockedTimes.' prefix\n if (x.startsWith('events.') || x.startsWith('lockedTimes.')) return x;\n return `events.${x}`;\n })\n );\n }\n\n\n // we will work only with connected schedule data\n const connectedData = makeConnected(data);\n\n return {\n meta: {\n structure: structure,\n division: pick(connectedData.division, 'displayName', 'start', 'end'),\n },\n algorithmParameters: {\n weights:
|
|
1
|
+
{"version":3,"file":"schedules.js","names":["partialScheduleOptions: Types.parsedToOptions['partialScheduleOptions']"],"sources":["../../../src/RS/to/schedules.ts"],"sourcesContent":["import { pick } from 'lodash-es';\nimport { parseInput } from './input/input';\nimport { makeConnected } from '../make-connected';\nimport { initialConfiguration } from './initial-configuration';\nimport type { Types } from '../types';\nimport { CoreMap } from '../../core';\nimport { structure } from '../types/to';\n\nexport function schedules (\n data: Types.toInput,\n _options: Types.toOptions = {}\n): Types.toOutput {\n ////\n //// parse the options\n ////\n const options = ((): Types.parsedToOptions => {\n const x = _options.partialScheduleOptions;\n const partialScheduleOptions: Types.parsedToOptions['partialScheduleOptions'] = x\n ? {\n includedEvents: x.includedEvents ? new Set(x.includedEvents) : undefined,\n includedLocations: x.includedLocations ? new Set(x.includedLocations) : undefined,\n omittedEventsHandling: x.omittedEventsHandling\n }\n : undefined;\n\n return { ..._options, partialScheduleOptions };\n })();\n\n ////\n //// for backward compatibility: add default collection to included events set\n ////\n if (options.partialScheduleOptions?.includedEvents?.size) {\n options.partialScheduleOptions.includedEvents = new Set(\n [...options.partialScheduleOptions.includedEvents]\n .map(x => {\n // should start with 'events.' or 'lockedTimes.' prefix\n if (x.startsWith('events.') || x.startsWith('lockedTimes.')) return x;\n return `events.${x}`;\n })\n );\n }\n\n\n // we will work only with connected schedule data\n const connectedData = makeConnected(data);\n\n return {\n meta: {\n structure: structure,\n division: pick(connectedData.division, 'displayName', 'start', 'end'),\n },\n algorithmParameters: {\n weights: options.algorithmWeightParameters,\n computeTimeMultiplier: options.computeTimeMultiplier\n },\n input: parseInput(connectedData, options),\n ...options.appendCoreData && { coreData: CoreMap.to.schedules(data) },\n ...options.appendOutput && { output: initialConfiguration(connectedData.events, connectedData.lockedTimes, options) },\n };\n};"],"mappings":";;;;;;;;AAQA,SAAgB,UACd,MACA,WAA4B,EAAE,EACd;CAIhB,MAAM,iBAAwC;EAC5C,MAAM,IAAI,SAAS;EACnB,MAAMA,yBAA0E,IAC5E;GACA,gBAAuB,EAAE,iBAAoB,IAAI,IAAI,EAAE,eAAe,GAAM;GAC5E,mBAAuB,EAAE,oBAAoB,IAAI,IAAI,EAAE,kBAAkB,GAAG;GAC5E,uBAAuB,EAAE;GAC1B,GACC;AAEJ,SAAO;GAAE,GAAG;GAAU;GAAwB;KAC5C;AAKJ,KAAI,QAAQ,wBAAwB,gBAAgB,KAClD,SAAQ,uBAAuB,iBAAiB,IAAI,IAClD,CAAC,GAAG,QAAQ,uBAAuB,eAAe,CAC/C,KAAI,MAAK;AAER,MAAI,EAAE,WAAW,UAAU,IAAI,EAAE,WAAW,eAAe,CAAE,QAAO;AACpE,SAAO,UAAU;GACjB,CACL;CAKH,MAAM,gBAAgB,cAAc,KAAK;AAEzC,QAAO;EACL,MAAM;GACO;GACX,UAAW,KAAK,cAAc,UAAU,eAAe,SAAS,MAAM;GACvE;EACD,qBAAqB;GACnB,SAAuB,QAAQ;GAC/B,uBAAuB,QAAQ;GAChC;EACD,OAAO,WAAW,eAAe,QAAQ;EACzC,GAAG,QAAQ,kBAAkB,EAAE,UAAU,QAAQ,GAAG,UAAU,KAAK,EAAE;EACrE,GAAG,QAAQ,gBAAkB,EAAE,QAAQ,qBAAqB,cAAc,QAAQ,cAAc,aAAa,QAAQ,EAAE;EACxH"}
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
//#region src/RS/types/algorithm-parameters.d.ts
|
|
2
2
|
type ParameterName = 'overlap' | 'doubleBooking' | 'timeFrame' | 'breakLength' | 'clustering' | 'dailyOvertime' | 'position' | 'gap' | 'dependencyAlternation' | 'overtime' | 'dependencyRank' | 'dayRank' | 'groupRank';
|
|
3
3
|
type AlgorithmWeightParameters = Record<ParameterName, number | false>;
|
|
4
|
+
type AlgorithmParameters = {
|
|
5
|
+
/**
|
|
6
|
+
* Weights for different features used in the scheduling algorithm.
|
|
7
|
+
*/
|
|
8
|
+
weights?: AlgorithmWeightParameters;
|
|
9
|
+
/**
|
|
10
|
+
* A multiplier that lets the schedule algorithm run for a longer time to find better solutions.
|
|
11
|
+
*
|
|
12
|
+
* @default 1
|
|
13
|
+
*/
|
|
14
|
+
computeTimeMultiplier?: number;
|
|
15
|
+
};
|
|
4
16
|
//#endregion
|
|
5
|
-
export { AlgorithmWeightParameters };
|
|
17
|
+
export { AlgorithmParameters, AlgorithmWeightParameters };
|
|
6
18
|
//# sourceMappingURL=algorithm-parameters.d.ts.map
|
package/dist/RS/types/to.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { BaseOptions } from "../../common/types.js";
|
|
|
2
2
|
import { Types } from "../../core/types/index.js";
|
|
3
3
|
import "../../core/index.js";
|
|
4
4
|
import { MixedScheduleData } from "../make-connected.js";
|
|
5
|
-
import { AlgorithmWeightParameters } from "./algorithm-parameters.js";
|
|
5
|
+
import { AlgorithmParameters, AlgorithmWeightParameters } from "./algorithm-parameters.js";
|
|
6
6
|
import { Types as Types$1 } from "./index.js";
|
|
7
7
|
|
|
8
8
|
//#region src/RS/types/to.d.ts
|
|
@@ -46,6 +46,7 @@ interface ToOptions extends BaseOptions {
|
|
|
46
46
|
oldFormat?: boolean;
|
|
47
47
|
partialScheduleOptions?: PartialScheduleOptions<Array<string> | Set<string>>;
|
|
48
48
|
algorithmWeightParameters?: AlgorithmWeightParameters;
|
|
49
|
+
computeTimeMultiplier?: number;
|
|
49
50
|
/**
|
|
50
51
|
* to be used before whe have migrated from "maxNumWorkingHours" and "maxNumDailyWorkingHours" to "maximumScheduleSpan"
|
|
51
52
|
*/
|
|
@@ -61,9 +62,7 @@ interface ToOutput {
|
|
|
61
62
|
structure?: Structure;
|
|
62
63
|
division: Pick<Types.Deep.Division, 'displayName' | 'start' | 'end'>;
|
|
63
64
|
};
|
|
64
|
-
algorithmParameters:
|
|
65
|
-
weights?: AlgorithmWeightParameters;
|
|
66
|
-
};
|
|
65
|
+
algorithmParameters: AlgorithmParameters;
|
|
67
66
|
score?: [number, number, number, number];
|
|
68
67
|
input: Types$1.scheduleData;
|
|
69
68
|
output?: Types$1.configuration[];
|
package/dist/RS/types/to.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"to.js","names":[],"sources":["../../../src/RS/types/to.ts"],"sourcesContent":["import type { BaseOptions } from '../../common/types';\nimport type { CoreTypes } from '../../core';\nimport type { MixedScheduleData } from '../make-connected';\nimport type { Types } from './';\nimport type { AlgorithmWeightParameters } from './algorithm-parameters';\n\n\nexport type ToInput = MixedScheduleData;\n\ntype PartialScheduleOptions<IDs extends Array<string> | Set<string>> = {\n /** @description undefined means all included */\n includedEvents?: IDs;\n /** @description undefined means all included */\n includedLocations?: IDs;\n omittedEventsHandling: 'ignore' | 'freeze';\n};\n\nexport interface ToOptions extends BaseOptions {\n /**\n * If enabled, each entity in the output (such as groups, dependencies, collections, events, etc.)\n * will include a `meta` object containing details like original IDs and display names.\n * Note: This is distinct from the root-level `meta` object in the mapped output which is always included.\n * @default false\n */\n includeEntityMeta?: boolean;\n\n /**\n * If true, the output will include the full core data. This enables the resulting output file to be uploaded as a new schedule.\n * @default false\n */\n appendCoreData?: boolean;\n\n /**\n * If true, the output will include current configuration of events and locked times as `output` entry.\n * @default false\n */\n appendOutput?: boolean;\n\n /**\n * @deprecated the only purpose of this backwards compatibility is to support the input-analyzer module\n *\n * If not set to true, these new features are taken into account:\n *\n * - New root level entries: `intervals` and `individuals`\n * - As the there is now a root level `intervals` the former may be references from `Collection.intervals`, `Group.intervals` etc.\n * - The `Collection.groups` and `Event.groups` supports referencing `individuals` (and `individuals sets`) in addition to `groups`\n * - The `Group.forbidOverlappingEvents` has been removed.\n * - The `Group.disableDayLengthPunishment` has been replaced by `Group.minimizeGaps`\n */\n oldFormat?: boolean;\n\n partialScheduleOptions?: PartialScheduleOptions<Array<string> | Set<string>>\n\n algorithmWeightParameters?: AlgorithmWeightParameters;\n\n /**\n * to be used before whe have migrated from \"maxNumWorkingHours\" and \"maxNumDailyWorkingHours\" to \"maximumScheduleSpan\"\n */\n useMaximumScheduleSpan?: boolean;\n}\n\nexport interface ParsedToOptions extends Omit<ToOptions, 'partialScheduleOptions'> {\n partialScheduleOptions?: PartialScheduleOptions<Set<string>>\n}\n\nexport const structure = 'RS/algorithm-5.0.2';\nexport type Structure = typeof structure;\nexport interface ToOutput {\n meta: {\n structure?: Structure;\n division: Pick<CoreTypes.Deep.Division, 'displayName' | 'start' | 'end'>;\n };\n algorithmParameters:
|
|
1
|
+
{"version":3,"file":"to.js","names":[],"sources":["../../../src/RS/types/to.ts"],"sourcesContent":["import type { BaseOptions } from '../../common/types';\nimport type { CoreTypes } from '../../core';\nimport type { MixedScheduleData } from '../make-connected';\nimport type { Types } from './';\nimport type { AlgorithmParameters, AlgorithmWeightParameters } from './algorithm-parameters';\n\n\nexport type ToInput = MixedScheduleData;\n\ntype PartialScheduleOptions<IDs extends Array<string> | Set<string>> = {\n /** @description undefined means all included */\n includedEvents?: IDs;\n /** @description undefined means all included */\n includedLocations?: IDs;\n omittedEventsHandling: 'ignore' | 'freeze';\n};\n\nexport interface ToOptions extends BaseOptions {\n /**\n * If enabled, each entity in the output (such as groups, dependencies, collections, events, etc.)\n * will include a `meta` object containing details like original IDs and display names.\n * Note: This is distinct from the root-level `meta` object in the mapped output which is always included.\n * @default false\n */\n includeEntityMeta?: boolean;\n\n /**\n * If true, the output will include the full core data. This enables the resulting output file to be uploaded as a new schedule.\n * @default false\n */\n appendCoreData?: boolean;\n\n /**\n * If true, the output will include current configuration of events and locked times as `output` entry.\n * @default false\n */\n appendOutput?: boolean;\n\n /**\n * @deprecated the only purpose of this backwards compatibility is to support the input-analyzer module\n *\n * If not set to true, these new features are taken into account:\n *\n * - New root level entries: `intervals` and `individuals`\n * - As the there is now a root level `intervals` the former may be references from `Collection.intervals`, `Group.intervals` etc.\n * - The `Collection.groups` and `Event.groups` supports referencing `individuals` (and `individuals sets`) in addition to `groups`\n * - The `Group.forbidOverlappingEvents` has been removed.\n * - The `Group.disableDayLengthPunishment` has been replaced by `Group.minimizeGaps`\n */\n oldFormat?: boolean;\n\n partialScheduleOptions?: PartialScheduleOptions<Array<string> | Set<string>>\n\n algorithmWeightParameters?: AlgorithmWeightParameters;\n\n computeTimeMultiplier?: number;\n\n /**\n * to be used before whe have migrated from \"maxNumWorkingHours\" and \"maxNumDailyWorkingHours\" to \"maximumScheduleSpan\"\n */\n useMaximumScheduleSpan?: boolean;\n}\n\nexport interface ParsedToOptions extends Omit<ToOptions, 'partialScheduleOptions'> {\n partialScheduleOptions?: PartialScheduleOptions<Set<string>>\n}\n\nexport const structure = 'RS/algorithm-5.0.2';\nexport type Structure = typeof structure;\nexport interface ToOutput {\n meta: {\n structure?: Structure;\n division: Pick<CoreTypes.Deep.Division, 'displayName' | 'start' | 'end'>;\n };\n algorithmParameters: AlgorithmParameters;\n score?: [number, number, number, number];\n input: Types.scheduleData;\n output?: Types.configuration[];\n coreData?: Partial<CoreTypes.SerializedWithOptionalId.Schedule>;\n}"],"mappings":";AAmEA,MAAa,YAAY"}
|
|
@@ -84,7 +84,7 @@ const schedules = (input, options = {}) => {
|
|
|
84
84
|
}] },
|
|
85
85
|
person: `teacher.${extractId(x.GUID)}`
|
|
86
86
|
}));
|
|
87
|
-
const teacherPersons = tables.Teacher?.map((x) => ({
|
|
87
|
+
const teacherPersons = tables.Teacher?.filter((x) => x.FirstName && x.LastName)?.map((x) => ({
|
|
88
88
|
ids: `teacher.${extractId(x.GUID)}`,
|
|
89
89
|
firstName: x.FirstName,
|
|
90
90
|
lastName: x.LastName,
|
|
@@ -175,7 +175,7 @@ const schedules = (input, options = {}) => {
|
|
|
175
175
|
plannedDuration: x.TotalHours ? `${x.TotalHours} hrs` : x.Weektime ? `${x.Weektime} min/week` : void 0,
|
|
176
176
|
...x.Period && { period: periodMap.get(x.Period) }
|
|
177
177
|
};
|
|
178
|
-
});
|
|
178
|
+
}) ?? [];
|
|
179
179
|
tables.TA?.forEach((x) => {
|
|
180
180
|
courseMap.set(`${x.Subject}.${x.Teacher}.${x.Group}`, x.GUID ? extractId(x.GUID) : void 0);
|
|
181
181
|
});
|
|
@@ -188,7 +188,8 @@ const schedules = (input, options = {}) => {
|
|
|
188
188
|
value: x.Category
|
|
189
189
|
}] }
|
|
190
190
|
}));
|
|
191
|
-
let
|
|
191
|
+
let lessonMissingCourseWarningsCount = 0;
|
|
192
|
+
const events = tables.Lesson?.filter((x) => !isNaN(parseInt(x.Length))).map((x) => {
|
|
192
193
|
const position = (() => {
|
|
193
194
|
const dayIndex = daysToIndex[x.DayOfWeek];
|
|
194
195
|
if (dayIndex == null) {
|
|
@@ -206,12 +207,29 @@ const schedules = (input, options = {}) => {
|
|
|
206
207
|
const periodName = options.createPeriodsFrom ? x[options.createPeriodsFrom] : x.Period;
|
|
207
208
|
const periodId = periodMap.get(periodName);
|
|
208
209
|
const courseKey = `${x.Subject}.${x.Teacher}.${x.Group}`;
|
|
209
|
-
|
|
210
|
+
let courseId = courseMap.get(courseKey);
|
|
210
211
|
const inLocations = (x.Room ?? []).split(",").map((x$1) => locationMap.get(x$1.trim())).filter((x$1) => !!x$1);
|
|
211
|
-
|
|
212
|
+
let displayName = courseId ? void 0 : parentCourseMap.get(x.Course)?.FullText || subjectMap.get(x.Subject)?.FullText || x.Course || x.Subject;
|
|
212
213
|
const teachers$1 = courseId ? void 0 : x.Teacher?.split(",").map((x$1) => teacherMap.get(x$1.trim())).filter((x$1) => !!x$1).map((to) => ({ to }));
|
|
213
214
|
const groups$1 = courseId ? void 0 : x.Group?.split(",").map((x$1) => groupMap.get(x$1.trim())).filter((x$1) => !!x$1).map((to) => ({ to }));
|
|
214
215
|
const duration = x.Length ? parseInt(x.Length) : void 0;
|
|
216
|
+
if (!courseId && options.includeEventsMissingCourse) {
|
|
217
|
+
courseId = v4();
|
|
218
|
+
const subject = subjectMap.get(x.Subject);
|
|
219
|
+
const subjectName = subject?.FullText || x.Subject;
|
|
220
|
+
displayName = displayName || subject?.FullText || x.Subject;
|
|
221
|
+
const newCourse = {
|
|
222
|
+
ids: courseId,
|
|
223
|
+
displayName,
|
|
224
|
+
subject: subjectName,
|
|
225
|
+
teachers: teachers$1,
|
|
226
|
+
groups: groups$1
|
|
227
|
+
};
|
|
228
|
+
courses?.push(newCourse);
|
|
229
|
+
} else if (!courseId) {
|
|
230
|
+
lessonMissingCourseWarningsCount += 1;
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
215
233
|
return {
|
|
216
234
|
ids: extractId(x.GUID),
|
|
217
235
|
displayName,
|
|
@@ -220,35 +238,23 @@ const schedules = (input, options = {}) => {
|
|
|
220
238
|
preferredDuration: duration ?? 0,
|
|
221
239
|
course: courseId,
|
|
222
240
|
period: periodId,
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
241
|
+
inLocations,
|
|
242
|
+
...!options.includeEventsMissingCourse ? {
|
|
243
|
+
teachers: teachers$1,
|
|
244
|
+
groups: groups$1
|
|
245
|
+
} : void 0
|
|
226
246
|
};
|
|
227
|
-
});
|
|
247
|
+
}).filter((x) => x != null);
|
|
228
248
|
const periods = tables.Period?.map((x) => parsePeriod(x, scheduleStart, warnings)).filter((x) => x.ranges.length > 0);
|
|
229
249
|
periodsFromWeekRanges.forEach((x) => {
|
|
230
250
|
const ids = periodMap.get(x);
|
|
231
251
|
if (!ids) throw new Error(`Unable to find period for ${x}`);
|
|
232
252
|
periods?.push(fromWeekNumberRange(ids, x, scheduleStart));
|
|
233
253
|
});
|
|
234
|
-
if (
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
ids: courseId,
|
|
238
|
-
displayName: event.displayName
|
|
239
|
-
});
|
|
240
|
-
event.course = courseId;
|
|
241
|
-
delete event.displayName;
|
|
254
|
+
if (lessonMissingCourseWarningsCount > 0 && !options.includeEventsMissingCourse) warnings.unshift({
|
|
255
|
+
code: "ignoring_lessons_missing_course",
|
|
256
|
+
context: { count: lessonMissingCourseWarningsCount }
|
|
242
257
|
});
|
|
243
|
-
else {
|
|
244
|
-
const numEventsPrior = events?.length ?? 0;
|
|
245
|
-
events = events?.filter((x) => x.course);
|
|
246
|
-
const diff = numEventsPrior - (events?.length ?? 0);
|
|
247
|
-
if (diff) warnings.unshift({
|
|
248
|
-
code: "ignoring_lessons_missing_course",
|
|
249
|
-
context: { count: diff }
|
|
250
|
-
});
|
|
251
|
-
}
|
|
252
258
|
return {
|
|
253
259
|
settings,
|
|
254
260
|
periods: periods ?? [],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schedules.js","names":["warnings: Warning[]","settings: OutTypes.settings","x","uuidv4","teachers","groups","getDate"],"sources":["../../../../src/Skola24/txt/from/schedules.ts"],"sourcesContent":["import Papa from 'papaparse';\nimport { v4 as uuidv4 } from 'uuid'; // as we cannot use crypto's randomUUID in browser\nimport moment from 'moment';\nimport getDate from '../../../common/get-date';\nimport type { CoreTypes } from '../../../core';\nimport type { Data, Options, Types as Skola24Types, Warning } from '../types';\nimport { extractId } from './util';\nimport { fromWeekNumberRange, parsePeriod } from './period';\nimport { parseCalendarExceptions } from './calendar-exceptions';\nimport { extractStartAndEnd } from './division';\n\n\nconst daysToIndex = {\n 'Måndag': 0,\n 'Tisdag': 1,\n 'Onsdag': 2,\n 'Torsdag': 3,\n 'Fredag': 4,\n 'Lördag': 5,\n 'Söndag': 6,\n\n // and if ÅÄÖ is loaded correctly\n 'M�ndag': 0,\n 'L�rdag': 5,\n 'S�ndag': 6,\n} as Record<string, number | undefined>;\n\n\nfunction transformHeader (header: string) {\n return header.split(/[^a-zA-Z]+/g)[0];\n}\nconst parseConfig = {\n quotes: false, //or array of booleans\n quoteChar: '\"',\n escapeChar: '\"',\n delimiter: '\\t',\n header: true,\n // newline: \"\\r\\n\",\n skipEmptyLines: false, //other option is 'greedy', meaning skip delimiters, quotes, and whitespace.\n} as Papa.ParseConfig;\n\n\nfunction extractTables (input: string, warnings: Warning[]) {\n // split at [Tables] to get meta section and table section\n const split = input.split('[Tables]');\n const tables = split.at(1);\n if (!tables) throw new Error('Unable to extract tables from input');\n\n ////\n //// Capture the TABLE NAME and the TABLE CONTENT using regex\n ////\n //// TABLE NAME\n //// [Rows]\n //// TABLE CONTENT\n ////\n const regex = /([^\\r\\n]+)(?:\\r\\n|\\r|\\n)\\[Rows\\](?:\\r\\n|\\r|\\n)((?:[^\\r\\n].+(?:(?:\\r\\n|\\r|\\n)|$))*)/gm;\n const matches = [...tables.trim().matchAll(regex)];\n\n return matches\n .map(x => {\n // extract only the true table name \"<table name> (<number>)\", i.e., ignore the brackets and the preceding space\n const tableName = x.at(1)\n ?.trim()\n .match(/(.*?)(?:\\s*\\(\\d+\\))$/m)\n ?.at(1);\n if (!tableName) return;\n\n const tableContent = x.at(2)?.trim();\n if (!tableContent) return;\n const parsed = Papa.parse(tableContent, { ...parseConfig, transformHeader });\n return {\n tableName: tableName as keyof Data,\n parsed: parsed.data\n };\n })\n .filter((x): x is NonNullable<typeof x> => x != null)\n .reduce<Data>((acc, { tableName, parsed }) => {\n acc[tableName] = parsed;\n return acc;\n }, {} as Data);\n}\n\n\nfunction parseColor (colorValue: string | undefined) {\n if (colorValue == null) return;\n\n const integerValue = parseInt(colorValue);\n if (isNaN(integerValue)) return;\n\n // convert to decimal string\n const hex = integerValue.toString(16);\n\n // ensure its a valid color\n if (!/^(?:[0-9a-fA-F]{3}){1,2}$/.test(hex)) return;\n return `#${ hex }`;\n}\n\n\nexport namespace OutTypes {\n export type settings = CoreTypes.SerializedWithOptionalId.Settings;\n export type teacher = CoreTypes.SerializedWithOptionalId.Teacher;\n export type person = CoreTypes.SerializedWithOptionalId.Person;\n export type group = CoreTypes.SerializedWithOptionalId.Group;\n export type course = CoreTypes.SerializedWithOptionalId.Course;\n export type location = CoreTypes.SerializedWithOptionalId.Location;\n export type event = CoreTypes.SerializedWithOptionalId.Event;\n export type period = CoreTypes.SerializedWithOptionalId.Period;\n}\n\ntype Out = {\n settings: OutTypes.settings;\n periods: OutTypes.period [];\n teachers: OutTypes.teacher [];\n persons: OutTypes.person [];\n groups: OutTypes.group [];\n locations: OutTypes.location[];\n courses: OutTypes.course [];\n events: OutTypes.event [];\n meta?: {\n warnings: Warning[]\n };\n};\n\n\nexport const schedules = (\n input: string,\n options: Options = {}\n): Out => {\n const warnings: Warning[] = [];\n\n const tables = extractTables(input, warnings);\n\n const _scheduleRange = extractStartAndEnd(input); // need whole input file\n if (!_scheduleRange) throw new Error('Unable to extract schedule range');\n\n const scheduleStart = moment.utc(_scheduleRange.start);\n const startYear = scheduleStart.year();\n\n const settings: OutTypes.settings = {\n discretization: 5,\n numDays: 5,\n dayStart: '8:00',\n potentialCenter: '12:00',\n dayEnd: '17:00',\n calendarExceptions: parseCalendarExceptions(tables.PeriodGeneral?.at(0), startYear, warnings)\n };\n\n\n // Map to core structure\n const teachers = tables.Teacher\n ?.map((x): OutTypes.teacher => ({\n ids: extractId(x.GUID),\n signature: x.Teacher,\n displayName: `${x.FirstName} ${x.LastName}`,\n ...x.Category && {\n tags: [\n {\n type: 'category',\n value: x.Category\n }\n ]\n },\n person: `teacher.${ extractId(x.GUID) }`\n }));\n const teacherPersons = tables.Teacher\n ?.map((x): OutTypes.person => ({\n ids: `teacher.${ extractId(x.GUID) }`,\n firstName: x.FirstName,\n lastName: x.LastName,\n ...x.PersonalCode && {\n SSN: {\n value: x.PersonalCode,\n }\n },\n ...x.EMail && {\n emails: [{\n value: x.EMail,\n type: 'organization'\n }]\n },\n ...x.Phone && {\n phoneNumbers: [\n {\n value: x.Phone,\n type: 'organization'\n }\n ]\n }\n }));\n\n const studentMap = new Map<string, string>();\n // create map of student SSN to student GUID\n tables.Student?.forEach(x => {\n const id = extractId(x.GUID);\n if (id) studentMap.set(x.Student, id);\n });\n\n const students = tables.Student?.map((x): OutTypes.person => ({\n ids: extractId(x.GUID),\n firstName: x.FirstName,\n lastName: x.LastName,\n type: 'Student',\n ...x.Student && {\n SSN: {\n value: x.Student,\n }\n },\n ...x.EMail && {\n emails: [{\n value: x.EMail,\n type: 'organization'\n }]\n }\n }));\n\n const groups = tables.Group?.map((x): OutTypes.group => ({\n ids: extractId(x.GUID),\n displayName: x.Group,\n ...(x.Class == '1') && { species: 'class' },\n members: x.Student?.split(',').map(x => studentMap.get(x)).filter(x => x != null) ?? []\n }));\n\n const periodMap = new Map<string, string>();\n const periodsFromWeekRanges = new Set<string>();\n if (tables.Period) {\n tables.Period.forEach(period => {\n const id = extractId(period.GUID);\n if (id) periodMap.set(period.Period, id);\n });\n\n // create additional periods corresponding to the lessons' week/actual weeks\n const _createPeriodsFrom = options.createPeriodsFrom;\n if (_createPeriodsFrom) {\n tables.Lesson?.forEach(x => {\n const key = x[_createPeriodsFrom];\n if (key) periodsFromWeekRanges.add(key);\n });\n periodsFromWeekRanges.forEach(x => periodMap.set(x, uuidv4()));\n }\n }\n\n const teacherMap = new Map<string, string>();\n if (tables.Teacher) {\n tables.Teacher.forEach(teacher => {\n const id = extractId(teacher.GUID);\n if (id) teacherMap.set(teacher.Teacher, id);\n });\n }\n\n const groupMap = new Map<string, string>();\n if (tables.Group) {\n tables.Group.forEach(group => {\n const id = extractId(group.GUID);\n if (id) groupMap.set(group.Group, id);\n });\n }\n\n const locationMap = new Map<string, string>();\n if (tables.Room) {\n tables.Room.forEach(room => {\n const id = extractId(room.GUID);\n if (id) locationMap.set(room.Room, id);\n });\n }\n\n // subject contains BackgroundColor(decimal) and FullText\n const subjectMap = new Map<string, Skola24Types.subject>();\n if (tables.Subject) {\n tables.Subject.forEach(subject => {\n subjectMap.set(subject.Subject, subject);\n });\n }\n\n // Course can contain FullText and Subject\n const parentCourseMap = new Map<string, Skola24Types.course>();\n if (tables.Course) {\n tables.Course.forEach(course => {\n parentCourseMap.set(course.Course, course);\n });\n }\n\n const courseMap = new Map<string, string | undefined>();\n const courses = tables.TA?.map((x): OutTypes.course => {\n const color = parseColor(subjectMap.get(x.Subject)?.BackgroundColor);\n\n // Course name is most specific (eg Administration 1), then subject name (Administration), then course code (eg ADMADM01), then subject code (eg ADM)\n const displayName = parentCourseMap.get(x.Course)?.FullText || subjectMap.get(x.Subject)?.FullText || x.Course || x.Subject;\n\n const teachers = (x.Teacher ?? [])\n .split(',')\n .map(x => teacherMap.get(x.trim()))\n .filter((x): x is NonNullable<typeof x> => !!x)\n .map(to => ({ to }));\n const groups = (x.Group ?? [])\n .split(',')\n .map(x => groupMap.get(x.trim()))\n .filter((x): x is NonNullable<typeof x> => !!x)\n .map(to => ({ to }));\n\n return {\n ids: x.GUID ? extractId(x.GUID) : uuidv4(),\n displayName: displayName,\n color: color,\n subject: x.Subject || parentCourseMap.get(x.Course)?.Subject,\n teachers: teachers,\n groups: groups,\n plannedDuration: x.TotalHours ? `${x.TotalHours} hrs` : (x.Weektime ? `${x.Weektime} min/week` : undefined),\n ...x.Period && { period: periodMap.get(x.Period) },\n } satisfies OutTypes.course;\n });\n\n tables.TA?.forEach(x => {\n courseMap.set(`${x.Subject}.${x.Teacher}.${x.Group}`, x.GUID ? extractId(x.GUID) : undefined);\n });\n\n const locations = tables.Room?.map((x): OutTypes.location => ({\n ids: extractId(x.GUID),\n displayName: x.Room,\n maximumCapacity: x.SeatingCapacity ? parseInt(x.SeatingCapacity) : undefined,\n ...x.Category?.length && {\n tags: [\n {\n type: 'category',\n value: x.Category\n }\n ]\n }\n }));\n\n let events = tables.Lesson\n ?.filter(x => !isNaN(parseInt(x.Length)))\n .map(x => {\n\n const position = (() => {\n const dayIndex = daysToIndex[x.DayOfWeek];\n\n if (dayIndex == null) {\n warnings.push({ code: 'lesson.invalid_day', context: x } satisfies Warning);\n return;\n }\n\n return {\n start: getDate(dayIndex, x.Starttime),\n end: getDate(dayIndex, x.Starttime).add(x.Length, 'minutes'),\n };\n })();\n\n const periodName = options.createPeriodsFrom ? x[options.createPeriodsFrom] : x.Period;\n const periodId = periodMap.get(periodName);\n\n const courseKey = `${x.Subject}.${x.Teacher}.${x.Group}`;\n const courseId = courseMap.get(courseKey);\n\n const inLocations = (x.Room ?? [])\n .split(',')\n .map(x => locationMap.get(x.trim()))\n .filter((x): x is NonNullable<typeof x> => !!x);\n\n // if there is a connected course use its display name\n const displayName = courseId\n ? undefined\n : parentCourseMap.get(x.Course)?.FullText || subjectMap.get(x.Subject)?.FullText || x.Course || x.Subject;\n\n // if there is a connected course use its teachers\n const teachers = courseId\n ? undefined\n : x.Teacher\n ?.split(',')\n .map(x => teacherMap.get(x.trim()))\n .filter((x): x is NonNullable<typeof x> => !!x)\n .map(to => ({ to }));\n\n // if there is a connected course use its groups\n const groups = courseId\n ? undefined\n : x.Group\n ?.split(',')\n .map(x => groupMap.get(x.trim()))\n .filter((x): x is NonNullable<typeof x> => !!x)\n .map(to => ({ to }));\n\n const duration = x.Length ? parseInt(x.Length) : undefined;\n\n return {\n ids: extractId(x.GUID),\n displayName: displayName,\n ...position,\n duration: duration,\n preferredDuration: duration ?? 0,\n course: courseId,\n period: periodId,\n teachers, groups, inLocations\n } satisfies OutTypes.event;\n });\n\n const periods = tables.Period\n ?.map(x => parsePeriod(x, scheduleStart, warnings))\n .filter(x => x.ranges.length > 0);\n\n periodsFromWeekRanges.forEach(x => {\n const ids = periodMap.get(x);\n if (!ids) {\n throw new Error(`Unable to find period for ${x}`);\n return;\n }\n periods?.push(fromWeekNumberRange(ids, x, scheduleStart));\n });\n\n // handle events without a course\n if (options.includeEventsMissingCourse) {\n // create a dummy course for each event without a course\n events?.filter(x => !x.course)\n .forEach(event => {\n // create a dummy course\n const courseId = uuidv4();\n courses?.push({\n ids: courseId,\n displayName: event.displayName\n } satisfies OutTypes.course);\n\n // assign the course to the event and remove its display name\n event.course = courseId;\n delete event.displayName;\n });\n\n } else {\n // remove all events without a course\n const numEventsPrior = events?.length ?? 0;\n events = events?.filter(x => x.course);\n const diff = numEventsPrior - (events?.length ?? 0);\n if (diff) {\n warnings.unshift({\n code: 'ignoring_lessons_missing_course',\n context: { count: diff }\n } satisfies Warning);\n }\n }\n\n\n return {\n settings,\n periods: periods ?? [],\n teachers: teachers ?? [],\n persons: (students ?? []).concat(teacherPersons ?? []),\n groups: groups ?? [],\n locations: locations ?? [],\n courses: courses ?? [],\n events: events ?? [],\n\n meta: { warnings }\n } satisfies Out;\n};"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"schedules.js","names":["warnings: Warning[]","settings: OutTypes.settings","x","uuidv4","teachers","groups","getDate","newCourse: OutTypes.course"],"sources":["../../../../src/Skola24/txt/from/schedules.ts"],"sourcesContent":["import Papa from 'papaparse';\nimport { v4 as uuidv4 } from 'uuid'; // as we cannot use crypto's randomUUID in browser\nimport moment from 'moment';\nimport getDate from '../../../common/get-date';\nimport type { CoreTypes } from '../../../core';\nimport type { Data, Options, Types as Skola24Types, Warning } from '../types';\nimport { extractId } from './util';\nimport { fromWeekNumberRange, parsePeriod } from './period';\nimport { parseCalendarExceptions } from './calendar-exceptions';\nimport { extractStartAndEnd } from './division';\n\n\nconst daysToIndex = {\n 'Måndag': 0,\n 'Tisdag': 1,\n 'Onsdag': 2,\n 'Torsdag': 3,\n 'Fredag': 4,\n 'Lördag': 5,\n 'Söndag': 6,\n\n // and if ÅÄÖ is loaded correctly\n 'M�ndag': 0,\n 'L�rdag': 5,\n 'S�ndag': 6,\n} as Record<string, number | undefined>;\n\n\nfunction transformHeader (header: string) {\n return header.split(/[^a-zA-Z]+/g)[0];\n}\nconst parseConfig = {\n quotes: false, //or array of booleans\n quoteChar: '\"',\n escapeChar: '\"',\n delimiter: '\\t',\n header: true,\n // newline: \"\\r\\n\",\n skipEmptyLines: false, //other option is 'greedy', meaning skip delimiters, quotes, and whitespace.\n} as Papa.ParseConfig;\n\n\nfunction extractTables (input: string, warnings: Warning[]) {\n // split at [Tables] to get meta section and table section\n const split = input.split('[Tables]');\n const tables = split.at(1);\n if (!tables) throw new Error('Unable to extract tables from input');\n\n ////\n //// Capture the TABLE NAME and the TABLE CONTENT using regex\n ////\n //// TABLE NAME\n //// [Rows]\n //// TABLE CONTENT\n ////\n const regex = /([^\\r\\n]+)(?:\\r\\n|\\r|\\n)\\[Rows\\](?:\\r\\n|\\r|\\n)((?:[^\\r\\n].+(?:(?:\\r\\n|\\r|\\n)|$))*)/gm;\n const matches = [...tables.trim().matchAll(regex)];\n\n return matches\n .map(x => {\n // extract only the true table name \"<table name> (<number>)\", i.e., ignore the brackets and the preceding space\n const tableName = x.at(1)\n ?.trim()\n .match(/(.*?)(?:\\s*\\(\\d+\\))$/m)\n ?.at(1);\n if (!tableName) return;\n\n const tableContent = x.at(2)?.trim();\n if (!tableContent) return;\n const parsed = Papa.parse(tableContent, { ...parseConfig, transformHeader });\n return {\n tableName: tableName as keyof Data,\n parsed: parsed.data\n };\n })\n .filter((x): x is NonNullable<typeof x> => x != null)\n .reduce<Data>((acc, { tableName, parsed }) => {\n acc[tableName] = parsed;\n return acc;\n }, {} as Data);\n}\n\n\nfunction parseColor (colorValue: string | undefined) {\n if (colorValue == null) return;\n\n const integerValue = parseInt(colorValue);\n if (isNaN(integerValue)) return;\n\n // convert to decimal string\n const hex = integerValue.toString(16);\n\n // ensure its a valid color\n if (!/^(?:[0-9a-fA-F]{3}){1,2}$/.test(hex)) return;\n return `#${ hex }`;\n}\n\n\nexport namespace OutTypes {\n export type settings = CoreTypes.SerializedWithOptionalId.Settings;\n export type teacher = CoreTypes.SerializedWithOptionalId.Teacher;\n export type person = CoreTypes.SerializedWithOptionalId.Person;\n export type group = CoreTypes.SerializedWithOptionalId.Group;\n export type course = CoreTypes.SerializedWithOptionalId.Course;\n export type location = CoreTypes.SerializedWithOptionalId.Location;\n export type event = CoreTypes.SerializedWithOptionalId.Event;\n export type period = CoreTypes.SerializedWithOptionalId.Period;\n}\n\ntype Out = {\n settings: OutTypes.settings;\n periods: OutTypes.period [];\n teachers: OutTypes.teacher [];\n persons: OutTypes.person [];\n groups: OutTypes.group [];\n locations: OutTypes.location[];\n courses: OutTypes.course [];\n events: OutTypes.event [];\n meta?: {\n warnings: Warning[]\n };\n};\n\n\nexport const schedules = (\n input: string,\n options: Options = {}\n): Out => {\n const warnings: Warning[] = [];\n\n const tables = extractTables(input, warnings);\n\n const _scheduleRange = extractStartAndEnd(input); // need whole input file\n if (!_scheduleRange) throw new Error('Unable to extract schedule range');\n\n const scheduleStart = moment.utc(_scheduleRange.start);\n const startYear = scheduleStart.year();\n\n const settings: OutTypes.settings = {\n discretization: 5,\n numDays: 5,\n dayStart: '8:00',\n potentialCenter: '12:00',\n dayEnd: '17:00',\n calendarExceptions: parseCalendarExceptions(tables.PeriodGeneral?.at(0), startYear, warnings)\n };\n\n\n // Map to core structure\n const teachers = tables.Teacher\n ?.map((x): OutTypes.teacher => ({\n ids: extractId(x.GUID),\n signature: x.Teacher,\n displayName: `${x.FirstName} ${x.LastName}`,\n ...x.Category && {\n tags: [\n {\n type: 'category',\n value: x.Category\n }\n ]\n },\n person: `teacher.${ extractId(x.GUID) }`\n }));\n const teacherPersons = tables.Teacher\n // Filter out where either of firstname, lastname i missing, else it gives invalid persons\n ?.filter(x => x.FirstName && x.LastName)\n ?.map((x): OutTypes.person => ({\n ids: `teacher.${ extractId(x.GUID) }`,\n firstName: x.FirstName,\n lastName: x.LastName,\n ...x.PersonalCode && {\n SSN: {\n value: x.PersonalCode,\n }\n },\n ...x.EMail && {\n emails: [{\n value: x.EMail,\n type: 'organization'\n }]\n },\n ...x.Phone && {\n phoneNumbers: [\n {\n value: x.Phone,\n type: 'organization'\n }\n ]\n }\n }));\n\n const studentMap = new Map<string, string>();\n // create map of student SSN to student GUID\n tables.Student?.forEach(x => {\n const id = extractId(x.GUID);\n if (id) studentMap.set(x.Student, id);\n });\n\n const students = tables.Student?.map((x): OutTypes.person => ({\n ids: extractId(x.GUID),\n firstName: x.FirstName,\n lastName: x.LastName,\n type: 'Student',\n ...x.Student && {\n SSN: {\n value: x.Student,\n }\n },\n ...x.EMail && {\n emails: [{\n value: x.EMail,\n type: 'organization'\n }]\n }\n }));\n\n const groups = tables.Group?.map((x): OutTypes.group => ({\n ids: extractId(x.GUID),\n displayName: x.Group,\n ...(x.Class == '1') && { species: 'class' },\n members: x.Student?.split(',').map(x => studentMap.get(x)).filter(x => x != null) ?? []\n }));\n\n const periodMap = new Map<string, string>();\n const periodsFromWeekRanges = new Set<string>();\n if (tables.Period) {\n tables.Period.forEach(period => {\n const id = extractId(period.GUID);\n if (id) periodMap.set(period.Period, id);\n });\n\n // create additional periods corresponding to the lessons' week/actual weeks\n const _createPeriodsFrom = options.createPeriodsFrom;\n if (_createPeriodsFrom) {\n tables.Lesson?.forEach(x => {\n const key = x[_createPeriodsFrom];\n if (key) periodsFromWeekRanges.add(key);\n });\n periodsFromWeekRanges.forEach(x => periodMap.set(x, uuidv4()));\n }\n }\n\n const teacherMap = new Map<string, string>();\n if (tables.Teacher) {\n tables.Teacher.forEach(teacher => {\n const id = extractId(teacher.GUID);\n if (id) teacherMap.set(teacher.Teacher, id);\n });\n }\n\n const groupMap = new Map<string, string>();\n if (tables.Group) {\n tables.Group.forEach(group => {\n const id = extractId(group.GUID);\n if (id) groupMap.set(group.Group, id);\n });\n }\n\n const locationMap = new Map<string, string>();\n if (tables.Room) {\n tables.Room.forEach(room => {\n const id = extractId(room.GUID);\n if (id) locationMap.set(room.Room, id);\n });\n }\n\n // subject contains BackgroundColor(decimal) and FullText\n const subjectMap = new Map<string, Skola24Types.subject>();\n if (tables.Subject) {\n tables.Subject.forEach(subject => {\n subjectMap.set(subject.Subject, subject);\n });\n }\n\n // Course can contain FullText and Subject\n const parentCourseMap = new Map<string, Skola24Types.course>();\n if (tables.Course) {\n tables.Course.forEach(course => {\n parentCourseMap.set(course.Course, course);\n });\n }\n\n const courseMap = new Map<string, string | undefined>();\n const courses = tables.TA?.map((x): OutTypes.course => {\n const color = parseColor(subjectMap.get(x.Subject)?.BackgroundColor);\n\n // Course name is most specific (eg Administration 1), then subject name (Administration), then course code (eg ADMADM01), then subject code (eg ADM)\n const displayName = parentCourseMap.get(x.Course)?.FullText || subjectMap.get(x.Subject)?.FullText || x.Course || x.Subject;\n\n const teachers = (x.Teacher ?? [])\n .split(',')\n .map(x => teacherMap.get(x.trim()))\n .filter((x): x is NonNullable<typeof x> => !!x)\n .map(to => ({ to }));\n const groups = (x.Group ?? [])\n .split(',')\n .map(x => groupMap.get(x.trim()))\n .filter((x): x is NonNullable<typeof x> => !!x)\n .map(to => ({ to }));\n\n return {\n ids: x.GUID ? extractId(x.GUID) : uuidv4(),\n displayName: displayName,\n color: color,\n subject: x.Subject || parentCourseMap.get(x.Course)?.Subject,\n teachers: teachers,\n groups: groups,\n plannedDuration: x.TotalHours ? `${x.TotalHours} hrs` : (x.Weektime ? `${x.Weektime} min/week` : undefined),\n ...x.Period && { period: periodMap.get(x.Period) },\n } satisfies OutTypes.course;\n }) ?? [];\n\n tables.TA?.forEach(x => {\n courseMap.set(`${x.Subject}.${x.Teacher}.${x.Group}`, x.GUID ? extractId(x.GUID) : undefined);\n });\n\n const locations = tables.Room?.map((x): OutTypes.location => ({\n ids: extractId(x.GUID),\n displayName: x.Room,\n maximumCapacity: x.SeatingCapacity ? parseInt(x.SeatingCapacity) : undefined,\n ...x.Category?.length && {\n tags: [\n {\n type: 'category',\n value: x.Category\n }\n ]\n }\n }));\n\n let lessonMissingCourseWarningsCount = 0;\n\n const events = tables.Lesson\n ?.filter(x => !isNaN(parseInt(x.Length)))\n .map(x => {\n\n const position = (() => {\n const dayIndex = daysToIndex[x.DayOfWeek];\n\n if (dayIndex == null) {\n warnings.push({ code: 'lesson.invalid_day', context: x } satisfies Warning);\n return;\n }\n\n return {\n start: getDate(dayIndex, x.Starttime),\n end: getDate(dayIndex, x.Starttime).add(x.Length, 'minutes'),\n };\n })();\n\n const periodName = options.createPeriodsFrom ? x[options.createPeriodsFrom] : x.Period;\n const periodId = periodMap.get(periodName);\n\n const courseKey = `${x.Subject}.${x.Teacher}.${x.Group}`;\n let courseId = courseMap.get(courseKey);\n\n const inLocations = (x.Room ?? [])\n .split(',')\n .map(x => locationMap.get(x.trim()))\n .filter((x): x is NonNullable<typeof x> => !!x);\n\n // if there is a connected course use its display name\n let displayName = courseId\n ? undefined\n : parentCourseMap.get(x.Course)?.FullText || subjectMap.get(x.Subject)?.FullText || x.Course || x.Subject;\n\n // if there is a connected course use its teachers\n const teachers = courseId\n ? undefined\n : x.Teacher\n ?.split(',')\n .map(x => teacherMap.get(x.trim()))\n .filter((x): x is NonNullable<typeof x> => !!x)\n .map(to => ({ to }));\n\n // if there is a connected course use its groups\n const groups = courseId\n ? undefined\n : x.Group\n ?.split(',')\n .map(x => groupMap.get(x.trim()))\n .filter((x): x is NonNullable<typeof x> => !!x)\n .map(to => ({ to }));\n\n const duration = x.Length ? parseInt(x.Length) : undefined;\n\n // If no courseId found, we handle it according to options.includeEventsMissingCourse\n if (!courseId && options.includeEventsMissingCourse) {\n // Create a new course for this event\n courseId = uuidv4();\n const subject = subjectMap.get(x.Subject);\n const subjectName = subject?.FullText || x.Subject;\n displayName = displayName || subject?.FullText || x.Subject;\n const newCourse: OutTypes.course = {\n ids: courseId,\n displayName: displayName,\n subject: subjectName,\n teachers: teachers,\n groups: groups,\n };\n courses?.push(newCourse);\n } else if (!courseId) {\n lessonMissingCourseWarningsCount += 1;\n return null; // will be filtered out later\n }\n\n return {\n ids: extractId(x.GUID),\n displayName: displayName,\n ...position,\n duration: duration,\n preferredDuration: duration ?? 0,\n course: courseId,\n period: periodId,\n inLocations,\n ...(!options.includeEventsMissingCourse ? { teachers, groups } : undefined),\n } satisfies OutTypes.event;\n }).filter((x): x is NonNullable<typeof x> => x != null);\n\n const periods = tables.Period\n ?.map(x => parsePeriod(x, scheduleStart, warnings))\n .filter(x => x.ranges.length > 0);\n\n periodsFromWeekRanges.forEach(x => {\n const ids = periodMap.get(x);\n if (!ids) {\n throw new Error(`Unable to find period for ${x}`);\n return;\n }\n periods?.push(fromWeekNumberRange(ids, x, scheduleStart));\n });\n\n if (lessonMissingCourseWarningsCount > 0 && !options.includeEventsMissingCourse) {\n warnings.unshift({\n code: 'ignoring_lessons_missing_course',\n context: { count: lessonMissingCourseWarningsCount }\n } satisfies Warning);\n }\n\n return {\n settings,\n periods: periods ?? [],\n teachers: teachers ?? [],\n persons: (students ?? []).concat(teacherPersons ?? []),\n groups: groups ?? [],\n locations: locations ?? [],\n courses: courses ?? [],\n events: events ?? [],\n\n meta: { warnings }\n } satisfies Out;\n};"],"mappings":"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"}
|
|
@@ -11,11 +11,12 @@ import root_intervals_default from "./root-intervals.js";
|
|
|
11
11
|
import events_default from "./events.js";
|
|
12
12
|
import syllabuses_default from "./syllabuses.js";
|
|
13
13
|
import configurations_default from "./configurations.js";
|
|
14
|
+
import settings_default from "./settings.js";
|
|
14
15
|
|
|
15
16
|
//#region src/core/from/schedules.ts
|
|
16
17
|
function schedules_default(schedule) {
|
|
17
18
|
return {
|
|
18
|
-
...schedule.settings && { settings: schedule.settings },
|
|
19
|
+
...schedule.settings && { settings: settings_default(schedule.settings) },
|
|
19
20
|
...schedule.periods && { periods: periods_default(schedule.periods) },
|
|
20
21
|
...schedule.groups && { groups: groups_default(schedule.groups) },
|
|
21
22
|
...schedule.teachers && { teachers: teachers_default(schedule.teachers) },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schedules.js","names":["_periods","_groups","_teachers","_persons","_locations","_courses","_events","_overlapGroups","_lockedTimes","_rootIntervals","_exceptions","_syllabuses","_configurations"],"sources":["../../../src/core/from/schedules.ts"],"sourcesContent":["import _exceptions from './exceptions';\nimport _periods from './periods';\nimport _locations from './locations';\nimport _teachers from './teachers';\nimport _groups from './groups';\nimport _persons from './persons';\nimport _courses from './courses';\nimport _overlapGroups from './overlap-groups';\nimport _lockedTimes from './locked-times';\nimport _rootIntervals from './root-intervals';\nimport _events from './events';\nimport _syllabuses from './syllabuses';\nimport _configurations from './configurations';\nimport type transform from '../to/schedules';\n\nexport default function (schedule: ReturnType<typeof transform>): Omit<ReturnType<typeof transform>, 'meta'> {\n return {\n ...schedule.settings && { settings:
|
|
1
|
+
{"version":3,"file":"schedules.js","names":["_settings","_periods","_groups","_teachers","_persons","_locations","_courses","_events","_overlapGroups","_lockedTimes","_rootIntervals","_exceptions","_syllabuses","_configurations"],"sources":["../../../src/core/from/schedules.ts"],"sourcesContent":["import _exceptions from './exceptions';\nimport _periods from './periods';\nimport _locations from './locations';\nimport _teachers from './teachers';\nimport _groups from './groups';\nimport _persons from './persons';\nimport _courses from './courses';\nimport _overlapGroups from './overlap-groups';\nimport _lockedTimes from './locked-times';\nimport _rootIntervals from './root-intervals';\nimport _events from './events';\nimport _syllabuses from './syllabuses';\nimport _configurations from './configurations';\nimport _settings from './settings';\nimport type transform from '../to/schedules';\n\nexport default function (schedule: ReturnType<typeof transform>): Omit<ReturnType<typeof transform>, 'meta'> {\n return {\n ...schedule.settings && { settings: _settings (schedule.settings ) },\n ...schedule.periods && { periods: _periods (schedule.periods ) },\n ...schedule.groups && { groups: _groups (schedule.groups ) },\n ...schedule.teachers && { teachers: _teachers (schedule.teachers ) },\n ...schedule.persons && { persons: _persons (schedule.persons ) },\n ...schedule.locations && { locations: _locations (schedule.locations ) },\n ...schedule.courses && { courses: _courses (schedule.courses ) },\n ...schedule.events && { events: _events (schedule.events ) },\n ...schedule.overlapGroups && { overlapGroups: _overlapGroups (schedule.overlapGroups ) },\n ...schedule.lockedTimes && { lockedTimes: _lockedTimes (schedule.lockedTimes ) },\n ...schedule.rootIntervals && { rootIntervals: _rootIntervals (schedule.rootIntervals ) },\n ...schedule.exceptions && { exceptions: _exceptions (schedule.exceptions ) },\n ...schedule.syllabuses && { syllabuses: _syllabuses (schedule.syllabuses ) },\n ...schedule.configurations && { configurations: _configurations(schedule.configurations) }\n };\n}"],"mappings":";;;;;;;;;;;;;;;;AAgBA,2BAAyB,UAAoF;AAC3G,QAAO;EACL,GAAG,SAAS,YAAkB,EAAE,UAAgBA,iBAAgB,SAAS,SAAe,EAAE;EAC1F,GAAG,SAAS,WAAkB,EAAE,SAAgBC,gBAAgB,SAAS,QAAe,EAAE;EAC1F,GAAG,SAAS,UAAkB,EAAE,QAAgBC,eAAgB,SAAS,OAAe,EAAE;EAC1F,GAAG,SAAS,YAAkB,EAAE,UAAgBC,iBAAgB,SAAS,SAAe,EAAE;EAC1F,GAAG,SAAS,WAAkB,EAAE,SAAgBC,gBAAgB,SAAS,QAAe,EAAE;EAC1F,GAAG,SAAS,aAAkB,EAAE,WAAgBC,kBAAgB,SAAS,UAAe,EAAE;EAC1F,GAAG,SAAS,WAAkB,EAAE,SAAgBC,gBAAgB,SAAS,QAAe,EAAE;EAC1F,GAAG,SAAS,UAAkB,EAAE,QAAgBC,eAAgB,SAAS,OAAe,EAAE;EAC1F,GAAG,SAAS,iBAAkB,EAAE,eAAgBC,uBAAgB,SAAS,cAAe,EAAE;EAC1F,GAAG,SAAS,eAAkB,EAAE,aAAgBC,qBAAgB,SAAS,YAAe,EAAE;EAC1F,GAAG,SAAS,iBAAkB,EAAE,eAAgBC,uBAAgB,SAAS,cAAe,EAAE;EAC1F,GAAG,SAAS,cAAkB,EAAE,YAAgBC,mBAAgB,SAAS,WAAe,EAAE;EAC1F,GAAG,SAAS,cAAkB,EAAE,YAAgBC,mBAAgB,SAAS,WAAe,EAAE;EAC1F,GAAG,SAAS,kBAAkB,EAAE,gBAAgBC,uBAAgB,SAAS,eAAe,EAAE;EAC3F"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import moment from "moment";
|
|
2
|
+
|
|
3
|
+
//#region src/core/from/settings.ts
|
|
4
|
+
var settings_default = (settings) => {
|
|
5
|
+
settings.calendarExceptions = settings.calendarExceptions?.map((exception) => {
|
|
6
|
+
let start = moment.utc(exception.start);
|
|
7
|
+
if (start.hour() === 23 && start.minute() > 55) start = start.minute(55);
|
|
8
|
+
let end = moment.utc(exception.end);
|
|
9
|
+
if (end.hour() === 0 && end.minute() < 5) end = end.endOf("day");
|
|
10
|
+
return {
|
|
11
|
+
...exception,
|
|
12
|
+
start,
|
|
13
|
+
end
|
|
14
|
+
};
|
|
15
|
+
});
|
|
16
|
+
return settings;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
//#endregion
|
|
20
|
+
export { settings_default as default };
|
|
21
|
+
//# sourceMappingURL=settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.js","names":[],"sources":["../../../src/core/from/settings.ts"],"sourcesContent":["import moment from 'moment';\nimport type transform from '../to/settings';\n\nexport default (settings: ReturnType<typeof transform>) => {\n\n settings.calendarExceptions = settings.calendarExceptions?.map(exception => {\n // the start time should not be later than 23:55 of the specified date\n let start = moment.utc(exception.start);\n if (start.hour() === 23 && start.minute() > 55) start = start.minute(55);\n\n // the end time should not be before 00:05 of the specified date, in such a case set it to the end of day\n // (this has to do with backwards compatibility with older versions)\n let end = moment.utc(exception.end);\n if (end.hour() === 0 && end.minute() < 5) end = end.endOf('day');\n\n return { ...exception, start, end };\n });\n\n return settings;\n};\n"],"mappings":";;;AAGA,wBAAgB,aAA2C;AAEzD,UAAS,qBAAqB,SAAS,oBAAoB,KAAI,cAAa;EAE1E,IAAI,QAAQ,OAAO,IAAI,UAAU,MAAM;AACvC,MAAI,MAAM,MAAM,KAAK,MAAM,MAAM,QAAQ,GAAG,GAAI,SAAQ,MAAM,OAAO,GAAG;EAIxE,IAAI,MAAM,OAAO,IAAI,UAAU,IAAI;AACnC,MAAI,IAAI,MAAM,KAAK,KAAK,IAAI,QAAQ,GAAG,EAAG,OAAM,IAAI,MAAM,MAAM;AAEhE,SAAO;GAAE,GAAG;GAAW;GAAO;GAAK;GACnC;AAEF,QAAO"}
|
package/dist/core/interfaces/vertices/util/custom-vertex-export/assert-no-invalid-expand-keys.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Collection, Vertex } from "../vertex.js";
|
|
2
|
+
import { DeepNonNullable } from "../util.js";
|
|
3
|
+
import { ExpandKey } from "../common.js";
|
|
4
|
+
import { VertexQuery } from "../vertex-query/index.js";
|
|
5
|
+
import { Lookup } from "./util.js";
|
|
6
|
+
|
|
7
|
+
//#region src/core/interfaces/vertices/util/custom-vertex-export/assert-no-invalid-expand-keys.d.ts
|
|
8
|
+
type _AssertNoInvalidExpandKeys<Selected extends object, Available extends object> = { [K in keyof Selected]: K extends keyof Available ? Lookup<Selected[K], ExpandKey, false> extends infer a extends object ? Lookup<Available[K], ExpandKey, false> extends infer b extends object ? _AssertNoInvalidExpandKeys<a, b> : 'wtf!?' : never : `invalid expand key: ${K & string}` }[keyof Selected];
|
|
9
|
+
/**
|
|
10
|
+
* Recursively asserts that all keys in the 'expand' section of Q are valid.
|
|
11
|
+
* If any invalid keys are found, a descriptive string literal type is returned, otherwise `unknown` is returned.
|
|
12
|
+
*/
|
|
13
|
+
type AssertNoInvalidExpandKeys<V extends Vertex<Collection>, Q extends VertexQuery<V>> = ExpandKey & keyof Q extends never ? unknown : [_AssertNoInvalidExpandKeys<DeepNonNullable<Q>[ExpandKey], DeepNonNullable<VertexQuery<V>>[ExpandKey]>] extends [infer T] ? [T] extends [never] ? unknown : T : never;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { AssertNoInvalidExpandKeys };
|
|
16
|
+
//# sourceMappingURL=assert-no-invalid-expand-keys.d.ts.map
|
|
@@ -5,17 +5,19 @@ import { ExpandKey, OmitEdges, PickEdges } from "../common.js";
|
|
|
5
5
|
import { KeysOf } from "../keys-of.js";
|
|
6
6
|
import { VertexQuery } from "../vertex-query/index.js";
|
|
7
7
|
import { ExtractChildKeys, ExtractChildObject, ExtractParentKeys, IntersectExpandSelectPath, Lookup, RelaxedPick } from "./util.js";
|
|
8
|
+
import { AssertNoInvalidExpandKeys } from "./assert-no-invalid-expand-keys.js";
|
|
8
9
|
|
|
9
10
|
//#region src/core/interfaces/vertices/util/custom-vertex-export/index.d.ts
|
|
10
11
|
declare namespace HandleEdge {
|
|
11
|
-
type Recursion<V extends Vertex<Collection>, Query> = [Query] extends [never] ? string : Query extends VertexQuery<V> ?
|
|
12
|
+
type Recursion<V extends Vertex<Collection>, Query> = [Query] extends [never] ? string : Query extends VertexQuery<V> ? _CustomVertexExport<V, Query> : never;
|
|
12
13
|
export type Plain<E$1 extends EdgeBase<any, any>, Query> = E$1 extends Plain.Edge<infer V> ? Recursion<V, Query> : never;
|
|
13
14
|
export type Wrapped<E$1 extends EdgeBase<any, any>, Query> = E$1 extends Wrapped.Edge<infer K, infer V extends Vertex<Collection>, infer Extra extends object> ? Wrapped.Util.Value<K, Recursion<V, IntersectExpandSelectPath<Lookup<Query, K>, VertexQuery<V>>>, Extra> : never;
|
|
14
|
-
export type Coalesced<E$1 extends EdgeBase<any, any>, Query> = E$1 extends Coalesced.Edge<infer V, infer O
|
|
15
|
+
export type Coalesced<E$1 extends EdgeBase<any, any>, Query> = E$1 extends Coalesced.Edge<infer V, infer O, infer Extra extends object> ? V extends Vertex<Collection> ? Coalesced.Util.Value<Recursion<V, IntersectExpandSelectPath<Lookup<Query, Coalesced.Util.Keys.To>, VertexQuery<V>>>, Coalesced.Util.ToModel<V>, O, Extra> : never : never;
|
|
15
16
|
export type GroupWithExclude<E$1 extends EdgeBase<any, any>, Query> = E$1 extends GroupWithExclude.Edge<infer G extends Vertex<any>, infer P extends Vertex<any>, infer Extra extends object> ? GroupWithExclude.Util.Value<Recursion<G, IntersectExpandSelectPath<Lookup<Query, GroupWithExclude.Util.Keys.To>, VertexQuery<G>>>, Recursion<P, IntersectExpandSelectPath<Lookup<Query, GroupWithExclude.Util.Keys.Exclude>, VertexQuery<P>>>, Extra> : never;
|
|
16
17
|
export type AvailableLocation<E$1 extends EdgeBase<any, any>, Query> = E$1 extends AvailableLocation.Edge<infer L extends Vertex<any>, infer Extra extends object> ? AvailableLocation.Util.Value<Recursion<L, IntersectExpandSelectPath<Lookup<Query, AvailableLocation.Util.Keys.Locations>, VertexQuery<L>>>, Extra> : never;
|
|
17
18
|
export {};
|
|
18
19
|
}
|
|
20
|
+
type _CustomVertexExport<V extends Vertex<Collection>, Q extends VertexQuery<V>> = Prettify<{ [K in keyof OmitEdges<V> as K extends KeysOf<V, Q> ? K : never]: V[K] } & { [K in keyof PickEdges<V> as K extends ExtractParentKeys<KeysOf<V, Q>> ? K : never]: [V[K]] extends [never] ? never : NonNullable<V[K]> extends EdgeWrapper<infer M, infer E extends EdgeBase<any, any> | null | undefined> ? (SetMultiplicity<Prettify<E extends EdgeBase<any, any> ? (HandleEdge.Plain<E, Lookup<Q[ExpandKey], K>> | RelaxedPick<HandleEdge.Wrapped<E, ExtractChildObject<Q[ExpandKey], K>> | HandleEdge.Coalesced<E, ExtractChildObject<Q[ExpandKey], K>> | HandleEdge.GroupWithExclude<E, ExtractChildObject<Q[ExpandKey], K>> | HandleEdge.AvailableLocation<E, ExtractChildObject<Q[ExpandKey], K>>, ExtractChildKeys<KeysOf<V, Q>, K>>) : E>, M> | ExtractNullish<V[K]>) : never }>;
|
|
19
21
|
/**
|
|
20
22
|
* Recursively exports a Vertex type to a plain object structure,
|
|
21
23
|
* selecting and expanding properties and edges according to the provided expand/select path.
|
|
@@ -25,7 +27,7 @@ declare namespace HandleEdge {
|
|
|
25
27
|
* - Invalid or unsupported edge unions are filtered out as `never`.
|
|
26
28
|
* - Supports dot-notation for nested property selection and expansion.
|
|
27
29
|
*/
|
|
28
|
-
type CustomVertexExport<V extends Vertex<Collection>, Q extends VertexQuery<V>
|
|
30
|
+
type CustomVertexExport<V extends Vertex<Collection>, Q extends VertexQuery<V> & AssertNoInvalidExpandKeys<V, Q>> = _CustomVertexExport<V, Q>;
|
|
29
31
|
//#endregion
|
|
30
32
|
export { CustomVertexExport };
|
|
31
33
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DeepNonNullable } from "../util.js";
|
|
1
2
|
import { ExpandKey, SelectKey } from "../common.js";
|
|
2
3
|
|
|
3
4
|
//#region src/core/interfaces/vertices/util/custom-vertex-export/util.d.ts
|
|
@@ -5,7 +6,7 @@ import { ExpandKey, SelectKey } from "../common.js";
|
|
|
5
6
|
/**
|
|
6
7
|
* Lookup type that returns the value type for key K in object Obj,
|
|
7
8
|
*/
|
|
8
|
-
type Lookup<Obj, K$1> = K$1 extends keyof Obj ? Obj[K$1] :
|
|
9
|
+
type Lookup<Obj, K$1, ELSE = never> = K$1 extends keyof Obj ? Obj[K$1] : ELSE;
|
|
9
10
|
/**
|
|
10
11
|
* Intersect two expand/select specifications.
|
|
11
12
|
*
|
|
@@ -18,7 +19,8 @@ type Lookup<Obj, K$1> = K$1 extends keyof Obj ? Obj[K$1] : never;
|
|
|
18
19
|
* Useful to constrain a requested expand/select spec (A) by an allowed/spec (B),
|
|
19
20
|
* yielding only the common subset.
|
|
20
21
|
*/
|
|
21
|
-
type IntersectExpandSelectPath<A, B$1> =
|
|
22
|
+
type IntersectExpandSelectPath<A, B$1> = _IntersectExpandSelectPath<DeepNonNullable<A>, DeepNonNullable<B$1>>;
|
|
23
|
+
type _IntersectExpandSelectPath<A, B$1> = [A] extends [never] ? never : { [K in keyof A & keyof B$1]: K extends SelectKey ? A[K] extends (infer V1)[] ? B$1[K] extends (infer V2)[] ? (V1 & V2)[] | Extract<A[K], null | undefined> : never : never : K extends ExpandKey ? { [S in keyof A[K] & keyof B$1[K]]: A[K][S] extends object ? B$1[K][S] extends object ? IntersectExpandSelectPath<A[K][S], B$1[K][S]> : never : never } : never };
|
|
22
24
|
/**
|
|
23
25
|
* Extracts the parent keys from a set of dot-notation keys.
|
|
24
26
|
*
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Collection, PseudoCollection, RealCollection, Vertex, VertexFactory } from "./vertex.js";
|
|
2
2
|
import { AvailableLocation, Coalesced, EdgeWrapper, GroupWithExclude, Plain, Wrapped } from "./edges.js";
|
|
3
|
+
import { AssertNoInvalidExpandKeys } from "./custom-vertex-export/assert-no-invalid-expand-keys.js";
|
|
3
4
|
import { CustomVertexExport } from "./custom-vertex-export/index.js";
|
|
4
5
|
import { DeepVertexExport, MixedVertexExport, MixedWithOptionalIdVertexExport } from "./deep-vertex-export/index.js";
|
|
5
6
|
import { SerializedVertexExport } from "./serialized-vertex-export.js";
|
|
@@ -26,6 +26,10 @@ type MakeMixed<T$1> = MakeMixedNs.MakeMixed<T$1>;
|
|
|
26
26
|
* Deep partial type that allows for partial properties at any level of nesting.
|
|
27
27
|
*/
|
|
28
28
|
type DeepPartial<T$1> = T$1 extends Array<infer U> ? Array<DeepPartial<U>> : T$1 extends object ? { [K in keyof T$1]?: DeepPartial<T$1[K]> } : T$1;
|
|
29
|
+
/**
|
|
30
|
+
* A deep version of NonNullable<T> that recursively removes null and undefined from all properties and nested properties.
|
|
31
|
+
*/
|
|
32
|
+
type DeepNonNullable<T$1> = T$1 extends any ? T$1 extends ((...args: any[]) => any) ? T$1 : T$1 extends Array<infer U> ? Array<DeepNonNullable<NonNullable<U>>> : T$1 extends object ? { [K in keyof T$1]-?: DeepNonNullable<NonNullable<T$1[K]>> } : NonNullable<T$1> : never;
|
|
29
33
|
type _IsUnion<T$1, U$1 = T$1> = T$1 extends any ? [U$1] extends [T$1] ? false : true : never;
|
|
30
34
|
/**
|
|
31
35
|
* Lets a type pass if it is a union type, otherwise returns `never`.
|
|
@@ -72,5 +76,5 @@ type SetMultiplicity<T$1, M = EdgeMultiplicity> = M extends 'array' ? T$1[] : T$
|
|
|
72
76
|
*/
|
|
73
77
|
type ExtractNullish<T$1> = Extract<T$1, null | undefined>;
|
|
74
78
|
//#endregion
|
|
75
|
-
export { AllKeys, AllTrue, DeepPartial, ExtractNullish, IsUnion, MakeMixed, NoneIsUnion, Prettify, SetMultiplicity, Tail };
|
|
79
|
+
export { AllKeys, AllTrue, DeepNonNullable, DeepPartial, ExtractNullish, IsUnion, MakeMixed, NoneIsUnion, Prettify, SetMultiplicity, Tail };
|
|
76
80
|
//# sourceMappingURL=util.d.ts.map
|
|
@@ -11,7 +11,7 @@ declare namespace HandleEdge {
|
|
|
11
11
|
type Wrapped<E$1 extends EdgeBase<any, any>, D extends SupportedDepths> = E$1 extends Wrapped.Edge<infer K extends string, infer V extends Vertex<Collection>, object> ? ({
|
|
12
12
|
[FLATTEN_KEY]: true;
|
|
13
13
|
} & { [k in K]: V extends any ? _VertexQuery<V, D> : never }) : never;
|
|
14
|
-
type Coalesced<E$1 extends EdgeBase<any, any>, D extends SupportedDepths> = (E$1 extends Coalesced.Edge<infer V,
|
|
14
|
+
type Coalesced<E$1 extends EdgeBase<any, any>, D extends SupportedDepths> = (E$1 extends Coalesced.Edge<infer V, any, object> ? V : null) extends (infer V extends Vertex<Collection>) ? {
|
|
15
15
|
[FLATTEN_KEY]: true;
|
|
16
16
|
[Coalesced.Util.Keys.TO]: MakeMixed<
|
|
17
17
|
// must mix here to support all different vertex types
|
|
@@ -30,7 +30,9 @@ declare namespace HandleEdge {
|
|
|
30
30
|
/**
|
|
31
31
|
*
|
|
32
32
|
*/
|
|
33
|
-
type _VertexQuery<V$1 extends Vertex<Collection>, D extends SupportedDepths> = D extends MinDepth ?
|
|
33
|
+
type _VertexQuery<V$1 extends Vertex<Collection>, D extends SupportedDepths> = D extends MinDepth ? {
|
|
34
|
+
[SELECT_KEY]: Array<AllKeysOf<V$1>>;
|
|
35
|
+
} : {
|
|
34
36
|
[EXPAND_KEY]: { [K in keyof PickEdges<V$1> as V$1[K] extends never ? K : never]: InvalidEdgeMessage } & _Flatten<RemoveNeverValues<{ [K in keyof PickEdges<V$1> as V$1[K] extends never ? never : K]-?: NonNullable<V$1[K]> extends EdgeWrapper<EdgeMultiplicity, infer E extends EdgeBase<any, any> | null | undefined> ? (HandleEdge.Plain<NonNullable<E>, Decrement<D>> | HandleEdge.Wrapped<NonNullable<E>, Decrement<D>> | HandleEdge.Coalesced<NonNullable<E>, Decrement<D>> | HandleEdge.GroupWithExclude<NonNullable<E>, Decrement<D>> | HandleEdge.AvailableLocation<NonNullable<E>, Decrement<D>>) : never }>>;
|
|
35
37
|
} & {
|
|
36
38
|
[SELECT_KEY]: Array<AllKeysOf<V$1>>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { VertexQuery } from "./util/vertex-query/index.js";
|
|
2
|
+
import { AssertNoInvalidExpandKeys } from "./util/custom-vertex-export/assert-no-invalid-expand-keys.js";
|
|
2
3
|
import { CustomVertexExport } from "./util/custom-vertex-export/index.js";
|
|
3
4
|
import "./util/index.js";
|
|
4
5
|
import { PeriodVertex } from "./periods.js";
|
|
@@ -49,7 +50,7 @@ type BaseQueryRecord<C$1 extends keyof VertexRecord> = VertexQuery<VertexRecord[
|
|
|
49
50
|
/**
|
|
50
51
|
* See {@link createVertexQuery}
|
|
51
52
|
*/
|
|
52
|
-
declare class VertexQuery$1<C$1 extends keyof VertexRecord, Q$1 extends BaseQueryRecord<C$1>> {
|
|
53
|
+
declare class VertexQuery$1<C$1 extends keyof VertexRecord, Q$1 extends BaseQueryRecord<C$1> & AssertNoInvalidExpandKeys<VertexRecord[C$1], Q$1>> {
|
|
53
54
|
private readonly _collection;
|
|
54
55
|
private readonly _query;
|
|
55
56
|
constructor(_collection: C$1, _query: Q$1);
|
|
@@ -79,23 +80,25 @@ type Infer<T extends VertexQuery$1<any, any>> = T extends VertexQuery$1<infer C,
|
|
|
79
80
|
* type GroupType = Infer<typeof groupQuery>;
|
|
80
81
|
*/
|
|
81
82
|
declare namespace createVertexQuery {
|
|
82
|
-
function division<Q$1 extends VertexQuery<DivisionVertex>>(query: Q$1): VertexQuery$1<"divisions", Q$1>;
|
|
83
|
-
function settings<Q$1 extends VertexQuery<DivisionSettingsVertex>>(query: Q$1): VertexQuery$1<"settings", Q$1>;
|
|
84
|
-
function exception<Q$1 extends VertexQuery<ExceptionVertex>>(query: Q$1): VertexQuery$1<"exceptions", Q$1>;
|
|
85
|
-
function event<Q$1 extends VertexQuery<EventVertex>>(query: Q$1): VertexQuery$1<"events", Q$1>;
|
|
86
|
-
function scheduleEvent<Q$1 extends VertexQuery<ScheduleEventVertex>>(query: Q$1): VertexQuery$1<"scheduleEvents", Q$1>;
|
|
87
|
-
function calendarEvent<Q$1 extends VertexQuery<CalendarEventVertex>>(query: Q$1): VertexQuery$1<"calendarEvents", Q$1>;
|
|
88
|
-
function course<Q$1 extends VertexQuery<CourseVertex>>(query: Q$1): VertexQuery$1<"courses", Q$1>;
|
|
89
|
-
function generation<Q$1 extends VertexQuery<GenerationVertex>>(query: Q$1): VertexQuery$1<"generations", Q$1>;
|
|
90
|
-
function location<Q$1 extends VertexQuery<LocationVertex>>(query: Q$1): VertexQuery$1<"locations", Q$1>;
|
|
91
|
-
function lockedTime<Q$1 extends VertexQuery<LockedTimeVertex>>(query: Q$1): VertexQuery$1<"lockedTimes", Q$1>;
|
|
92
|
-
function overlapGroup<Q$1 extends VertexQuery<OverlapGroupVertex>>(query: Q$1): VertexQuery$1<"overlapGroups", Q$1>;
|
|
93
|
-
function period<Q$1 extends VertexQuery<PeriodVertex>>(query: Q$1): VertexQuery$1<"periods", Q$1>;
|
|
94
|
-
function person<Q$1 extends VertexQuery<PersonVertex>>(query: Q$1): VertexQuery$1<"persons", Q$1>;
|
|
95
|
-
function
|
|
96
|
-
function
|
|
97
|
-
function
|
|
98
|
-
function
|
|
83
|
+
function division<Q$1 extends VertexQuery<DivisionVertex> & AssertNoInvalidExpandKeys<DivisionVertex, Q$1>>(query: Q$1): VertexQuery$1<"divisions", Q$1>;
|
|
84
|
+
function settings<Q$1 extends VertexQuery<DivisionSettingsVertex> & AssertNoInvalidExpandKeys<DivisionSettingsVertex, Q$1>>(query: Q$1): VertexQuery$1<"settings", Q$1>;
|
|
85
|
+
function exception<Q$1 extends VertexQuery<ExceptionVertex> & AssertNoInvalidExpandKeys<ExceptionVertex, Q$1>>(query: Q$1): VertexQuery$1<"exceptions", Q$1>;
|
|
86
|
+
function event<Q$1 extends VertexQuery<EventVertex> & AssertNoInvalidExpandKeys<EventVertex, Q$1>>(query: Q$1): VertexQuery$1<"events", Q$1>;
|
|
87
|
+
function scheduleEvent<Q$1 extends VertexQuery<ScheduleEventVertex> & AssertNoInvalidExpandKeys<ScheduleEventVertex, Q$1>>(query: Q$1): VertexQuery$1<"scheduleEvents", Q$1>;
|
|
88
|
+
function calendarEvent<Q$1 extends VertexQuery<CalendarEventVertex> & AssertNoInvalidExpandKeys<CalendarEventVertex, Q$1>>(query: Q$1): VertexQuery$1<"calendarEvents", Q$1>;
|
|
89
|
+
function course<Q$1 extends VertexQuery<CourseVertex> & AssertNoInvalidExpandKeys<CourseVertex, Q$1>>(query: Q$1): VertexQuery$1<"courses", Q$1>;
|
|
90
|
+
function generation<Q$1 extends VertexQuery<GenerationVertex> & AssertNoInvalidExpandKeys<GenerationVertex, Q$1>>(query: Q$1): VertexQuery$1<"generations", Q$1>;
|
|
91
|
+
function location<Q$1 extends VertexQuery<LocationVertex> & AssertNoInvalidExpandKeys<LocationVertex, Q$1>>(query: Q$1): VertexQuery$1<"locations", Q$1>;
|
|
92
|
+
function lockedTime<Q$1 extends VertexQuery<LockedTimeVertex> & AssertNoInvalidExpandKeys<LockedTimeVertex, Q$1>>(query: Q$1): VertexQuery$1<"lockedTimes", Q$1>;
|
|
93
|
+
function overlapGroup<Q$1 extends VertexQuery<OverlapGroupVertex> & AssertNoInvalidExpandKeys<OverlapGroupVertex, Q$1>>(query: Q$1): VertexQuery$1<"overlapGroups", Q$1>;
|
|
94
|
+
function period<Q$1 extends VertexQuery<PeriodVertex> & AssertNoInvalidExpandKeys<PeriodVertex, Q$1>>(query: Q$1): VertexQuery$1<"periods", Q$1>;
|
|
95
|
+
function person<Q$1 extends VertexQuery<PersonVertex> & AssertNoInvalidExpandKeys<PersonVertex, Q$1>>(query: Q$1): VertexQuery$1<"persons", Q$1>;
|
|
96
|
+
function student<Q$1 extends VertexQuery<PersonVertex> & AssertNoInvalidExpandKeys<PersonVertex, Q$1>>(query: Q$1): VertexQuery$1<"students", Q$1>;
|
|
97
|
+
function rootInterval<Q$1 extends VertexQuery<RootIntervalVertex> & AssertNoInvalidExpandKeys<RootIntervalVertex, Q$1>>(query: Q$1): VertexQuery$1<"rootIntervals", Q$1>;
|
|
98
|
+
function syllabus<Q$1 extends VertexQuery<SyllabusVertex> & AssertNoInvalidExpandKeys<SyllabusVertex, Q$1>>(query: Q$1): VertexQuery$1<"syllabuses", Q$1>;
|
|
99
|
+
function group<Q$1 extends VertexQuery<GroupVertex> & AssertNoInvalidExpandKeys<GroupVertex, Q$1>>(query: Q$1): VertexQuery$1<"groups", Q$1>;
|
|
100
|
+
function teacher<Q$1 extends VertexQuery<TeacherVertex> & AssertNoInvalidExpandKeys<TeacherVertex, Q$1>>(query: Q$1): VertexQuery$1<"teachers", Q$1>;
|
|
101
|
+
function configuration<Q$1 extends VertexQuery<ConfigurationVertex> & AssertNoInvalidExpandKeys<ConfigurationVertex, Q$1>>(query: Q$1): VertexQuery$1<"configurations", Q$1>;
|
|
99
102
|
}
|
|
100
103
|
//#endregion
|
|
101
104
|
export { Infer, VertexQuery$1 as VertexQuery, createVertexQuery };
|
|
@@ -71,6 +71,10 @@ let createVertexQuery;
|
|
|
71
71
|
return new VertexQuery("persons", query);
|
|
72
72
|
}
|
|
73
73
|
_createVertexQuery.person = person;
|
|
74
|
+
function student(query) {
|
|
75
|
+
return new VertexQuery("students", query);
|
|
76
|
+
}
|
|
77
|
+
_createVertexQuery.student = student;
|
|
74
78
|
function rootInterval(query) {
|
|
75
79
|
return new VertexQuery("rootIntervals", query);
|
|
76
80
|
}
|
|
@@ -87,6 +91,10 @@ let createVertexQuery;
|
|
|
87
91
|
return new VertexQuery("teachers", query);
|
|
88
92
|
}
|
|
89
93
|
_createVertexQuery.teacher = teacher;
|
|
94
|
+
function configuration(query) {
|
|
95
|
+
return new VertexQuery("configurations", query);
|
|
96
|
+
}
|
|
97
|
+
_createVertexQuery.configuration = configuration;
|
|
90
98
|
})(createVertexQuery || (createVertexQuery = {}));
|
|
91
99
|
|
|
92
100
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vertex-query.js","names":["_collection: C","_query: Q"],"sources":["../../../../src/core/interfaces/vertices/vertex-query.ts"],"sourcesContent":["import type { Collection, CustomVertexExport } from './util';\nimport type { TeacherVertex } from './teachers';\nimport type { ExceptionVertex } from './exceptions';\nimport type { EventVertex, ScheduleEventVertex, CalendarEventVertex } from './events';\nimport type { CourseVertex } from './courses';\nimport type { DivisionSettingsVertex } from './division-settings';\nimport type { DivisionVertex } from './divisions';\nimport type { GenerationVertex } from './generations';\nimport type { GroupVertex } from './groups';\nimport type { LocationVertex } from './locations';\nimport type { LockedTimeVertex } from './locked-times';\nimport type { OverlapGroupVertex } from './overlap-groups';\nimport type { PeriodVertex } from './periods';\nimport type { PersonVertex } from './persons';\nimport type { RootIntervalVertex } from './root-intervals';\nimport type { SyllabusVertex } from './syllabuses';\nimport type { ConfigurationVertex } from './configurations';\nimport type { CompanyVertex } from './companies';\nimport type { UserVertex } from './users';\nimport type { VertexQuery as Query } from './util/vertex-query';\nimport type { TypeEqual } from 'ts-expect';\nimport { expectType } from 'ts-expect';\n\n\
|
|
1
|
+
{"version":3,"file":"vertex-query.js","names":["_collection: C","_query: Q"],"sources":["../../../../src/core/interfaces/vertices/vertex-query.ts"],"sourcesContent":["import type { AssertNoInvalidExpandKeys, Collection, CustomVertexExport } from './util';\nimport type { TeacherVertex } from './teachers';\nimport type { ExceptionVertex } from './exceptions';\nimport type { EventVertex, ScheduleEventVertex, CalendarEventVertex } from './events';\nimport type { CourseVertex } from './courses';\nimport type { DivisionSettingsVertex } from './division-settings';\nimport type { DivisionVertex } from './divisions';\nimport type { GenerationVertex } from './generations';\nimport type { GroupVertex } from './groups';\nimport type { LocationVertex } from './locations';\nimport type { LockedTimeVertex } from './locked-times';\nimport type { OverlapGroupVertex } from './overlap-groups';\nimport type { PeriodVertex } from './periods';\nimport type { PersonVertex } from './persons';\nimport type { RootIntervalVertex } from './root-intervals';\nimport type { SyllabusVertex } from './syllabuses';\nimport type { ConfigurationVertex } from './configurations';\nimport type { CompanyVertex } from './companies';\nimport type { UserVertex } from './users';\nimport type { VertexQuery as Query } from './util/vertex-query';\nimport type { TypeEqual } from 'ts-expect';\nimport { expectType } from 'ts-expect';\n\n\nexport type VertexRecord = {\n divisions: DivisionVertex;\n divisionSettings: DivisionSettingsVertex;\n settings: DivisionSettingsVertex;\n teachers: TeacherVertex;\n exceptions: ExceptionVertex;\n events: EventVertex;\n scheduleEvents: ScheduleEventVertex;\n calendarEvents: CalendarEventVertex;\n courses: CourseVertex;\n generations: GenerationVertex;\n groups: GroupVertex;\n locations: LocationVertex;\n lockedTimes: LockedTimeVertex;\n overlapGroups: OverlapGroupVertex;\n periods: PeriodVertex;\n persons: PersonVertex;\n students: PersonVertex;\n rootIntervals: RootIntervalVertex;\n syllabuses: SyllabusVertex;\n configurations: ConfigurationVertex;\n companies: CompanyVertex;\n users: UserVertex;\n};\nexport type BaseQueryRecord<C extends keyof VertexRecord> = Query<VertexRecord[C]>;\n{\n // the keys must all be a collection\n type Mismatches = keyof {\n [K in keyof VertexRecord as K extends Collection ? never : K]: true\n };\n expectType<TypeEqual<Mismatches, never>>(true);\n}\n\n/**\n * See {@link createVertexQuery}\n */\nexport class VertexQuery <\n C extends keyof VertexRecord,\n Q extends BaseQueryRecord<C> & AssertNoInvalidExpandKeys<VertexRecord[C], Q>\n> {\n constructor (\n private readonly _collection: C,\n private readonly _query: Q\n ) {}\n\n get collection () { return this._collection }\n get query () { return this._query }\n}\n\n\n/**\n * Infers the result type for a query created via createVertexQuery.\n *\n * @example\n * const personQuery = createVertexQuery('persons', { select: ['id', 'firstName'] });\n * type PersonType = Infer<typeof personQuery>;\n */\nexport type Infer<T extends VertexQuery<any, any>> = // eslint-disable-line @typescript-eslint/no-explicit-any\n T extends VertexQuery<infer C, infer Q>\n ? CustomVertexExport<VertexRecord[C], Q>\n : never;\n\n\n/**\n * Builds a typed vertex query for a given vertex type using a select/expand shape.\n *\n * Use together with Infer<T> to obtain the serialized result type.\n *\n * @typeParam Q - The select/expand query shape for that vertex.\n *\n * @example\n * const groupQuery = createVertexQuery.group({\n * select: ['id', 'displayName'],\n * expand: { members: { select: ['id'] } }\n * });\n * type GroupType = Infer<typeof groupQuery>;\n */\nexport namespace createVertexQuery {\n //\n // The following did not work: it seems we need to define Q as an completely independent type parameter (?)\n //\n // export function createVertexQuery <\n // C extends keyof VertexRecord,\n // const Q extends Query<VertexRecord[C]>\n // > (\n // collection: C,\n // query: Q\n // ) {\n // return new VertexQuery(collection, query);\n // }\n\n export function division <Q extends Query<DivisionVertex > & AssertNoInvalidExpandKeys<DivisionVertex, Q>> (query: Q) { return new VertexQuery('divisions', query) }\n export function settings <Q extends Query<DivisionSettingsVertex> & AssertNoInvalidExpandKeys<DivisionSettingsVertex, Q>> (query: Q) { return new VertexQuery('settings', query) }\n export function exception <Q extends Query<ExceptionVertex > & AssertNoInvalidExpandKeys<ExceptionVertex, Q>> (query: Q) { return new VertexQuery('exceptions', query) }\n export function event <Q extends Query<EventVertex > & AssertNoInvalidExpandKeys<EventVertex, Q>> (query: Q) { return new VertexQuery('events', query) }\n export function scheduleEvent<Q extends Query<ScheduleEventVertex > & AssertNoInvalidExpandKeys<ScheduleEventVertex, Q>> (query: Q) { return new VertexQuery('scheduleEvents', query) }\n export function calendarEvent<Q extends Query<CalendarEventVertex > & AssertNoInvalidExpandKeys<CalendarEventVertex, Q>> (query: Q) { return new VertexQuery('calendarEvents', query) }\n export function course <Q extends Query<CourseVertex > & AssertNoInvalidExpandKeys<CourseVertex, Q>> (query: Q) { return new VertexQuery('courses', query) }\n export function generation <Q extends Query<GenerationVertex > & AssertNoInvalidExpandKeys<GenerationVertex, Q>> (query: Q) { return new VertexQuery('generations', query) }\n export function location <Q extends Query<LocationVertex > & AssertNoInvalidExpandKeys<LocationVertex, Q>> (query: Q) { return new VertexQuery('locations', query) }\n export function lockedTime <Q extends Query<LockedTimeVertex > & AssertNoInvalidExpandKeys<LockedTimeVertex, Q>> (query: Q) { return new VertexQuery('lockedTimes', query) }\n export function overlapGroup <Q extends Query<OverlapGroupVertex > & AssertNoInvalidExpandKeys<OverlapGroupVertex, Q>> (query: Q) { return new VertexQuery('overlapGroups', query) }\n export function period <Q extends Query<PeriodVertex > & AssertNoInvalidExpandKeys<PeriodVertex, Q>> (query: Q) { return new VertexQuery('periods', query) }\n export function person <Q extends Query<PersonVertex > & AssertNoInvalidExpandKeys<PersonVertex, Q>> (query: Q) { return new VertexQuery('persons', query) }\n export function student <Q extends Query<PersonVertex > & AssertNoInvalidExpandKeys<PersonVertex, Q>> (query: Q) { return new VertexQuery('students', query) }\n export function rootInterval <Q extends Query<RootIntervalVertex > & AssertNoInvalidExpandKeys<RootIntervalVertex, Q>> (query: Q) { return new VertexQuery('rootIntervals', query) }\n export function syllabus <Q extends Query<SyllabusVertex > & AssertNoInvalidExpandKeys<SyllabusVertex, Q>> (query: Q) { return new VertexQuery('syllabuses', query) }\n export function group <Q extends Query<GroupVertex > & AssertNoInvalidExpandKeys<GroupVertex, Q>> (query: Q) { return new VertexQuery('groups', query) }\n export function teacher <Q extends Query<TeacherVertex > & AssertNoInvalidExpandKeys<TeacherVertex, Q>> (query: Q) { return new VertexQuery('teachers', query) }\n export function configuration<Q extends Query<ConfigurationVertex > & AssertNoInvalidExpandKeys<ConfigurationVertex, Q>> (query: Q) { return new VertexQuery('configurations', query) }\n}"],"mappings":";;;AAsDE,WAAyC,KAAK;;;;AAMhD,IAAa,cAAb,MAGE;CACA,YACE,AAAiBA,aACjB,AAAiBC,QACjB;EAFiB;EACA;;CAGnB,IAAI,aAAc;AAAE,SAAO,KAAK;;CAChC,IAAI,QAAc;AAAE,SAAO,KAAK;;;;;CA6CzB,SAAS,SAA+G,OAAU;AAAE,SAAO,IAAI,YAAY,aAAoB,MAAM;;;CACrL,SAAS,SAA+G,OAAU;AAAE,SAAO,IAAI,YAAY,YAAoB,MAAM;;;CACrL,SAAS,UAA+G,OAAU;AAAE,SAAO,IAAI,YAAY,cAAoB,MAAM;;;CACrL,SAAS,MAA+G,OAAU;AAAE,SAAO,IAAI,YAAY,UAAoB,MAAM;;;CACrL,SAAS,cAA+G,OAAU;AAAE,SAAO,IAAI,YAAY,kBAAoB,MAAM;;;CACrL,SAAS,cAA+G,OAAU;AAAE,SAAO,IAAI,YAAY,kBAAoB,MAAM;;;CACrL,SAAS,OAA+G,OAAU;AAAE,SAAO,IAAI,YAAY,WAAoB,MAAM;;;CACrL,SAAS,WAA+G,OAAU;AAAE,SAAO,IAAI,YAAY,eAAoB,MAAM;;;CACrL,SAAS,SAA+G,OAAU;AAAE,SAAO,IAAI,YAAY,aAAoB,MAAM;;;CACrL,SAAS,WAA+G,OAAU;AAAE,SAAO,IAAI,YAAY,eAAoB,MAAM;;;CACrL,SAAS,aAA+G,OAAU;AAAE,SAAO,IAAI,YAAY,iBAAoB,MAAM;;;CACrL,SAAS,OAA+G,OAAU;AAAE,SAAO,IAAI,YAAY,WAAoB,MAAM;;;CACrL,SAAS,OAA+G,OAAU;AAAE,SAAO,IAAI,YAAY,WAAoB,MAAM;;;CACrL,SAAS,QAA+G,OAAU;AAAE,SAAO,IAAI,YAAY,YAAoB,MAAM;;;CACrL,SAAS,aAA+G,OAAU;AAAE,SAAO,IAAI,YAAY,iBAAoB,MAAM;;;CACrL,SAAS,SAA+G,OAAU;AAAE,SAAO,IAAI,YAAY,cAAoB,MAAM;;;CACrL,SAAS,MAA+G,OAAU;AAAE,SAAO,IAAI,YAAY,UAAoB,MAAM;;;CACrL,SAAS,QAA+G,OAAU;AAAE,SAAO,IAAI,YAAY,YAAoB,MAAM;;;CACrL,SAAS,cAA+G,OAAU;AAAE,SAAO,IAAI,YAAY,kBAAoB,MAAM"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@royalschedule/maps",
|
|
3
3
|
"description": "",
|
|
4
|
-
"version": "4.0.
|
|
4
|
+
"version": "4.0.21",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"tsx": "^4.20.6",
|
|
71
71
|
"typescript": "^5.9.3",
|
|
72
72
|
"typescript-eslint": "^8.46.2",
|
|
73
|
-
"vitest": "^4.0.
|
|
73
|
+
"vitest": "^4.0.14"
|
|
74
74
|
},
|
|
75
75
|
"dependencies": {
|
|
76
76
|
"@json2csv/plainjs": "^7.0.6",
|