gantt-lib 0.126.0 → 0.127.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.
- package/dist/core/scheduling/index.d.mts +1 -1
- package/dist/core/scheduling/index.d.ts +1 -1
- package/dist/core/scheduling/index.js +16 -0
- package/dist/core/scheduling/index.js.map +1 -1
- package/dist/core/scheduling/index.mjs +15 -0
- package/dist/core/scheduling/index.mjs.map +1 -1
- package/dist/{index-B1yy4LX0.d.mts → index-B1YUnlWS.d.mts} +9 -1
- package/dist/{index-B1yy4LX0.d.ts → index-B1YUnlWS.d.ts} +9 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +16 -26
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +16 -26
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
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,
|
|
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, ai as cascadeTaskProgress, u as clampTaskRangeForIncomingFS, v as computeCriticalPath, w as computeLagFromDates, x as computeParentDates, y as computeParentProgress, aj as createCascadeContext, z as detectCycles, A as extendCriticalIdsToParents, E as findParentId, F as getAllDependencyEdges, H as getAllDescendants, I as getBusinessDayOffset, ak 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, al as subtractBusinessDays, a8 as universalCascade, a9 as validateDependencies } from '../../index-B1YUnlWS.mjs';
|
|
2
2
|
import 'react';
|
|
@@ -1,2 +1,2 @@
|
|
|
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,
|
|
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, ai as cascadeTaskProgress, u as clampTaskRangeForIncomingFS, v as computeCriticalPath, w as computeLagFromDates, x as computeParentDates, y as computeParentProgress, aj as createCascadeContext, z as detectCycles, A as extendCriticalIdsToParents, E as findParentId, F as getAllDependencyEdges, H as getAllDescendants, I as getBusinessDayOffset, ak 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, al as subtractBusinessDays, a8 as universalCascade, a9 as validateDependencies } from '../../index-B1YUnlWS.js';
|
|
2
2
|
import 'react';
|
|
@@ -29,6 +29,7 @@ __export(scheduling_exports, {
|
|
|
29
29
|
buildTaskRangeFromStart: () => buildTaskRangeFromStart,
|
|
30
30
|
calculateSuccessorDate: () => calculateSuccessorDate,
|
|
31
31
|
cascadeByLinks: () => cascadeByLinks,
|
|
32
|
+
cascadeTaskProgress: () => cascadeTaskProgress,
|
|
32
33
|
clampTaskRangeForIncomingFS: () => clampTaskRangeForIncomingFS,
|
|
33
34
|
computeCriticalPath: () => computeCriticalPath,
|
|
34
35
|
computeLagFromDates: () => computeLagFromDates,
|
|
@@ -912,6 +913,20 @@ function getAllDescendants(parentId, tasks) {
|
|
|
912
913
|
collectChildren(parentId);
|
|
913
914
|
return descendants;
|
|
914
915
|
}
|
|
916
|
+
function cascadeTaskProgress(task, tasks) {
|
|
917
|
+
const progress = task.progress;
|
|
918
|
+
if (progress !== 0 && progress !== 100) {
|
|
919
|
+
return [task];
|
|
920
|
+
}
|
|
921
|
+
const descendants = getAllDescendants(task.id, tasks);
|
|
922
|
+
if (descendants.length === 0) {
|
|
923
|
+
return [task];
|
|
924
|
+
}
|
|
925
|
+
return [
|
|
926
|
+
{ ...task, progress },
|
|
927
|
+
...descendants.map((descendant) => ({ ...descendant, progress }))
|
|
928
|
+
];
|
|
929
|
+
}
|
|
915
930
|
function getAllDependencyEdges(tasks) {
|
|
916
931
|
const edges = [];
|
|
917
932
|
for (const task of tasks) {
|
|
@@ -1425,6 +1440,7 @@ function validateDependencies(tasks) {
|
|
|
1425
1440
|
buildTaskRangeFromStart,
|
|
1426
1441
|
calculateSuccessorDate,
|
|
1427
1442
|
cascadeByLinks,
|
|
1443
|
+
cascadeTaskProgress,
|
|
1428
1444
|
clampTaskRangeForIncomingFS,
|
|
1429
1445
|
computeCriticalPath,
|
|
1430
1446
|
computeLagFromDates,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/scheduling/index.ts","../../../src/core/scheduling/dateMath.ts","../../../src/core/scheduling/dependencies.ts","../../../src/core/scheduling/criticalPath.ts","../../../src/core/scheduling/commands.ts","../../../src/core/scheduling/cascade.ts","../../../src/core/scheduling/hierarchy.ts","../../../src/core/scheduling/execute.ts","../../../src/core/scheduling/modeSwitch.ts","../../../src/core/scheduling/validation.ts"],"sourcesContent":["/**\n * Core scheduling module — runtime-agnostic scheduling logic.\n * Zero React/DOM/date-fns dependencies.\n */\nexport * from './types';\nexport * from './dateMath';\nexport * from './dependencies';\nexport * from './criticalPath';\nexport * from './cascade';\nexport * from './modeSwitch';\nexport * from './commands';\nexport * from './execute';\nexport * from './validation';\nexport * from './hierarchy';\n","/**\n * Pure date math utilities for the core scheduling module.\n * Zero React/DOM/date-fns dependencies.\n *\n * Functions moved from:\n * - dependencyUtils.ts: normalizeUTCDate, parseDateOnly, getBusinessDayOffset, shiftBusinessDayOffset, DAY_MS\n * - dateUtils.ts: getBusinessDaysCount, addBusinessDays, subtractBusinessDays\n */\n\nexport const DAY_MS = 24 * 60 * 60 * 1000;\n\n/**\n * Normalize a Date to UTC midnight (hours/minutes/seconds zeroed).\n */\nexport function normalizeUTCDate(date: Date): Date {\n return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));\n}\n\n/**\n * Parse a date string or Date object to a UTC midnight Date.\n * Handles ISO strings like \"2025-01-15\" by appending T00:00:00.000Z.\n */\nexport function parseDateOnly(date: string | Date): Date {\n const parsed = typeof date === 'string'\n ? new Date(`${date.split('T')[0]}T00:00:00.000Z`)\n : normalizeUTCDate(date);\n return normalizeUTCDate(parsed);\n}\n\n/**\n * Compute the business-day offset between two dates.\n * Steps through each calendar day, counting only non-weekend days.\n * Returns a positive number if toDate > fromDate, negative if toDate < fromDate.\n */\nexport function getBusinessDayOffset(\n fromDate: Date,\n toDate: Date,\n weekendPredicate: (date: Date) => boolean\n): number {\n const from = normalizeUTCDate(fromDate);\n const to = normalizeUTCDate(toDate);\n\n if (from.getTime() === to.getTime()) {\n return 0;\n }\n\n const step = to.getTime() > from.getTime() ? 1 : -1;\n const current = new Date(from);\n let offset = 0;\n\n while (current.getTime() !== to.getTime()) {\n current.setUTCDate(current.getUTCDate() + step);\n if (!weekendPredicate(current)) {\n offset += step;\n }\n }\n\n return offset;\n}\n\n/**\n * Shift a date by a business-day offset, skipping weekends.\n */\nexport function shiftBusinessDayOffset(\n date: Date,\n offset: number,\n weekendPredicate: (date: Date) => boolean\n): Date {\n const current = normalizeUTCDate(date);\n\n if (offset === 0) {\n return current;\n }\n\n const step = offset > 0 ? 1 : -1;\n let remaining = Math.abs(offset);\n\n while (remaining > 0) {\n current.setUTCDate(current.getUTCDate() + step);\n if (!weekendPredicate(current)) {\n remaining--;\n }\n }\n\n return current;\n}\n\n/**\n * Count business days between two dates (inclusive), excluding weekends.\n * Returns minimum 1.\n */\nexport function getBusinessDaysCount(\n startDate: string | Date,\n endDate: string | Date,\n weekendPredicate: (date: Date) => boolean\n): number {\n const start = typeof startDate === 'string'\n ? new Date(`${startDate.split('T')[0]}T00:00:00.000Z`)\n : normalizeUTCDate(startDate);\n const end = typeof endDate === 'string'\n ? new Date(`${endDate.split('T')[0]}T00:00:00.000Z`)\n : normalizeUTCDate(endDate);\n\n let count = 0;\n const current = new Date(start);\n\n while (current.getTime() <= end.getTime()) {\n if (!weekendPredicate(current)) {\n count++;\n }\n current.setUTCDate(current.getUTCDate() + 1);\n }\n\n return Math.max(1, count);\n}\n\n/**\n * Calculate end date by adding N business days to start date.\n * Returns a Date object.\n */\nexport function addBusinessDays(\n startDate: string | Date,\n businessDays: number,\n weekendPredicate: (date: Date) => boolean\n): Date {\n const start = typeof startDate === 'string'\n ? new Date(`${startDate.split('T')[0]}T00:00:00.000Z`)\n : normalizeUTCDate(startDate);\n const current = new Date(start);\n let targetDays = Math.max(1, businessDays);\n let businessDaysCounted = 0;\n\n while (businessDaysCounted < targetDays) {\n if (!weekendPredicate(current)) {\n businessDaysCounted++;\n }\n if (businessDaysCounted < targetDays) {\n current.setUTCDate(current.getUTCDate() + 1);\n }\n }\n\n return current;\n}\n\n/**\n * Calculate start date by subtracting N business days from end date.\n * Returns a Date object.\n */\nexport function subtractBusinessDays(\n endDate: string | Date,\n businessDays: number,\n weekendPredicate: (date: Date) => boolean\n): Date {\n const end = typeof endDate === 'string'\n ? new Date(`${endDate.split('T')[0]}T00:00:00.000Z`)\n : normalizeUTCDate(endDate);\n const current = new Date(end);\n let targetDays = Math.max(1, businessDays);\n let businessDaysCounted = 0;\n\n while (businessDaysCounted < targetDays) {\n if (!weekendPredicate(current)) {\n businessDaysCounted++;\n }\n if (businessDaysCounted < targetDays) {\n current.setUTCDate(current.getUTCDate() - 1);\n }\n }\n\n return current;\n}\n\n/**\n * Snap a date to the nearest working day in the given direction.\n */\nexport function alignToWorkingDay(\n date: Date,\n direction: 1 | -1,\n weekendPredicate: (date: Date) => boolean\n): Date {\n const current = normalizeUTCDate(date);\n\n while (weekendPredicate(current)) {\n current.setUTCDate(current.getUTCDate() + direction);\n }\n\n return current;\n}\n\n/**\n * Get task duration in days (inclusive).\n * If businessDays mode, counts business days using weekendPredicate.\n * Otherwise, counts calendar days.\n */\nexport function getTaskDuration(\n startDate: string | Date,\n endDate: string | Date,\n businessDays: boolean = false,\n weekendPredicate?: (date: Date) => boolean\n): number {\n const start = parseDateOnly(startDate);\n const end = parseDateOnly(endDate);\n\n if (businessDays && weekendPredicate) {\n return getBusinessDaysCount(start, end, weekendPredicate);\n }\n\n return Math.max(1, Math.round((end.getTime() - start.getTime()) / DAY_MS) + 1);\n}\n","/**\n * Dependency calculation functions.\n * Moved from dependencyUtils.ts — verbatim implementations.\n * Zero React/DOM/date-fns imports.\n */\n\n// START_MODULE_CONTRACT\n// PURPOSE: Calculate dependency dates and lags using inclusive task dates and explicit milestone semantics.\n// SCOPE: Normalize dependency inputs, calculate successor anchors, and derive lag values from task ranges.\n// DEPENDS: dateMath, scheduling types\n// LINKS: M-SCHEDULING, fn-calculateSuccessorDate, fn-computeLagFromDates\n// ROLE: RUNTIME\n// MAP_MODE: EXPORTS\n// END_MODULE_CONTRACT\n\nimport type { LinkType, TaskDependency, Task } from './types';\nimport {\n getBusinessDayOffset,\n shiftBusinessDayOffset,\n DAY_MS,\n getTaskDuration,\n} from './dateMath';\n\n/**\n * Normalize predecessor dates for scheduling calculations.\n * Milestones have a real zero-duration finish anchor at startDate. The\n * successor type, rather than a fabricated predecessor date, determines\n * whether FS lag=0 lands on the same day (milestone successor) or the next\n * day (regular successor).\n */\nexport function normalizePredecessorDates(\n predecessor: Pick<Task, 'startDate' | 'endDate' | 'type'>,\n parseDateFn: (d: string | Date) => Date\n): { predStart: Date; predEnd: Date } {\n const predStart = parseDateFn(predecessor.startDate);\n const predEnd = predecessor.type === 'milestone'\n ? predStart\n : parseDateFn(predecessor.endDate);\n return { predStart, predEnd };\n}\n\n/**\n * Get lag value from dependency, defaulting to 0.\n */\nexport function getDependencyLag(dep: Pick<TaskDependency, 'lag'>): number {\n return Number.isFinite(dep.lag) ? dep.lag : 0;\n}\n\n/**\n * Return a copy of a task with dependency lag values normalized.\n *\n * FS lag normalization depends on predecessor duration, so this helper\n * intentionally leaves dependencies unchanged.\n */\nexport function normalizeTaskDependencyLags<TTask extends Pick<Task, 'dependencies'>>(task: TTask): TTask {\n return task;\n}\n\n/**\n * Normalize lag for FS links. Regular successors clamp to\n * `-predecessorDuration`; milestone successors use one fewer day because\n * their zero-duration FS anchor is the predecessor finish date itself.\n */\nexport function normalizeDependencyLag(\n linkType: LinkType,\n lag: number,\n predecessorStart: Date,\n predecessorEnd: Date,\n businessDays: boolean = false,\n weekendPredicate?: (date: Date) => boolean,\n successorType?: Task['type']\n): number {\n if (linkType !== 'FS') {\n return lag;\n }\n\n const predecessorDuration = getTaskDuration(\n predecessorStart,\n predecessorEnd,\n businessDays,\n weekendPredicate\n );\n\n const minimumLag = successorType === 'milestone'\n ? -(Math.max(0, predecessorDuration - 1))\n : -predecessorDuration;\n\n return Math.max(minimumLag, lag);\n}\n\n/**\n * Compute lag (in days) from actual predecessor/successor dates.\n * This is the single source of truth for lag semantics.\n *\n * Semantics (lag=0 = natural, gap-free connection):\n * - FS: lag = succStart - predEnd - 1 (adjacent regular-task days = 0)\n * milestone successor uses succStart - predEnd (same-day = 0)\n * - SS: lag = succStart - predStart\n * - FF: lag = succEnd - predEnd\n * - SF: lag = succEnd - predStart + 1 (symmetric to FS)\n */\nexport function computeLagFromDates(\n linkType: LinkType,\n predStart: Date,\n predEnd: Date,\n succStart: Date,\n succEnd: Date,\n businessDays: boolean = false,\n weekendPredicate?: (date: Date) => boolean,\n successorType?: Task['type']\n): number {\n const pS = Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate());\n const pE = Date.UTC(predEnd.getUTCFullYear(), predEnd.getUTCMonth(), predEnd.getUTCDate());\n const sS = Date.UTC(succStart.getUTCFullYear(), succStart.getUTCMonth(), succStart.getUTCDate());\n const sE = Date.UTC(succEnd.getUTCFullYear(), succEnd.getUTCMonth(), succEnd.getUTCDate());\n\n // Calendar days (original logic)\n if (!businessDays || !weekendPredicate) {\n switch (linkType) {\n case 'FS':\n return normalizeDependencyLag(\n linkType,\n Math.round((sS - pE) / DAY_MS) - (successorType === 'milestone' ? 0 : 1),\n predStart,\n predEnd,\n businessDays,\n weekendPredicate,\n successorType\n );\n case 'SS': return Math.round((sS - pS) / DAY_MS);\n case 'FF': return Math.round((sE - pE) / DAY_MS);\n case 'SF': return Math.round((sE - pS) / DAY_MS) + 1;\n }\n }\n\n const anchorDate = linkType === 'SS' || linkType === 'SF' ? predStart : predEnd;\n const targetDate = linkType === 'FS' || linkType === 'SS' ? succStart : succEnd;\n const businessOffset = getBusinessDayOffset(anchorDate, targetDate, weekendPredicate);\n\n switch (linkType) {\n case 'FS':\n return normalizeDependencyLag(\n linkType,\n businessOffset - (successorType === 'milestone' ? 0 : 1),\n predStart,\n predEnd,\n businessDays,\n weekendPredicate,\n successorType\n );\n case 'SS': return businessOffset;\n case 'FF': return businessOffset;\n case 'SF': return businessOffset + 1;\n }\n}\n\n/**\n * Calculate successor date based on predecessor dates, link type, and lag.\n *\n * Link type semantics:\n * - FS: Successor start = Predecessor end + lag + 1 day for regular tasks\n * and Predecessor end + lag for milestone successors\n * - SS: Successor start = Predecessor start + lag\n * - FF: Successor end = Predecessor end + lag\n * - SF: Successor end = Predecessor start + lag - 1 day (lag=0 -> day before)\n */\nexport function calculateSuccessorDate(\n predecessorStart: Date,\n predecessorEnd: Date,\n linkType: LinkType,\n lag: number = 0,\n businessDays: boolean = false,\n weekendPredicate?: (date: Date) => boolean,\n successorType?: Task['type']\n): Date {\n const normalizedLag = normalizeDependencyLag(\n linkType,\n lag,\n predecessorStart,\n predecessorEnd,\n businessDays,\n weekendPredicate,\n successorType\n );\n\n // Calendar days (original logic)\n if (!businessDays || !weekendPredicate) {\n switch (linkType) {\n case 'FS':\n return new Date(predecessorEnd.getTime() + (\n normalizedLag + (successorType === 'milestone' ? 0 : 1)\n ) * DAY_MS);\n case 'SS':\n return new Date(predecessorStart.getTime() + normalizedLag * DAY_MS);\n case 'FF':\n return new Date(predecessorEnd.getTime() + normalizedLag * DAY_MS);\n case 'SF':\n return new Date(predecessorStart.getTime() + (normalizedLag - 1) * DAY_MS);\n }\n }\n\n const anchorDate = (linkType === 'FS' || linkType === 'FF') ? predecessorEnd : predecessorStart;\n let offset: number;\n switch (linkType) {\n case 'FS':\n offset = normalizedLag + (successorType === 'milestone' ? 0 : 1);\n break;\n case 'SS':\n offset = normalizedLag;\n break;\n case 'FF':\n offset = normalizedLag;\n break;\n case 'SF':\n offset = normalizedLag - 1;\n break;\n }\n return shiftBusinessDayOffset(anchorDate, offset, weekendPredicate);\n}\n","/**\n * Critical path (CPM) calculation over dependency links.\n * Zero React/DOM/date-fns imports.\n *\n * Semantics:\n * - Only leaf tasks (no task references them as parentId) participate in the graph.\n * - All link types are edges — FS, SS, FF, SF — with calendar lags, mirroring\n * calculateSuccessorDate:\n * FS: succStart >= predEnd + lag SS: succStart >= predStart + lag\n * FF: succEnd >= predEnd + lag SF: succEnd >= predStart + lag\n * - A dependency on a parent task (a task that has children) is expanded to its\n * leaf descendants with the same link type and lag. For finish-anchored links\n * (FS/FF) the group is bounded by its latest-finishing leaf; for start-anchored\n * links (SS/SF) by its latest-starting leaf — a conservative approximation of\n * the group's span.\n * - Task weight = business-day duration (getTaskDuration); edge weight = lag in the\n * active scheduling unit.\n * - The scheduled task dates are used as the current starts. The project finish is\n * the latest scheduled leaf finish, so a late short branch can be critical even\n * when a longer branch started earlier.\n * - Task is critical when its total float (late start - scheduled start) is <= 0.\n * A standalone task can therefore be critical when it determines the project\n * finish; dependency membership is not a prerequisite for criticality.\n * - Cycles are skipped by topological ordering (Kahn) — cyclic tasks are not critical.\n */\n\nimport type { ScheduleTask, LinkType } from './types';\nimport { DAY_MS, getBusinessDayOffset, getTaskDuration, parseDateOnly } from './dateMath';\nimport { getDependencyLag } from './dependencies';\n\nexport interface CriticalPathOptions {\n businessDays?: boolean;\n weekendPredicate?: (date: Date) => boolean;\n}\n\ninterface Edge {\n succId: string;\n lag: number;\n type: LinkType;\n}\n\nexport function computeCriticalPath(\n tasks: ScheduleTask[],\n options: CriticalPathOptions = {}\n): Set<string> {\n const { businessDays = false, weekendPredicate } = options;\n\n const taskById = new Map(tasks.map((task) => [task.id, task]));\n\n const childIds = new Set<string>();\n for (const task of tasks) {\n if (task.parentId) childIds.add(task.parentId);\n }\n const leafTasks = tasks.filter((task) => !childIds.has(task.id));\n const leafIds = new Set(leafTasks.map((task) => task.id));\n\n // Map any task id (parent or not) to ALL of its leaf descendants (transitive).\n const leafIdsByAncestor = new Map<string, Set<string>>();\n for (const leaf of leafTasks) {\n let ancestor: string | undefined = leaf.parentId;\n while (ancestor) {\n const set = leafIdsByAncestor.get(ancestor) ?? new Set<string>();\n set.add(leaf.id);\n leafIdsByAncestor.set(ancestor, set);\n ancestor = taskById.get(ancestor)?.parentId;\n }\n }\n\n const durationOf = (task: ScheduleTask): number =>\n getTaskDuration(task.startDate, task.endDate, businessDays, weekendPredicate);\n\n const projectStartDate = leafTasks.reduce((earliest, task) => {\n const taskStart = parseDateOnly(task.startDate);\n return taskStart.getTime() < earliest.getTime() ? taskStart : earliest;\n }, parseDateOnly(leafTasks[0]?.startDate ?? new Date()));\n\n const offsetFromProjectStart = (date: string | Date): number => {\n const targetDate = parseDateOnly(date);\n if (businessDays && weekendPredicate) {\n return getBusinessDayOffset(projectStartDate, targetDate, weekendPredicate);\n }\n return Math.round((targetDate.getTime() - projectStartDate.getTime()) / DAY_MS);\n };\n\n // The current schedule is the forward pass. Do not reset every root task to\n // day zero: its actual start date is what gives it (or removes) total float.\n const scheduledStart = new Map<string, number>();\n for (const leaf of leafTasks) {\n scheduledStart.set(leaf.id, offsetFromProjectStart(leaf.startDate));\n }\n\n // Adjacency over all link types: predecessor -> successors, successor -> predecessors.\n const succByPred = new Map<string, Edge[]>();\n const predBySucc = new Map<string, Array<{ predId: string; lag: number; type: LinkType }>>();\n const seenEdges = new Set<string>();\n\n const addEdge = (predecessorId: string, succId: string, lag: number, type: LinkType) => {\n const edgeKey = `${predecessorId}|${succId}|${type}`;\n if (seenEdges.has(edgeKey)) return;\n seenEdges.add(edgeKey);\n\n const outEdges = succByPred.get(predecessorId) ?? [];\n outEdges.push({ succId, lag, type });\n succByPred.set(predecessorId, outEdges);\n\n const inEdges = predBySucc.get(succId) ?? [];\n inEdges.push({ predId: predecessorId, lag, type });\n predBySucc.set(succId, inEdges);\n };\n\n for (const succ of leafTasks) {\n for (const dep of succ.dependencies ?? []) {\n const lag = getDependencyLag(dep);\n\n // Predecessor is a leaf: direct edge.\n if (leafIds.has(dep.taskId)) {\n addEdge(dep.taskId, succ.id, lag, dep.type);\n continue;\n }\n\n // Predecessor is a parent/group: expand to every leaf descendant.\n // The successor's own leaf (self-loop) is skipped.\n const descendants = leafIdsByAncestor.get(dep.taskId);\n if (!descendants || descendants.size === 0) continue;\n for (const leafId of descendants) {\n if (leafId === succ.id) continue;\n addEdge(leafId, succ.id, lag, dep.type);\n }\n }\n }\n\n // Topological order (Kahn). Vertices trapped in cycles never enter the order\n // (indegree never drops to 0) and are therefore excluded from criticality.\n const indegree = new Map<string, number>();\n for (const leaf of leafTasks) indegree.set(leaf.id, 0);\n for (const edges of succByPred.values()) {\n for (const { succId } of edges) {\n indegree.set(succId, (indegree.get(succId) ?? 0) + 1);\n }\n }\n\n const order: string[] = [];\n const enqueued = new Set<string>();\n const queue = leafTasks\n .filter((leaf) => (indegree.get(leaf.id) ?? 0) === 0)\n .map((leaf) => leaf.id);\n for (const id of queue) enqueued.add(id);\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n order.push(current);\n for (const { succId } of succByPred.get(current) ?? []) {\n const next = (indegree.get(succId) ?? 0) - 1;\n indegree.set(succId, next);\n if (next === 0 && !enqueued.has(succId)) {\n enqueued.add(succId);\n queue.push(succId);\n }\n }\n }\n\n const projectFinish = Math.max(\n 0,\n ...leafTasks.map((leaf) => (scheduledStart.get(leaf.id) ?? 0) + durationOf(leaf))\n );\n\n // Backward pass: late finish / late start.\n const LF = new Map<string, number>();\n const LS = new Map<string, number>();\n for (const leaf of leafTasks) LF.set(leaf.id, projectFinish);\n\n for (let i = order.length - 1; i >= 0; i--) {\n const id = order[i];\n const task = taskById.get(id)!;\n const durPred = durationOf(task);\n const outEdges = succByPred.get(id) ?? [];\n let lf = projectFinish;\n if (outEdges.length > 0) {\n const candidates = outEdges.map(({ succId, lag, type }) => {\n const succLs = LS.get(succId) ?? projectFinish;\n const durSucc = durationOf(taskById.get(succId)!);\n switch (type) {\n case 'FS': return succLs - lag;\n case 'SS': return succLs - lag + durPred;\n case 'FF': return succLs + durSucc - lag;\n case 'SF': return succLs + durSucc - lag + durPred;\n default: return projectFinish;\n }\n });\n lf = Math.min(projectFinish, ...candidates);\n }\n LF.set(id, lf);\n LS.set(id, lf - durPred);\n }\n\n const critical = new Set<string>();\n const ordered = new Set(order);\n for (const leaf of leafTasks) {\n // Vertices trapped in cycles never entered the topological order and are\n // never critical.\n if (!ordered.has(leaf.id)) continue;\n const hasGraphEdge =\n (succByPred.get(leaf.id)?.length ?? 0) > 0 ||\n (predBySucc.get(leaf.id)?.length ?? 0) > 0;\n // A task with no declared dependencies is a legitimate standalone\n // project task and may determine the project finish. If it declares\n // dependencies but none resolved to a valid graph edge (for example a\n // self-reference through its own parent), it is not a schedulable path.\n if (!hasGraphEdge && (leaf.dependencies?.length ?? 0) > 0) continue;\n const es = scheduledStart.get(leaf.id) ?? 0;\n const ls = LS.get(leaf.id) ?? 0;\n if (ls - es <= 0) critical.add(leaf.id);\n }\n\n return critical;\n}\n\n/**\n * Extend criticality from leaf ids upward through the parent chain.\n * A parent is critical when any of its descendants is critical.\n */\nexport function extendCriticalIdsToParents(\n criticalLeafIds: Set<string>,\n tasks: ScheduleTask[]\n): Set<string> {\n const result = new Set(criticalLeafIds);\n const parentByChild = new Map<string, string>();\n for (const task of tasks) {\n if (task.parentId) parentByChild.set(task.id, task.parentId);\n }\n\n const stack = Array.from(criticalLeafIds);\n while (stack.length > 0) {\n const id = stack.pop()!;\n const parentId = parentByChild.get(id);\n if (parentId && !result.has(parentId)) {\n result.add(parentId);\n stack.push(parentId);\n }\n }\n\n return result;\n}\n","/**\n * High-level schedule command functions.\n * Moved from dependencyUtils.ts — verbatim implementations.\n * Zero React/DOM/date-fns imports.\n */\n\n// START_MODULE_CONTRACT\n// PURPOSE: Build task ranges and update dependency lags for interactive scheduling commands.\n// SCOPE: Range construction, incoming FS clamping, and lag recalculation.\n// DEPENDS: dateMath, dependencies, scheduling types\n// LINKS: M-SCHEDULING, fn-clampTaskRangeForIncomingFS, fn-recalculateIncomingLags\n// ROLE: RUNTIME\n// MAP_MODE: EXPORTS\n// END_MODULE_CONTRACT\n\nimport type { Task } from './types';\nimport {\n normalizeUTCDate,\n parseDateOnly,\n addBusinessDays,\n subtractBusinessDays,\n alignToWorkingDay,\n getTaskDuration,\n getBusinessDaysCount,\n} from './dateMath';\nimport {\n calculateSuccessorDate,\n getDependencyLag,\n computeLagFromDates,\n normalizePredecessorDates,\n} from './dependencies';\n\n// Re-export for backward compat — these live in dateMath now\nexport { alignToWorkingDay, getTaskDuration };\n\n/**\n * Build a task range (start/end dates) from a start date and duration.\n */\nexport function buildTaskRangeFromStart(\n startDate: Date,\n duration: number,\n businessDays: boolean = false,\n weekendPredicate?: (date: Date) => boolean,\n snapDirection: 1 | -1 = 1\n): { start: Date; end: Date } {\n const normalizedStart = businessDays && weekendPredicate\n ? alignToWorkingDay(startDate, snapDirection, weekendPredicate)\n : normalizeUTCDate(startDate);\n\n if (businessDays && weekendPredicate) {\n return {\n start: normalizedStart,\n end: parseDateOnly(addBusinessDays(normalizedStart, duration, weekendPredicate)),\n };\n }\n\n const DAY_MS = 24 * 60 * 60 * 1000;\n return {\n start: normalizedStart,\n end: new Date(normalizedStart.getTime() + (Math.max(1, duration) - 1) * DAY_MS),\n };\n}\n\n/**\n * Build a task range (start/end dates) from an end date and duration.\n */\nexport function buildTaskRangeFromEnd(\n endDate: Date,\n duration: number,\n businessDays: boolean = false,\n weekendPredicate?: (date: Date) => boolean,\n snapDirection: 1 | -1 = -1\n): { start: Date; end: Date } {\n const normalizedEnd = businessDays && weekendPredicate\n ? alignToWorkingDay(endDate, snapDirection, weekendPredicate)\n : normalizeUTCDate(endDate);\n\n if (businessDays && weekendPredicate) {\n return {\n start: parseDateOnly(subtractBusinessDays(normalizedEnd, duration, weekendPredicate)),\n end: normalizedEnd,\n };\n }\n\n const DAY_MS = 24 * 60 * 60 * 1000;\n return {\n start: new Date(normalizedEnd.getTime() - (Math.max(1, duration) - 1) * DAY_MS),\n end: normalizedEnd,\n };\n}\n\n/**\n * Move a task range to a new start date, preserving duration.\n */\nexport function moveTaskRange(\n originalStart: string | Date,\n originalEnd: string | Date,\n proposedStart: Date,\n businessDays: boolean = false,\n weekendPredicate?: (date: Date) => boolean,\n snapDirection: 1 | -1 = 1\n): { start: Date; end: Date } {\n return buildTaskRangeFromStart(\n proposedStart,\n getTaskDuration(originalStart, originalEnd, businessDays, weekendPredicate),\n businessDays,\n weekendPredicate,\n snapDirection\n );\n}\n\n/**\n * Clamp task range start date based on incoming FS dependencies.\n */\nexport function clampTaskRangeForIncomingFS(\n task: Pick<Task, 'dependencies' | 'type'>,\n proposedStart: Date,\n proposedEnd: Date,\n allTasks: Task[],\n businessDays: boolean = false,\n weekendPredicate?: (date: Date) => boolean,\n taskById?: Map<string, Task>\n): { start: Date; end: Date } {\n if (!task.dependencies?.length) {\n return { start: proposedStart, end: proposedEnd };\n }\n\n let minAllowedStart: Date | null = null;\n\n for (const dep of task.dependencies) {\n if (dep.type !== 'FS') {\n continue;\n }\n\n const predecessor = taskById?.get(dep.taskId) ?? allTasks.find(candidate => candidate.id === dep.taskId);\n if (!predecessor) {\n continue;\n }\n\n const { predStart: predecessorStart, predEnd: predecessorEnd } = normalizePredecessorDates(predecessor, parseDateOnly);\n const predecessorDuration = getTaskDuration(\n predecessorStart,\n predecessorEnd,\n businessDays,\n weekendPredicate\n );\n const candidateMinStart = calculateSuccessorDate(\n predecessorStart,\n predecessorEnd,\n 'FS',\n -predecessorDuration,\n businessDays,\n weekendPredicate,\n task.type\n );\n\n if (!minAllowedStart || candidateMinStart.getTime() > minAllowedStart.getTime()) {\n minAllowedStart = candidateMinStart;\n }\n }\n\n if (!minAllowedStart || proposedStart.getTime() >= minAllowedStart.getTime()) {\n return { start: proposedStart, end: proposedEnd };\n }\n\n return buildTaskRangeFromStart(\n minAllowedStart,\n getTaskDuration(proposedStart, proposedEnd, businessDays, weekendPredicate),\n businessDays,\n weekendPredicate\n );\n}\n\n/**\n * Recalculate incoming dependency lags after a task's dates change.\n */\nexport function recalculateIncomingLags(\n task: Task,\n newStartDate: Date,\n newEndDate: Date,\n allTasks: Task[],\n businessDays: boolean = false,\n weekendPredicate?: (date: Date) => boolean,\n taskById?: Map<string, Task>\n): NonNullable<Task['dependencies']> {\n if (!task.dependencies) return [];\n return task.dependencies.map(dep => {\n const predecessor = taskById?.get(dep.taskId) ?? allTasks.find(candidate => candidate.id === dep.taskId);\n if (!predecessor) {\n return { ...dep, lag: getDependencyLag(dep) };\n }\n\n const { predStart: predecessorStart, predEnd: predecessorEnd } = normalizePredecessorDates(\n predecessor,\n (d) => new Date(d instanceof Date ? d.getTime() : `${String(d).split('T')[0]}T00:00:00.000Z`)\n );\n const nextLag = computeLagFromDates(\n dep.type,\n predecessorStart,\n predecessorEnd,\n newStartDate,\n newEndDate,\n businessDays,\n weekendPredicate,\n task.type\n );\n\n return { ...dep, lag: nextLag };\n });\n}\n\n","/**\n * Cascade engine functions.\n * Moved from dependencyUtils.ts — verbatim implementations.\n * Zero React/DOM/date-fns imports.\n */\n\n// START_MODULE_CONTRACT\n// PURPOSE: Propagate moved task dates through dependency and hierarchy graphs.\n// SCOPE: Dependency cascades, parent/child propagation, and business-day alignment.\n// DEPENDS: commands, dateMath, dependencies, scheduling types\n// LINKS: M-SCHEDULING, fn-cascadeByLinks, fn-universalCascade\n// ROLE: RUNTIME\n// MAP_MODE: EXPORTS\n// END_MODULE_CONTRACT\n\nimport type { Task, LinkType } from './types';\nimport {\n normalizeUTCDate,\n getTaskDuration,\n alignToWorkingDay,\n} from './dateMath';\nimport {\n calculateSuccessorDate,\n getDependencyLag,\n normalizeTaskDependencyLags,\n normalizePredecessorDates,\n} from './dependencies';\nimport {\n buildTaskRangeFromStart,\n buildTaskRangeFromEnd,\n moveTaskRange,\n} from './commands';\n\nfunction parseCascadeDateInput(date: string | Date): Date {\n if (date instanceof Date) {\n return normalizeUTCDate(date);\n }\n return normalizeUTCDate(new Date(`${date.split('T')[0]}T00:00:00.000Z`));\n}\n\nexport interface CascadeContext {\n childrenByParentId: Map<string, Task[]>;\n dependentsByPredecessorId: Map<string, Array<{ task: Task; dependencyIndex: number }>>;\n taskById: Map<string, Task>;\n}\n\nexport function createCascadeContext(allTasks: Task[]): CascadeContext {\n const childrenByParentId = new Map<string, Task[]>();\n const dependentsByPredecessorId = new Map<string, Array<{ task: Task; dependencyIndex: number }>>();\n const taskById = new Map<string, Task>();\n\n for (const task of allTasks) {\n taskById.set(task.id, task);\n\n if (task.parentId) {\n const children = childrenByParentId.get(task.parentId) ?? [];\n children.push(task);\n childrenByParentId.set(task.parentId, children);\n }\n\n if (!task.dependencies) continue;\n\n task.dependencies.forEach((dependency, dependencyIndex) => {\n const dependents = dependentsByPredecessorId.get(dependency.taskId) ?? [];\n dependents.push({ task, dependencyIndex });\n dependentsByPredecessorId.set(dependency.taskId, dependents);\n });\n }\n\n return { childrenByParentId, dependentsByPredecessorId, taskById };\n}\n\n/**\n * Get successor tasks of a dragged task using BFS, filtered by link type(s).\n */\nexport function getSuccessorChain(\n draggedTaskId: string,\n allTasks: Task[],\n linkTypes: LinkType[] = ['FS']\n): Task[] {\n const { dependentsByPredecessorId, taskById } = createCascadeContext(allTasks);\n const visited = new Set<string>();\n const queue: string[] = [draggedTaskId];\n const chain: Task[] = [];\n visited.add(draggedTaskId);\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n const successors = dependentsByPredecessorId.get(current) ?? [];\n for (const { task } of successors) {\n if (!linkTypes.includes(task.dependencies?.find((dependency) => dependency.taskId === current)?.type ?? 'FS')) {\n continue;\n }\n const sid = task.id;\n if (!visited.has(sid)) {\n visited.add(sid);\n const successorTask = taskById.get(sid);\n if (successorTask) {\n chain.push(successorTask);\n queue.push(sid);\n }\n }\n }\n }\n\n return chain;\n}\n\n/**\n * Cascade successors by actual link constraints (BFS, constraint-based).\n */\nexport function cascadeByLinks(\n movedTaskId: string,\n newStart: Date,\n newEnd: Date,\n allTasks: Task[],\n skipChildCascade: boolean = false\n): Task[] {\n const { childrenByParentId, dependentsByPredecessorId, taskById } = createCascadeContext(allTasks);\n\n const updatedDates = new Map<string, { start: Date; end: Date }>();\n updatedDates.set(movedTaskId, { start: newStart, end: newEnd });\n\n const result: Task[] = [];\n const queue: string[] = [movedTaskId];\n const visited = new Set<string>([movedTaskId]);\n\n while (queue.length > 0) {\n const currentId = queue.shift()!;\n const { start: predStart, end: predEnd } = updatedDates.get(currentId)!;\n\n if (!skipChildCascade) {\n const children = childrenByParentId.get(currentId) ?? [];\n for (const child of children) {\n if (visited.has(child.id) || child.locked) continue;\n\n const origStart = new Date(child.startDate as string);\n const origEnd = new Date(child.endDate as string);\n const durationMs = origEnd.getTime() - origStart.getTime();\n\n const parentOrig = taskById.get(currentId)!;\n const parentOrigStart = new Date(parentOrig.startDate as string);\n const parentOrigEnd = new Date(parentOrig.endDate as string);\n\n const parentStartDelta = predStart.getTime() - parentOrigStart.getTime();\n const parentEndDelta = predEnd.getTime() - parentOrigEnd.getTime();\n\n const newChildStart = new Date(origStart.getTime() + parentStartDelta);\n const newChildEnd = new Date(origEnd.getTime() + parentEndDelta);\n\n visited.add(child.id);\n updatedDates.set(child.id, { start: newChildStart, end: newChildEnd });\n result.push(normalizeTaskDependencyLags({\n ...child,\n startDate: newChildStart.toISOString().split('T')[0],\n endDate: newChildEnd.toISOString().split('T')[0],\n }));\n queue.push(child.id);\n }\n }\n\n const dependents = dependentsByPredecessorId.get(currentId) ?? [];\n for (const { task, dependencyIndex } of dependents) {\n if (visited.has(task.id) || !task.dependencies || task.locked) continue;\n const dep = task.dependencies[dependencyIndex];\n if (!dep) continue;\n\n const orig = taskById.get(task.id)!;\n const origStart = new Date(orig.startDate as string);\n const origEnd = new Date(orig.endDate as string);\n const duration = getTaskDuration(origStart, origEnd);\n const currentTask = taskById.get(currentId)!;\n const { predStart: normalizedPredStart, predEnd: normalizedPredEnd } = normalizePredecessorDates(\n {\n startDate: predStart,\n endDate: predEnd,\n type: currentTask.type,\n },\n parseCascadeDateInput\n );\n const constraintDate = calculateSuccessorDate(\n normalizedPredStart,\n normalizedPredEnd,\n dep.type,\n getDependencyLag(dep),\n false,\n undefined,\n task.type\n );\n\n let newSuccStart: Date;\n let newSuccEnd: Date;\n\n if (dep.type === 'FS' || dep.type === 'SS') {\n ({ start: newSuccStart, end: newSuccEnd } = buildTaskRangeFromStart(constraintDate, duration));\n } else {\n ({ start: newSuccStart, end: newSuccEnd } = buildTaskRangeFromEnd(constraintDate, duration));\n }\n\n visited.add(task.id);\n updatedDates.set(task.id, { start: newSuccStart, end: newSuccEnd });\n result.push(normalizeTaskDependencyLags({\n ...task,\n startDate: newSuccStart.toISOString().split('T')[0],\n endDate: newSuccEnd.toISOString().split('T')[0],\n }));\n queue.push(task.id);\n }\n }\n\n return result;\n}\n\n/**\n * Get transitive closure of successors for cascading.\n */\nexport function getTransitiveCascadeChain(\n changedTaskId: string,\n allTasks: Task[],\n firstLevelLinkTypes: LinkType[]\n): Task[] {\n const { childrenByParentId, dependentsByPredecessorId } = createCascadeContext(allTasks);\n\n const directChildren = childrenByParentId.get(changedTaskId) ?? [];\n const directSuccessors = getSuccessorChain(changedTaskId, allTasks, firstLevelLinkTypes);\n const initialChain = [...directChildren, ...directSuccessors].filter((task, index, arr) =>\n arr.findIndex(candidate => candidate.id === task.id) === index\n );\n\n const chain = [...initialChain];\n const visited = new Set<string>([changedTaskId, ...initialChain.map(t => t.id)]);\n const queue = [...initialChain];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n\n const children = childrenByParentId.get(current.id) ?? [];\n for (const child of children) {\n if (!visited.has(child.id)) {\n visited.add(child.id);\n chain.push(child);\n queue.push(child);\n }\n }\n\n const successors = dependentsByPredecessorId.get(current.id) ?? [];\n for (const { task: successor } of successors) {\n if (!visited.has(successor.id)) {\n visited.add(successor.id);\n chain.push(successor);\n queue.push(successor);\n }\n }\n }\n\n return chain;\n}\n\n/**\n * Arrival mode for universal cascade BFS entries.\n */\ntype ArrivalMode = 'direct' | 'child-delta' | 'parent-recalc' | 'dependency';\n\n/**\n * Universal cascade engine that propagates a moved task's new position through\n * the entire dependency+hierarchy graph using BFS with change detection.\n */\nexport function universalCascade(\n movedTask: Task,\n newStart: Date,\n newEnd: Date,\n allTasks: Task[],\n businessDays: boolean = false,\n weekendPredicate?: (date: Date) => boolean,\n context: CascadeContext = createCascadeContext(allTasks)\n): Task[] {\n const { childrenByParentId, dependentsByPredecessorId, taskById } = context;\n const normalizedMovedTask = normalizeTaskDependencyLags({\n ...movedTask,\n startDate: newStart.toISOString().split('T')[0],\n endDate: newEnd.toISOString().split('T')[0],\n });\n\n if (\n !movedTask.parentId &&\n !childrenByParentId.has(movedTask.id) &&\n !dependentsByPredecessorId.has(movedTask.id)\n ) {\n return [normalizedMovedTask];\n }\n\n const updatedDates = new Map<string, { start: Date; end: Date }>();\n updatedDates.set(movedTask.id, { start: newStart, end: newEnd });\n\n const resultMap = new Map<string, Task>();\n resultMap.set(movedTask.id, normalizedMovedTask);\n\n const queue: Array<[string, ArrivalMode]> = [[movedTask.id, 'direct']];\n\n const childShifted = new Set<string>();\n\n let iterations = 0;\n const MAX_ITERATIONS = allTasks.length * 3;\n\n while (queue.length > 0 && iterations < MAX_ITERATIONS) {\n iterations++;\n const [currentId, arrivalMode] = queue.shift()!;\n const { start: currStart, end: currEnd } = updatedDates.get(currentId)!;\n const currentOriginal = taskById.get(currentId)!;\n\n // RULE 1: Hierarchy children follow their parent\n if (arrivalMode !== 'parent-recalc') {\n const children = childrenByParentId.get(currentId) ?? [];\n for (const child of children) {\n if (childShifted.has(child.id) || child.locked) continue;\n\n const parentOrigStart = new Date(currentOriginal.startDate as string);\n const parentOrigEnd = new Date(currentOriginal.endDate as string);\n\n const childOrigStart = new Date(child.startDate as string);\n const childOrigEnd = new Date(child.endDate as string);\n\n const startDeltaMs = currStart.getTime() - parentOrigStart.getTime();\n const endDeltaMs = currEnd.getTime() - parentOrigEnd.getTime();\n\n let childNewStart: Date;\n let childNewEnd: Date;\n\n if (businessDays && weekendPredicate) {\n const proposedStart = new Date(childOrigStart.getTime() + startDeltaMs);\n const snapDirection: 1 | -1 = currStart.getTime() >= parentOrigStart.getTime() ? 1 : -1;\n const movedRange = moveTaskRange(\n child.startDate,\n child.endDate,\n proposedStart,\n true,\n weekendPredicate,\n snapDirection\n );\n childNewStart = movedRange.start;\n childNewEnd = movedRange.end;\n } else {\n childNewStart = new Date(childOrigStart.getTime() + startDeltaMs);\n childNewEnd = new Date(childOrigEnd.getTime() + endDeltaMs);\n }\n\n const prev = updatedDates.get(child.id);\n if (prev && prev.start.getTime() === childNewStart.getTime() && prev.end.getTime() === childNewEnd.getTime()) {\n continue;\n }\n\n updatedDates.set(child.id, { start: childNewStart, end: childNewEnd });\n childShifted.add(child.id);\n queue.push([child.id, 'child-delta']);\n resultMap.set(child.id, normalizeTaskDependencyLags({\n ...child,\n startDate: childNewStart.toISOString().split('T')[0],\n endDate: childNewEnd.toISOString().split('T')[0],\n }));\n }\n }\n\n // RULE 2: Parent task is recomputed from its children\n const parentId = (currentOriginal as any).parentId as string | undefined;\n if (parentId) {\n const parent = taskById.get(parentId);\n if (parent && !parent.locked) {\n const siblings = childrenByParentId.get(parentId) ?? [];\n\n const siblingPositions = siblings.map(sib => {\n if (updatedDates.has(sib.id)) return updatedDates.get(sib.id)!;\n return { start: new Date(sib.startDate as string), end: new Date(sib.endDate as string) };\n });\n\n const minStart = new Date(Math.min(...siblingPositions.map(p => p.start.getTime())));\n const maxEnd = new Date(Math.max(...siblingPositions.map(p => p.end.getTime())));\n\n const prev = updatedDates.get(parentId);\n if (!prev || prev.start.getTime() !== minStart.getTime() || prev.end.getTime() !== maxEnd.getTime()) {\n updatedDates.set(parentId, { start: minStart, end: maxEnd });\n queue.push([parentId, 'parent-recalc']);\n resultMap.set(parentId, normalizeTaskDependencyLags({\n ...parent,\n startDate: minStart.toISOString().split('T')[0],\n endDate: maxEnd.toISOString().split('T')[0],\n }));\n }\n }\n }\n\n // RULE 3: Dependency successors are repositioned\n const dependents = dependentsByPredecessorId.get(currentId) ?? [];\n for (const { task, dependencyIndex } of dependents) {\n if (task.locked || !task.dependencies) continue;\n const dep = task.dependencies[dependencyIndex];\n if (!dep) continue;\n\n const origStart = new Date(task.startDate as string);\n const origEnd = new Date(task.endDate as string);\n const { predStart: normalizedPredStart, predEnd: normalizedPredEnd } = normalizePredecessorDates(\n {\n startDate: currStart,\n endDate: currEnd,\n type: currentOriginal.type,\n },\n parseCascadeDateInput\n );\n const constraintDate = calculateSuccessorDate(\n normalizedPredStart, normalizedPredEnd, dep.type, getDependencyLag(dep),\n businessDays, weekendPredicate, task.type\n );\n\n let succNewStart: Date;\n let succNewEnd: Date;\n const duration = getTaskDuration(origStart, origEnd, businessDays, weekendPredicate);\n\n if (dep.type === 'FS' || dep.type === 'SS') {\n ({ start: succNewStart, end: succNewEnd } = buildTaskRangeFromStart(\n constraintDate,\n duration,\n businessDays,\n weekendPredicate\n ));\n } else {\n ({ start: succNewStart, end: succNewEnd } = buildTaskRangeFromEnd(\n constraintDate,\n duration,\n businessDays,\n weekendPredicate\n ));\n }\n\n const prev = updatedDates.get(task.id);\n if (prev && prev.start.getTime() === succNewStart.getTime() && prev.end.getTime() === succNewEnd.getTime()) {\n continue;\n }\n\n updatedDates.set(task.id, { start: succNewStart, end: succNewEnd });\n queue.push([task.id, 'dependency']);\n resultMap.set(task.id, normalizeTaskDependencyLags({\n ...task,\n startDate: succNewStart.toISOString().split('T')[0],\n endDate: succNewEnd.toISOString().split('T')[0],\n }));\n }\n }\n\n return Array.from(resultMap.values());\n}\n\n","/**\n * Hierarchy scheduling functions.\n * Moved from dependencyUtils.ts — verbatim implementations.\n * Zero React/DOM/date-fns imports.\n */\n\nimport type { Task } from './types';\n\n/**\n * Get all child tasks of a parent task.\n * Returns tasks where task.parentId === parentId.\n */\nexport function getChildren(parentId: string, tasks: Task[]): Task[] {\n return tasks.filter(t => (t as any).parentId === parentId);\n}\n\n/**\n * Check if a task is a parent (has children).\n * Returns true if any task has this task as parentId.\n */\nexport function isTaskParent(taskId: string, tasks: Task[]): boolean {\n return tasks.some(t => (t as any).parentId === taskId);\n}\n\n/**\n * Compute parent task dates from children.\n * Returns { startDate, endDate } where:\n * - startDate = min(children.startDate) or own startDate if no children\n * - endDate = max(children.endDate) or own endDate if no children\n */\nexport function computeParentDates(parentId: string, tasks: Task[]): { startDate: Date; endDate: Date } {\n const children = getChildren(parentId, tasks);\n\n if (children.length === 0) {\n const parent = tasks.find(t => t.id === parentId);\n const start = parent ? new Date(parent.startDate) : new Date();\n const end = parent ? new Date(parent.endDate) : new Date();\n return { startDate: start, endDate: end };\n }\n\n const startDates = children.map(c => new Date(c.startDate));\n const endDates = children.map(c => new Date(c.endDate));\n\n const minTime = Math.min(...startDates.map(d => d.getTime()));\n const maxTime = Math.max(...endDates.map(d => d.getTime()));\n\n return {\n startDate: new Date(minTime),\n endDate: new Date(maxTime),\n };\n}\n\n/**\n * Compute parent task progress from children (weighted average by duration).\n * Returns 0 if no children.\n * Progress is rounded to 1 decimal place.\n */\nexport function computeParentProgress(parentId: string, tasks: Task[]): number {\n const children = getChildren(parentId, tasks);\n\n if (children.length === 0) {\n return 0;\n }\n\n const DAY_MS = 24 * 60 * 60 * 1000;\n let totalWeight = 0;\n let weightedSum = 0;\n\n for (const child of children) {\n const start = new Date(child.startDate).getTime();\n const end = new Date(child.endDate).getTime();\n // Inclusive duration: (end - start + 1 day) / DAY_MS\n const duration = (end - start + DAY_MS) / DAY_MS;\n const progress = (child.progress ?? 0);\n\n totalWeight += duration;\n weightedSum += duration * progress;\n }\n\n if (totalWeight === 0) {\n return 0;\n }\n\n // Round to 1 decimal place\n return Math.round((weightedSum / totalWeight) * 10) / 10;\n}\n\n/**\n * Get all descendant tasks of a parent task (transitive closure of children).\n * Returns all tasks where task.parentId is in the hierarchy of the parent.\n */\nexport function getAllDescendants(parentId: string, tasks: Task[]): Task[] {\n const descendants: Task[] = [];\n const visited = new Set<string>();\n\n function collectChildren(taskId: string) {\n if (visited.has(taskId)) return;\n visited.add(taskId);\n\n const children = getChildren(taskId, tasks);\n for (const child of children) {\n descendants.push(child);\n collectChildren(child.id);\n }\n }\n\n collectChildren(parentId);\n return descendants;\n}\n\n/**\n * Get all dependency edges for rendering.\n * Returns array of { predecessorId, successorId, type, lag }\n */\nexport function getAllDependencyEdges(tasks: Task[]): Array<{\n predecessorId: string;\n successorId: string;\n type: 'FS' | 'SS' | 'FF' | 'SF';\n lag: number;\n}> {\n const edges: Array<{ predecessorId: string; successorId: string; type: 'FS' | 'SS' | 'FF' | 'SF'; lag: number }> = [];\n\n for (const task of tasks) {\n if (task.dependencies) {\n for (const dep of task.dependencies) {\n edges.push({\n predecessorId: dep.taskId,\n successorId: task.id,\n type: dep.type,\n lag: dep.lag ?? 0,\n });\n }\n }\n }\n\n return edges;\n}\n\n/**\n * Remove dependencies between two tasks in both directions.\n */\nexport function removeDependenciesBetweenTasks(\n taskId1: string,\n taskId2: string,\n tasks: Task[]\n): Task[] {\n return tasks.map(task => {\n if (task.id === taskId1 || task.id === taskId2) {\n if (!task.dependencies) return task;\n const otherTaskId = task.id === taskId1 ? taskId2 : taskId1;\n const filteredDependencies = task.dependencies.filter(dep => dep.taskId !== otherTaskId);\n if (filteredDependencies.length === task.dependencies.length) {\n return task;\n }\n return {\n ...task,\n dependencies: filteredDependencies.length > 0 ? filteredDependencies : undefined,\n };\n }\n return task;\n });\n}\n\n/**\n * Find the parent ID of a task.\n */\nexport function findParentId(taskId: string, tasks: Task[]): string | undefined {\n const task = tasks.find(t => t.id === taskId);\n return task?.parentId;\n}\n\n/**\n * Returns true when ancestorId is an ancestor of taskId in the current hierarchy.\n */\nexport function isAncestorTask(ancestorId: string, taskId: string, tasks: Task[]): boolean {\n const taskById = new Map(tasks.map(task => [task.id, task]));\n const visited = new Set<string>();\n let current = taskById.get(taskId);\n\n while (current?.parentId) {\n if (current.parentId === ancestorId) {\n return true;\n }\n\n if (visited.has(current.parentId)) {\n return false;\n }\n\n visited.add(current.parentId);\n current = taskById.get(current.parentId);\n }\n\n return false;\n}\n\n/**\n * Returns true when tasks are in the same ancestry chain.\n */\nexport function areTasksHierarchicallyRelated(taskId1: string, taskId2: string, tasks: Task[]): boolean {\n if (taskId1 === taskId2) {\n return true;\n }\n\n return isAncestorTask(taskId1, taskId2, tasks) || isAncestorTask(taskId2, taskId1, tasks);\n}\n","/**\n * Command-level scheduling API.\n * High-level functions that compose low-level scheduling primitives.\n * Zero React/DOM/date-fns imports.\n */\n\n// START_MODULE_CONTRACT\n// PURPOSE: Execute authoritative task and project schedule recalculations.\n// SCOPE: Move, resize, dependency recalculation, cascade, and full-project scheduling.\n// DEPENDS: commands, cascade, dateMath, dependencies, hierarchy, scheduling types\n// LINKS: M-SCHEDULING, fn-recalculateTaskFromDependencies, fn-recalculateProjectSchedule\n// ROLE: RUNTIME\n// MAP_MODE: EXPORTS\n// END_MODULE_CONTRACT\n\nimport type { Task, ScheduleCommandResult, ScheduleCommandOptions } from './types';\nimport { moveTaskRange, recalculateIncomingLags, buildTaskRangeFromEnd, buildTaskRangeFromStart, getTaskDuration } from './commands';\nimport { universalCascade } from './cascade';\nimport { parseDateOnly } from './dateMath';\nimport { calculateSuccessorDate, getDependencyLag, normalizePredecessorDates } from './dependencies';\nimport { computeParentDates, isTaskParent } from './hierarchy';\n\nfunction toIsoDate(date: Date): string {\n return date.toISOString().split('T')[0];\n}\n\nfunction createChangedResult(snapshot: Task[], nextTasks: Task[]): ScheduleCommandResult {\n const originalById = new Map(snapshot.map(task => [task.id, task]));\n const changedTasks = nextTasks.filter(task => JSON.stringify(originalById.get(task.id)) !== JSON.stringify(task));\n\n return {\n changedTasks,\n changedIds: changedTasks.map(task => task.id),\n };\n}\n\n/**\n * Move a task to a new start date with cascade and lag recalculation.\n * Identical to manual composition: moveTaskRange -> recalculateIncomingLags -> universalCascade.\n */\nexport function moveTaskWithCascade(\n taskId: string,\n newStart: Date,\n snapshot: Task[],\n options?: ScheduleCommandOptions\n): ScheduleCommandResult {\n const task = snapshot.find(t => t.id === taskId);\n if (!task) {\n return { changedTasks: [], changedIds: [] };\n }\n\n const businessDays = options?.businessDays ?? false;\n const weekendPredicate = options?.weekendPredicate;\n\n // Step 1: Calculate new range preserving duration\n const newRange = moveTaskRange(\n task.startDate,\n task.endDate,\n newStart,\n businessDays,\n weekendPredicate\n );\n\n // Step 2: Recalculate incoming dependency lags\n const updatedDependencies = recalculateIncomingLags(\n task,\n newRange.start,\n newRange.end,\n snapshot,\n businessDays,\n weekendPredicate\n );\n\n // Step 3: Create moved task with updated deps\n const movedTask: Task = {\n ...task,\n startDate: newRange.start.toISOString().split('T')[0],\n endDate: newRange.end.toISOString().split('T')[0],\n dependencies: updatedDependencies,\n };\n\n // Step 4: Cascade through dependency graph\n if (options?.skipCascade) {\n return {\n changedTasks: [movedTask],\n changedIds: [movedTask.id],\n };\n }\n\n const cascadeResult = universalCascade(\n movedTask,\n newRange.start,\n newRange.end,\n snapshot,\n businessDays,\n weekendPredicate\n );\n\n // Merge: movedTask + cascade results\n const resultMap = new Map<string, Task>();\n resultMap.set(movedTask.id, movedTask);\n for (const t of cascadeResult) {\n resultMap.set(t.id, t);\n }\n\n const changedTasks = Array.from(resultMap.values());\n return {\n changedTasks,\n changedIds: changedTasks.map(t => t.id),\n };\n}\n\n/**\n * Resize a task by changing its start or end date.\n * anchor='end': new end date, start stays fixed.\n * anchor='start': new start date, end stays fixed.\n */\nexport function resizeTaskWithCascade(\n taskId: string,\n anchor: 'start' | 'end',\n newDate: Date,\n snapshot: Task[],\n options?: ScheduleCommandOptions\n): ScheduleCommandResult {\n const task = snapshot.find(t => t.id === taskId);\n if (!task) {\n return { changedTasks: [], changedIds: [] };\n }\n\n const businessDays = options?.businessDays ?? false;\n const weekendPredicate = options?.weekendPredicate;\n\n const originalStart = parseDateOnly(task.startDate);\n const originalEnd = parseDateOnly(task.endDate);\n let newRange: { start: Date; end: Date };\n\n if (anchor === 'end') {\n // anchor='end': new end date, start stays fixed\n newRange = { start: originalStart, end: newDate };\n } else {\n // anchor='start': new start date, end stays fixed\n newRange = { start: newDate, end: originalEnd };\n }\n\n // Recalculate lags\n const updatedDependencies = recalculateIncomingLags(\n task,\n newRange.start,\n newRange.end,\n snapshot,\n businessDays,\n weekendPredicate\n );\n\n // Create resized task\n const resizedTask: Task = {\n ...task,\n startDate: newRange.start.toISOString().split('T')[0],\n endDate: newRange.end.toISOString().split('T')[0],\n dependencies: updatedDependencies,\n };\n\n if (options?.skipCascade) {\n return {\n changedTasks: [resizedTask],\n changedIds: [resizedTask.id],\n };\n }\n\n // Cascade through dependency graph\n const cascadeResult = universalCascade(\n resizedTask,\n newRange.start,\n newRange.end,\n snapshot,\n businessDays,\n weekendPredicate\n );\n\n const resultMap = new Map<string, Task>();\n resultMap.set(resizedTask.id, resizedTask);\n for (const t of cascadeResult) {\n resultMap.set(t.id, t);\n }\n\n const changedTasks = Array.from(resultMap.values());\n return {\n changedTasks,\n changedIds: changedTasks.map(t => t.id),\n };\n}\n\n/**\n * Recalculate a task's dates based on its dependency constraints.\n * Finds all predecessors and computes the most constrained date.\n */\nexport function recalculateTaskFromDependencies(\n taskId: string,\n snapshot: Task[],\n options?: ScheduleCommandOptions\n): ScheduleCommandResult {\n const task = snapshot.find(t => t.id === taskId);\n if (!task) {\n return { changedTasks: [], changedIds: [] };\n }\n\n const businessDays = options?.businessDays ?? false;\n const weekendPredicate = options?.weekendPredicate;\n\n if (!task.dependencies || task.dependencies.length === 0) {\n // No dependencies — return the task as-is\n return {\n changedTasks: [task],\n changedIds: [task.id],\n };\n }\n\n // Find the most constrained start/end based on all predecessors\n let constrainedStart: Date | null = null;\n let constrainedEnd: Date | null = null;\n\n for (const dep of task.dependencies) {\n const predecessor = snapshot.find(t => t.id === dep.taskId);\n if (!predecessor) continue;\n\n const { predStart, predEnd } = normalizePredecessorDates(predecessor, parseDateOnly);\n const constraintDate = calculateSuccessorDate(\n predStart,\n predEnd,\n dep.type,\n getDependencyLag(dep),\n businessDays,\n weekendPredicate,\n task.type\n );\n\n const duration = getTaskDuration(\n parseDateOnly(task.startDate),\n parseDateOnly(task.endDate),\n businessDays,\n weekendPredicate\n );\n\n let range: { start: Date; end: Date };\n if (dep.type === 'FS' || dep.type === 'SS') {\n range = buildTaskRangeFromStart(constraintDate, duration, businessDays, weekendPredicate);\n } else {\n range = buildTaskRangeFromEnd(constraintDate, duration, businessDays, weekendPredicate);\n }\n\n // Take the latest start as the effective constraint\n if (!constrainedStart || range.start.getTime() > constrainedStart.getTime()) {\n constrainedStart = range.start;\n constrainedEnd = range.end;\n }\n }\n\n if (!constrainedStart || !constrainedEnd) {\n return {\n changedTasks: [task],\n changedIds: [task.id],\n };\n }\n\n // Recalculate lags for the new position\n const updatedDependencies = recalculateIncomingLags(\n task,\n constrainedStart,\n constrainedEnd,\n snapshot,\n businessDays,\n weekendPredicate\n );\n\n const recalculatedTask: Task = {\n ...task,\n startDate: constrainedStart.toISOString().split('T')[0],\n endDate: constrainedEnd.toISOString().split('T')[0],\n dependencies: updatedDependencies,\n };\n\n if (options?.skipCascade) {\n return {\n changedTasks: [recalculatedTask],\n changedIds: [recalculatedTask.id],\n };\n }\n\n // Cascade through dependency graph\n const cascadeResult = universalCascade(\n recalculatedTask,\n constrainedStart,\n constrainedEnd,\n snapshot,\n businessDays,\n weekendPredicate\n );\n\n const resultMap = new Map<string, Task>();\n resultMap.set(recalculatedTask.id, recalculatedTask);\n for (const t of cascadeResult) {\n resultMap.set(t.id, t);\n }\n\n const changedTasks = Array.from(resultMap.values());\n return {\n changedTasks,\n changedIds: changedTasks.map(t => t.id),\n };\n}\n\n/**\n * Full project schedule recalculation.\n * Recomputes the project against a continuously updated working snapshot.\n * Returns only tasks whose normalized state changed.\n */\nexport function recalculateProjectSchedule(\n snapshot: Task[],\n options?: ScheduleCommandOptions\n): ScheduleCommandResult {\n const businessDays = options?.businessDays ?? false;\n const weekendPredicate = options?.weekendPredicate;\n const workingMap = new Map(snapshot.map(task => [task.id, { ...task }]));\n const indegree = new Map<string, number>();\n const successorIdsByTask = new Map<string, string[]>();\n\n for (const task of snapshot) {\n indegree.set(task.id, 0);\n successorIdsByTask.set(task.id, []);\n }\n\n for (const task of snapshot) {\n for (const dep of task.dependencies ?? []) {\n if (!workingMap.has(dep.taskId)) {\n continue;\n }\n\n indegree.set(task.id, (indegree.get(task.id) ?? 0) + 1);\n successorIdsByTask.get(dep.taskId)?.push(task.id);\n }\n }\n\n const queue = snapshot\n .filter(task => (indegree.get(task.id) ?? 0) === 0)\n .map(task => task.id);\n\n while (queue.length > 0) {\n const currentId = queue.shift()!;\n\n for (const successorId of successorIdsByTask.get(currentId) ?? []) {\n const nextIndegree = (indegree.get(successorId) ?? 0) - 1;\n indegree.set(successorId, nextIndegree);\n\n if (nextIndegree !== 0) {\n continue;\n }\n\n const currentTask = workingMap.get(successorId);\n if (!currentTask || currentTask.locked || !currentTask.dependencies?.length) {\n queue.push(successorId);\n continue;\n }\n\n const duration = getTaskDuration(\n parseDateOnly(currentTask.startDate),\n parseDateOnly(currentTask.endDate),\n businessDays,\n weekendPredicate\n );\n\n let constrainedRange: { start: Date; end: Date } | null = null;\n\n for (const dep of currentTask.dependencies) {\n const predecessor = workingMap.get(dep.taskId);\n if (!predecessor) {\n continue;\n }\n\n const { predStart: predecessorStart, predEnd: predecessorEnd } = normalizePredecessorDates(predecessor, parseDateOnly);\n const constraintDate = calculateSuccessorDate(\n predecessorStart,\n predecessorEnd,\n dep.type,\n getDependencyLag(dep),\n businessDays,\n weekendPredicate,\n currentTask.type\n );\n\n const candidateRange = dep.type === 'FS' || dep.type === 'SS'\n ? buildTaskRangeFromStart(constraintDate, duration, businessDays, weekendPredicate)\n : buildTaskRangeFromEnd(constraintDate, duration, businessDays, weekendPredicate);\n\n if (\n !constrainedRange ||\n candidateRange.start.getTime() > constrainedRange.start.getTime() ||\n (\n candidateRange.start.getTime() === constrainedRange.start.getTime() &&\n candidateRange.end.getTime() > constrainedRange.end.getTime()\n )\n ) {\n constrainedRange = candidateRange;\n }\n }\n\n if (!constrainedRange) {\n queue.push(successorId);\n continue;\n }\n\n workingMap.set(successorId, {\n ...currentTask,\n startDate: toIsoDate(constrainedRange.start),\n endDate: toIsoDate(constrainedRange.end),\n });\n queue.push(successorId);\n }\n }\n\n const parentsByDepth = snapshot\n .filter(task => isTaskParent(task.id, snapshot))\n .map(task => {\n let depth = 0;\n let current = task.parentId ? workingMap.get(task.parentId) : undefined;\n while (current) {\n depth++;\n current = current.parentId ? workingMap.get(current.parentId) : undefined;\n }\n return { taskId: task.id, depth };\n })\n .sort((left, right) => right.depth - left.depth);\n\n const workingTasks = () => Array.from(workingMap.values());\n\n for (const { taskId } of parentsByDepth) {\n const parent = workingMap.get(taskId);\n if (!parent || parent.locked) {\n continue;\n }\n\n const { startDate, endDate } = computeParentDates(taskId, workingTasks());\n workingMap.set(taskId, {\n ...parent,\n startDate: toIsoDate(startDate),\n endDate: toIsoDate(endDate),\n });\n }\n\n return createChangedResult(snapshot, Array.from(workingMap.values()));\n}\n","import type { Task } from './types';\nimport { normalizeUTCDate, getTaskDuration, alignToWorkingDay } from './dateMath';\nimport { buildTaskRangeFromStart } from './commands';\nimport { computeParentDates, isTaskParent } from './hierarchy';\nimport { recalculateProjectSchedule } from './execute';\n\n/**\n * Recalculate all task dates when switching between business/calendar day modes.\n *\n * Mode switch semantics are not a simple per-task move:\n * 1. Leaf tasks first preserve their current duration count while snapping to\n * the target calendar rules.\n * 2. Parent tasks roll up from children.\n * 3. The full dependency graph is then recalculated in the target mode so\n * successors obey the new FS/SS/FF/SF semantics (for example Fri -> Mon in\n * business mode, Fri -> Sat in calendar mode).\n */\nexport function reflowTasksOnModeSwitch(\n sourceTasks: Task[],\n toBusinessDays: boolean,\n weekendPredicate: (date: Date) => boolean\n): Task[] {\n const fromBusinessDays = !toBusinessDays;\n let tasks: Task[] = sourceTasks.map(task => ({\n ...task,\n dependencies: task.dependencies?.map(dependency => ({ ...dependency })),\n }));\n\n const toISO = (date: Date) => date.toISOString().split('T')[0];\n\n for (const task of tasks) {\n if (isTaskParent(task.id, tasks)) continue;\n\n const start = normalizeUTCDate(new Date(`${task.startDate}T00:00:00.000Z`));\n const duration = getTaskDuration(task.startDate, task.endDate, fromBusinessDays, weekendPredicate);\n\n const range = toBusinessDays\n ? buildTaskRangeFromStart(\n alignToWorkingDay(start, 1, weekendPredicate),\n duration,\n true,\n weekendPredicate\n )\n : buildTaskRangeFromStart(start, duration, false);\n\n task.startDate = toISO(range.start);\n task.endDate = toISO(range.end);\n }\n\n for (const task of tasks) {\n if (!isTaskParent(task.id, tasks)) continue;\n const { startDate, endDate } = computeParentDates(task.id, tasks);\n task.startDate = toISO(startDate);\n task.endDate = toISO(endDate);\n }\n\n const rescheduled = recalculateProjectSchedule(tasks, {\n businessDays: toBusinessDays,\n weekendPredicate,\n });\n\n if (rescheduled.changedTasks.length === 0) {\n return tasks;\n }\n\n const updates = new Map(rescheduled.changedTasks.map((task): [string, Task] => [task.id, task]));\n return tasks.map(task => updates.get(task.id) ?? task);\n}\n","/**\n * Dependency validation and cycle detection.\n * Moved from dependencyUtils.ts — verbatim implementations.\n * Zero React/DOM/date-fns imports.\n */\n\nimport type { Task, DependencyError, ValidationResult } from './types';\nimport { areTasksHierarchicallyRelated } from './hierarchy';\n\n/**\n * Build adjacency list for dependency graph (task -> successors)\n */\nexport function buildAdjacencyList(tasks: Task[]): Map<string, string[]> {\n const graph = new Map<string, string[]>();\n\n for (const task of tasks) {\n const successors: string[] = [];\n\n // Find all tasks that depend on this task (this task is a predecessor)\n for (const otherTask of tasks) {\n if (otherTask.dependencies) {\n for (const dep of otherTask.dependencies) {\n if (dep.taskId === task.id) {\n successors.push(otherTask.id);\n break;\n }\n }\n }\n }\n\n graph.set(task.id, successors);\n }\n\n return graph;\n}\n\n/**\n * Detect circular dependencies using depth-first search\n */\nexport function detectCycles(tasks: Task[]): { hasCycle: boolean; cyclePath?: string[] } {\n const graph = buildAdjacencyList(tasks);\n const visiting = new Set<string>();\n const visited = new Set<string>();\n const path: string[] = [];\n\n function dfs(taskId: string): boolean {\n if (visiting.has(taskId)) {\n return true;\n }\n if (visited.has(taskId)) {\n return false;\n }\n\n visiting.add(taskId);\n path.push(taskId);\n\n const successors = graph.get(taskId) || [];\n for (const successor of successors) {\n if (dfs(successor)) {\n return true;\n }\n }\n\n visiting.delete(taskId);\n path.pop();\n visited.add(taskId);\n return false;\n }\n\n for (const task of tasks) {\n if (dfs(task.id)) {\n return { hasCycle: true, cyclePath: [...path] };\n }\n }\n\n return { hasCycle: false };\n}\n\n/**\n * Validate all dependencies in the task list\n */\nexport function validateDependencies(tasks: Task[]): ValidationResult {\n const errors: DependencyError[] = [];\n const taskIds = new Set(tasks.map(t => t.id));\n\n // Check for missing predecessor references\n for (const task of tasks) {\n if (task.dependencies) {\n for (const dep of task.dependencies) {\n if (!taskIds.has(dep.taskId)) {\n errors.push({\n type: 'missing-task',\n taskId: task.id,\n message: `Dependency references non-existent task: ${dep.taskId}`,\n relatedTaskIds: [dep.taskId],\n });\n }\n }\n }\n }\n\n // Check for invalid hierarchy links (ancestor <-> descendant)\n for (const task of tasks) {\n if (!task.dependencies) continue;\n\n for (const dep of task.dependencies) {\n if (!taskIds.has(dep.taskId)) {\n continue;\n }\n\n if (areTasksHierarchicallyRelated(task.id, dep.taskId, tasks)) {\n errors.push({\n type: 'constraint',\n taskId: task.id,\n message: `Dependencies between parent and child tasks are not allowed: ${dep.taskId} -> ${task.id}`,\n relatedTaskIds: [dep.taskId, task.id],\n });\n }\n }\n }\n\n // Check for cycles\n const cycleResult = detectCycles(tasks);\n if (cycleResult.hasCycle && cycleResult.cyclePath) {\n errors.push({\n type: 'cycle',\n taskId: cycleResult.cyclePath[0],\n message: 'Circular dependency detected',\n relatedTaskIds: cycleResult.cyclePath,\n });\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n };\n}\n"],"mappings":"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","names":["DAY_MS","DAY_MS"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/core/scheduling/index.ts","../../../src/core/scheduling/dateMath.ts","../../../src/core/scheduling/dependencies.ts","../../../src/core/scheduling/criticalPath.ts","../../../src/core/scheduling/commands.ts","../../../src/core/scheduling/cascade.ts","../../../src/core/scheduling/hierarchy.ts","../../../src/core/scheduling/execute.ts","../../../src/core/scheduling/modeSwitch.ts","../../../src/core/scheduling/validation.ts"],"sourcesContent":["/**\n * Core scheduling module — runtime-agnostic scheduling logic.\n * Zero React/DOM/date-fns dependencies.\n */\nexport * from './types';\nexport * from './dateMath';\nexport * from './dependencies';\nexport * from './criticalPath';\nexport * from './cascade';\nexport * from './modeSwitch';\nexport * from './commands';\nexport * from './execute';\nexport * from './validation';\nexport * from './hierarchy';\n","/**\n * Pure date math utilities for the core scheduling module.\n * Zero React/DOM/date-fns dependencies.\n *\n * Functions moved from:\n * - dependencyUtils.ts: normalizeUTCDate, parseDateOnly, getBusinessDayOffset, shiftBusinessDayOffset, DAY_MS\n * - dateUtils.ts: getBusinessDaysCount, addBusinessDays, subtractBusinessDays\n */\n\nexport const DAY_MS = 24 * 60 * 60 * 1000;\n\n/**\n * Normalize a Date to UTC midnight (hours/minutes/seconds zeroed).\n */\nexport function normalizeUTCDate(date: Date): Date {\n return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));\n}\n\n/**\n * Parse a date string or Date object to a UTC midnight Date.\n * Handles ISO strings like \"2025-01-15\" by appending T00:00:00.000Z.\n */\nexport function parseDateOnly(date: string | Date): Date {\n const parsed = typeof date === 'string'\n ? new Date(`${date.split('T')[0]}T00:00:00.000Z`)\n : normalizeUTCDate(date);\n return normalizeUTCDate(parsed);\n}\n\n/**\n * Compute the business-day offset between two dates.\n * Steps through each calendar day, counting only non-weekend days.\n * Returns a positive number if toDate > fromDate, negative if toDate < fromDate.\n */\nexport function getBusinessDayOffset(\n fromDate: Date,\n toDate: Date,\n weekendPredicate: (date: Date) => boolean\n): number {\n const from = normalizeUTCDate(fromDate);\n const to = normalizeUTCDate(toDate);\n\n if (from.getTime() === to.getTime()) {\n return 0;\n }\n\n const step = to.getTime() > from.getTime() ? 1 : -1;\n const current = new Date(from);\n let offset = 0;\n\n while (current.getTime() !== to.getTime()) {\n current.setUTCDate(current.getUTCDate() + step);\n if (!weekendPredicate(current)) {\n offset += step;\n }\n }\n\n return offset;\n}\n\n/**\n * Shift a date by a business-day offset, skipping weekends.\n */\nexport function shiftBusinessDayOffset(\n date: Date,\n offset: number,\n weekendPredicate: (date: Date) => boolean\n): Date {\n const current = normalizeUTCDate(date);\n\n if (offset === 0) {\n return current;\n }\n\n const step = offset > 0 ? 1 : -1;\n let remaining = Math.abs(offset);\n\n while (remaining > 0) {\n current.setUTCDate(current.getUTCDate() + step);\n if (!weekendPredicate(current)) {\n remaining--;\n }\n }\n\n return current;\n}\n\n/**\n * Count business days between two dates (inclusive), excluding weekends.\n * Returns minimum 1.\n */\nexport function getBusinessDaysCount(\n startDate: string | Date,\n endDate: string | Date,\n weekendPredicate: (date: Date) => boolean\n): number {\n const start = typeof startDate === 'string'\n ? new Date(`${startDate.split('T')[0]}T00:00:00.000Z`)\n : normalizeUTCDate(startDate);\n const end = typeof endDate === 'string'\n ? new Date(`${endDate.split('T')[0]}T00:00:00.000Z`)\n : normalizeUTCDate(endDate);\n\n let count = 0;\n const current = new Date(start);\n\n while (current.getTime() <= end.getTime()) {\n if (!weekendPredicate(current)) {\n count++;\n }\n current.setUTCDate(current.getUTCDate() + 1);\n }\n\n return Math.max(1, count);\n}\n\n/**\n * Calculate end date by adding N business days to start date.\n * Returns a Date object.\n */\nexport function addBusinessDays(\n startDate: string | Date,\n businessDays: number,\n weekendPredicate: (date: Date) => boolean\n): Date {\n const start = typeof startDate === 'string'\n ? new Date(`${startDate.split('T')[0]}T00:00:00.000Z`)\n : normalizeUTCDate(startDate);\n const current = new Date(start);\n let targetDays = Math.max(1, businessDays);\n let businessDaysCounted = 0;\n\n while (businessDaysCounted < targetDays) {\n if (!weekendPredicate(current)) {\n businessDaysCounted++;\n }\n if (businessDaysCounted < targetDays) {\n current.setUTCDate(current.getUTCDate() + 1);\n }\n }\n\n return current;\n}\n\n/**\n * Calculate start date by subtracting N business days from end date.\n * Returns a Date object.\n */\nexport function subtractBusinessDays(\n endDate: string | Date,\n businessDays: number,\n weekendPredicate: (date: Date) => boolean\n): Date {\n const end = typeof endDate === 'string'\n ? new Date(`${endDate.split('T')[0]}T00:00:00.000Z`)\n : normalizeUTCDate(endDate);\n const current = new Date(end);\n let targetDays = Math.max(1, businessDays);\n let businessDaysCounted = 0;\n\n while (businessDaysCounted < targetDays) {\n if (!weekendPredicate(current)) {\n businessDaysCounted++;\n }\n if (businessDaysCounted < targetDays) {\n current.setUTCDate(current.getUTCDate() - 1);\n }\n }\n\n return current;\n}\n\n/**\n * Snap a date to the nearest working day in the given direction.\n */\nexport function alignToWorkingDay(\n date: Date,\n direction: 1 | -1,\n weekendPredicate: (date: Date) => boolean\n): Date {\n const current = normalizeUTCDate(date);\n\n while (weekendPredicate(current)) {\n current.setUTCDate(current.getUTCDate() + direction);\n }\n\n return current;\n}\n\n/**\n * Get task duration in days (inclusive).\n * If businessDays mode, counts business days using weekendPredicate.\n * Otherwise, counts calendar days.\n */\nexport function getTaskDuration(\n startDate: string | Date,\n endDate: string | Date,\n businessDays: boolean = false,\n weekendPredicate?: (date: Date) => boolean\n): number {\n const start = parseDateOnly(startDate);\n const end = parseDateOnly(endDate);\n\n if (businessDays && weekendPredicate) {\n return getBusinessDaysCount(start, end, weekendPredicate);\n }\n\n return Math.max(1, Math.round((end.getTime() - start.getTime()) / DAY_MS) + 1);\n}\n","/**\n * Dependency calculation functions.\n * Moved from dependencyUtils.ts — verbatim implementations.\n * Zero React/DOM/date-fns imports.\n */\n\n// START_MODULE_CONTRACT\n// PURPOSE: Calculate dependency dates and lags using inclusive task dates and explicit milestone semantics.\n// SCOPE: Normalize dependency inputs, calculate successor anchors, and derive lag values from task ranges.\n// DEPENDS: dateMath, scheduling types\n// LINKS: M-SCHEDULING, fn-calculateSuccessorDate, fn-computeLagFromDates\n// ROLE: RUNTIME\n// MAP_MODE: EXPORTS\n// END_MODULE_CONTRACT\n\nimport type { LinkType, TaskDependency, Task } from './types';\nimport {\n getBusinessDayOffset,\n shiftBusinessDayOffset,\n DAY_MS,\n getTaskDuration,\n} from './dateMath';\n\n/**\n * Normalize predecessor dates for scheduling calculations.\n * Milestones have a real zero-duration finish anchor at startDate. The\n * successor type, rather than a fabricated predecessor date, determines\n * whether FS lag=0 lands on the same day (milestone successor) or the next\n * day (regular successor).\n */\nexport function normalizePredecessorDates(\n predecessor: Pick<Task, 'startDate' | 'endDate' | 'type'>,\n parseDateFn: (d: string | Date) => Date\n): { predStart: Date; predEnd: Date } {\n const predStart = parseDateFn(predecessor.startDate);\n const predEnd = predecessor.type === 'milestone'\n ? predStart\n : parseDateFn(predecessor.endDate);\n return { predStart, predEnd };\n}\n\n/**\n * Get lag value from dependency, defaulting to 0.\n */\nexport function getDependencyLag(dep: Pick<TaskDependency, 'lag'>): number {\n return Number.isFinite(dep.lag) ? dep.lag : 0;\n}\n\n/**\n * Return a copy of a task with dependency lag values normalized.\n *\n * FS lag normalization depends on predecessor duration, so this helper\n * intentionally leaves dependencies unchanged.\n */\nexport function normalizeTaskDependencyLags<TTask extends Pick<Task, 'dependencies'>>(task: TTask): TTask {\n return task;\n}\n\n/**\n * Normalize lag for FS links. Regular successors clamp to\n * `-predecessorDuration`; milestone successors use one fewer day because\n * their zero-duration FS anchor is the predecessor finish date itself.\n */\nexport function normalizeDependencyLag(\n linkType: LinkType,\n lag: number,\n predecessorStart: Date,\n predecessorEnd: Date,\n businessDays: boolean = false,\n weekendPredicate?: (date: Date) => boolean,\n successorType?: Task['type']\n): number {\n if (linkType !== 'FS') {\n return lag;\n }\n\n const predecessorDuration = getTaskDuration(\n predecessorStart,\n predecessorEnd,\n businessDays,\n weekendPredicate\n );\n\n const minimumLag = successorType === 'milestone'\n ? -(Math.max(0, predecessorDuration - 1))\n : -predecessorDuration;\n\n return Math.max(minimumLag, lag);\n}\n\n/**\n * Compute lag (in days) from actual predecessor/successor dates.\n * This is the single source of truth for lag semantics.\n *\n * Semantics (lag=0 = natural, gap-free connection):\n * - FS: lag = succStart - predEnd - 1 (adjacent regular-task days = 0)\n * milestone successor uses succStart - predEnd (same-day = 0)\n * - SS: lag = succStart - predStart\n * - FF: lag = succEnd - predEnd\n * - SF: lag = succEnd - predStart + 1 (symmetric to FS)\n */\nexport function computeLagFromDates(\n linkType: LinkType,\n predStart: Date,\n predEnd: Date,\n succStart: Date,\n succEnd: Date,\n businessDays: boolean = false,\n weekendPredicate?: (date: Date) => boolean,\n successorType?: Task['type']\n): number {\n const pS = Date.UTC(predStart.getUTCFullYear(), predStart.getUTCMonth(), predStart.getUTCDate());\n const pE = Date.UTC(predEnd.getUTCFullYear(), predEnd.getUTCMonth(), predEnd.getUTCDate());\n const sS = Date.UTC(succStart.getUTCFullYear(), succStart.getUTCMonth(), succStart.getUTCDate());\n const sE = Date.UTC(succEnd.getUTCFullYear(), succEnd.getUTCMonth(), succEnd.getUTCDate());\n\n // Calendar days (original logic)\n if (!businessDays || !weekendPredicate) {\n switch (linkType) {\n case 'FS':\n return normalizeDependencyLag(\n linkType,\n Math.round((sS - pE) / DAY_MS) - (successorType === 'milestone' ? 0 : 1),\n predStart,\n predEnd,\n businessDays,\n weekendPredicate,\n successorType\n );\n case 'SS': return Math.round((sS - pS) / DAY_MS);\n case 'FF': return Math.round((sE - pE) / DAY_MS);\n case 'SF': return Math.round((sE - pS) / DAY_MS) + 1;\n }\n }\n\n const anchorDate = linkType === 'SS' || linkType === 'SF' ? predStart : predEnd;\n const targetDate = linkType === 'FS' || linkType === 'SS' ? succStart : succEnd;\n const businessOffset = getBusinessDayOffset(anchorDate, targetDate, weekendPredicate);\n\n switch (linkType) {\n case 'FS':\n return normalizeDependencyLag(\n linkType,\n businessOffset - (successorType === 'milestone' ? 0 : 1),\n predStart,\n predEnd,\n businessDays,\n weekendPredicate,\n successorType\n );\n case 'SS': return businessOffset;\n case 'FF': return businessOffset;\n case 'SF': return businessOffset + 1;\n }\n}\n\n/**\n * Calculate successor date based on predecessor dates, link type, and lag.\n *\n * Link type semantics:\n * - FS: Successor start = Predecessor end + lag + 1 day for regular tasks\n * and Predecessor end + lag for milestone successors\n * - SS: Successor start = Predecessor start + lag\n * - FF: Successor end = Predecessor end + lag\n * - SF: Successor end = Predecessor start + lag - 1 day (lag=0 -> day before)\n */\nexport function calculateSuccessorDate(\n predecessorStart: Date,\n predecessorEnd: Date,\n linkType: LinkType,\n lag: number = 0,\n businessDays: boolean = false,\n weekendPredicate?: (date: Date) => boolean,\n successorType?: Task['type']\n): Date {\n const normalizedLag = normalizeDependencyLag(\n linkType,\n lag,\n predecessorStart,\n predecessorEnd,\n businessDays,\n weekendPredicate,\n successorType\n );\n\n // Calendar days (original logic)\n if (!businessDays || !weekendPredicate) {\n switch (linkType) {\n case 'FS':\n return new Date(predecessorEnd.getTime() + (\n normalizedLag + (successorType === 'milestone' ? 0 : 1)\n ) * DAY_MS);\n case 'SS':\n return new Date(predecessorStart.getTime() + normalizedLag * DAY_MS);\n case 'FF':\n return new Date(predecessorEnd.getTime() + normalizedLag * DAY_MS);\n case 'SF':\n return new Date(predecessorStart.getTime() + (normalizedLag - 1) * DAY_MS);\n }\n }\n\n const anchorDate = (linkType === 'FS' || linkType === 'FF') ? predecessorEnd : predecessorStart;\n let offset: number;\n switch (linkType) {\n case 'FS':\n offset = normalizedLag + (successorType === 'milestone' ? 0 : 1);\n break;\n case 'SS':\n offset = normalizedLag;\n break;\n case 'FF':\n offset = normalizedLag;\n break;\n case 'SF':\n offset = normalizedLag - 1;\n break;\n }\n return shiftBusinessDayOffset(anchorDate, offset, weekendPredicate);\n}\n","/**\n * Critical path (CPM) calculation over dependency links.\n * Zero React/DOM/date-fns imports.\n *\n * Semantics:\n * - Only leaf tasks (no task references them as parentId) participate in the graph.\n * - All link types are edges — FS, SS, FF, SF — with calendar lags, mirroring\n * calculateSuccessorDate:\n * FS: succStart >= predEnd + lag SS: succStart >= predStart + lag\n * FF: succEnd >= predEnd + lag SF: succEnd >= predStart + lag\n * - A dependency on a parent task (a task that has children) is expanded to its\n * leaf descendants with the same link type and lag. For finish-anchored links\n * (FS/FF) the group is bounded by its latest-finishing leaf; for start-anchored\n * links (SS/SF) by its latest-starting leaf — a conservative approximation of\n * the group's span.\n * - Task weight = business-day duration (getTaskDuration); edge weight = lag in the\n * active scheduling unit.\n * - The scheduled task dates are used as the current starts. The project finish is\n * the latest scheduled leaf finish, so a late short branch can be critical even\n * when a longer branch started earlier.\n * - Task is critical when its total float (late start - scheduled start) is <= 0.\n * A standalone task can therefore be critical when it determines the project\n * finish; dependency membership is not a prerequisite for criticality.\n * - Cycles are skipped by topological ordering (Kahn) — cyclic tasks are not critical.\n */\n\nimport type { ScheduleTask, LinkType } from './types';\nimport { DAY_MS, getBusinessDayOffset, getTaskDuration, parseDateOnly } from './dateMath';\nimport { getDependencyLag } from './dependencies';\n\nexport interface CriticalPathOptions {\n businessDays?: boolean;\n weekendPredicate?: (date: Date) => boolean;\n}\n\ninterface Edge {\n succId: string;\n lag: number;\n type: LinkType;\n}\n\nexport function computeCriticalPath(\n tasks: ScheduleTask[],\n options: CriticalPathOptions = {}\n): Set<string> {\n const { businessDays = false, weekendPredicate } = options;\n\n const taskById = new Map(tasks.map((task) => [task.id, task]));\n\n const childIds = new Set<string>();\n for (const task of tasks) {\n if (task.parentId) childIds.add(task.parentId);\n }\n const leafTasks = tasks.filter((task) => !childIds.has(task.id));\n const leafIds = new Set(leafTasks.map((task) => task.id));\n\n // Map any task id (parent or not) to ALL of its leaf descendants (transitive).\n const leafIdsByAncestor = new Map<string, Set<string>>();\n for (const leaf of leafTasks) {\n let ancestor: string | undefined = leaf.parentId;\n while (ancestor) {\n const set = leafIdsByAncestor.get(ancestor) ?? new Set<string>();\n set.add(leaf.id);\n leafIdsByAncestor.set(ancestor, set);\n ancestor = taskById.get(ancestor)?.parentId;\n }\n }\n\n const durationOf = (task: ScheduleTask): number =>\n getTaskDuration(task.startDate, task.endDate, businessDays, weekendPredicate);\n\n const projectStartDate = leafTasks.reduce((earliest, task) => {\n const taskStart = parseDateOnly(task.startDate);\n return taskStart.getTime() < earliest.getTime() ? taskStart : earliest;\n }, parseDateOnly(leafTasks[0]?.startDate ?? new Date()));\n\n const offsetFromProjectStart = (date: string | Date): number => {\n const targetDate = parseDateOnly(date);\n if (businessDays && weekendPredicate) {\n return getBusinessDayOffset(projectStartDate, targetDate, weekendPredicate);\n }\n return Math.round((targetDate.getTime() - projectStartDate.getTime()) / DAY_MS);\n };\n\n // The current schedule is the forward pass. Do not reset every root task to\n // day zero: its actual start date is what gives it (or removes) total float.\n const scheduledStart = new Map<string, number>();\n for (const leaf of leafTasks) {\n scheduledStart.set(leaf.id, offsetFromProjectStart(leaf.startDate));\n }\n\n // Adjacency over all link types: predecessor -> successors, successor -> predecessors.\n const succByPred = new Map<string, Edge[]>();\n const predBySucc = new Map<string, Array<{ predId: string; lag: number; type: LinkType }>>();\n const seenEdges = new Set<string>();\n\n const addEdge = (predecessorId: string, succId: string, lag: number, type: LinkType) => {\n const edgeKey = `${predecessorId}|${succId}|${type}`;\n if (seenEdges.has(edgeKey)) return;\n seenEdges.add(edgeKey);\n\n const outEdges = succByPred.get(predecessorId) ?? [];\n outEdges.push({ succId, lag, type });\n succByPred.set(predecessorId, outEdges);\n\n const inEdges = predBySucc.get(succId) ?? [];\n inEdges.push({ predId: predecessorId, lag, type });\n predBySucc.set(succId, inEdges);\n };\n\n for (const succ of leafTasks) {\n for (const dep of succ.dependencies ?? []) {\n const lag = getDependencyLag(dep);\n\n // Predecessor is a leaf: direct edge.\n if (leafIds.has(dep.taskId)) {\n addEdge(dep.taskId, succ.id, lag, dep.type);\n continue;\n }\n\n // Predecessor is a parent/group: expand to every leaf descendant.\n // The successor's own leaf (self-loop) is skipped.\n const descendants = leafIdsByAncestor.get(dep.taskId);\n if (!descendants || descendants.size === 0) continue;\n for (const leafId of descendants) {\n if (leafId === succ.id) continue;\n addEdge(leafId, succ.id, lag, dep.type);\n }\n }\n }\n\n // Topological order (Kahn). Vertices trapped in cycles never enter the order\n // (indegree never drops to 0) and are therefore excluded from criticality.\n const indegree = new Map<string, number>();\n for (const leaf of leafTasks) indegree.set(leaf.id, 0);\n for (const edges of succByPred.values()) {\n for (const { succId } of edges) {\n indegree.set(succId, (indegree.get(succId) ?? 0) + 1);\n }\n }\n\n const order: string[] = [];\n const enqueued = new Set<string>();\n const queue = leafTasks\n .filter((leaf) => (indegree.get(leaf.id) ?? 0) === 0)\n .map((leaf) => leaf.id);\n for (const id of queue) enqueued.add(id);\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n order.push(current);\n for (const { succId } of succByPred.get(current) ?? []) {\n const next = (indegree.get(succId) ?? 0) - 1;\n indegree.set(succId, next);\n if (next === 0 && !enqueued.has(succId)) {\n enqueued.add(succId);\n queue.push(succId);\n }\n }\n }\n\n const projectFinish = Math.max(\n 0,\n ...leafTasks.map((leaf) => (scheduledStart.get(leaf.id) ?? 0) + durationOf(leaf))\n );\n\n // Backward pass: late finish / late start.\n const LF = new Map<string, number>();\n const LS = new Map<string, number>();\n for (const leaf of leafTasks) LF.set(leaf.id, projectFinish);\n\n for (let i = order.length - 1; i >= 0; i--) {\n const id = order[i];\n const task = taskById.get(id)!;\n const durPred = durationOf(task);\n const outEdges = succByPred.get(id) ?? [];\n let lf = projectFinish;\n if (outEdges.length > 0) {\n const candidates = outEdges.map(({ succId, lag, type }) => {\n const succLs = LS.get(succId) ?? projectFinish;\n const durSucc = durationOf(taskById.get(succId)!);\n switch (type) {\n case 'FS': return succLs - lag;\n case 'SS': return succLs - lag + durPred;\n case 'FF': return succLs + durSucc - lag;\n case 'SF': return succLs + durSucc - lag + durPred;\n default: return projectFinish;\n }\n });\n lf = Math.min(projectFinish, ...candidates);\n }\n LF.set(id, lf);\n LS.set(id, lf - durPred);\n }\n\n const critical = new Set<string>();\n const ordered = new Set(order);\n for (const leaf of leafTasks) {\n // Vertices trapped in cycles never entered the topological order and are\n // never critical.\n if (!ordered.has(leaf.id)) continue;\n const hasGraphEdge =\n (succByPred.get(leaf.id)?.length ?? 0) > 0 ||\n (predBySucc.get(leaf.id)?.length ?? 0) > 0;\n // A task with no declared dependencies is a legitimate standalone\n // project task and may determine the project finish. If it declares\n // dependencies but none resolved to a valid graph edge (for example a\n // self-reference through its own parent), it is not a schedulable path.\n if (!hasGraphEdge && (leaf.dependencies?.length ?? 0) > 0) continue;\n const es = scheduledStart.get(leaf.id) ?? 0;\n const ls = LS.get(leaf.id) ?? 0;\n if (ls - es <= 0) critical.add(leaf.id);\n }\n\n return critical;\n}\n\n/**\n * Extend criticality from leaf ids upward through the parent chain.\n * A parent is critical when any of its descendants is critical.\n */\nexport function extendCriticalIdsToParents(\n criticalLeafIds: Set<string>,\n tasks: ScheduleTask[]\n): Set<string> {\n const result = new Set(criticalLeafIds);\n const parentByChild = new Map<string, string>();\n for (const task of tasks) {\n if (task.parentId) parentByChild.set(task.id, task.parentId);\n }\n\n const stack = Array.from(criticalLeafIds);\n while (stack.length > 0) {\n const id = stack.pop()!;\n const parentId = parentByChild.get(id);\n if (parentId && !result.has(parentId)) {\n result.add(parentId);\n stack.push(parentId);\n }\n }\n\n return result;\n}\n","/**\n * High-level schedule command functions.\n * Moved from dependencyUtils.ts — verbatim implementations.\n * Zero React/DOM/date-fns imports.\n */\n\n// START_MODULE_CONTRACT\n// PURPOSE: Build task ranges and update dependency lags for interactive scheduling commands.\n// SCOPE: Range construction, incoming FS clamping, and lag recalculation.\n// DEPENDS: dateMath, dependencies, scheduling types\n// LINKS: M-SCHEDULING, fn-clampTaskRangeForIncomingFS, fn-recalculateIncomingLags\n// ROLE: RUNTIME\n// MAP_MODE: EXPORTS\n// END_MODULE_CONTRACT\n\nimport type { Task } from './types';\nimport {\n normalizeUTCDate,\n parseDateOnly,\n addBusinessDays,\n subtractBusinessDays,\n alignToWorkingDay,\n getTaskDuration,\n getBusinessDaysCount,\n} from './dateMath';\nimport {\n calculateSuccessorDate,\n getDependencyLag,\n computeLagFromDates,\n normalizePredecessorDates,\n} from './dependencies';\n\n// Re-export for backward compat — these live in dateMath now\nexport { alignToWorkingDay, getTaskDuration };\n\n/**\n * Build a task range (start/end dates) from a start date and duration.\n */\nexport function buildTaskRangeFromStart(\n startDate: Date,\n duration: number,\n businessDays: boolean = false,\n weekendPredicate?: (date: Date) => boolean,\n snapDirection: 1 | -1 = 1\n): { start: Date; end: Date } {\n const normalizedStart = businessDays && weekendPredicate\n ? alignToWorkingDay(startDate, snapDirection, weekendPredicate)\n : normalizeUTCDate(startDate);\n\n if (businessDays && weekendPredicate) {\n return {\n start: normalizedStart,\n end: parseDateOnly(addBusinessDays(normalizedStart, duration, weekendPredicate)),\n };\n }\n\n const DAY_MS = 24 * 60 * 60 * 1000;\n return {\n start: normalizedStart,\n end: new Date(normalizedStart.getTime() + (Math.max(1, duration) - 1) * DAY_MS),\n };\n}\n\n/**\n * Build a task range (start/end dates) from an end date and duration.\n */\nexport function buildTaskRangeFromEnd(\n endDate: Date,\n duration: number,\n businessDays: boolean = false,\n weekendPredicate?: (date: Date) => boolean,\n snapDirection: 1 | -1 = -1\n): { start: Date; end: Date } {\n const normalizedEnd = businessDays && weekendPredicate\n ? alignToWorkingDay(endDate, snapDirection, weekendPredicate)\n : normalizeUTCDate(endDate);\n\n if (businessDays && weekendPredicate) {\n return {\n start: parseDateOnly(subtractBusinessDays(normalizedEnd, duration, weekendPredicate)),\n end: normalizedEnd,\n };\n }\n\n const DAY_MS = 24 * 60 * 60 * 1000;\n return {\n start: new Date(normalizedEnd.getTime() - (Math.max(1, duration) - 1) * DAY_MS),\n end: normalizedEnd,\n };\n}\n\n/**\n * Move a task range to a new start date, preserving duration.\n */\nexport function moveTaskRange(\n originalStart: string | Date,\n originalEnd: string | Date,\n proposedStart: Date,\n businessDays: boolean = false,\n weekendPredicate?: (date: Date) => boolean,\n snapDirection: 1 | -1 = 1\n): { start: Date; end: Date } {\n return buildTaskRangeFromStart(\n proposedStart,\n getTaskDuration(originalStart, originalEnd, businessDays, weekendPredicate),\n businessDays,\n weekendPredicate,\n snapDirection\n );\n}\n\n/**\n * Clamp task range start date based on incoming FS dependencies.\n */\nexport function clampTaskRangeForIncomingFS(\n task: Pick<Task, 'dependencies' | 'type'>,\n proposedStart: Date,\n proposedEnd: Date,\n allTasks: Task[],\n businessDays: boolean = false,\n weekendPredicate?: (date: Date) => boolean,\n taskById?: Map<string, Task>\n): { start: Date; end: Date } {\n if (!task.dependencies?.length) {\n return { start: proposedStart, end: proposedEnd };\n }\n\n let minAllowedStart: Date | null = null;\n\n for (const dep of task.dependencies) {\n if (dep.type !== 'FS') {\n continue;\n }\n\n const predecessor = taskById?.get(dep.taskId) ?? allTasks.find(candidate => candidate.id === dep.taskId);\n if (!predecessor) {\n continue;\n }\n\n const { predStart: predecessorStart, predEnd: predecessorEnd } = normalizePredecessorDates(predecessor, parseDateOnly);\n const predecessorDuration = getTaskDuration(\n predecessorStart,\n predecessorEnd,\n businessDays,\n weekendPredicate\n );\n const candidateMinStart = calculateSuccessorDate(\n predecessorStart,\n predecessorEnd,\n 'FS',\n -predecessorDuration,\n businessDays,\n weekendPredicate,\n task.type\n );\n\n if (!minAllowedStart || candidateMinStart.getTime() > minAllowedStart.getTime()) {\n minAllowedStart = candidateMinStart;\n }\n }\n\n if (!minAllowedStart || proposedStart.getTime() >= minAllowedStart.getTime()) {\n return { start: proposedStart, end: proposedEnd };\n }\n\n return buildTaskRangeFromStart(\n minAllowedStart,\n getTaskDuration(proposedStart, proposedEnd, businessDays, weekendPredicate),\n businessDays,\n weekendPredicate\n );\n}\n\n/**\n * Recalculate incoming dependency lags after a task's dates change.\n */\nexport function recalculateIncomingLags(\n task: Task,\n newStartDate: Date,\n newEndDate: Date,\n allTasks: Task[],\n businessDays: boolean = false,\n weekendPredicate?: (date: Date) => boolean,\n taskById?: Map<string, Task>\n): NonNullable<Task['dependencies']> {\n if (!task.dependencies) return [];\n return task.dependencies.map(dep => {\n const predecessor = taskById?.get(dep.taskId) ?? allTasks.find(candidate => candidate.id === dep.taskId);\n if (!predecessor) {\n return { ...dep, lag: getDependencyLag(dep) };\n }\n\n const { predStart: predecessorStart, predEnd: predecessorEnd } = normalizePredecessorDates(\n predecessor,\n (d) => new Date(d instanceof Date ? d.getTime() : `${String(d).split('T')[0]}T00:00:00.000Z`)\n );\n const nextLag = computeLagFromDates(\n dep.type,\n predecessorStart,\n predecessorEnd,\n newStartDate,\n newEndDate,\n businessDays,\n weekendPredicate,\n task.type\n );\n\n return { ...dep, lag: nextLag };\n });\n}\n\n","/**\n * Cascade engine functions.\n * Moved from dependencyUtils.ts — verbatim implementations.\n * Zero React/DOM/date-fns imports.\n */\n\n// START_MODULE_CONTRACT\n// PURPOSE: Propagate moved task dates through dependency and hierarchy graphs.\n// SCOPE: Dependency cascades, parent/child propagation, and business-day alignment.\n// DEPENDS: commands, dateMath, dependencies, scheduling types\n// LINKS: M-SCHEDULING, fn-cascadeByLinks, fn-universalCascade\n// ROLE: RUNTIME\n// MAP_MODE: EXPORTS\n// END_MODULE_CONTRACT\n\nimport type { Task, LinkType } from './types';\nimport {\n normalizeUTCDate,\n getTaskDuration,\n alignToWorkingDay,\n} from './dateMath';\nimport {\n calculateSuccessorDate,\n getDependencyLag,\n normalizeTaskDependencyLags,\n normalizePredecessorDates,\n} from './dependencies';\nimport {\n buildTaskRangeFromStart,\n buildTaskRangeFromEnd,\n moveTaskRange,\n} from './commands';\n\nfunction parseCascadeDateInput(date: string | Date): Date {\n if (date instanceof Date) {\n return normalizeUTCDate(date);\n }\n return normalizeUTCDate(new Date(`${date.split('T')[0]}T00:00:00.000Z`));\n}\n\nexport interface CascadeContext {\n childrenByParentId: Map<string, Task[]>;\n dependentsByPredecessorId: Map<string, Array<{ task: Task; dependencyIndex: number }>>;\n taskById: Map<string, Task>;\n}\n\nexport function createCascadeContext(allTasks: Task[]): CascadeContext {\n const childrenByParentId = new Map<string, Task[]>();\n const dependentsByPredecessorId = new Map<string, Array<{ task: Task; dependencyIndex: number }>>();\n const taskById = new Map<string, Task>();\n\n for (const task of allTasks) {\n taskById.set(task.id, task);\n\n if (task.parentId) {\n const children = childrenByParentId.get(task.parentId) ?? [];\n children.push(task);\n childrenByParentId.set(task.parentId, children);\n }\n\n if (!task.dependencies) continue;\n\n task.dependencies.forEach((dependency, dependencyIndex) => {\n const dependents = dependentsByPredecessorId.get(dependency.taskId) ?? [];\n dependents.push({ task, dependencyIndex });\n dependentsByPredecessorId.set(dependency.taskId, dependents);\n });\n }\n\n return { childrenByParentId, dependentsByPredecessorId, taskById };\n}\n\n/**\n * Get successor tasks of a dragged task using BFS, filtered by link type(s).\n */\nexport function getSuccessorChain(\n draggedTaskId: string,\n allTasks: Task[],\n linkTypes: LinkType[] = ['FS']\n): Task[] {\n const { dependentsByPredecessorId, taskById } = createCascadeContext(allTasks);\n const visited = new Set<string>();\n const queue: string[] = [draggedTaskId];\n const chain: Task[] = [];\n visited.add(draggedTaskId);\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n const successors = dependentsByPredecessorId.get(current) ?? [];\n for (const { task } of successors) {\n if (!linkTypes.includes(task.dependencies?.find((dependency) => dependency.taskId === current)?.type ?? 'FS')) {\n continue;\n }\n const sid = task.id;\n if (!visited.has(sid)) {\n visited.add(sid);\n const successorTask = taskById.get(sid);\n if (successorTask) {\n chain.push(successorTask);\n queue.push(sid);\n }\n }\n }\n }\n\n return chain;\n}\n\n/**\n * Cascade successors by actual link constraints (BFS, constraint-based).\n */\nexport function cascadeByLinks(\n movedTaskId: string,\n newStart: Date,\n newEnd: Date,\n allTasks: Task[],\n skipChildCascade: boolean = false\n): Task[] {\n const { childrenByParentId, dependentsByPredecessorId, taskById } = createCascadeContext(allTasks);\n\n const updatedDates = new Map<string, { start: Date; end: Date }>();\n updatedDates.set(movedTaskId, { start: newStart, end: newEnd });\n\n const result: Task[] = [];\n const queue: string[] = [movedTaskId];\n const visited = new Set<string>([movedTaskId]);\n\n while (queue.length > 0) {\n const currentId = queue.shift()!;\n const { start: predStart, end: predEnd } = updatedDates.get(currentId)!;\n\n if (!skipChildCascade) {\n const children = childrenByParentId.get(currentId) ?? [];\n for (const child of children) {\n if (visited.has(child.id) || child.locked) continue;\n\n const origStart = new Date(child.startDate as string);\n const origEnd = new Date(child.endDate as string);\n const durationMs = origEnd.getTime() - origStart.getTime();\n\n const parentOrig = taskById.get(currentId)!;\n const parentOrigStart = new Date(parentOrig.startDate as string);\n const parentOrigEnd = new Date(parentOrig.endDate as string);\n\n const parentStartDelta = predStart.getTime() - parentOrigStart.getTime();\n const parentEndDelta = predEnd.getTime() - parentOrigEnd.getTime();\n\n const newChildStart = new Date(origStart.getTime() + parentStartDelta);\n const newChildEnd = new Date(origEnd.getTime() + parentEndDelta);\n\n visited.add(child.id);\n updatedDates.set(child.id, { start: newChildStart, end: newChildEnd });\n result.push(normalizeTaskDependencyLags({\n ...child,\n startDate: newChildStart.toISOString().split('T')[0],\n endDate: newChildEnd.toISOString().split('T')[0],\n }));\n queue.push(child.id);\n }\n }\n\n const dependents = dependentsByPredecessorId.get(currentId) ?? [];\n for (const { task, dependencyIndex } of dependents) {\n if (visited.has(task.id) || !task.dependencies || task.locked) continue;\n const dep = task.dependencies[dependencyIndex];\n if (!dep) continue;\n\n const orig = taskById.get(task.id)!;\n const origStart = new Date(orig.startDate as string);\n const origEnd = new Date(orig.endDate as string);\n const duration = getTaskDuration(origStart, origEnd);\n const currentTask = taskById.get(currentId)!;\n const { predStart: normalizedPredStart, predEnd: normalizedPredEnd } = normalizePredecessorDates(\n {\n startDate: predStart,\n endDate: predEnd,\n type: currentTask.type,\n },\n parseCascadeDateInput\n );\n const constraintDate = calculateSuccessorDate(\n normalizedPredStart,\n normalizedPredEnd,\n dep.type,\n getDependencyLag(dep),\n false,\n undefined,\n task.type\n );\n\n let newSuccStart: Date;\n let newSuccEnd: Date;\n\n if (dep.type === 'FS' || dep.type === 'SS') {\n ({ start: newSuccStart, end: newSuccEnd } = buildTaskRangeFromStart(constraintDate, duration));\n } else {\n ({ start: newSuccStart, end: newSuccEnd } = buildTaskRangeFromEnd(constraintDate, duration));\n }\n\n visited.add(task.id);\n updatedDates.set(task.id, { start: newSuccStart, end: newSuccEnd });\n result.push(normalizeTaskDependencyLags({\n ...task,\n startDate: newSuccStart.toISOString().split('T')[0],\n endDate: newSuccEnd.toISOString().split('T')[0],\n }));\n queue.push(task.id);\n }\n }\n\n return result;\n}\n\n/**\n * Get transitive closure of successors for cascading.\n */\nexport function getTransitiveCascadeChain(\n changedTaskId: string,\n allTasks: Task[],\n firstLevelLinkTypes: LinkType[]\n): Task[] {\n const { childrenByParentId, dependentsByPredecessorId } = createCascadeContext(allTasks);\n\n const directChildren = childrenByParentId.get(changedTaskId) ?? [];\n const directSuccessors = getSuccessorChain(changedTaskId, allTasks, firstLevelLinkTypes);\n const initialChain = [...directChildren, ...directSuccessors].filter((task, index, arr) =>\n arr.findIndex(candidate => candidate.id === task.id) === index\n );\n\n const chain = [...initialChain];\n const visited = new Set<string>([changedTaskId, ...initialChain.map(t => t.id)]);\n const queue = [...initialChain];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n\n const children = childrenByParentId.get(current.id) ?? [];\n for (const child of children) {\n if (!visited.has(child.id)) {\n visited.add(child.id);\n chain.push(child);\n queue.push(child);\n }\n }\n\n const successors = dependentsByPredecessorId.get(current.id) ?? [];\n for (const { task: successor } of successors) {\n if (!visited.has(successor.id)) {\n visited.add(successor.id);\n chain.push(successor);\n queue.push(successor);\n }\n }\n }\n\n return chain;\n}\n\n/**\n * Arrival mode for universal cascade BFS entries.\n */\ntype ArrivalMode = 'direct' | 'child-delta' | 'parent-recalc' | 'dependency';\n\n/**\n * Universal cascade engine that propagates a moved task's new position through\n * the entire dependency+hierarchy graph using BFS with change detection.\n */\nexport function universalCascade(\n movedTask: Task,\n newStart: Date,\n newEnd: Date,\n allTasks: Task[],\n businessDays: boolean = false,\n weekendPredicate?: (date: Date) => boolean,\n context: CascadeContext = createCascadeContext(allTasks)\n): Task[] {\n const { childrenByParentId, dependentsByPredecessorId, taskById } = context;\n const normalizedMovedTask = normalizeTaskDependencyLags({\n ...movedTask,\n startDate: newStart.toISOString().split('T')[0],\n endDate: newEnd.toISOString().split('T')[0],\n });\n\n if (\n !movedTask.parentId &&\n !childrenByParentId.has(movedTask.id) &&\n !dependentsByPredecessorId.has(movedTask.id)\n ) {\n return [normalizedMovedTask];\n }\n\n const updatedDates = new Map<string, { start: Date; end: Date }>();\n updatedDates.set(movedTask.id, { start: newStart, end: newEnd });\n\n const resultMap = new Map<string, Task>();\n resultMap.set(movedTask.id, normalizedMovedTask);\n\n const queue: Array<[string, ArrivalMode]> = [[movedTask.id, 'direct']];\n\n const childShifted = new Set<string>();\n\n let iterations = 0;\n const MAX_ITERATIONS = allTasks.length * 3;\n\n while (queue.length > 0 && iterations < MAX_ITERATIONS) {\n iterations++;\n const [currentId, arrivalMode] = queue.shift()!;\n const { start: currStart, end: currEnd } = updatedDates.get(currentId)!;\n const currentOriginal = taskById.get(currentId)!;\n\n // RULE 1: Hierarchy children follow their parent\n if (arrivalMode !== 'parent-recalc') {\n const children = childrenByParentId.get(currentId) ?? [];\n for (const child of children) {\n if (childShifted.has(child.id) || child.locked) continue;\n\n const parentOrigStart = new Date(currentOriginal.startDate as string);\n const parentOrigEnd = new Date(currentOriginal.endDate as string);\n\n const childOrigStart = new Date(child.startDate as string);\n const childOrigEnd = new Date(child.endDate as string);\n\n const startDeltaMs = currStart.getTime() - parentOrigStart.getTime();\n const endDeltaMs = currEnd.getTime() - parentOrigEnd.getTime();\n\n let childNewStart: Date;\n let childNewEnd: Date;\n\n if (businessDays && weekendPredicate) {\n const proposedStart = new Date(childOrigStart.getTime() + startDeltaMs);\n const snapDirection: 1 | -1 = currStart.getTime() >= parentOrigStart.getTime() ? 1 : -1;\n const movedRange = moveTaskRange(\n child.startDate,\n child.endDate,\n proposedStart,\n true,\n weekendPredicate,\n snapDirection\n );\n childNewStart = movedRange.start;\n childNewEnd = movedRange.end;\n } else {\n childNewStart = new Date(childOrigStart.getTime() + startDeltaMs);\n childNewEnd = new Date(childOrigEnd.getTime() + endDeltaMs);\n }\n\n const prev = updatedDates.get(child.id);\n if (prev && prev.start.getTime() === childNewStart.getTime() && prev.end.getTime() === childNewEnd.getTime()) {\n continue;\n }\n\n updatedDates.set(child.id, { start: childNewStart, end: childNewEnd });\n childShifted.add(child.id);\n queue.push([child.id, 'child-delta']);\n resultMap.set(child.id, normalizeTaskDependencyLags({\n ...child,\n startDate: childNewStart.toISOString().split('T')[0],\n endDate: childNewEnd.toISOString().split('T')[0],\n }));\n }\n }\n\n // RULE 2: Parent task is recomputed from its children\n const parentId = (currentOriginal as any).parentId as string | undefined;\n if (parentId) {\n const parent = taskById.get(parentId);\n if (parent && !parent.locked) {\n const siblings = childrenByParentId.get(parentId) ?? [];\n\n const siblingPositions = siblings.map(sib => {\n if (updatedDates.has(sib.id)) return updatedDates.get(sib.id)!;\n return { start: new Date(sib.startDate as string), end: new Date(sib.endDate as string) };\n });\n\n const minStart = new Date(Math.min(...siblingPositions.map(p => p.start.getTime())));\n const maxEnd = new Date(Math.max(...siblingPositions.map(p => p.end.getTime())));\n\n const prev = updatedDates.get(parentId);\n if (!prev || prev.start.getTime() !== minStart.getTime() || prev.end.getTime() !== maxEnd.getTime()) {\n updatedDates.set(parentId, { start: minStart, end: maxEnd });\n queue.push([parentId, 'parent-recalc']);\n resultMap.set(parentId, normalizeTaskDependencyLags({\n ...parent,\n startDate: minStart.toISOString().split('T')[0],\n endDate: maxEnd.toISOString().split('T')[0],\n }));\n }\n }\n }\n\n // RULE 3: Dependency successors are repositioned\n const dependents = dependentsByPredecessorId.get(currentId) ?? [];\n for (const { task, dependencyIndex } of dependents) {\n if (task.locked || !task.dependencies) continue;\n const dep = task.dependencies[dependencyIndex];\n if (!dep) continue;\n\n const origStart = new Date(task.startDate as string);\n const origEnd = new Date(task.endDate as string);\n const { predStart: normalizedPredStart, predEnd: normalizedPredEnd } = normalizePredecessorDates(\n {\n startDate: currStart,\n endDate: currEnd,\n type: currentOriginal.type,\n },\n parseCascadeDateInput\n );\n const constraintDate = calculateSuccessorDate(\n normalizedPredStart, normalizedPredEnd, dep.type, getDependencyLag(dep),\n businessDays, weekendPredicate, task.type\n );\n\n let succNewStart: Date;\n let succNewEnd: Date;\n const duration = getTaskDuration(origStart, origEnd, businessDays, weekendPredicate);\n\n if (dep.type === 'FS' || dep.type === 'SS') {\n ({ start: succNewStart, end: succNewEnd } = buildTaskRangeFromStart(\n constraintDate,\n duration,\n businessDays,\n weekendPredicate\n ));\n } else {\n ({ start: succNewStart, end: succNewEnd } = buildTaskRangeFromEnd(\n constraintDate,\n duration,\n businessDays,\n weekendPredicate\n ));\n }\n\n const prev = updatedDates.get(task.id);\n if (prev && prev.start.getTime() === succNewStart.getTime() && prev.end.getTime() === succNewEnd.getTime()) {\n continue;\n }\n\n updatedDates.set(task.id, { start: succNewStart, end: succNewEnd });\n queue.push([task.id, 'dependency']);\n resultMap.set(task.id, normalizeTaskDependencyLags({\n ...task,\n startDate: succNewStart.toISOString().split('T')[0],\n endDate: succNewEnd.toISOString().split('T')[0],\n }));\n }\n }\n\n return Array.from(resultMap.values());\n}\n\n","/**\n * Hierarchy scheduling functions.\n * Moved from dependencyUtils.ts — verbatim implementations.\n * Zero React/DOM/date-fns imports.\n */\n\n// START_MODULE_CONTRACT\n// PURPOSE: Query task hierarchy and build parent/descendant progress updates.\n// SCOPE: Child/descendant lookup, parent date/progress rollups, and boundary progress batch updates.\n// DEPENDS: scheduling types\n// LINKS: M-SCHEDULE, fn-getAllDescendants, fn-cascadeTaskProgress\n// ROLE: RUNTIME\n// MAP_MODE: EXPORTS\n// END_MODULE_CONTRACT\n\nimport type { Task } from './types';\n\n/**\n * Get all child tasks of a parent task.\n * Returns tasks where task.parentId === parentId.\n */\nexport function getChildren(parentId: string, tasks: Task[]): Task[] {\n return tasks.filter(t => (t as any).parentId === parentId);\n}\n\n/**\n * Check if a task is a parent (has children).\n * Returns true if any task has this task as parentId.\n */\nexport function isTaskParent(taskId: string, tasks: Task[]): boolean {\n return tasks.some(t => (t as any).parentId === taskId);\n}\n\n/**\n * Compute parent task dates from children.\n * Returns { startDate, endDate } where:\n * - startDate = min(children.startDate) or own startDate if no children\n * - endDate = max(children.endDate) or own endDate if no children\n */\nexport function computeParentDates(parentId: string, tasks: Task[]): { startDate: Date; endDate: Date } {\n const children = getChildren(parentId, tasks);\n\n if (children.length === 0) {\n const parent = tasks.find(t => t.id === parentId);\n const start = parent ? new Date(parent.startDate) : new Date();\n const end = parent ? new Date(parent.endDate) : new Date();\n return { startDate: start, endDate: end };\n }\n\n const startDates = children.map(c => new Date(c.startDate));\n const endDates = children.map(c => new Date(c.endDate));\n\n const minTime = Math.min(...startDates.map(d => d.getTime()));\n const maxTime = Math.max(...endDates.map(d => d.getTime()));\n\n return {\n startDate: new Date(minTime),\n endDate: new Date(maxTime),\n };\n}\n\n/**\n * Compute parent task progress from children (weighted average by duration).\n * Returns 0 if no children.\n * Progress is rounded to 1 decimal place.\n */\nexport function computeParentProgress(parentId: string, tasks: Task[]): number {\n const children = getChildren(parentId, tasks);\n\n if (children.length === 0) {\n return 0;\n }\n\n const DAY_MS = 24 * 60 * 60 * 1000;\n let totalWeight = 0;\n let weightedSum = 0;\n\n for (const child of children) {\n const start = new Date(child.startDate).getTime();\n const end = new Date(child.endDate).getTime();\n // Inclusive duration: (end - start + 1 day) / DAY_MS\n const duration = (end - start + DAY_MS) / DAY_MS;\n const progress = (child.progress ?? 0);\n\n totalWeight += duration;\n weightedSum += duration * progress;\n }\n\n if (totalWeight === 0) {\n return 0;\n }\n\n // Round to 1 decimal place\n return Math.round((weightedSum / totalWeight) * 10) / 10;\n}\n\n/**\n * Get all descendant tasks of a parent task (transitive closure of children).\n * Returns all tasks where task.parentId is in the hierarchy of the parent.\n */\nexport function getAllDescendants(parentId: string, tasks: Task[]): Task[] {\n const descendants: Task[] = [];\n const visited = new Set<string>();\n\n function collectChildren(taskId: string) {\n if (visited.has(taskId)) return;\n visited.add(taskId);\n\n const children = getChildren(taskId, tasks);\n for (const child of children) {\n descendants.push(child);\n collectChildren(child.id);\n }\n }\n\n collectChildren(parentId);\n return descendants;\n}\n\n/**\n * Propagate an explicit boundary progress value through a task subtree.\n *\n * Fractional parent progress is intentionally left untouched: without\n * knowing which child work was completed, there is no reliable distribution.\n * Returns the changed parent and descendants as one sparse update batch.\n */\nexport function cascadeTaskProgress(task: Task, tasks: Task[]): Task[] {\n const progress = task.progress;\n if (progress !== 0 && progress !== 100) {\n return [task];\n }\n\n const descendants = getAllDescendants(task.id, tasks);\n if (descendants.length === 0) {\n return [task];\n }\n\n return [\n { ...task, progress },\n ...descendants.map((descendant) => ({ ...descendant, progress })),\n ];\n}\n\n/**\n * Get all dependency edges for rendering.\n * Returns array of { predecessorId, successorId, type, lag }\n */\nexport function getAllDependencyEdges(tasks: Task[]): Array<{\n predecessorId: string;\n successorId: string;\n type: 'FS' | 'SS' | 'FF' | 'SF';\n lag: number;\n}> {\n const edges: Array<{ predecessorId: string; successorId: string; type: 'FS' | 'SS' | 'FF' | 'SF'; lag: number }> = [];\n\n for (const task of tasks) {\n if (task.dependencies) {\n for (const dep of task.dependencies) {\n edges.push({\n predecessorId: dep.taskId,\n successorId: task.id,\n type: dep.type,\n lag: dep.lag ?? 0,\n });\n }\n }\n }\n\n return edges;\n}\n\n/**\n * Remove dependencies between two tasks in both directions.\n */\nexport function removeDependenciesBetweenTasks(\n taskId1: string,\n taskId2: string,\n tasks: Task[]\n): Task[] {\n return tasks.map(task => {\n if (task.id === taskId1 || task.id === taskId2) {\n if (!task.dependencies) return task;\n const otherTaskId = task.id === taskId1 ? taskId2 : taskId1;\n const filteredDependencies = task.dependencies.filter(dep => dep.taskId !== otherTaskId);\n if (filteredDependencies.length === task.dependencies.length) {\n return task;\n }\n return {\n ...task,\n dependencies: filteredDependencies.length > 0 ? filteredDependencies : undefined,\n };\n }\n return task;\n });\n}\n\n/**\n * Find the parent ID of a task.\n */\nexport function findParentId(taskId: string, tasks: Task[]): string | undefined {\n const task = tasks.find(t => t.id === taskId);\n return task?.parentId;\n}\n\n/**\n * Returns true when ancestorId is an ancestor of taskId in the current hierarchy.\n */\nexport function isAncestorTask(ancestorId: string, taskId: string, tasks: Task[]): boolean {\n const taskById = new Map(tasks.map(task => [task.id, task]));\n const visited = new Set<string>();\n let current = taskById.get(taskId);\n\n while (current?.parentId) {\n if (current.parentId === ancestorId) {\n return true;\n }\n\n if (visited.has(current.parentId)) {\n return false;\n }\n\n visited.add(current.parentId);\n current = taskById.get(current.parentId);\n }\n\n return false;\n}\n\n/**\n * Returns true when tasks are in the same ancestry chain.\n */\nexport function areTasksHierarchicallyRelated(taskId1: string, taskId2: string, tasks: Task[]): boolean {\n if (taskId1 === taskId2) {\n return true;\n }\n\n return isAncestorTask(taskId1, taskId2, tasks) || isAncestorTask(taskId2, taskId1, tasks);\n}\n","/**\n * Command-level scheduling API.\n * High-level functions that compose low-level scheduling primitives.\n * Zero React/DOM/date-fns imports.\n */\n\n// START_MODULE_CONTRACT\n// PURPOSE: Execute authoritative task and project schedule recalculations.\n// SCOPE: Move, resize, dependency recalculation, cascade, and full-project scheduling.\n// DEPENDS: commands, cascade, dateMath, dependencies, hierarchy, scheduling types\n// LINKS: M-SCHEDULING, fn-recalculateTaskFromDependencies, fn-recalculateProjectSchedule\n// ROLE: RUNTIME\n// MAP_MODE: EXPORTS\n// END_MODULE_CONTRACT\n\nimport type { Task, ScheduleCommandResult, ScheduleCommandOptions } from './types';\nimport { moveTaskRange, recalculateIncomingLags, buildTaskRangeFromEnd, buildTaskRangeFromStart, getTaskDuration } from './commands';\nimport { universalCascade } from './cascade';\nimport { parseDateOnly } from './dateMath';\nimport { calculateSuccessorDate, getDependencyLag, normalizePredecessorDates } from './dependencies';\nimport { computeParentDates, isTaskParent } from './hierarchy';\n\nfunction toIsoDate(date: Date): string {\n return date.toISOString().split('T')[0];\n}\n\nfunction createChangedResult(snapshot: Task[], nextTasks: Task[]): ScheduleCommandResult {\n const originalById = new Map(snapshot.map(task => [task.id, task]));\n const changedTasks = nextTasks.filter(task => JSON.stringify(originalById.get(task.id)) !== JSON.stringify(task));\n\n return {\n changedTasks,\n changedIds: changedTasks.map(task => task.id),\n };\n}\n\n/**\n * Move a task to a new start date with cascade and lag recalculation.\n * Identical to manual composition: moveTaskRange -> recalculateIncomingLags -> universalCascade.\n */\nexport function moveTaskWithCascade(\n taskId: string,\n newStart: Date,\n snapshot: Task[],\n options?: ScheduleCommandOptions\n): ScheduleCommandResult {\n const task = snapshot.find(t => t.id === taskId);\n if (!task) {\n return { changedTasks: [], changedIds: [] };\n }\n\n const businessDays = options?.businessDays ?? false;\n const weekendPredicate = options?.weekendPredicate;\n\n // Step 1: Calculate new range preserving duration\n const newRange = moveTaskRange(\n task.startDate,\n task.endDate,\n newStart,\n businessDays,\n weekendPredicate\n );\n\n // Step 2: Recalculate incoming dependency lags\n const updatedDependencies = recalculateIncomingLags(\n task,\n newRange.start,\n newRange.end,\n snapshot,\n businessDays,\n weekendPredicate\n );\n\n // Step 3: Create moved task with updated deps\n const movedTask: Task = {\n ...task,\n startDate: newRange.start.toISOString().split('T')[0],\n endDate: newRange.end.toISOString().split('T')[0],\n dependencies: updatedDependencies,\n };\n\n // Step 4: Cascade through dependency graph\n if (options?.skipCascade) {\n return {\n changedTasks: [movedTask],\n changedIds: [movedTask.id],\n };\n }\n\n const cascadeResult = universalCascade(\n movedTask,\n newRange.start,\n newRange.end,\n snapshot,\n businessDays,\n weekendPredicate\n );\n\n // Merge: movedTask + cascade results\n const resultMap = new Map<string, Task>();\n resultMap.set(movedTask.id, movedTask);\n for (const t of cascadeResult) {\n resultMap.set(t.id, t);\n }\n\n const changedTasks = Array.from(resultMap.values());\n return {\n changedTasks,\n changedIds: changedTasks.map(t => t.id),\n };\n}\n\n/**\n * Resize a task by changing its start or end date.\n * anchor='end': new end date, start stays fixed.\n * anchor='start': new start date, end stays fixed.\n */\nexport function resizeTaskWithCascade(\n taskId: string,\n anchor: 'start' | 'end',\n newDate: Date,\n snapshot: Task[],\n options?: ScheduleCommandOptions\n): ScheduleCommandResult {\n const task = snapshot.find(t => t.id === taskId);\n if (!task) {\n return { changedTasks: [], changedIds: [] };\n }\n\n const businessDays = options?.businessDays ?? false;\n const weekendPredicate = options?.weekendPredicate;\n\n const originalStart = parseDateOnly(task.startDate);\n const originalEnd = parseDateOnly(task.endDate);\n let newRange: { start: Date; end: Date };\n\n if (anchor === 'end') {\n // anchor='end': new end date, start stays fixed\n newRange = { start: originalStart, end: newDate };\n } else {\n // anchor='start': new start date, end stays fixed\n newRange = { start: newDate, end: originalEnd };\n }\n\n // Recalculate lags\n const updatedDependencies = recalculateIncomingLags(\n task,\n newRange.start,\n newRange.end,\n snapshot,\n businessDays,\n weekendPredicate\n );\n\n // Create resized task\n const resizedTask: Task = {\n ...task,\n startDate: newRange.start.toISOString().split('T')[0],\n endDate: newRange.end.toISOString().split('T')[0],\n dependencies: updatedDependencies,\n };\n\n if (options?.skipCascade) {\n return {\n changedTasks: [resizedTask],\n changedIds: [resizedTask.id],\n };\n }\n\n // Cascade through dependency graph\n const cascadeResult = universalCascade(\n resizedTask,\n newRange.start,\n newRange.end,\n snapshot,\n businessDays,\n weekendPredicate\n );\n\n const resultMap = new Map<string, Task>();\n resultMap.set(resizedTask.id, resizedTask);\n for (const t of cascadeResult) {\n resultMap.set(t.id, t);\n }\n\n const changedTasks = Array.from(resultMap.values());\n return {\n changedTasks,\n changedIds: changedTasks.map(t => t.id),\n };\n}\n\n/**\n * Recalculate a task's dates based on its dependency constraints.\n * Finds all predecessors and computes the most constrained date.\n */\nexport function recalculateTaskFromDependencies(\n taskId: string,\n snapshot: Task[],\n options?: ScheduleCommandOptions\n): ScheduleCommandResult {\n const task = snapshot.find(t => t.id === taskId);\n if (!task) {\n return { changedTasks: [], changedIds: [] };\n }\n\n const businessDays = options?.businessDays ?? false;\n const weekendPredicate = options?.weekendPredicate;\n\n if (!task.dependencies || task.dependencies.length === 0) {\n // No dependencies — return the task as-is\n return {\n changedTasks: [task],\n changedIds: [task.id],\n };\n }\n\n // Find the most constrained start/end based on all predecessors\n let constrainedStart: Date | null = null;\n let constrainedEnd: Date | null = null;\n\n for (const dep of task.dependencies) {\n const predecessor = snapshot.find(t => t.id === dep.taskId);\n if (!predecessor) continue;\n\n const { predStart, predEnd } = normalizePredecessorDates(predecessor, parseDateOnly);\n const constraintDate = calculateSuccessorDate(\n predStart,\n predEnd,\n dep.type,\n getDependencyLag(dep),\n businessDays,\n weekendPredicate,\n task.type\n );\n\n const duration = getTaskDuration(\n parseDateOnly(task.startDate),\n parseDateOnly(task.endDate),\n businessDays,\n weekendPredicate\n );\n\n let range: { start: Date; end: Date };\n if (dep.type === 'FS' || dep.type === 'SS') {\n range = buildTaskRangeFromStart(constraintDate, duration, businessDays, weekendPredicate);\n } else {\n range = buildTaskRangeFromEnd(constraintDate, duration, businessDays, weekendPredicate);\n }\n\n // Take the latest start as the effective constraint\n if (!constrainedStart || range.start.getTime() > constrainedStart.getTime()) {\n constrainedStart = range.start;\n constrainedEnd = range.end;\n }\n }\n\n if (!constrainedStart || !constrainedEnd) {\n return {\n changedTasks: [task],\n changedIds: [task.id],\n };\n }\n\n // Recalculate lags for the new position\n const updatedDependencies = recalculateIncomingLags(\n task,\n constrainedStart,\n constrainedEnd,\n snapshot,\n businessDays,\n weekendPredicate\n );\n\n const recalculatedTask: Task = {\n ...task,\n startDate: constrainedStart.toISOString().split('T')[0],\n endDate: constrainedEnd.toISOString().split('T')[0],\n dependencies: updatedDependencies,\n };\n\n if (options?.skipCascade) {\n return {\n changedTasks: [recalculatedTask],\n changedIds: [recalculatedTask.id],\n };\n }\n\n // Cascade through dependency graph\n const cascadeResult = universalCascade(\n recalculatedTask,\n constrainedStart,\n constrainedEnd,\n snapshot,\n businessDays,\n weekendPredicate\n );\n\n const resultMap = new Map<string, Task>();\n resultMap.set(recalculatedTask.id, recalculatedTask);\n for (const t of cascadeResult) {\n resultMap.set(t.id, t);\n }\n\n const changedTasks = Array.from(resultMap.values());\n return {\n changedTasks,\n changedIds: changedTasks.map(t => t.id),\n };\n}\n\n/**\n * Full project schedule recalculation.\n * Recomputes the project against a continuously updated working snapshot.\n * Returns only tasks whose normalized state changed.\n */\nexport function recalculateProjectSchedule(\n snapshot: Task[],\n options?: ScheduleCommandOptions\n): ScheduleCommandResult {\n const businessDays = options?.businessDays ?? false;\n const weekendPredicate = options?.weekendPredicate;\n const workingMap = new Map(snapshot.map(task => [task.id, { ...task }]));\n const indegree = new Map<string, number>();\n const successorIdsByTask = new Map<string, string[]>();\n\n for (const task of snapshot) {\n indegree.set(task.id, 0);\n successorIdsByTask.set(task.id, []);\n }\n\n for (const task of snapshot) {\n for (const dep of task.dependencies ?? []) {\n if (!workingMap.has(dep.taskId)) {\n continue;\n }\n\n indegree.set(task.id, (indegree.get(task.id) ?? 0) + 1);\n successorIdsByTask.get(dep.taskId)?.push(task.id);\n }\n }\n\n const queue = snapshot\n .filter(task => (indegree.get(task.id) ?? 0) === 0)\n .map(task => task.id);\n\n while (queue.length > 0) {\n const currentId = queue.shift()!;\n\n for (const successorId of successorIdsByTask.get(currentId) ?? []) {\n const nextIndegree = (indegree.get(successorId) ?? 0) - 1;\n indegree.set(successorId, nextIndegree);\n\n if (nextIndegree !== 0) {\n continue;\n }\n\n const currentTask = workingMap.get(successorId);\n if (!currentTask || currentTask.locked || !currentTask.dependencies?.length) {\n queue.push(successorId);\n continue;\n }\n\n const duration = getTaskDuration(\n parseDateOnly(currentTask.startDate),\n parseDateOnly(currentTask.endDate),\n businessDays,\n weekendPredicate\n );\n\n let constrainedRange: { start: Date; end: Date } | null = null;\n\n for (const dep of currentTask.dependencies) {\n const predecessor = workingMap.get(dep.taskId);\n if (!predecessor) {\n continue;\n }\n\n const { predStart: predecessorStart, predEnd: predecessorEnd } = normalizePredecessorDates(predecessor, parseDateOnly);\n const constraintDate = calculateSuccessorDate(\n predecessorStart,\n predecessorEnd,\n dep.type,\n getDependencyLag(dep),\n businessDays,\n weekendPredicate,\n currentTask.type\n );\n\n const candidateRange = dep.type === 'FS' || dep.type === 'SS'\n ? buildTaskRangeFromStart(constraintDate, duration, businessDays, weekendPredicate)\n : buildTaskRangeFromEnd(constraintDate, duration, businessDays, weekendPredicate);\n\n if (\n !constrainedRange ||\n candidateRange.start.getTime() > constrainedRange.start.getTime() ||\n (\n candidateRange.start.getTime() === constrainedRange.start.getTime() &&\n candidateRange.end.getTime() > constrainedRange.end.getTime()\n )\n ) {\n constrainedRange = candidateRange;\n }\n }\n\n if (!constrainedRange) {\n queue.push(successorId);\n continue;\n }\n\n workingMap.set(successorId, {\n ...currentTask,\n startDate: toIsoDate(constrainedRange.start),\n endDate: toIsoDate(constrainedRange.end),\n });\n queue.push(successorId);\n }\n }\n\n const parentsByDepth = snapshot\n .filter(task => isTaskParent(task.id, snapshot))\n .map(task => {\n let depth = 0;\n let current = task.parentId ? workingMap.get(task.parentId) : undefined;\n while (current) {\n depth++;\n current = current.parentId ? workingMap.get(current.parentId) : undefined;\n }\n return { taskId: task.id, depth };\n })\n .sort((left, right) => right.depth - left.depth);\n\n const workingTasks = () => Array.from(workingMap.values());\n\n for (const { taskId } of parentsByDepth) {\n const parent = workingMap.get(taskId);\n if (!parent || parent.locked) {\n continue;\n }\n\n const { startDate, endDate } = computeParentDates(taskId, workingTasks());\n workingMap.set(taskId, {\n ...parent,\n startDate: toIsoDate(startDate),\n endDate: toIsoDate(endDate),\n });\n }\n\n return createChangedResult(snapshot, Array.from(workingMap.values()));\n}\n","import type { Task } from './types';\nimport { normalizeUTCDate, getTaskDuration, alignToWorkingDay } from './dateMath';\nimport { buildTaskRangeFromStart } from './commands';\nimport { computeParentDates, isTaskParent } from './hierarchy';\nimport { recalculateProjectSchedule } from './execute';\n\n/**\n * Recalculate all task dates when switching between business/calendar day modes.\n *\n * Mode switch semantics are not a simple per-task move:\n * 1. Leaf tasks first preserve their current duration count while snapping to\n * the target calendar rules.\n * 2. Parent tasks roll up from children.\n * 3. The full dependency graph is then recalculated in the target mode so\n * successors obey the new FS/SS/FF/SF semantics (for example Fri -> Mon in\n * business mode, Fri -> Sat in calendar mode).\n */\nexport function reflowTasksOnModeSwitch(\n sourceTasks: Task[],\n toBusinessDays: boolean,\n weekendPredicate: (date: Date) => boolean\n): Task[] {\n const fromBusinessDays = !toBusinessDays;\n let tasks: Task[] = sourceTasks.map(task => ({\n ...task,\n dependencies: task.dependencies?.map(dependency => ({ ...dependency })),\n }));\n\n const toISO = (date: Date) => date.toISOString().split('T')[0];\n\n for (const task of tasks) {\n if (isTaskParent(task.id, tasks)) continue;\n\n const start = normalizeUTCDate(new Date(`${task.startDate}T00:00:00.000Z`));\n const duration = getTaskDuration(task.startDate, task.endDate, fromBusinessDays, weekendPredicate);\n\n const range = toBusinessDays\n ? buildTaskRangeFromStart(\n alignToWorkingDay(start, 1, weekendPredicate),\n duration,\n true,\n weekendPredicate\n )\n : buildTaskRangeFromStart(start, duration, false);\n\n task.startDate = toISO(range.start);\n task.endDate = toISO(range.end);\n }\n\n for (const task of tasks) {\n if (!isTaskParent(task.id, tasks)) continue;\n const { startDate, endDate } = computeParentDates(task.id, tasks);\n task.startDate = toISO(startDate);\n task.endDate = toISO(endDate);\n }\n\n const rescheduled = recalculateProjectSchedule(tasks, {\n businessDays: toBusinessDays,\n weekendPredicate,\n });\n\n if (rescheduled.changedTasks.length === 0) {\n return tasks;\n }\n\n const updates = new Map(rescheduled.changedTasks.map((task): [string, Task] => [task.id, task]));\n return tasks.map(task => updates.get(task.id) ?? task);\n}\n","/**\n * Dependency validation and cycle detection.\n * Moved from dependencyUtils.ts — verbatim implementations.\n * Zero React/DOM/date-fns imports.\n */\n\nimport type { Task, DependencyError, ValidationResult } from './types';\nimport { areTasksHierarchicallyRelated } from './hierarchy';\n\n/**\n * Build adjacency list for dependency graph (task -> successors)\n */\nexport function buildAdjacencyList(tasks: Task[]): Map<string, string[]> {\n const graph = new Map<string, string[]>();\n\n for (const task of tasks) {\n const successors: string[] = [];\n\n // Find all tasks that depend on this task (this task is a predecessor)\n for (const otherTask of tasks) {\n if (otherTask.dependencies) {\n for (const dep of otherTask.dependencies) {\n if (dep.taskId === task.id) {\n successors.push(otherTask.id);\n break;\n }\n }\n }\n }\n\n graph.set(task.id, successors);\n }\n\n return graph;\n}\n\n/**\n * Detect circular dependencies using depth-first search\n */\nexport function detectCycles(tasks: Task[]): { hasCycle: boolean; cyclePath?: string[] } {\n const graph = buildAdjacencyList(tasks);\n const visiting = new Set<string>();\n const visited = new Set<string>();\n const path: string[] = [];\n\n function dfs(taskId: string): boolean {\n if (visiting.has(taskId)) {\n return true;\n }\n if (visited.has(taskId)) {\n return false;\n }\n\n visiting.add(taskId);\n path.push(taskId);\n\n const successors = graph.get(taskId) || [];\n for (const successor of successors) {\n if (dfs(successor)) {\n return true;\n }\n }\n\n visiting.delete(taskId);\n path.pop();\n visited.add(taskId);\n return false;\n }\n\n for (const task of tasks) {\n if (dfs(task.id)) {\n return { hasCycle: true, cyclePath: [...path] };\n }\n }\n\n return { hasCycle: false };\n}\n\n/**\n * Validate all dependencies in the task list\n */\nexport function validateDependencies(tasks: Task[]): ValidationResult {\n const errors: DependencyError[] = [];\n const taskIds = new Set(tasks.map(t => t.id));\n\n // Check for missing predecessor references\n for (const task of tasks) {\n if (task.dependencies) {\n for (const dep of task.dependencies) {\n if (!taskIds.has(dep.taskId)) {\n errors.push({\n type: 'missing-task',\n taskId: task.id,\n message: `Dependency references non-existent task: ${dep.taskId}`,\n relatedTaskIds: [dep.taskId],\n });\n }\n }\n }\n }\n\n // Check for invalid hierarchy links (ancestor <-> descendant)\n for (const task of tasks) {\n if (!task.dependencies) continue;\n\n for (const dep of task.dependencies) {\n if (!taskIds.has(dep.taskId)) {\n continue;\n }\n\n if (areTasksHierarchicallyRelated(task.id, dep.taskId, tasks)) {\n errors.push({\n type: 'constraint',\n taskId: task.id,\n message: `Dependencies between parent and child tasks are not allowed: ${dep.taskId} -> ${task.id}`,\n relatedTaskIds: [dep.taskId, task.id],\n });\n }\n }\n }\n\n // Check for cycles\n const cycleResult = detectCycles(tasks);\n if (cycleResult.hasCycle && cycleResult.cyclePath) {\n errors.push({\n type: 'cycle',\n taskId: cycleResult.cyclePath[0],\n message: 'Circular dependency detected',\n relatedTaskIds: cycleResult.cyclePath,\n });\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n };\n}\n"],"mappings":"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","names":["DAY_MS","DAY_MS"]}
|
|
@@ -841,6 +841,20 @@ function getAllDescendants(parentId, tasks) {
|
|
|
841
841
|
collectChildren(parentId);
|
|
842
842
|
return descendants;
|
|
843
843
|
}
|
|
844
|
+
function cascadeTaskProgress(task, tasks) {
|
|
845
|
+
const progress = task.progress;
|
|
846
|
+
if (progress !== 0 && progress !== 100) {
|
|
847
|
+
return [task];
|
|
848
|
+
}
|
|
849
|
+
const descendants = getAllDescendants(task.id, tasks);
|
|
850
|
+
if (descendants.length === 0) {
|
|
851
|
+
return [task];
|
|
852
|
+
}
|
|
853
|
+
return [
|
|
854
|
+
{ ...task, progress },
|
|
855
|
+
...descendants.map((descendant) => ({ ...descendant, progress }))
|
|
856
|
+
];
|
|
857
|
+
}
|
|
844
858
|
function getAllDependencyEdges(tasks) {
|
|
845
859
|
const edges = [];
|
|
846
860
|
for (const task of tasks) {
|
|
@@ -1353,6 +1367,7 @@ export {
|
|
|
1353
1367
|
buildTaskRangeFromStart,
|
|
1354
1368
|
calculateSuccessorDate,
|
|
1355
1369
|
cascadeByLinks,
|
|
1370
|
+
cascadeTaskProgress,
|
|
1356
1371
|
clampTaskRangeForIncomingFS,
|
|
1357
1372
|
computeCriticalPath,
|
|
1358
1373
|
computeLagFromDates,
|