@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.
package/dist/index.js CHANGED
@@ -1,4 +1,15 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ compileLayoutsDocument,
4
+ compileProfileDocument,
5
+ compileUsersDocument,
6
+ detectDocumentType,
7
+ isBundleDocument,
8
+ isDocumentReference,
9
+ isLayoutsDocument,
10
+ isProfileDocument,
11
+ isUsersDocument
12
+ } from "./chunk-VHT6HO3N.js";
2
13
 
3
14
  // src/index.ts
4
15
  import { Command as Command4 } from "commander";
@@ -34,452 +45,177 @@ function hasComponent(nodes, componentType) {
34
45
  }
35
46
  return false;
36
47
  }
37
- function validateProfile(profile) {
48
+ function validateProfileSettings(settings, prefix = "") {
38
49
  const issues = [];
39
- if (!profile.name?.trim()) {
40
- issues.push({ type: "error", message: "Profile name is required" });
50
+ const p = prefix ? `${prefix}: ` : "";
51
+ if (!settings.name?.trim()) {
52
+ issues.push({ type: "error", message: `${p}Profile name is required` });
41
53
  }
42
- if (!profile.code?.trim()) {
43
- issues.push({ type: "error", message: "Profile code is required" });
54
+ if (!settings.code?.trim()) {
55
+ issues.push({ type: "error", message: `${p}Profile code is required` });
44
56
  }
45
- if (!profile.workspace || profile.workspace.length === 0) {
46
- issues.push({ type: "error", message: "Workspace must have at least one element" });
57
+ if (!settings.workspace || settings.workspace.length === 0) {
58
+ issues.push({ type: "error", message: `${p}Workspace must have at least one element` });
47
59
  } else {
48
- const componentCount = countComponents(profile.workspace);
60
+ const componentCount = countComponents(settings.workspace);
49
61
  if (componentCount === 0) {
50
- issues.push({ type: "warning", message: "Workspace has no components" });
62
+ issues.push({ type: "warning", message: `${p}Workspace has no components` });
51
63
  }
52
- const hasPlanningBoard = hasComponent(profile.workspace, "planningBoard");
64
+ const hasPlanningBoard = hasComponent(settings.workspace, "planningBoard");
53
65
  if (!hasPlanningBoard) {
54
- issues.push({ type: "warning", message: "Consider adding a Planning Board component" });
66
+ issues.push({ type: "warning", message: `${p}Consider adding a Planning Board component` });
55
67
  }
56
68
  }
57
- if (profile.users && profile.users.length > 0) {
58
- profile.users.forEach((user, index) => {
59
- if (!user.name?.trim()) {
60
- issues.push({ type: "error", message: `User ${index + 1}: Name is required` });
61
- }
62
- if (!user.email?.trim()) {
63
- issues.push({ type: "error", message: `User ${index + 1}: Email is required` });
64
- }
65
- });
66
- }
67
- const errors = issues.filter((i) => i.type === "error");
68
- const warnings = issues.filter((i) => i.type === "warning");
69
- return {
70
- valid: errors.length === 0,
71
- errors,
72
- warnings
73
- };
74
- }
75
-
76
- // src/core/compile.ts
77
- var SNAP_MODE_MAP = {
78
- "none": 1,
79
- "off": 1,
80
- "5min": 2,
81
- "5minutes": 2,
82
- "10min": 3,
83
- "10minutes": 3,
84
- "15min": 4,
85
- "15minutes": 4,
86
- "30min": 5,
87
- "30minutes": 5,
88
- "halfhour": 5,
89
- "1hour": 6,
90
- "1h": 6,
91
- "hour": 6,
92
- "12hours": 7,
93
- "12h": 7,
94
- "1day": 8,
95
- "1d": 8,
96
- "day": 8,
97
- "2hours": 9,
98
- "2h": 9,
99
- "4hours": 10,
100
- "4h": 10
101
- };
102
- var RANGE_MODE_MAP = {
103
- "day": 1,
104
- "days": 1,
105
- "hours": 1,
106
- "week": 2,
107
- "weeks": 2,
108
- "month": 3,
109
- "months": 3,
110
- "custom": 4
111
- };
112
- var START_MODE_MAP = {
113
- "today": 1,
114
- "absolute": 1,
115
- "startofweek": 2,
116
- "relative": 2,
117
- "startofmonth": 3,
118
- "todayoffset": 4
119
- };
120
- var COMPONENT_TO_GL = {
121
- "openTasks": "openTasksGridComponent",
122
- "planningBoard": "schedulerComponent",
123
- "mapComponent": "mapComponent",
124
- "indicators": "categoriesComponent",
125
- "resourceFilters": "filterComponent",
126
- "plannedTasksGridComponent": "plannedTasksGridComponent",
127
- "propertygridComponent": "propertygridComponent",
128
- "datePickerComponent": "datePickerComponent",
129
- "ganttComponent": "ganttComponent",
130
- "capacityComponent": "capacityComponent",
131
- "routeSequenceComponent": "routeSequenceComponent",
132
- "notificationsComponent": "notificationsComponent"
133
- };
134
- var COMPONENT_TO_CONTEXT = {
135
- "planningBoard": "scheduler",
136
- "openTasks": "unplannedTasksGrid",
137
- "plannedTasksGridComponent": "plannedTasksGrid",
138
- "notificationsComponent": "notificationsGrid",
139
- "propertygridComponent": "detailsGrid",
140
- "capacityComponent": "pivotGrid",
141
- "ganttComponent": "gantt",
142
- "routeSequenceComponent": "routeSequenceGrid"
143
- };
144
- var VIEW_PRESET_MAP = {
145
- "day": "1",
146
- "1": "1",
147
- "week": "2",
148
- "2": "2",
149
- "workweek": "3",
150
- "workWeek": "3",
151
- "work_week": "3",
152
- "3": "3",
153
- "month": "4",
154
- "4": "4"
155
- };
156
- var ROW_HEIGHT_MAP = {
157
- "1row": 25,
158
- "1rows": 25,
159
- "1": 25,
160
- "25": 25,
161
- "2rows": 38,
162
- "2row": 38,
163
- "2": 38,
164
- "38": 38,
165
- "3rows": 50,
166
- "3row": 50,
167
- "3": 50,
168
- "50": 50,
169
- "4rows": 63,
170
- "4row": 63,
171
- "4": 63,
172
- "63": 63
173
- };
174
- function mapSnapMode(mode) {
175
- if (!mode) return 6;
176
- return SNAP_MODE_MAP[mode.toLowerCase()] ?? 6;
177
- }
178
- function mapRangeMode(mode) {
179
- if (!mode) return 2;
180
- return RANGE_MODE_MAP[mode.toLowerCase()] ?? 2;
69
+ return issues;
181
70
  }
182
- function mapStartMode(mode) {
183
- if (!mode) return 2;
184
- return START_MODE_MAP[mode.toLowerCase().replace(/\s+/g, "")] ?? 2;
185
- }
186
- function mapUnitOfDistance(unit) {
187
- if (!unit) return "Kilometers";
188
- const v = unit.toLowerCase();
189
- if (["km", "kilometer", "kilometers"].includes(v)) return "Kilometers";
190
- if (["mi", "mile", "miles"].includes(v)) return "Miles";
191
- return unit;
192
- }
193
- function componentToGlName(name) {
194
- return COMPONENT_TO_GL[name] ?? name;
195
- }
196
- function componentToContext(name) {
197
- return COMPONENT_TO_CONTEXT[name] ?? name.toLowerCase();
198
- }
199
- function mapViewPreset(value) {
200
- if (value === void 0 || value === null) return "2";
201
- const v = String(value).toLowerCase().replace(/[\s_-]+/g, "");
202
- return VIEW_PRESET_MAP[v] ?? String(value);
203
- }
204
- function mapRowHeight(value) {
205
- if (value === void 0 || value === null) return 38;
206
- const v = String(value).toLowerCase().replace(/[\s_-]+/g, "");
207
- if (ROW_HEIGHT_MAP[v] !== void 0) return ROW_HEIGHT_MAP[v];
208
- const parsed = parseInt(String(value), 10);
209
- return isNaN(parsed) ? 38 : parsed;
210
- }
211
- function workspaceNodeToGL(node) {
212
- const gl = { type: node.type };
213
- if ("width" in node && node.width !== void 0) {
214
- gl.width = node.width;
215
- }
216
- if ("height" in node && node.height !== void 0) {
217
- gl.height = node.height;
218
- }
219
- if (node.type === "row" || node.type === "column" || node.type === "stack") {
220
- gl.isClosable = true;
221
- gl.reorderEnabled = true;
222
- gl.title = "";
223
- if ("content" in node && node.content) {
224
- gl.content = node.content.map(workspaceNodeToGL);
71
+ function validateUsers(users, prefix = "") {
72
+ const issues = [];
73
+ const p = prefix ? `${prefix} ` : "";
74
+ users.forEach((user, index) => {
75
+ if (!user.name?.trim()) {
76
+ issues.push({ type: "error", message: `${p}User ${index + 1}: Name is required` });
225
77
  }
226
- if (node.type === "stack") {
227
- gl.activeItemIndex = 0;
78
+ if (!user.email?.trim()) {
79
+ issues.push({ type: "error", message: `${p}User ${index + 1}: Email is required` });
228
80
  }
229
- return gl;
81
+ });
82
+ return issues;
83
+ }
84
+ function validateProfile(doc) {
85
+ const issues = [];
86
+ if (!doc || typeof doc !== "object") {
87
+ issues.push({ type: "error", message: "Invalid document: expected an object" });
88
+ return { valid: false, errors: issues, warnings: [] };
230
89
  }
231
- if (node.type === "component") {
232
- const compName = componentToGlName(node.component);
233
- if (compName) {
234
- gl.componentName = compName;
90
+ const obj = doc;
91
+ const docType = obj.type;
92
+ switch (docType) {
93
+ case "profile": {
94
+ if (!obj.payload || typeof obj.payload !== "object") {
95
+ issues.push({ type: "error", message: 'Profile document must have a "payload" property' });
96
+ } else {
97
+ issues.push(...validateProfileSettings(obj.payload));
98
+ }
99
+ break;
235
100
  }
236
- if (node.title !== void 0) {
237
- gl.title = node.title;
101
+ case "users": {
102
+ if (!Array.isArray(obj.payload)) {
103
+ issues.push({ type: "error", message: 'Users document must have a "payload" array' });
104
+ } else {
105
+ issues.push(...validateUsers(obj.payload));
106
+ }
107
+ break;
238
108
  }
239
- gl.isClosable = true;
240
- gl.reorderEnabled = true;
241
- const compState = {};
242
- const compId = node.id;
243
- if (compId) {
244
- gl.id = compId;
245
- compState.id = compId;
246
- } else if (compName === "schedulerComponent") {
247
- gl.id = "schedulerContainer";
248
- compState.id = "scheduler";
109
+ case "layouts": {
110
+ if (!Array.isArray(obj.payload)) {
111
+ issues.push({ type: "error", message: 'Layouts document must have a "payload" array' });
112
+ }
113
+ break;
249
114
  }
250
- if (compName === "datePickerComponent" && compId) {
251
- compState.wrapperId = compId;
115
+ case "bundle": {
116
+ if (!obj.name?.toString().trim()) {
117
+ issues.push({ type: "error", message: "Bundle name is required" });
118
+ }
119
+ if (!Array.isArray(obj.documents)) {
120
+ issues.push({ type: "error", message: 'Bundle must have a "documents" array' });
121
+ } else {
122
+ const documents = obj.documents;
123
+ let profileCount = 0;
124
+ documents.forEach((item, index) => {
125
+ if ("$ref" in item) {
126
+ if (typeof item.$ref !== "string") {
127
+ issues.push({ type: "error", message: `Document ${index + 1}: $ref must be a string` });
128
+ }
129
+ } else if (item.type === "profile") {
130
+ profileCount++;
131
+ if (item.payload && typeof item.payload === "object") {
132
+ const profileName = item.payload.name || `Profile ${profileCount}`;
133
+ issues.push(...validateProfileSettings(item.payload, profileName));
134
+ } else {
135
+ issues.push({ type: "error", message: `Document ${index + 1}: Profile must have a "payload" property` });
136
+ }
137
+ } else if (item.type === "users") {
138
+ if (Array.isArray(item.payload)) {
139
+ issues.push(...validateUsers(item.payload));
140
+ }
141
+ }
142
+ });
143
+ if (profileCount === 0) {
144
+ issues.push({ type: "warning", message: "Bundle contains no profile documents" });
145
+ }
146
+ }
147
+ break;
252
148
  }
253
- if (Object.keys(compState).length > 0) {
254
- gl.componentState = compState;
149
+ default: {
150
+ issues.push(...validateProfileSettings({
151
+ name: obj.name,
152
+ code: obj.code,
153
+ workspace: obj.workspace
154
+ }));
155
+ if (Array.isArray(obj.users)) {
156
+ issues.push(...validateUsers(obj.users));
157
+ }
255
158
  }
256
- return gl;
257
159
  }
258
- return gl;
259
- }
260
- function workspaceToGoldenLayout(workspace) {
160
+ const errors = issues.filter((i) => i.type === "error");
161
+ const warnings = issues.filter((i) => i.type === "warning");
261
162
  return {
262
- settings: {
263
- hasHeaders: true,
264
- constrainDragToContainer: false,
265
- reorderEnabled: true,
266
- selectionEnabled: true,
267
- popoutWholeStack: false,
268
- blockedPopoutsThrowError: true,
269
- closePopoutsOnUnload: true,
270
- showPopoutIcon: false,
271
- showMaximiseIcon: true,
272
- showCloseIcon: true,
273
- responsiveMode: "onload",
274
- tabOverlapAllowance: 0,
275
- reorderOnTabMenuClick: true,
276
- tabControlOffset: 10
277
- },
278
- dimensions: {
279
- borderWidth: 5,
280
- borderGrabWidth: 15,
281
- minItemHeight: 10,
282
- minItemWidth: 10,
283
- headerHeight: 20,
284
- dragProxyWidth: 300,
285
- dragProxyHeight: 200
286
- },
287
- labels: {
288
- close: "Close",
289
- maximise: "Maximize",
290
- minimise: "Minimize",
291
- popout: "open in new window",
292
- popin: "pop in",
293
- tabDropdown: "Additional Tabs"
294
- },
295
- content: [
296
- {
297
- type: "row",
298
- isClosable: true,
299
- reorderEnabled: true,
300
- title: "",
301
- content: workspace.map(workspaceNodeToGL)
302
- }
303
- ],
304
- isClosable: true,
305
- reorderEnabled: true,
306
- title: "",
307
- openPopouts: [],
308
- maximisedItemId: null
163
+ valid: errors.length === 0,
164
+ errors,
165
+ warnings
309
166
  };
310
167
  }
311
- function buildLayoutState(layout, gridName) {
312
- const columns = (layout.columns || []).filter((c) => c.property).map((c) => ({ dataIndex: c.property }));
313
- const sorters = (layout.sorters || []).filter((s) => s.property && s.direction).map((s) => ({ direction: s.direction, property: s.property }));
314
- let grouper = null;
315
- if (layout.grouper && layout.grouper.property && layout.grouper.direction) {
316
- grouper = {
317
- root: "data",
318
- property: layout.grouper.property,
319
- direction: layout.grouper.direction,
320
- id: layout.grouper.id || layout.grouper.property
321
- };
322
- }
323
- const filters = (layout.filters || []).map((f) => ({
324
- operator: f.operator || "like",
325
- value: f.value || "",
326
- property: f.property,
327
- exactMatch: f.exactMatch ?? false
328
- }));
329
- const lockedGridWidth = layout.lockedGridWidth || layout.resourcesGridWidth || null;
330
- const fitToScreen = typeof layout.fitToScreen === "boolean" ? layout.fitToScreen : layout.fitToScreen === "true";
331
- const ignoreCalendars = typeof layout.ignoreCalendars === "boolean" ? layout.ignoreCalendars : layout.ignoreCalendars === "true";
332
- const pageSize = layout.pageSize !== void 0 ? typeof layout.pageSize === "number" ? layout.pageSize : parseInt(String(layout.pageSize), 10) : 50;
333
- const state = {
334
- columns,
335
- storeState: grouper ? { grouper } : {},
336
- filters,
337
- viewPreset: layout.viewPreset !== void 0 ? mapViewPreset(layout.viewPreset) : null,
338
- Id: layout.id || gridName,
339
- lockedGridWidth,
340
- pageSize: isNaN(pageSize) ? 50 : pageSize,
341
- fitToScreen,
342
- rowHeight: mapRowHeight(layout.rowHeight),
343
- ignoreCalendars
168
+
169
+ // src/core/compile/index.ts
170
+ function compileToApiPayload(doc) {
171
+ const result = {
172
+ profiles: [],
173
+ layouts: [],
174
+ profileLayouts: [],
175
+ users: []
344
176
  };
345
- if (sorters.length > 0) {
346
- state.sorters = sorters;
347
- }
348
- if (layout.default) {
349
- state.default = true;
350
- }
351
- if (layout.name) {
352
- state.name = layout.name;
353
- }
354
- const extraFields = [
355
- "viewLayoutType",
356
- "startRowGroupsCollapsed",
357
- "startColGroupsCollapsed",
358
- "enableColumnSort",
359
- "expandedItems",
360
- "matrix",
361
- "pivotcolumns",
362
- "collapsed",
363
- "hideEmptyRows"
364
- ];
365
- for (const field of extraFields) {
366
- if (layout[field] !== void 0) {
367
- state[field] = layout[field];
368
- }
369
- }
370
- return state;
371
- }
372
- function collectLayouts(nodes) {
373
- const acc = [];
374
- for (const node of nodes) {
375
- if (node.type === "row" || node.type === "column" || node.type === "stack") {
376
- if ("content" in node && node.content) {
377
- acc.push(...collectLayouts(node.content));
177
+ if (isProfileDocument(doc)) {
178
+ const compiled = compileProfileDocument(doc);
179
+ result.profiles = compiled.payload.profiles;
180
+ result.layouts = compiled.payload.layouts;
181
+ result.profileLayouts = compiled.payload.profileLayouts;
182
+ result.owner = compiled.payload.owner;
183
+ result.notificationEmail = compiled.payload.notificationEmail;
184
+ } else if (isUsersDocument(doc)) {
185
+ const compiled = compileUsersDocument(doc);
186
+ result.users = compiled.payload.users;
187
+ result.owner = compiled.payload.owner;
188
+ result.notificationEmail = compiled.payload.notificationEmail;
189
+ } else if (isLayoutsDocument(doc)) {
190
+ const compiled = compileLayoutsDocument(doc);
191
+ result.layouts = compiled.payload.layouts;
192
+ result.owner = compiled.payload.owner;
193
+ result.notificationEmail = compiled.payload.notificationEmail;
194
+ } else if (isBundleDocument(doc)) {
195
+ const bundle = doc;
196
+ for (const item of bundle.documents) {
197
+ if (isDocumentReference(item)) {
198
+ throw new Error("Bundle contains $ref items. Use compileToApiPayloadAsync instead.");
378
199
  }
379
- } else if (node.type === "component") {
380
- const layouts = node.layouts || [];
381
- const layoutArray = Array.isArray(layouts) ? layouts : [layouts];
382
- for (const layoutItem of layoutArray) {
383
- const context = componentToContext(node.component);
384
- let gridName;
385
- if (node.component === "planningBoard" && !layoutItem.id) {
386
- gridName = "scheduler_panel";
387
- } else {
388
- gridName = layoutItem.id || `${node.id}_panel`;
389
- }
390
- const layoutName = layoutItem.name || node.title || gridName;
391
- let layoutCode = layoutItem.code;
392
- if (!layoutCode && gridName) {
393
- layoutCode = gridName.toUpperCase().replace(/-/g, "_");
394
- }
395
- acc.push({
396
- context,
397
- grid: gridName,
398
- value: buildLayoutState(layoutItem, gridName),
399
- name: layoutName,
400
- code: layoutCode || gridName.toUpperCase(),
401
- componentId: gridName,
402
- default: layoutItem.default ?? false,
403
- public: layoutItem.shared?.public ?? false,
404
- userGroup: layoutItem.shared?.userGroup
405
- });
200
+ if (isProfileDocument(item)) {
201
+ const compiled = compileProfileDocument(item);
202
+ result.profiles.push(...compiled.payload.profiles);
203
+ result.layouts.push(...compiled.payload.layouts);
204
+ result.profileLayouts.push(...compiled.payload.profileLayouts);
205
+ } else if (isUsersDocument(item)) {
206
+ const compiled = compileUsersDocument(item);
207
+ result.users.push(...compiled.payload.users);
208
+ } else if (isLayoutsDocument(item)) {
209
+ const compiled = compileLayoutsDocument(item);
210
+ result.layouts.push(...compiled.payload.layouts);
406
211
  }
407
212
  }
213
+ result.owner = bundle.owner;
214
+ result.notificationEmail = bundle.notificationEmail;
215
+ } else {
216
+ throw new Error("Unknown document type. Expected profile, users, layouts, or bundle at root.");
408
217
  }
409
- return acc;
410
- }
411
- function buildLayoutDtos(workspace) {
412
- const layouts = collectLayouts(workspace);
413
- return layouts.map((L) => ({
414
- context: L.context,
415
- grid: L.grid,
416
- value: JSON.stringify(L.value),
417
- default: L.default,
418
- public: L.public,
419
- userGroup: L.userGroup,
420
- isOwner: true,
421
- isNew: true,
422
- name: L.name,
423
- code: L.code
424
- }));
425
- }
426
- function buildProfileLayoutDtos(workspace, profileCode) {
427
- const layouts = collectLayouts(workspace);
428
- return layouts.filter((L) => L.default && L.code).map((L) => ({
429
- profileCode,
430
- layoutCode: L.code,
431
- default: true,
432
- public: false,
433
- name: L.componentId
434
- }));
435
- }
436
- function compileProfile(profile) {
437
- const theme = profile.theme || { color: "default", scheme: "sdtd" };
438
- const shared = profile.shared || { global: false, userGroup: "" };
439
- const route = profile.route || {
440
- profile: "default",
441
- calculateRoutes: true,
442
- showSequenceIndicators: true,
443
- unitOfDistance: "km"
444
- };
445
- const planning = profile.planning || {
446
- snapInterval: { mode: "1hour", value: 0 },
447
- range: { mode: "week", value: 0 },
448
- start: { mode: "startOfWeek", value: 2 },
449
- hours: { start: 8, end: 18 }
450
- };
451
- const workspace = profile.workspace || [];
452
- const goldenLayout = workspaceToGoldenLayout(workspace);
453
- const layouts = buildLayoutDtos(workspace);
454
- const profileLayouts = buildProfileLayoutDtos(workspace, profile.code || "");
455
- return {
456
- profile: {
457
- name: profile.name || "",
458
- code: profile.code || "",
459
- color: theme.color || "default",
460
- theme: theme.scheme || "sdtd",
461
- public: shared.global ?? false,
462
- userGroup: shared.userGroup || "",
463
- snapMode: mapSnapMode(planning.snapInterval?.mode),
464
- snapValue: planning.snapInterval?.value ?? null,
465
- rangeMode: mapRangeMode(planning.range?.mode),
466
- rangeValue: planning.range?.value ?? null,
467
- startMode: mapStartMode(planning.start?.mode),
468
- startValue: planning.start?.value ?? null,
469
- startTime: planning.hours?.start ?? 8,
470
- endTime: planning.hours?.end ?? 18,
471
- unitOfDistance: mapUnitOfDistance(route.unitOfDistance),
472
- autoRouteCalculation: route.calculateRoutes ?? true,
473
- showSequenceIndicators: route.showSequenceIndicators ?? true,
474
- routeProfile: route.profile || "default",
475
- layout: JSON.stringify(goldenLayout)
476
- },
477
- layouts,
478
- profileLayouts,
479
- users: profile.users || [],
480
- owner: profile.owner,
481
- notificationEmail: profile.notificationEmail
482
- };
218
+ return result;
483
219
  }
484
220
 
485
221
  // src/commands/validate.ts
@@ -487,9 +223,9 @@ var validateCommand = new Command("validate").description("Validate a configurat
487
223
  try {
488
224
  const filePath = resolve(normalize(file));
489
225
  const content = readFileSync(filePath, "utf-8");
490
- let profile;
226
+ let doc;
491
227
  try {
492
- profile = JSON5.parse(content);
228
+ doc = JSON5.parse(content);
493
229
  } catch {
494
230
  if (options.json) {
495
231
  console.log(JSON.stringify({ valid: false, errors: [{ type: "error", message: "Invalid JSON5 syntax" }], warnings: [] }));
@@ -498,7 +234,7 @@ var validateCommand = new Command("validate").description("Validate a configurat
498
234
  }
499
235
  process.exit(1);
500
236
  }
501
- const result = validateProfile(profile);
237
+ const result = validateProfile(doc);
502
238
  if (options.json) {
503
239
  console.log(JSON.stringify(result, null, 2));
504
240
  } else {
@@ -543,15 +279,20 @@ var compileCommand = new Command2("compile").description("Compile a JSON5 config
543
279
  try {
544
280
  const filePath = resolve2(normalize2(file));
545
281
  const content = readFileSync2(filePath, "utf-8");
546
- let profile;
282
+ let doc;
547
283
  try {
548
- profile = JSON52.parse(content);
284
+ doc = JSON52.parse(content);
549
285
  } catch {
550
286
  console.error(pc2.red("Error:"), "Invalid JSON5 syntax in", file);
551
287
  process.exit(1);
552
288
  }
289
+ const docType = detectDocumentType(doc);
290
+ if (!docType) {
291
+ console.error(pc2.red("Error:"), "Unknown document type. Expected profile, users, layouts, or bundle at root.");
292
+ process.exit(1);
293
+ }
553
294
  if (!options.skipValidation) {
554
- const validation = validateProfile(profile);
295
+ const validation = validateProfile(doc);
555
296
  if (!validation.valid) {
556
297
  console.error(pc2.red("Error:"), "Configuration has validation errors:");
557
298
  for (const error of validation.errors) {
@@ -562,8 +303,8 @@ var compileCommand = new Command2("compile").description("Compile a JSON5 config
562
303
  process.exit(1);
563
304
  }
564
305
  }
565
- const payload = compileProfile(profile);
566
- const jsonOutput = JSON.stringify(payload, null, 2);
306
+ const result = compileToApiPayload(doc);
307
+ const jsonOutput = JSON.stringify(result, null, 2);
567
308
  if (options.stdout) {
568
309
  console.log(jsonOutput);
569
310
  } else {
@@ -572,7 +313,7 @@ var compileCommand = new Command2("compile").description("Compile a JSON5 config
572
313
  const outputPath = resolve2(outputDir, `${inputBasename}.json`);
573
314
  mkdirSync(outputDir, { recursive: true });
574
315
  writeFileSync(outputPath, jsonOutput, "utf-8");
575
- console.log(pc2.green("\u2713"), "Compiled to", outputPath);
316
+ console.log(pc2.green("\u2713"), `Compiled ${docType} document to`, outputPath);
576
317
  }
577
318
  process.exit(0);
578
319
  } catch (err) {
@@ -605,7 +346,7 @@ async function confirm(message) {
605
346
  });
606
347
  });
607
348
  }
608
- async function deployToApi(payload, url, apiKey) {
349
+ async function deployToApi(result, docType, url, apiKey) {
609
350
  try {
610
351
  const response = await fetch(`${url}/import/setup`, {
611
352
  method: "POST",
@@ -613,10 +354,10 @@ async function deployToApi(payload, url, apiKey) {
613
354
  "Content-Type": "application/json",
614
355
  "X-API-KEY": apiKey
615
356
  },
616
- body: JSON.stringify(payload)
357
+ body: JSON.stringify(result)
617
358
  });
618
359
  if (response.ok) {
619
- return { success: true, message: "Profile deployed successfully" };
360
+ return { success: true, message: `${docType} document deployed successfully` };
620
361
  } else {
621
362
  const text = await response.text();
622
363
  return { success: false, message: `HTTP ${response.status}`, error: text };
@@ -648,9 +389,9 @@ var deployCommand = new Command3("deploy").description("Deploy a configuration t
648
389
  process.exit(1);
649
390
  }
650
391
  const apiUrl = ENVIRONMENT_URLS[options.env];
651
- let profile;
392
+ let doc;
652
393
  try {
653
- profile = JSON53.parse(content);
394
+ doc = JSON53.parse(content);
654
395
  } catch {
655
396
  if (options.json) {
656
397
  console.log(JSON.stringify({ success: false, error: "Invalid JSON5 syntax" }));
@@ -659,8 +400,17 @@ var deployCommand = new Command3("deploy").description("Deploy a configuration t
659
400
  }
660
401
  process.exit(1);
661
402
  }
662
- if (!options.skipValidation) {
663
- const validation = validateProfile(profile);
403
+ const docType = detectDocumentType(doc);
404
+ if (!docType) {
405
+ if (options.json) {
406
+ console.log(JSON.stringify({ success: false, error: "Unknown document type. Expected profile, users, or layouts at root." }));
407
+ } else {
408
+ console.error(pc3.red("Error:"), "Unknown document type. Expected profile, users, or layouts at root.");
409
+ }
410
+ process.exit(1);
411
+ }
412
+ if (!options.skipValidation && isProfileDocument(doc)) {
413
+ const validation = validateProfile(doc);
664
414
  if (!validation.valid) {
665
415
  if (options.json) {
666
416
  console.log(JSON.stringify({ success: false, error: "Validation failed", details: validation.errors }));
@@ -673,12 +423,12 @@ var deployCommand = new Command3("deploy").description("Deploy a configuration t
673
423
  process.exit(1);
674
424
  }
675
425
  }
676
- const payload = compileProfile(profile);
426
+ const result = compileToApiPayload(doc);
677
427
  if (options.dryRun) {
678
428
  if (options.json) {
679
- console.log(JSON.stringify({ success: true, message: "Dry run successful", payload }));
429
+ console.log(JSON.stringify({ success: true, message: "Dry run successful", result }));
680
430
  } else {
681
- console.log(pc3.green("\u2713"), "Dry run successful - configuration is valid and compiled");
431
+ console.log(pc3.green("\u2713"), `Dry run successful - ${docType} document is valid and compiled`);
682
432
  console.log(pc3.dim(" Would deploy to:"), apiUrl);
683
433
  }
684
434
  process.exit(0);
@@ -686,7 +436,10 @@ var deployCommand = new Command3("deploy").description("Deploy a configuration t
686
436
  if (!options.yes && !options.json) {
687
437
  console.log();
688
438
  console.log(pc3.bold("Deploy Summary:"));
689
- console.log(` Profile: ${pc3.cyan(profile.name || "unnamed")} (${profile.code || "no code"})`);
439
+ console.log(` Document type: ${pc3.cyan(docType)}`);
440
+ if (isProfileDocument(doc)) {
441
+ console.log(` Profile: ${pc3.cyan(doc.payload.name || "unnamed")} (${doc.payload.code || "no code"})`);
442
+ }
690
443
  console.log(` Environment: ${pc3.yellow(options.env)}`);
691
444
  console.log(` Target: ${pc3.dim(apiUrl)}`);
692
445
  console.log();
@@ -699,20 +452,20 @@ var deployCommand = new Command3("deploy").description("Deploy a configuration t
699
452
  if (!options.json) {
700
453
  console.log(pc3.dim("Deploying..."));
701
454
  }
702
- const result = await deployToApi(payload, apiUrl, apiKey);
455
+ const deployResult = await deployToApi(result, docType, apiUrl, apiKey);
703
456
  if (options.json) {
704
- console.log(JSON.stringify(result));
457
+ console.log(JSON.stringify(deployResult));
705
458
  } else {
706
- if (result.success) {
707
- console.log(pc3.green("\u2713"), result.message);
459
+ if (deployResult.success) {
460
+ console.log(pc3.green("\u2713"), deployResult.message);
708
461
  } else {
709
- console.error(pc3.red("\u2717"), result.message);
710
- if (result.error) {
711
- console.error(pc3.dim(" "), result.error);
462
+ console.error(pc3.red("\u2717"), deployResult.message);
463
+ if (deployResult.error) {
464
+ console.error(pc3.dim(" "), deployResult.error);
712
465
  }
713
466
  }
714
467
  }
715
- process.exit(result.success ? 0 : 2);
468
+ process.exit(deployResult.success ? 0 : 2);
716
469
  } catch (err) {
717
470
  if (options.json) {
718
471
  console.log(JSON.stringify({ success: false, error: String(err) }));
@@ -725,8 +478,12 @@ var deployCommand = new Command3("deploy").description("Deploy a configuration t
725
478
 
726
479
  // src/index.ts
727
480
  var program = new Command4();
728
- program.name("dimescheduler-setup").description("CLI tool to validate, compile, and deploy Dime.Scheduler configurations").version("0.1.0");
481
+ program.name("dimescheduler-setup").description("CLI tool to validate, compile, and deploy Dime.Scheduler configurations").version("0.1.3");
729
482
  program.addCommand(validateCommand);
730
483
  program.addCommand(compileCommand);
731
484
  program.addCommand(deployCommand);
485
+ if (process.argv.length <= 2) {
486
+ program.outputHelp();
487
+ process.exit(0);
488
+ }
732
489
  program.parse();