gantt-lib 0.123.0 → 0.124.0

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.
@@ -1,2 +1,2 @@
1
- export { a7 as CascadeContext, D as DAY_MS, e as DependencyError, L as LinkType, a8 as ScheduleCommandOptions, a9 as ScheduleCommandResult, aa as ScheduleDependency, ab as ScheduleTask, ac as ScheduleTaskUpdate, T as Task, ad as TaskDependency, V as ValidationResult, ae as addBusinessDays, n as alignToWorkingDay, o as areTasksHierarchicallyRelated, p as buildAdjacencyList, q as buildTaskRangeFromEnd, r as buildTaskRangeFromStart, s as calculateSuccessorDate, t as cascadeByLinks, u as clampTaskRangeForIncomingFS, v as computeLagFromDates, w as computeParentDates, x as computeParentProgress, af as createCascadeContext, y as detectCycles, z as findParentId, A as getAllDependencyEdges, C as getAllDescendants, E as getBusinessDayOffset, ag as getBusinessDaysCount, F as getChildren, H as getDependencyLag, I as getSuccessorChain, J as getTaskDuration, K as getTransitiveCascadeChain, N as isAncestorTask, O as isTaskParent, P as moveTaskRange, Q as moveTaskWithCascade, S as normalizeDependencyLag, U as normalizePredecessorDates, X as normalizeTaskDependencyLags, Y as normalizeUTCDate, Z as parseDateOnly, _ as recalculateIncomingLags, $ as recalculateProjectSchedule, a0 as recalculateTaskFromDependencies, a1 as reflowTasksOnModeSwitch, a2 as removeDependenciesBetweenTasks, a3 as resizeTaskWithCascade, a4 as shiftBusinessDayOffset, ah as subtractBusinessDays, a5 as universalCascade, a6 as validateDependencies } from '../../index-OZVb2o_D.mjs';
1
+ export { aa as CascadeContext, C as CriticalPathOptions, D as DAY_MS, e as DependencyError, L as LinkType, ab as ScheduleCommandOptions, ac as ScheduleCommandResult, ad as ScheduleDependency, ae as ScheduleTask, af as ScheduleTaskUpdate, T as Task, ag as TaskDependency, V as ValidationResult, ah as addBusinessDays, n as alignToWorkingDay, o as areTasksHierarchicallyRelated, p as buildAdjacencyList, q as buildTaskRangeFromEnd, r as buildTaskRangeFromStart, s as calculateSuccessorDate, t as cascadeByLinks, u as clampTaskRangeForIncomingFS, v as computeCriticalPath, w as computeLagFromDates, x as computeParentDates, y as computeParentProgress, ai as createCascadeContext, z as detectCycles, A as extendCriticalIdsToParents, E as findParentId, F as getAllDependencyEdges, H as getAllDescendants, I as getBusinessDayOffset, aj as getBusinessDaysCount, J as getChildren, K as getDependencyLag, N as getSuccessorChain, O as getTaskDuration, P as getTransitiveCascadeChain, Q as isAncestorTask, S as isTaskParent, U as moveTaskRange, X as moveTaskWithCascade, Y as normalizeDependencyLag, Z as normalizePredecessorDates, _ as normalizeTaskDependencyLags, $ as normalizeUTCDate, a0 as parseDateOnly, a1 as recalculateIncomingLags, a2 as recalculateProjectSchedule, a3 as recalculateTaskFromDependencies, a4 as reflowTasksOnModeSwitch, a5 as removeDependenciesBetweenTasks, a6 as resizeTaskWithCascade, a7 as shiftBusinessDayOffset, ak as subtractBusinessDays, a8 as universalCascade, a9 as validateDependencies } from '../../index-DD3YvhvA.mjs';
2
2
  import 'react';
