Packages
A library for validating Markdown task lists with structured format specifications. Features: checkbox subtasks, dependencies, code quality KPIs, task categories, multi-project prefixes, and comprehensive error handling documentation.
Current section
Files
Jump to
Current section
Files
lib/task_validator.ex
defmodule TaskValidator do
@moduledoc """
Validates TaskList.md format compliance according to project guidelines.
The `TaskValidator` ensures that task documents follow a consistent structure,
making it easier to track and manage work across multiple project components,
with a strong focus on error handling practices.
## Validation Checks
* ID format compliance (like SSH0001, SCP0001, ERR001, etc.)
* Unique task IDs across the document
* Required sections and fields present in each task, including Error Handling Guidelines
* Different error handling requirements for main tasks and subtasks:
- Main tasks: Comprehensive error handling documentation with GenServer-specific examples
- Subtasks: Simplified error handling focused on task-specific approaches
* Proper subtask structure with consistent prefixes
* Valid status values from the allowed list
* Proper review rating format for completed tasks
* Error handling patterns and conventions
## Error Handling Requirements
Main tasks must include comprehensive error handling sections:
```markdown
**Error Handling**
**Core Principles**
- Pass raw errors
- Use {:ok, result} | {:error, reason}
- Let it crash
**Error Implementation**
- No wrapping
- Minimal rescue
- function/1 & /! versions
**Error Examples**
- Raw error passthrough
- Simple rescue case
- Supervisor handling
**GenServer Specifics**
- Handle_call/3 error pattern
- Terminate/2 proper usage
- Process linking considerations
```
Subtasks have a simplified error handling format:
```markdown
**Error Handling**
**Task-Specific Approach**
- Error pattern for this task
**Error Reporting**
- Monitoring approach
```
## Usage Example
case TaskValidator.validate_file("path/to/TaskList.md") do
{:ok, message} ->
# Task list validation succeeded
IO.puts("Validation passed: " <> message)
{:error, reason} ->
# Task list validation failed
IO.puts("Validation failed: " <> reason)
end
"""
alias TaskValidator.Core.ValidationError
alias TaskValidator.Core.ValidationResult
alias TaskValidator.Parsers.MarkdownParser
@doc """
Validates a TaskList.md file for format compliance.
This is the main validation entry point that uses the new modular architecture
with dedicated parsers and individual validators.
## Parameters
- `file_path`: Path to the TaskList.md file to validate
## Returns
- `{:ok, message}` if validation passes
- `{:error, error_message}` if validation fails
## Examples
iex> TaskValidator.validate_file("docs/TaskList.md")
{:ok, "TaskList.md validation passed!"}
iex> TaskValidator.validate_file("invalid_tasklist.md")
{:error, "Invalid task ID format for: INVALID. Expected pattern: ..."}
"""
@spec validate_file(String.t()) :: {:ok, String.t()} | {:error, String.t()}
def validate_file(file_path) do
with {:ok, content} <- File.read(file_path),
{:ok, task_list} <- MarkdownParser.parse(content),
:ok <- validate_references_new(task_list) do
result = validate_tasks_with_new_validators(task_list)
case result do
%ValidationResult{valid?: true} ->
{:ok, "TaskList.md validation passed!"}
%ValidationResult{valid?: false, errors: errors} ->
error_messages = Enum.map(errors, &ValidationError.format/1)
{:error, Enum.join(error_messages, "\n")}
end
end
end
@doc """
Validates a file using the new validation pipeline with options.
This function provides more control over the validation process and
returns detailed validation results.
## Parameters
- `file_path`: Path to the TaskList.md file to validate
- `options`: Keyword list of validation options (optional)
## Options
- `:strict` - Enable strict validation mode (default: false)
- `:validators` - List of specific validators to run (default: all)
## Returns
- `{:ok, ValidationResult.t()}` with detailed validation information
- `{:error, String.t()}` if file reading or parsing fails
"""
@spec validate_file_with_pipeline(String.t(), keyword()) ::
{:ok, ValidationResult.t()} | {:error, String.t()}
def validate_file_with_pipeline(file_path, options \\ []) do
with {:ok, content} <- File.read(file_path),
{:ok, task_list} <- MarkdownParser.parse(content),
:ok <- validate_references_new(task_list) do
context = %{
config: TaskValidator.Config.get_all(),
all_tasks: task_list.tasks,
references: task_list.references,
task_list: task_list,
options: options
}
result = TaskValidator.ValidationPipeline.run_many(task_list.tasks, context)
{:ok, result}
end
end
@doc """
Alternative validation function that returns detailed ValidationResult.
This provides more detailed validation information including warnings
and structured error data for programmatic use.
"""
@spec validate_file_detailed(String.t()) ::
{:ok, ValidationResult.t()} | {:error, String.t()}
def validate_file_detailed(file_path) do
with {:ok, content} <- File.read(file_path),
{:ok, task_list} <- MarkdownParser.parse(content),
:ok <- validate_references_new(task_list) do
result = validate_tasks_with_new_validators(task_list)
{:ok, result}
end
end
# New validation functions using the parser modules and validator pipeline
defp validate_tasks_with_new_validators(task_list) do
context = %{
config: TaskValidator.Config.get_all(),
all_tasks: task_list.tasks,
references: task_list.references,
task_list: task_list
}
# Use the new validation pipeline
TaskValidator.ValidationPipeline.run_many(task_list.tasks, context)
end
# Validate that all referenced placeholders have corresponding definitions
defp validate_references_new(task_list) do
result = TaskValidator.Parsers.ReferenceResolver.validate_references(task_list)
if result.valid? do
:ok
else
error_messages = Enum.map(result.errors, &ValidationError.format/1)
{:error, Enum.join(error_messages, "\n")}
end
end
end