@royalschedule/maps 4.0.19 → 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/Excel/v1/index.d.ts +3 -3
- package/dist/Excel/v2/index.d.ts +3 -3
- package/dist/RS/to/input/events.js +1 -1
- package/dist/RS/to/input/events.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/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 -20
- package/dist/core/interfaces/vertices/vertex-query.js.map +1 -1
- package/package.json +2 -2
package/dist/Excel/v1/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { PlannedScheduledDuration } from "../../core/interfaces/vertices/propert
|
|
|
7
7
|
import { MinBreakLength } from "../../core/interfaces/vertices/properties/min-break-length.js";
|
|
8
8
|
import { Types } from "./types/index.js";
|
|
9
9
|
import "../../index.js";
|
|
10
|
-
import * as
|
|
10
|
+
import * as moment199 from "moment";
|
|
11
11
|
|
|
12
12
|
//#region src/Excel/v1/index.d.ts
|
|
13
13
|
declare class Map {
|
|
@@ -200,8 +200,8 @@ declare class Map {
|
|
|
200
200
|
lastModifiedBy?: string | undefined;
|
|
201
201
|
course?: string | undefined;
|
|
202
202
|
period?: string | undefined;
|
|
203
|
-
start?: (
|
|
204
|
-
end?: (
|
|
203
|
+
start?: (moment199.Moment | string) | undefined;
|
|
204
|
+
end?: (moment199.Moment | string) | undefined;
|
|
205
205
|
belongsTo?: string | undefined;
|
|
206
206
|
potentialCenter?: string | undefined;
|
|
207
207
|
type?: string | undefined;
|
package/dist/Excel/v2/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { PlannedScheduledDuration } from "../../core/interfaces/vertices/propert
|
|
|
7
7
|
import { MinBreakLength } from "../../core/interfaces/vertices/properties/min-break-length.js";
|
|
8
8
|
import { Types } from "./types/index.js";
|
|
9
9
|
import "../../index.js";
|
|
10
|
-
import * as
|
|
10
|
+
import * as moment197 from "moment";
|
|
11
11
|
|
|
12
12
|
//#region src/Excel/v2/index.d.ts
|
|
13
13
|
declare class Map {
|
|
@@ -198,8 +198,8 @@ declare class Map {
|
|
|
198
198
|
createdAt?: string | undefined;
|
|
199
199
|
updatedAt?: string | undefined;
|
|
200
200
|
lastModifiedBy?: string | undefined;
|
|
201
|
-
start?: (
|
|
202
|
-
end?: (
|
|
201
|
+
start?: (moment197.Moment | string) | undefined;
|
|
202
|
+
end?: (moment197.Moment | string) | undefined;
|
|
203
203
|
potentialCenter?: string | undefined;
|
|
204
204
|
type?: string | undefined;
|
|
205
205
|
tags?: Tag[] | undefined;
|
|
@@ -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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"}
|
|
@@ -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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"}
|
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,25 +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 student<Q$1 extends VertexQuery<PersonVertex>>(query: Q$1): VertexQuery$1<"students", Q$1>;
|
|
96
|
-
function rootInterval<Q$1 extends VertexQuery<RootIntervalVertex>>(query: Q$1): VertexQuery$1<"rootIntervals", Q$1>;
|
|
97
|
-
function syllabus<Q$1 extends VertexQuery<SyllabusVertex>>(query: Q$1): VertexQuery$1<"syllabuses", Q$1>;
|
|
98
|
-
function group<Q$1 extends VertexQuery<GroupVertex>>(query: Q$1): VertexQuery$1<"groups", Q$1>;
|
|
99
|
-
function teacher<Q$1 extends VertexQuery<TeacherVertex>>(query: Q$1): VertexQuery$1<"teachers", Q$1>;
|
|
100
|
-
function configuration<Q$1 extends VertexQuery<ConfigurationVertex>>(query: Q$1): VertexQuery$1<"configurations", Q$1>;
|
|
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>;
|
|
101
102
|
}
|
|
102
103
|
//#endregion
|
|
103
104
|
export { Infer, VertexQuery$1 as VertexQuery, createVertexQuery };
|
|
@@ -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",
|