@@ -1,2 +1,2 @@
1
- export { a7 as CascadeContext, D as DAY_MS, e as DependencyError, L as LinkType, a8 as ScheduleCommandOptions, a9 as ScheduleCommandResult, aa as ScheduleDependency, ab as ScheduleTask, ac as ScheduleTaskUpdate, T as Task, ad as TaskDependency, V as ValidationResult, ae as addBusinessDays, n as alignToWorkingDay, o as areTasksHierarchicallyRelated, p as buildAdjacencyList, q as buildTaskRangeFromEnd, r as buildTaskRangeFromStart, s as calculateSuccessorDate, t as cascadeByLinks, u as clampTaskRangeForIncomingFS, v as computeLagFromDates, w as computeParentDates, x as computeParentProgress, af as createCascadeContext, y as detectCycles, z as findParentId, A as getAllDependencyEdges, C as getAllDescendants, E as getBusinessDayOffset, ag as getBusinessDaysCount, F as getChildren, H as getDependencyLag, I as getSuccessorChain, J as getTaskDuration, K as getTransitiveCascadeChain, N as isAncestorTask, O as isTaskParent, P as moveTaskRange, Q as moveTaskWithCascade, S as normalizeDependencyLag, U as normalizePredecessorDates, X as normalizeTaskDependencyLags, Y as normalizeUTCDate, Z as parseDateOnly, _ as recalculateIncomingLags, $ as recalculateProjectSchedule, a0 as recalculateTaskFromDependencies, a1 as reflowTasksOnModeSwitch, a2 as removeDependenciesBetweenTasks, a3 as resizeTaskWithCascade, a4 as shiftBusinessDayOffset, ah as subtractBusinessDays, a5 as universalCascade, a6 as validateDependencies } from '../../index-OZVb2o_D.js';
1
+ export { aa as CascadeContext, C as CriticalPathOptions, D as DAY_MS, e as DependencyError, L as LinkType, ab as ScheduleCommandOptions, ac as ScheduleCommandResult, ad as ScheduleDependency, ae as ScheduleTask, af as ScheduleTaskUpdate, T as Task, ag as TaskDependency, V as ValidationResult, ah as addBusinessDays, n as alignToWorkingDay, o as areTasksHierarchicallyRelated, p as buildAdjacencyList, q as buildTaskRangeFromEnd, r as buildTaskRangeFromStart, s as calculateSuccessorDate, t as cascadeByLinks, u as clampTaskRangeForIncomingFS, v as computeCriticalPath, w as computeLagFromDates, x as computeParentDates, y as computeParentProgress, ai as createCascadeContext, z as detectCycles, A as extendCriticalIdsToParents, E as findParentId, F as getAllDependencyEdges, H as getAllDescendants, I as getBusinessDayOffset, aj as getBusinessDaysCount, J as getChildren, K as getDependencyLag, N as getSuccessorChain, O as getTaskDuration, P as getTransitiveCascadeChain, Q as isAncestorTask, S as isTaskParent, U as moveTaskRange, X as moveTaskWithCascade, Y as normalizeDependencyLag, Z as normalizePredecessorDates, _ as normalizeTaskDependencyLags, $ as normalizeUTCDate, a0 as parseDateOnly, a1 as recalculateIncomingLags, a2 as recalculateProjectSchedule, a3 as recalculateTaskFromDependencies, a4 as reflowTasksOnModeSwitch, a5 as removeDependenciesBetweenTasks, a6 as resizeTaskWithCascade, a7 as shiftBusinessDayOffset, ak as subtractBusinessDays, a8 as universalCascade, a9 as validateDependencies } from '../../index-DD3YvhvA.js';
2
2
  import 'react';
