{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3D,eAAO,MAAM,eAAe,QAAsC,CAAC;AAEnE,qBAAa,mBAAoB,SAAQ,KAAK;IAC7C,YAAY,OAAO,EAAE,MAAM,EAG1B;CACD;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,cAAc,EAAE,EAAE,UAAU,UAAQ,GAAG,IAAI,CAwC9F;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAGpE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAGtE","sourcesContent":["import type { TodoDefinition, TodoTask } from \"./types.ts\";\n\nexport const TODO_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;\n\nexport class TodoValidationError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"TodoValidationError\";\n\t}\n}\n\nexport function validateDefinitions(items: readonly TodoDefinition[], allowEmpty = false): void {\n\tif (!allowEmpty && items.length === 0) throw new TodoValidationError(\"Todo list must contain at least one task\");\n\tconst byId = new Map<string, TodoDefinition>();\n\tfor (const item of items) {\n\t\tif (!TODO_ID_PATTERN.test(item.id)) {\n\t\t\tthrow new TodoValidationError(\n\t\t\t\t`Invalid todo id \"${item.id}\"; use 1-64 letters, numbers, dots, underscores, or hyphens`,\n\t\t\t);\n\t\t}\n\t\tif (byId.has(item.id)) throw new TodoValidationError(`Duplicate todo id \"${item.id}\"`);\n\t\tif (!item.subject.trim()) throw new TodoValidationError(`Todo \"${item.id}\" must have a subject`);\n\t\tif (item.depends_on.includes(item.id)) throw new TodoValidationError(`Todo \"${item.id}\" cannot depend on itself`);\n\t\tif (new Set(item.depends_on).size !== item.depends_on.length) {\n\t\t\tthrow new TodoValidationError(`Todo \"${item.id}\" contains duplicate dependencies`);\n\t\t}\n\t\tif (item.acceptance_criteria?.some((criterion) => !criterion.trim())) {\n\t\t\tthrow new TodoValidationError(`Todo \"${item.id}\" contains an empty acceptance criterion`);\n\t\t}\n\t\tbyId.set(item.id, item);\n\t}\n\n\tfor (const item of items) {\n\t\tfor (const dependency of item.depends_on) {\n\t\t\tif (!byId.has(dependency)) {\n\t\t\t\tthrow new TodoValidationError(`Todo \"${item.id}\" depends on unknown todo \"${dependency}\"`);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst visiting = new Set<string>();\n\tconst visited = new Set<string>();\n\tconst visit = (id: string): void => {\n\t\tif (visiting.has(id)) throw new TodoValidationError(`Todo dependency graph contains a cycle involving \"${id}\"`);\n\t\tif (visited.has(id)) return;\n\t\tvisiting.add(id);\n\t\tfor (const dependency of byId.get(id)?.depends_on ?? []) visit(dependency);\n\t\tvisiting.delete(id);\n\t\tvisited.add(id);\n\t};\n\tfor (const id of byId.keys()) visit(id);\n}\n\nexport function getReadyTasks(tasks: readonly TodoTask[]): TodoTask[] {\n\tconst completed = new Set(tasks.filter((task) => task.status === \"completed\").map((task) => task.id));\n\treturn tasks.filter((task) => task.status === \"pending\" && task.depends_on.every((id) => completed.has(id)));\n}\n\nexport function getBlockedTasks(tasks: readonly TodoTask[]): TodoTask[] {\n\tconst completed = new Set(tasks.filter((task) => task.status === \"completed\").map((task) => task.id));\n\treturn tasks.filter((task) => task.status === \"pending\" && task.depends_on.some((id) => !completed.has(id)));\n}\n"]}