@dimescheduler/setup 0.1.2 → 0.1.3

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.
@@ -0,0 +1,863 @@
1
+ // src/core/compile/bundle.ts
2
+ import { readFile } from "fs/promises";
3
+ import { dirname, resolve } from "path";
4
+ import JSON5 from "json5";
5
+
6
+ // src/core/types.ts
7
+ function isProfileDocument(doc) {
8
+ return typeof doc === "object" && doc !== null && doc.type === "profile";
9
+ }
10
+ function isUsersDocument(doc) {
11
+ return typeof doc === "object" && doc !== null && doc.type === "users";
12
+ }
13
+ function isLayoutsDocument(doc) {
14
+ return typeof doc === "object" && doc !== null && doc.type === "layouts";
15
+ }
16
+ function isBundleDocument(doc) {
17
+ return typeof doc === "object" && doc !== null && doc.type === "bundle";
18
+ }
19
+ function isDocumentReference(item) {
20
+ return "$ref" in item;
21
+ }
22
+ function detectDocumentType(doc) {
23
+ if (typeof doc !== "object" || doc === null) return null;
24
+ const type = doc.type;
25
+ if (type === "profile" || type === "users" || type === "layouts" || type === "bundle") {
26
+ return type;
27
+ }
28
+ return null;
29
+ }
30
+
31
+ // src/core/compile/merge.ts
32
+ function hasConflicts(a, b, key) {
33
+ const aKeys = new Set(a.map((item) => item[key]));
34
+ return b.some((item) => aKeys.has(item[key]));
35
+ }
36
+ function mergeLayouts(existing, incoming, strategy = "append") {
37
+ if (strategy === "replace") {
38
+ return [...incoming];
39
+ }
40
+ if (strategy === "error" && hasConflicts(existing, incoming, "code")) {
41
+ const existingCodes = new Set(existing.map((l) => l.code));
42
+ const conflicts = incoming.filter((l) => existingCodes.has(l.code)).map((l) => l.code);
43
+ throw new Error(`Layout code conflict detected: ${conflicts.join(", ")}`);
44
+ }
45
+ const merged = [...existing];
46
+ for (const layout of incoming) {
47
+ const existingIndex = merged.findIndex((l) => l.code === layout.code);
48
+ if (existingIndex >= 0) {
49
+ merged[existingIndex] = layout;
50
+ } else {
51
+ merged.push(layout);
52
+ }
53
+ }
54
+ return merged;
55
+ }
56
+ function mergeUsers(existing, incoming, strategy = "append") {
57
+ if (strategy === "replace") {
58
+ return [...incoming];
59
+ }
60
+ if (strategy === "error" && hasConflicts(existing, incoming, "email")) {
61
+ const existingEmails = new Set(existing.map((u) => u.email));
62
+ const conflicts = incoming.filter((u) => existingEmails.has(u.email)).map((u) => u.email);
63
+ throw new Error(`User email conflict detected: ${conflicts.join(", ")}`);
64
+ }
65
+ const merged = [...existing];
66
+ for (const user of incoming) {
67
+ const existingIndex = merged.findIndex((u) => u.email === user.email);
68
+ if (existingIndex >= 0) {
69
+ merged[existingIndex] = user;
70
+ } else {
71
+ merged.push(user);
72
+ }
73
+ }
74
+ return merged;
75
+ }
76
+ function deepMerge(target, source) {
77
+ const result = { ...target };
78
+ for (const key of Object.keys(source)) {
79
+ const sourceValue = source[key];
80
+ const targetValue = result[key];
81
+ if (sourceValue === void 0) {
82
+ continue;
83
+ }
84
+ if (Array.isArray(sourceValue)) {
85
+ if (Array.isArray(targetValue)) {
86
+ result[key] = [...targetValue, ...sourceValue];
87
+ } else {
88
+ result[key] = [...sourceValue];
89
+ }
90
+ } else if (typeof sourceValue === "object" && sourceValue !== null && typeof targetValue === "object" && targetValue !== null && !Array.isArray(targetValue)) {
91
+ result[key] = deepMerge(
92
+ targetValue,
93
+ sourceValue
94
+ );
95
+ } else {
96
+ result[key] = sourceValue;
97
+ }
98
+ }
99
+ return result;
100
+ }
101
+ function setPath(obj, path, value) {
102
+ const parts = path.split(".");
103
+ let current = obj;
104
+ for (let i = 0; i < parts.length - 1; i++) {
105
+ const part = parts[i];
106
+ if (!(part in current) || typeof current[part] !== "object" || current[part] === null) {
107
+ current[part] = {};
108
+ }
109
+ current = current[part];
110
+ }
111
+ const lastPart = parts[parts.length - 1];
112
+ if (Array.isArray(value) && Array.isArray(current[lastPart])) {
113
+ current[lastPart] = [...current[lastPart], ...value];
114
+ } else if (typeof value === "object" && value !== null && !Array.isArray(value) && typeof current[lastPart] === "object" && current[lastPart] !== null && !Array.isArray(current[lastPart])) {
115
+ current[lastPart] = deepMerge(
116
+ current[lastPart],
117
+ value
118
+ );
119
+ } else {
120
+ current[lastPart] = value;
121
+ }
122
+ }
123
+ function applyMergeOverrides(doc, mergeOverrides) {
124
+ const result = JSON.parse(JSON.stringify(doc));
125
+ for (const [path, value] of Object.entries(mergeOverrides)) {
126
+ setPath(result, path, value);
127
+ }
128
+ return result;
129
+ }
130
+
131
+ // src/core/compile/mappers.ts
132
+ var SNAP_MODE_MAP = {
133
+ "none": 1,
134
+ "off": 1,
135
+ "5min": 2,
136
+ "5minutes": 2,
137
+ "10min": 3,
138
+ "10minutes": 3,
139
+ "15min": 4,
140
+ "15minutes": 4,
141
+ "30min": 5,
142
+ "30minutes": 5,
143
+ "halfhour": 5,
144
+ "1hour": 6,
145
+ "1h": 6,
146
+ "hour": 6,
147
+ "12hours": 7,
148
+ "12h": 7,
149
+ "1day": 8,
150
+ "1d": 8,
151
+ "day": 8,
152
+ "2hours": 9,
153
+ "2h": 9,
154
+ "4hours": 10,
155
+ "4h": 10,
156
+ // Numeric string mappings
157
+ "1": 1,
158
+ "2": 2,
159
+ "3": 3,
160
+ "4": 4,
161
+ "5": 5,
162
+ "6": 6,
163
+ "7": 7,
164
+ "8": 8,
165
+ "9": 9,
166
+ "10": 10
167
+ };
168
+ function mapSnapMode(mode) {
169
+ if (mode === void 0 || mode === null) return 6;
170
+ return SNAP_MODE_MAP[String(mode).toLowerCase()] ?? 6;
171
+ }
172
+ var RANGE_MODE_MAP = {
173
+ "day": 1,
174
+ "days": 1,
175
+ "hours": 1,
176
+ "week": 2,
177
+ "weeks": 2,
178
+ "month": 3,
179
+ "months": 3,
180
+ "custom": 4,
181
+ // Numeric string mappings
182
+ "1": 1,
183
+ "2": 2,
184
+ "3": 3,
185
+ "4": 4
186
+ };
187
+ function mapRangeMode(mode) {
188
+ if (mode === void 0 || mode === null) return 2;
189
+ return RANGE_MODE_MAP[String(mode).toLowerCase()] ?? 2;
190
+ }
191
+ var START_MODE_MAP = {
192
+ "today": 1,
193
+ "absolute": 1,
194
+ "startofweek": 2,
195
+ "relative": 2,
196
+ "startofmonth": 3,
197
+ "todayoffset": 4,
198
+ // Numeric string mappings
199
+ "1": 1,
200
+ "2": 2,
201
+ "3": 3,
202
+ "4": 4
203
+ };
204
+ function mapStartMode(mode) {
205
+ if (mode === void 0 || mode === null) return 2;
206
+ return START_MODE_MAP[String(mode).toLowerCase().replace(/\s+/g, "")] ?? 2;
207
+ }
208
+ function mapUnitOfDistance(unit) {
209
+ if (!unit) return "Kilometers";
210
+ const v = unit.toLowerCase();
211
+ if (["km", "kilometer", "kilometers"].includes(v)) return "Kilometers";
212
+ if (["mi", "mile", "miles"].includes(v)) return "Miles";
213
+ return unit;
214
+ }
215
+ var COMPONENT_TO_GL = {
216
+ // Friendly names (user-facing DSL names)
217
+ "openTasks": "openTasksGridComponent",
218
+ "planningBoard": "schedulerComponent",
219
+ "map": "mapComponent",
220
+ "indicators": "categoriesComponent",
221
+ "resourceFilters": "filterComponent",
222
+ "plannedTasks": "plannedTasksGridComponent",
223
+ "details": "propertygridComponent",
224
+ "datePicker": "datePickerComponent",
225
+ "gantt": "ganttComponent",
226
+ "capacity": "capacityComponent",
227
+ "routeSequence": "routeSequenceComponent",
228
+ "notifications": "notificationsComponent",
229
+ // Internal names (for backwards compatibility)
230
+ "mapComponent": "mapComponent",
231
+ "plannedTasksGridComponent": "plannedTasksGridComponent",
232
+ "propertygridComponent": "propertygridComponent",
233
+ "datePickerComponent": "datePickerComponent",
234
+ "ganttComponent": "ganttComponent",
235
+ "capacityComponent": "capacityComponent",
236
+ "routeSequenceComponent": "routeSequenceComponent",
237
+ "notificationsComponent": "notificationsComponent"
238
+ };
239
+ function componentToGlName(name) {
240
+ return COMPONENT_TO_GL[name] ?? name;
241
+ }
242
+ var VIEW_PRESET_MAP = {
243
+ "day": "1",
244
+ "1": "1",
245
+ "week": "2",
246
+ "2": "2",
247
+ "workweek": "3",
248
+ "workWeek": "3",
249
+ "work_week": "3",
250
+ "3": "3",
251
+ "month": "4",
252
+ "4": "4"
253
+ };
254
+ function mapViewPreset(value) {
255
+ if (value === void 0 || value === null) return "2";
256
+ const v = String(value).toLowerCase().replace(/[\s_-]+/g, "");
257
+ return VIEW_PRESET_MAP[v] ?? String(value);
258
+ }
259
+ var ROW_HEIGHT_MAP = {
260
+ "1row": 25,
261
+ "1rows": 25,
262
+ "1": 25,
263
+ "25": 25,
264
+ "2rows": 38,
265
+ "2row": 38,
266
+ "2": 38,
267
+ "38": 38,
268
+ "3rows": 50,
269
+ "3row": 50,
270
+ "3": 50,
271
+ "50": 50,
272
+ "4rows": 63,
273
+ "4row": 63,
274
+ "4": 63,
275
+ "63": 63
276
+ };
277
+ function mapRowHeight(value) {
278
+ if (value === void 0 || value === null) return 38;
279
+ const v = String(value).toLowerCase().replace(/[\s_-]+/g, "");
280
+ if (ROW_HEIGHT_MAP[v] !== void 0) return ROW_HEIGHT_MAP[v];
281
+ const parsed = parseInt(String(value), 10);
282
+ return isNaN(parsed) ? 38 : parsed;
283
+ }
284
+ function mapRouteProfile(value) {
285
+ if (!value || value === "default") return "car";
286
+ return value;
287
+ }
288
+
289
+ // src/core/compile/goldenLayout.ts
290
+ function workspaceNodeToGL(node) {
291
+ const gl = { type: node.type };
292
+ if ("width" in node && node.width !== void 0) {
293
+ gl.width = node.width;
294
+ }
295
+ if ("height" in node && node.height !== void 0) {
296
+ gl.height = node.height;
297
+ }
298
+ if (node.type === "row" || node.type === "column" || node.type === "stack") {
299
+ gl.isClosable = true;
300
+ gl.reorderEnabled = true;
301
+ gl.title = "";
302
+ if ("content" in node && node.content) {
303
+ gl.content = node.content.map(workspaceNodeToGL);
304
+ }
305
+ if (node.type === "stack") {
306
+ gl.activeItemIndex = 0;
307
+ }
308
+ return gl;
309
+ }
310
+ if (node.type === "component") {
311
+ const compName = componentToGlName(node.component);
312
+ if (compName) {
313
+ gl.componentName = compName;
314
+ }
315
+ if (node.title !== void 0) {
316
+ gl.title = node.title;
317
+ }
318
+ gl.isClosable = true;
319
+ gl.reorderEnabled = true;
320
+ const compState = {};
321
+ const compId = node.id;
322
+ if (compId) {
323
+ gl.id = compId;
324
+ compState.id = compId;
325
+ } else if (compName === "schedulerComponent") {
326
+ gl.id = "schedulerContainer";
327
+ compState.id = "scheduler";
328
+ }
329
+ if (compName === "datePickerComponent" && compId) {
330
+ compState.wrapperId = compId;
331
+ }
332
+ if (Object.keys(compState).length > 0) {
333
+ gl.componentState = compState;
334
+ }
335
+ return gl;
336
+ }
337
+ return gl;
338
+ }
339
+ function detectRootType(workspace) {
340
+ if (workspace.length === 0) return "row";
341
+ let heightCount = 0;
342
+ let widthCount = 0;
343
+ for (const node of workspace) {
344
+ if ("height" in node && node.height !== void 0) heightCount++;
345
+ if ("width" in node && node.width !== void 0) widthCount++;
346
+ }
347
+ if (heightCount > widthCount) {
348
+ return "column";
349
+ }
350
+ return "row";
351
+ }
352
+ function workspaceToGoldenLayout(workspace) {
353
+ const rootType = detectRootType(workspace);
354
+ return {
355
+ settings: {
356
+ hasHeaders: true,
357
+ constrainDragToContainer: false,
358
+ reorderEnabled: true,
359
+ selectionEnabled: true,
360
+ popoutWholeStack: false,
361
+ blockedPopoutsThrowError: true,
362
+ closePopoutsOnUnload: true,
363
+ showPopoutIcon: false,
364
+ showMaximiseIcon: true,
365
+ showCloseIcon: true,
366
+ responsiveMode: "onload",
367
+ tabOverlapAllowance: 0,
368
+ reorderOnTabMenuClick: true,
369
+ tabControlOffset: 10
370
+ },
371
+ dimensions: {
372
+ borderWidth: 5,
373
+ borderGrabWidth: 15,
374
+ minItemHeight: 10,
375
+ minItemWidth: 10,
376
+ headerHeight: 20,
377
+ dragProxyWidth: 300,
378
+ dragProxyHeight: 200
379
+ },
380
+ labels: {
381
+ close: "Close",
382
+ maximise: "Maximize",
383
+ minimise: "Minimize",
384
+ popout: "open in new window",
385
+ popin: "pop in",
386
+ tabDropdown: "Additional Tabs"
387
+ },
388
+ content: [
389
+ {
390
+ type: rootType,
391
+ isClosable: true,
392
+ reorderEnabled: true,
393
+ title: "",
394
+ content: workspace.map(workspaceNodeToGL)
395
+ }
396
+ ],
397
+ isClosable: true,
398
+ reorderEnabled: true,
399
+ title: "",
400
+ openPopouts: [],
401
+ maximisedItemId: null
402
+ };
403
+ }
404
+
405
+ // src/core/compile/layoutBuilders/base.ts
406
+ function buildBaseLayoutState(layout, gridName) {
407
+ const columns = (layout.columns || []).filter((c) => c.property).map((c) => ({ dataIndex: c.property }));
408
+ const sorters = (layout.sorters || []).filter((s) => s.property && s.direction).map((s) => ({ direction: s.direction, property: s.property }));
409
+ let grouper;
410
+ if (layout.grouper && layout.grouper.property && layout.grouper.direction) {
411
+ grouper = {
412
+ root: "data",
413
+ property: layout.grouper.property,
414
+ direction: layout.grouper.direction,
415
+ id: layout.grouper.id || layout.grouper.property
416
+ };
417
+ }
418
+ const filters = (layout.filters || []).map((f) => ({
419
+ operator: f.operator || "like",
420
+ value: f.value || "",
421
+ property: f.property,
422
+ exactMatch: f.exactMatch ?? false
423
+ }));
424
+ const pageSize = layout.pageSize !== void 0 ? typeof layout.pageSize === "number" ? layout.pageSize : parseInt(String(layout.pageSize), 10) : 50;
425
+ const state = {
426
+ columns,
427
+ storeState: grouper ? { grouper } : {},
428
+ filters,
429
+ Id: layout.id || gridName,
430
+ pageSize: isNaN(pageSize) ? 50 : pageSize
431
+ };
432
+ if (sorters.length > 0) {
433
+ state.sorters = sorters;
434
+ }
435
+ if (layout.default) {
436
+ state.default = true;
437
+ }
438
+ if (layout.name) {
439
+ state.name = layout.name;
440
+ }
441
+ return state;
442
+ }
443
+
444
+ // src/core/compile/layoutBuilders/scheduler.ts
445
+ function buildSchedulerLayoutState(layout, gridName) {
446
+ const base = buildBaseLayoutState(layout, gridName);
447
+ const lockedGridWidth = layout.lockedGridWidth || layout.resourcesGridWidth || null;
448
+ const fitToScreen = typeof layout.fitToScreen === "boolean" ? layout.fitToScreen : layout.fitToScreen === "true";
449
+ const ignoreCalendars = typeof layout.ignoreCalendars === "boolean" ? layout.ignoreCalendars : layout.ignoreCalendars === "true";
450
+ return {
451
+ ...base,
452
+ viewPreset: layout.viewPreset !== void 0 ? mapViewPreset(layout.viewPreset) : null,
453
+ lockedGridWidth,
454
+ fitToScreen,
455
+ rowHeight: mapRowHeight(layout.rowHeight),
456
+ ignoreCalendars
457
+ };
458
+ }
459
+
460
+ // src/core/compile/layoutBuilders/capacity.ts
461
+ function buildCapacityLayoutState(layout, gridName) {
462
+ const base = buildBaseLayoutState(layout, gridName);
463
+ const state = { ...base };
464
+ if (layout.viewLayoutType !== void 0) state.viewLayoutType = layout.viewLayoutType;
465
+ if (layout.startRowGroupsCollapsed !== void 0) state.startRowGroupsCollapsed = layout.startRowGroupsCollapsed;
466
+ if (layout.startColGroupsCollapsed !== void 0) state.startColGroupsCollapsed = layout.startColGroupsCollapsed;
467
+ if (layout.enableColumnSort !== void 0) state.enableColumnSort = layout.enableColumnSort;
468
+ if (layout.expandedItems !== void 0) state.expandedItems = layout.expandedItems;
469
+ if (layout.matrix !== void 0) state.matrix = layout.matrix;
470
+ if (layout.pivotcolumns !== void 0) state.pivotcolumns = layout.pivotcolumns;
471
+ if (layout.collapsed !== void 0) state.collapsed = layout.collapsed;
472
+ return state;
473
+ }
474
+
475
+ // src/core/compile/layoutBuilders/gantt.ts
476
+ function buildGanttLayoutState(layout, gridName) {
477
+ const base = buildBaseLayoutState(layout, gridName);
478
+ const state = { ...base };
479
+ if (layout.viewPreset !== void 0) {
480
+ state.viewPreset = mapViewPreset(layout.viewPreset);
481
+ }
482
+ return state;
483
+ }
484
+
485
+ // src/core/compile/layoutBuilders/grid.ts
486
+ function buildGridLayoutState(layout, gridName) {
487
+ const base = buildBaseLayoutState(layout, gridName);
488
+ const state = { ...base };
489
+ if (layout.hideEmptyRows !== void 0) {
490
+ state.hideEmptyRows = layout.hideEmptyRows;
491
+ }
492
+ return state;
493
+ }
494
+
495
+ // src/core/compile/layoutBuilders/index.ts
496
+ function buildLayoutState(layout, gridName) {
497
+ const context = layout.context;
498
+ switch (context) {
499
+ case "scheduler":
500
+ return buildSchedulerLayoutState(layout, gridName);
501
+ case "pivotGrid":
502
+ return buildCapacityLayoutState(layout, gridName);
503
+ case "gantt":
504
+ return buildGanttLayoutState(layout, gridName);
505
+ case "unplannedTasksGrid":
506
+ case "plannedTasksGrid":
507
+ case "notificationsGrid":
508
+ case "detailsGrid":
509
+ case "routeSequenceGrid":
510
+ return buildGridLayoutState(layout, gridName);
511
+ default:
512
+ return buildBaseLayoutState(layout, gridName);
513
+ }
514
+ }
515
+
516
+ // src/core/compile/layoutBuilder.ts
517
+ function collectLayouts(layouts) {
518
+ return layouts.map((layout) => {
519
+ const gridName = layout.id || layout.code;
520
+ return {
521
+ context: layout.context,
522
+ grid: gridName,
523
+ value: buildLayoutState(layout, gridName),
524
+ name: layout.name || layout.code,
525
+ code: layout.code,
526
+ componentId: gridName,
527
+ default: layout.default ?? false,
528
+ public: layout.shared?.public ?? false,
529
+ userGroup: layout.shared?.userGroup
530
+ };
531
+ });
532
+ }
533
+ function buildLayoutDtos(layouts) {
534
+ if (!layouts || layouts.length === 0) return [];
535
+ return collectLayouts(layouts).map((L) => ({
536
+ context: L.context,
537
+ grid: L.grid,
538
+ value: JSON.stringify(L.value),
539
+ default: L.default,
540
+ public: L.public,
541
+ userGroup: L.userGroup,
542
+ isOwner: true,
543
+ isNew: true,
544
+ name: L.name,
545
+ code: L.code
546
+ }));
547
+ }
548
+ var PANEL_COMPONENTS = /* @__PURE__ */ new Set([
549
+ "planningBoard",
550
+ "scheduler",
551
+ "openTasks",
552
+ "tasks",
553
+ "plannedTasks",
554
+ "details",
555
+ "gantt",
556
+ "indicators",
557
+ "categories",
558
+ "capacity",
559
+ "pivot",
560
+ "notifications",
561
+ "routeSequence"
562
+ ]);
563
+ function buildProfileLayoutDtos(workspace, profileCode) {
564
+ if (!workspace || workspace.length === 0) return [];
565
+ const profileLayouts = [];
566
+ function traverse(nodes) {
567
+ for (const node of nodes) {
568
+ if (node.type === "row" || node.type === "column" || node.type === "stack") {
569
+ if ("content" in node && node.content) {
570
+ traverse(node.content);
571
+ }
572
+ } else if (node.type === "component") {
573
+ if (node.layoutRef) {
574
+ const refs = Array.isArray(node.layoutRef) ? node.layoutRef : [node.layoutRef];
575
+ const needsPanel = PANEL_COMPONENTS.has(node.component);
576
+ for (const code of refs) {
577
+ profileLayouts.push({
578
+ profileCode,
579
+ layoutCode: code,
580
+ default: true,
581
+ public: false,
582
+ name: node.id ? needsPanel ? `${node.id}_panel` : node.id : ""
583
+ });
584
+ }
585
+ }
586
+ }
587
+ }
588
+ }
589
+ traverse(workspace);
590
+ return profileLayouts;
591
+ }
592
+
593
+ // src/core/compile/profile.ts
594
+ var SNAP_MODE_VALUE = {
595
+ 1: 0,
596
+ // none
597
+ 2: 3e5,
598
+ // 5 min
599
+ 3: 6e5,
600
+ // 10 min
601
+ 4: 9e5,
602
+ // 15 min
603
+ 5: 18e5,
604
+ // 30 min
605
+ 6: 36e5,
606
+ // 1 hour
607
+ 7: 432e5,
608
+ // 12 hours
609
+ 8: 864e5,
610
+ // 1 day
611
+ 9: 72e5,
612
+ // 2 hours
613
+ 10: 144e5
614
+ // 4 hours
615
+ };
616
+ function getSnapMode(snapInterval) {
617
+ if (!snapInterval) return void 0;
618
+ if (typeof snapInterval === "string") return snapInterval;
619
+ return snapInterval.mode;
620
+ }
621
+ function getSnapValue(snapInterval, snapMode) {
622
+ if (typeof snapInterval === "object" && snapInterval?.value !== void 0 && snapInterval.value !== null) {
623
+ return snapInterval.value;
624
+ }
625
+ return SNAP_MODE_VALUE[snapMode] ?? 36e5;
626
+ }
627
+ function compileProfileDocument(doc) {
628
+ const profile = doc.payload;
629
+ const theme = profile.theme || { color: "default", scheme: "sdtd" };
630
+ const shared = profile.shared || { global: false, userGroup: "" };
631
+ const route = profile.route || {
632
+ profile: "default",
633
+ calculateRoutes: true,
634
+ showSequenceIndicators: true,
635
+ unitOfDistance: "km"
636
+ };
637
+ const planning = profile.planning || {
638
+ snapInterval: { mode: "1hour", value: 0 },
639
+ range: { mode: "week", value: 0 },
640
+ start: { mode: "startOfWeek", value: 2 },
641
+ hours: { start: 8, end: 18 }
642
+ };
643
+ const workspace = profile.workspace;
644
+ const goldenLayout = workspace && workspace.length > 0 ? workspaceToGoldenLayout(workspace) : null;
645
+ const layouts = [];
646
+ const profileLayouts = buildProfileLayoutDtos(workspace, profile.code || "");
647
+ const snapMode = mapSnapMode(getSnapMode(planning.snapInterval));
648
+ const snapValue = getSnapValue(planning.snapInterval, snapMode);
649
+ return {
650
+ id: "profile",
651
+ payload: {
652
+ profiles: [{
653
+ name: profile.name || "",
654
+ code: profile.code || "",
655
+ color: theme.color || "default",
656
+ theme: theme.scheme || "sdtd",
657
+ public: shared.global ?? false,
658
+ userGroup: shared.userGroup || "",
659
+ snapMode,
660
+ snapValue,
661
+ rangeMode: mapRangeMode(planning.range?.mode),
662
+ rangeValue: planning.range?.value ?? null,
663
+ startMode: mapStartMode(planning.start?.mode),
664
+ startValue: planning.start?.value ?? null,
665
+ startTime: planning.hours?.start ?? 8,
666
+ endTime: planning.hours?.end ?? 18,
667
+ unitOfDistance: mapUnitOfDistance(route.unitOfDistance),
668
+ autoRouteCalculation: route.calculateRoutes ?? true,
669
+ showSequenceIndicators: route.showSequenceIndicators ?? true,
670
+ routeProfile: mapRouteProfile(route.profile),
671
+ layout: goldenLayout ? JSON.stringify(goldenLayout) : ""
672
+ }],
673
+ layouts,
674
+ profileLayouts,
675
+ owner: doc.owner,
676
+ notificationEmail: doc.notificationEmail
677
+ }
678
+ };
679
+ }
680
+
681
+ // src/core/compile/users.ts
682
+ function compileUsersDocument(doc) {
683
+ return {
684
+ id: "users",
685
+ payload: {
686
+ users: doc.payload,
687
+ owner: doc.owner,
688
+ notificationEmail: doc.notificationEmail
689
+ }
690
+ };
691
+ }
692
+
693
+ // src/core/compile/layouts.ts
694
+ function compileLayoutsDocument(doc) {
695
+ return {
696
+ id: "layouts",
697
+ payload: {
698
+ layouts: buildLayoutDtos(doc.payload),
699
+ owner: doc.owner,
700
+ notificationEmail: doc.notificationEmail
701
+ }
702
+ };
703
+ }
704
+
705
+ // src/core/compile/bundle.ts
706
+ async function resolveBundle(bundle, basePath) {
707
+ const result = {
708
+ profiles: [],
709
+ users: [],
710
+ layouts: []
711
+ };
712
+ const strategy = bundle.mergeStrategy ?? {};
713
+ for (const item of bundle.documents) {
714
+ let doc;
715
+ if (isDocumentReference(item)) {
716
+ const refPath = resolve(dirname(basePath), item.$ref);
717
+ const content = await readFile(refPath, "utf-8");
718
+ const parsed = JSON5.parse(content);
719
+ if (!isProfileDocument(parsed) && !isUsersDocument(parsed) && !isLayoutsDocument(parsed)) {
720
+ throw new Error(`Referenced document at ${item.$ref} is not a valid document type (profile, users, or layouts)`);
721
+ }
722
+ doc = parsed;
723
+ if (item.$merge) {
724
+ doc = applyMergeOverrides(doc, item.$merge);
725
+ }
726
+ } else if (isProfileDocument(item) || isUsersDocument(item) || isLayoutsDocument(item)) {
727
+ doc = item;
728
+ } else {
729
+ continue;
730
+ }
731
+ if (isProfileDocument(doc)) {
732
+ result.profiles.push(doc);
733
+ } else if (isUsersDocument(doc)) {
734
+ result.users = mergeUsers(result.users, doc.payload ?? [], strategy.users);
735
+ } else if (isLayoutsDocument(doc)) {
736
+ result.layouts = mergeLayouts(result.layouts, doc.payload ?? [], strategy.layouts);
737
+ }
738
+ }
739
+ return result;
740
+ }
741
+ async function compileBundleDocument(bundle, basePath) {
742
+ const resolved = await resolveBundle(bundle, basePath);
743
+ const payloads = [];
744
+ const strategy = bundle.mergeStrategy ?? {};
745
+ if (resolved.profiles.length > 0) {
746
+ let profilesForCompile;
747
+ if (strategy.profiles === "error" && resolved.profiles.length > 1) {
748
+ throw new Error(`Multiple profiles found in bundle and mergeStrategy.profiles is 'error'`);
749
+ } else if (strategy.profiles === "first-wins") {
750
+ profilesForCompile = [resolved.profiles[0]];
751
+ } else {
752
+ profilesForCompile = [resolved.profiles[resolved.profiles.length - 1]];
753
+ }
754
+ for (const profile of profilesForCompile) {
755
+ payloads.push(compileProfileDocument(profile));
756
+ }
757
+ if (resolved.layouts.length > 0) {
758
+ const layoutsDoc = {
759
+ type: "layouts",
760
+ payload: resolved.layouts
761
+ };
762
+ payloads.push(compileLayoutsDocument(layoutsDoc));
763
+ }
764
+ }
765
+ if (resolved.profiles.length === 0) {
766
+ if (resolved.users.length > 0) {
767
+ const usersDoc = {
768
+ type: "users",
769
+ payload: resolved.users
770
+ };
771
+ payloads.push(compileUsersDocument(usersDoc));
772
+ }
773
+ if (resolved.layouts.length > 0) {
774
+ const layoutsDoc = {
775
+ type: "layouts",
776
+ payload: resolved.layouts
777
+ };
778
+ payloads.push(compileLayoutsDocument(layoutsDoc));
779
+ }
780
+ } else {
781
+ if (resolved.users.length > 0) {
782
+ const usersDoc = {
783
+ type: "users",
784
+ payload: resolved.users
785
+ };
786
+ payloads.push(compileUsersDocument(usersDoc));
787
+ }
788
+ }
789
+ return {
790
+ id: "bundle",
791
+ payloads
792
+ };
793
+ }
794
+ function compileBundleDocumentSync(bundle) {
795
+ for (const item of bundle.documents) {
796
+ if (isDocumentReference(item)) {
797
+ throw new Error("Bundle contains $ref items. Use compileBundleDocument (async) instead.");
798
+ }
799
+ }
800
+ const result = {
801
+ profiles: [],
802
+ users: [],
803
+ layouts: []
804
+ };
805
+ const strategy = bundle.mergeStrategy ?? {};
806
+ for (const item of bundle.documents) {
807
+ if (isProfileDocument(item)) {
808
+ result.profiles.push(item);
809
+ } else if (isUsersDocument(item)) {
810
+ result.users = mergeUsers(result.users, item.payload ?? [], strategy.users);
811
+ } else if (isLayoutsDocument(item)) {
812
+ result.layouts = mergeLayouts(result.layouts, item.payload ?? [], strategy.layouts);
813
+ }
814
+ }
815
+ const payloads = [];
816
+ if (result.profiles.length > 0) {
817
+ let profilesForCompile;
818
+ if (strategy.profiles === "error" && result.profiles.length > 1) {
819
+ throw new Error(`Multiple profiles found in bundle and mergeStrategy.profiles is 'error'`);
820
+ } else if (strategy.profiles === "first-wins") {
821
+ profilesForCompile = [result.profiles[0]];
822
+ } else {
823
+ profilesForCompile = [result.profiles[result.profiles.length - 1]];
824
+ }
825
+ for (const profile of profilesForCompile) {
826
+ payloads.push(compileProfileDocument(profile));
827
+ }
828
+ if (result.layouts.length > 0) {
829
+ payloads.push(compileLayoutsDocument({ type: "layouts", payload: result.layouts }));
830
+ }
831
+ }
832
+ if (result.profiles.length === 0) {
833
+ if (result.users.length > 0) {
834
+ payloads.push(compileUsersDocument({ type: "users", payload: result.users }));
835
+ }
836
+ if (result.layouts.length > 0) {
837
+ payloads.push(compileLayoutsDocument({ type: "layouts", payload: result.layouts }));
838
+ }
839
+ } else {
840
+ if (result.users.length > 0) {
841
+ payloads.push(compileUsersDocument({ type: "users", payload: result.users }));
842
+ }
843
+ }
844
+ return {
845
+ id: "bundle",
846
+ payloads
847
+ };
848
+ }
849
+
850
+ export {
851
+ isProfileDocument,
852
+ isUsersDocument,
853
+ isLayoutsDocument,
854
+ isBundleDocument,
855
+ isDocumentReference,
856
+ detectDocumentType,
857
+ compileProfileDocument,
858
+ compileUsersDocument,
859
+ compileLayoutsDocument,
860
+ resolveBundle,
861
+ compileBundleDocument,
862
+ compileBundleDocumentSync
863
+ };