@@ -30,11 +30,13 @@ __export(scheduling_exports, {
30
30
  calculateSuccessorDate: () => calculateSuccessorDate,
31
31
  cascadeByLinks: () => cascadeByLinks,
32
32
  clampTaskRangeForIncomingFS: () => clampTaskRangeForIncomingFS,
33
+ computeCriticalPath: () => computeCriticalPath,
33
34
  computeLagFromDates: () => computeLagFromDates,
34
35
  computeParentDates: () => computeParentDates,
35
36
  computeParentProgress: () => computeParentProgress,
36
37
  createCascadeContext: () => createCascadeContext,
37
38
  detectCycles: () => detectCycles,
39
+ extendCriticalIdsToParents: () => extendCriticalIdsToParents,
38
40
  findParentId: () => findParentId,
39
41
  getAllDependencyEdges: () => getAllDependencyEdges,
40
42
  getAllDescendants: () => getAllDescendants,
@@ -277,6 +279,159 @@ function calculateSuccessorDate(predecessorStart, predecessorEnd, linkType, lag
277
279
  return shiftBusinessDayOffset(anchorDate, offset, weekendPredicate);
278
280
  }
279
281
 
282
+ // src/core/scheduling/criticalPath.ts
283
+ function computeCriticalPath(tasks, options = {}) {
284
+ const { businessDays = false, weekendPredicate } = options;
285
+ const taskById = new Map(tasks.map((task) => [task.id, task]));
286
+ const childIds = /* @__PURE__ */ new Set();
287
+ for (const task of tasks) {
288
+ if (task.parentId) childIds.add(task.parentId);
289
+ }
290
+ const leafTasks = tasks.filter((task) => !childIds.has(task.id));
291
+ const leafIds = new Set(leafTasks.map((task) => task.id));
292
+ const leafIdsByAncestor = /* @__PURE__ */ new Map();
293
+ for (const leaf of leafTasks) {
294
+ let ancestor = leaf.parentId;
295
+ while (ancestor) {
296
+ const set = leafIdsByAncestor.get(ancestor) ?? /* @__PURE__ */ new Set();
297
+ set.add(leaf.id);
298
+ leafIdsByAncestor.set(ancestor, set);
299
+ ancestor = taskById.get(ancestor)?.parentId;
300
+ }
301
+ }
302
+ const durationOf = (task) => getTaskDuration(task.startDate, task.endDate, businessDays, weekendPredicate);
303
+ const projectStartDate = leafTasks.reduce((earliest, task) => {
304
+ const taskStart = parseDateOnly(task.startDate);
305
+ return taskStart.getTime() < earliest.getTime() ? taskStart : earliest;
306
+ }, parseDateOnly(leafTasks[0]?.startDate ?? /* @__PURE__ */ new Date()));
307
+ const offsetFromProjectStart = (date) => {
308
+ const targetDate = parseDateOnly(date);
309
+ if (businessDays && weekendPredicate) {
310
+ return getBusinessDayOffset(projectStartDate, targetDate, weekendPredicate);
311
+ }
312
+ return Math.round((targetDate.getTime() - projectStartDate.getTime()) / DAY_MS);
313
+ };
314
+ const scheduledStart = /* @__PURE__ */ new Map();
315
+ for (const leaf of leafTasks) {
316
+ scheduledStart.set(leaf.id, offsetFromProjectStart(leaf.startDate));
317
+ }
318
+ const succByPred = /* @__PURE__ */ new Map();
319
+ const predBySucc = /* @__PURE__ */ new Map();
320
+ const seenEdges = /* @__PURE__ */ new Set();
321
+ const addEdge = (predecessorId, succId, lag, type) => {
322
+ const edgeKey = `${predecessorId}|${succId}|${type}`;
323
+ if (seenEdges.has(edgeKey)) return;
324
+ seenEdges.add(edgeKey);
325
+ const outEdges = succByPred.get(predecessorId) ?? [];
326
+ outEdges.push({ succId, lag, type });
327
+ succByPred.set(predecessorId, outEdges);
328
+ const inEdges = predBySucc.get(succId) ?? [];
329
+ inEdges.push({ predId: predecessorId, lag, type });
330
+ predBySucc.set(succId, inEdges);
331
+ };
332
+ for (const succ of leafTasks) {
333
+ for (const dep of succ.dependencies ?? []) {
334
+ const lag = getDependencyLag(dep);
335
+ if (leafIds.has(dep.taskId)) {
336
+ addEdge(dep.taskId, succ.id, lag, dep.type);
337
+ continue;
338
+ }
339
+ const descendants = leafIdsByAncestor.get(dep.taskId);
340
+ if (!descendants || descendants.size === 0) continue;
341
+ for (const leafId of descendants) {
342
+ if (leafId === succ.id) continue;
343
+ addEdge(leafId, succ.id, lag, dep.type);
344
+ }
345
+ }
346
+ }
347
+ const indegree = /* @__PURE__ */ new Map();
348
+ for (const leaf of leafTasks) indegree.set(leaf.id, 0);
349
+ for (const edges of succByPred.values()) {
350
+ for (const { succId } of edges) {
351
+ indegree.set(succId, (indegree.get(succId) ?? 0) + 1);
352
+ }
353
+ }
354
+ const order = [];
355
+ const enqueued = /* @__PURE__ */ new Set();
356
+ const queue = leafTasks.filter((leaf) => (indegree.get(leaf.id) ?? 0) === 0).map((leaf) => leaf.id);
357
+ for (const id of queue) enqueued.add(id);
358
+ while (queue.length > 0) {
359
+ const current = queue.shift();
360
+ order.push(current);
361
+ for (const { succId } of succByPred.get(current) ?? []) {
362
+ const next = (indegree.get(succId) ?? 0) - 1;
363
+ indegree.set(succId, next);
364
+ if (next === 0 && !enqueued.has(succId)) {
365
+ enqueued.add(succId);
366
+ queue.push(succId);
367
+ }
368
+ }
369
+ }
370
+ const projectFinish = Math.max(
371
+ 0,
372
+ ...leafTasks.map((leaf) => (scheduledStart.get(leaf.id) ?? 0) + durationOf(leaf))
373
+ );
374
+ const LF = /* @__PURE__ */ new Map();
375
+ const LS = /* @__PURE__ */ new Map();
376
+ for (const leaf of leafTasks) LF.set(leaf.id, projectFinish);
377
+ for (let i = order.length - 1; i >= 0; i--) {
378
+ const id = order[i];
379
+ const task = taskById.get(id);
380
+ const durPred = durationOf(task);
381
+ const outEdges = succByPred.get(id) ?? [];
382
+ let lf = projectFinish;
383
+ if (outEdges.length > 0) {
384
+ const candidates = outEdges.map(({ succId, lag, type }) => {
385
+ const succLs = LS.get(succId) ?? projectFinish;
386
+ const durSucc = durationOf(taskById.get(succId));
387
+ switch (type) {
388
+ case "FS":
389
+ return succLs - lag;
390
+ case "SS":
391
+ return succLs - lag + durPred;
392
+ case "FF":
393
+ return succLs + durSucc - lag;
394
+ case "SF":
395
+ return succLs + durSucc - lag + durPred;
396
+ default:
397
+ return projectFinish;
398
+ }
399
+ });
400
+ lf = Math.min(projectFinish, ...candidates);
401
+ }
402
+ LF.set(id, lf);
403
+ LS.set(id, lf - durPred);
404
+ }
405
+ const critical = /* @__PURE__ */ new Set();
406
+ const ordered = new Set(order);
407
+ for (const leaf of leafTasks) {
408
+ if (!ordered.has(leaf.id)) continue;
409
+ const hasGraphEdge = (succByPred.get(leaf.id)?.length ?? 0) > 0 || (predBySucc.get(leaf.id)?.length ?? 0) > 0;
410
+ if (!hasGraphEdge && (leaf.dependencies?.length ?? 0) > 0) continue;
411
+ const es = scheduledStart.get(leaf.id) ?? 0;
412
+ const ls = LS.get(leaf.id) ?? 0;
413
+ if (ls - es <= 0) critical.add(leaf.id);
414
+ }
415
+ return critical;
416
+ }
417
+ function extendCriticalIdsToParents(criticalLeafIds, tasks) {
418
+ const result = new Set(criticalLeafIds);
419
+ const parentByChild = /* @__PURE__ */ new Map();
420
+ for (const task of tasks) {
421
+ if (task.parentId) parentByChild.set(task.id, task.parentId);
422
+ }
423
+ const stack = Array.from(criticalLeafIds);
424
+ while (stack.length > 0) {
425
+ const id = stack.pop();
426
+ const parentId = parentByChild.get(id);
427
+ if (parentId && !result.has(parentId)) {
428
+ result.add(parentId);
429
+ stack.push(parentId);
430
+ }
431
+ }
432
+ return result;
433
+ }
434
+
280
435
  // src/core/scheduling/commands.ts
281
436
  function buildTaskRangeFromStart(startDate, duration, businessDays = false, weekendPredicate, snapDirection = 1) {
282
437
  const normalizedStart = businessDays && weekendPredicate ? alignToWorkingDay(startDate, snapDirection, weekendPredicate) : normalizeUTCDate(startDate);
@@ -1260,11 +1415,13 @@ function validateDependencies(tasks) {
1260
1415
  calculateSuccessorDate,
1261
1416
  cascadeByLinks,
1262
1417
  clampTaskRangeForIncomingFS,
1418
+ computeCriticalPath,
1263
1419
  computeLagFromDates,
1264
1420
  computeParentDates,
1265
1421
  computeParentProgress,
1266
1422
  createCascadeContext,
1267
1423
  detectCycles,
1424
+ extendCriticalIdsToParents,
1268
1425
  findParentId,
1269
1426
  getAllDependencyEdges,
1270
1427
  getAllDescendants,