type-guards.ts•11.7 kB
import {
  CreateTaskArgs,
  GetTasksArgs,
  UpdateTaskArgs,
  TaskNameArgs,
  GetSectionsArgs,
  CreateProjectArgs,
  CreateSectionArgs,
  BulkCreateTasksArgs,
  BulkUpdateTasksArgs,
  BulkTaskFilterArgs,
  CreateCommentArgs,
  GetCommentsArgs,
  CreateLabelArgs,
  UpdateLabelArgs,
  LabelNameArgs,
  CreateSubtaskArgs,
  BulkCreateSubtasksArgs,
  ConvertToSubtaskArgs,
  PromoteSubtaskArgs,
  GetTaskHierarchyArgs,
} from "./types.js";
export function isCreateTaskArgs(args: unknown): args is CreateTaskArgs {
  return (
    typeof args === "object" &&
    args !== null &&
    "content" in args &&
    typeof (args as { content: string }).content === "string"
  );
}
export function isGetTasksArgs(args: unknown): args is GetTasksArgs {
  if (typeof args !== "object" || args === null) return false;
  const obj = args as Record<string, unknown>;
  return (
    (obj.project_id === undefined || typeof obj.project_id === "string") &&
    (obj.filter === undefined || typeof obj.filter === "string") &&
    (obj.label_id === undefined || typeof obj.label_id === "string") &&
    (obj.priority === undefined || typeof obj.priority === "number") &&
    (obj.limit === undefined || typeof obj.limit === "number") &&
    (obj.due_before === undefined || typeof obj.due_before === "string") &&
    (obj.due_after === undefined || typeof obj.due_after === "string") &&
    (obj.lang === undefined || typeof obj.lang === "string") &&
    (obj.task_name === undefined || typeof obj.task_name === "string")
  );
}
export function isUpdateTaskArgs(args: unknown): args is UpdateTaskArgs {
  if (typeof args !== "object" || args === null) {
    return false;
  }
  const obj = args as Record<string, unknown>;
  // Must have either task_id/taskId or task_name/taskName
  // Check both snake_case and camelCase since MCP might transform them
  const hasTaskId =
    ("task_id" in obj && typeof obj.task_id === "string") ||
    ("taskId" in obj && typeof obj.taskId === "string");
  const hasTaskName =
    ("task_name" in obj && typeof obj.task_name === "string") ||
    ("taskName" in obj && typeof obj.taskName === "string");
  if (!hasTaskId && !hasTaskName) {
    return false;
  }
  // Check optional fields
  return (
    (obj.content === undefined || typeof obj.content === "string") &&
    (obj.description === undefined || typeof obj.description === "string") &&
    (obj.due_string === undefined || typeof obj.due_string === "string") &&
    (obj.priority === undefined || typeof obj.priority === "number") &&
    (obj.project_id === undefined || typeof obj.project_id === "string") &&
    (obj.section_id === undefined || typeof obj.section_id === "string") &&
    (obj.labels === undefined ||
      (Array.isArray(obj.labels) &&
        obj.labels.every((label) => typeof label === "string")))
  );
}
export function isTaskNameArgs(args: unknown): args is TaskNameArgs {
  if (typeof args !== "object" || args === null) {
    return false;
  }
  const obj = args as Record<string, unknown>;
  // Must have either task_id/taskId or task_name/taskName
  // Check both snake_case and camelCase since MCP might transform them
  const hasTaskId =
    ("task_id" in obj && typeof obj.task_id === "string") ||
    ("taskId" in obj && typeof obj.taskId === "string");
  const hasTaskName =
    ("task_name" in obj && typeof obj.task_name === "string") ||
    ("taskName" in obj && typeof obj.taskName === "string");
  return hasTaskId || hasTaskName;
}
export function isGetProjectsArgs(
  args: unknown
): args is Record<string, never> {
  return typeof args === "object" && args !== null;
}
export function isGetSectionsArgs(args: unknown): args is GetSectionsArgs {
  return typeof args === "object" && args !== null;
}
export function isCreateProjectArgs(args: unknown): args is CreateProjectArgs {
  return (
    typeof args === "object" &&
    args !== null &&
    "name" in args &&
    typeof (args as { name: string }).name === "string"
  );
}
export function isCreateSectionArgs(args: unknown): args is CreateSectionArgs {
  return (
    typeof args === "object" &&
    args !== null &&
    "name" in args &&
    "project_id" in args &&
    typeof (args as { name: string }).name === "string" &&
    typeof (args as { project_id: string }).project_id === "string"
  );
}
export function isBulkCreateTasksArgs(
  args: unknown
): args is BulkCreateTasksArgs {
  if (typeof args !== "object" || args === null) return false;
  const obj = args as Record<string, unknown>;
  return (
    "tasks" in obj &&
    Array.isArray(obj.tasks) &&
    obj.tasks.length > 0 &&
    obj.tasks.every((task) => isCreateTaskArgs(task))
  );
}
export function isBulkUpdateTasksArgs(
  args: unknown
): args is BulkUpdateTasksArgs {
  if (typeof args !== "object" || args === null) return false;
  const obj = args as Record<string, unknown>;
  return (
    "search_criteria" in obj &&
    "updates" in obj &&
    typeof obj.search_criteria === "object" &&
    obj.search_criteria !== null &&
    typeof obj.updates === "object" &&
    obj.updates !== null
  );
}
export function isBulkTaskFilterArgs(
  args: unknown
): args is BulkTaskFilterArgs {
  if (typeof args !== "object" || args === null) return false;
  const obj = args as Record<string, unknown>;
  // The tool expects parameters at the top level, not in search_criteria
  // We need to wrap them into search_criteria for the handler
  if (
    (obj.project_id === undefined || typeof obj.project_id === "string") &&
    (obj.priority === undefined || typeof obj.priority === "number") &&
    (obj.due_before === undefined || typeof obj.due_before === "string") &&
    (obj.due_after === undefined || typeof obj.due_after === "string") &&
    (obj.content_contains === undefined ||
      typeof obj.content_contains === "string")
  ) {
    // Transform the flat structure to match BulkTaskFilterArgs
    (args as any).search_criteria = {
      project_id: obj.project_id,
      priority: obj.priority,
      due_before: obj.due_before,
      due_after: obj.due_after,
      content_contains: obj.content_contains,
    };
    return true;
  }
  // Also support the old format with search_criteria
  return (
    "search_criteria" in obj &&
    typeof obj.search_criteria === "object" &&
    obj.search_criteria !== null
  );
}
export function isCreateCommentArgs(args: unknown): args is CreateCommentArgs {
  if (typeof args !== "object" || args === null) return false;
  const obj = args as Record<string, unknown>;
  return (
    "content" in obj &&
    typeof obj.content === "string" &&
    (obj.task_id === undefined || typeof obj.task_id === "string") &&
    (obj.task_name === undefined || typeof obj.task_name === "string") &&
    (obj.task_id !== undefined || obj.task_name !== undefined)
  );
}
export function isGetCommentsArgs(args: unknown): args is GetCommentsArgs {
  if (typeof args !== "object" || args === null) return false;
  const obj = args as Record<string, unknown>;
  return (
    (obj.task_id === undefined || typeof obj.task_id === "string") &&
    (obj.task_name === undefined || typeof obj.task_name === "string") &&
    (obj.project_id === undefined || typeof obj.project_id === "string")
  );
}
export function isCreateLabelArgs(args: unknown): args is CreateLabelArgs {
  return (
    typeof args === "object" &&
    args !== null &&
    "name" in args &&
    typeof (args as { name: string }).name === "string"
  );
}
export function isUpdateLabelArgs(args: unknown): args is UpdateLabelArgs {
  if (typeof args !== "object" || args === null) return false;
  const obj = args as Record<string, unknown>;
  return (
    (obj.label_id === undefined || typeof obj.label_id === "string") &&
    (obj.label_name === undefined || typeof obj.label_name === "string") &&
    (obj.label_id !== undefined || obj.label_name !== undefined)
  );
}
export function isLabelNameArgs(args: unknown): args is LabelNameArgs {
  if (typeof args !== "object" || args === null) return false;
  const obj = args as Record<string, unknown>;
  return (
    (obj.label_id === undefined || typeof obj.label_id === "string") &&
    (obj.label_name === undefined || typeof obj.label_name === "string") &&
    (obj.label_id !== undefined || obj.label_name !== undefined)
  );
}
export function isGetLabelsArgs(args: unknown): args is Record<string, never> {
  return typeof args === "object" && args !== null;
}
export function isGetLabelStatsArgs(
  args: unknown
): args is Record<string, never> {
  return typeof args === "object" && args !== null;
}
export function isCreateSubtaskArgs(args: unknown): args is CreateSubtaskArgs {
  if (typeof args !== "object" || args === null) return false;
  const obj = args as Record<string, unknown>;
  return (
    "content" in obj &&
    typeof obj.content === "string" &&
    (obj.parent_task_id === undefined ||
      typeof obj.parent_task_id === "string") &&
    (obj.parent_task_name === undefined ||
      typeof obj.parent_task_name === "string") &&
    (obj.parent_task_id !== undefined || obj.parent_task_name !== undefined)
  );
}
export function isBulkCreateSubtasksArgs(
  args: unknown
): args is BulkCreateSubtasksArgs {
  if (typeof args !== "object" || args === null) return false;
  const obj = args as Record<string, unknown>;
  return (
    "subtasks" in obj &&
    Array.isArray(obj.subtasks) &&
    obj.subtasks.length > 0 &&
    obj.subtasks.every(
      (subtask) =>
        typeof subtask === "object" &&
        subtask !== null &&
        "content" in subtask &&
        typeof (subtask as { content: string }).content === "string"
    ) &&
    (obj.parent_task_id === undefined ||
      typeof obj.parent_task_id === "string") &&
    (obj.parent_task_name === undefined ||
      typeof obj.parent_task_name === "string") &&
    (obj.parent_task_id !== undefined || obj.parent_task_name !== undefined)
  );
}
export function isConvertToSubtaskArgs(
  args: unknown
): args is ConvertToSubtaskArgs {
  if (typeof args !== "object" || args === null) return false;
  const obj = args as Record<string, unknown>;
  return (
    (obj.task_id === undefined || typeof obj.task_id === "string") &&
    (obj.task_name === undefined || typeof obj.task_name === "string") &&
    (obj.task_id !== undefined || obj.task_name !== undefined) &&
    (obj.parent_task_id === undefined ||
      typeof obj.parent_task_id === "string") &&
    (obj.parent_task_name === undefined ||
      typeof obj.parent_task_name === "string") &&
    (obj.parent_task_id !== undefined || obj.parent_task_name !== undefined)
  );
}
export function isPromoteSubtaskArgs(
  args: unknown
): args is PromoteSubtaskArgs {
  if (typeof args !== "object" || args === null) return false;
  const obj = args as Record<string, unknown>;
  return (
    (obj.subtask_id === undefined || typeof obj.subtask_id === "string") &&
    (obj.subtask_name === undefined || typeof obj.subtask_name === "string") &&
    (obj.subtask_id !== undefined || obj.subtask_name !== undefined) &&
    (obj.project_id === undefined || typeof obj.project_id === "string") &&
    (obj.section_id === undefined || typeof obj.section_id === "string")
  );
}
export function isGetTaskHierarchyArgs(
  args: unknown
): args is GetTaskHierarchyArgs {
  if (typeof args !== "object" || args === null) return false;
  const obj = args as Record<string, unknown>;
  return (
    (obj.task_id === undefined || typeof obj.task_id === "string") &&
    (obj.task_name === undefined || typeof obj.task_name === "string") &&
    (obj.task_id !== undefined || obj.task_name !== undefined) &&
    (obj.include_completed === undefined ||
      typeof obj.include_completed === "boolean")
  );
}