Implemented comprehensive content command family for MarkdownMatters CLI following TDD8 methodology and MarkdownMatters specification. ## TDD8 Cycle 1 - Content Commands ### Core Implementation - Content parser for extracting main content without matter zones - Content statistics calculator (words, lines, paragraphs, characters) - CLI commands: `content-get` and `content-stats` - Full integration with existing markitect CLI ### MarkdownMatters Compliance - Correctly removes YAML/TOML/JSON frontmatter - Correctly removes tailmatter blocks (`yaml tailmatter`, `json tailmatter`) - Preserves contentmatter (MultiMarkdown key-value pairs within content) - Follows three-zone specification from wiki/MarkdownMatters.md ### Module Structure ``` markitect/content/ ├── __init__.py # Module exports ├── parser.py # ContentParser with matter zone removal ├── stats.py # ContentStats data class └── commands.py # CLI commands implementation ``` ### CLI Commands Added - `markitect content-get --file [path]` - Extract pure content - `markitect content-stats --file [path]` - Calculate content statistics ### Test Coverage - 16 comprehensive tests covering all scenarios - Test fixtures for different document types - CLI integration tests with Click testing - Edge case handling (file not found, empty content, etc.) ### Validation Results - All tests pass (16/16) - Manual CLI testing confirmed - Proper matter zone separation validated - Statistics calculation accuracy verified ## Technical Architecture ### ContentParser Class - `extract_content()` - Remove frontmatter and tailmatter - `calculate_stats()` - Generate comprehensive statistics - `_remove_frontmatter()` - YAML frontmatter removal - `_remove_tailmatter()` - Tailmatter block removal ### ContentStats Data Class - word_count, line_count, paragraph_count, character_count - JSON serialization support via `to_dict()` ## GAMEPLAN Progress - ✅ TDD8 Cycle 1: Content Commands (COMPLETE) - 🔄 Next: Cycle 2 - Frontmatter Commands - Remaining: Contentmatter, Tailmatter command families This implements the foundation for Issue #38 with 6 remaining cycles planned for complete MarkdownMatters CLI functionality. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
57 lines
1.9 KiB
Python
57 lines
1.9 KiB
Python
"""
|
|
CLI commands for content operations.
|
|
"""
|
|
|
|
import click
|
|
import json
|
|
from pathlib import Path
|
|
from .parser import ContentParser
|
|
|
|
|
|
@click.command('content-get')
|
|
@click.option('--file', 'file_path', required=True, type=click.Path(exists=True),
|
|
help='Path to markdown file')
|
|
def content_get(file_path):
|
|
"""Extract content without frontmatter and tailmatter."""
|
|
try:
|
|
file_path = Path(file_path)
|
|
with open(file_path, 'r', encoding='utf-8') as f:
|
|
text = f.read()
|
|
|
|
parser = ContentParser()
|
|
content = parser.extract_content(text)
|
|
|
|
click.echo(content)
|
|
|
|
except Exception as e:
|
|
click.echo(f"Error: {e}", err=True)
|
|
raise click.ClickException(f"Failed to extract content from {file_path}")
|
|
|
|
|
|
@click.command('content-stats')
|
|
@click.option('--file', 'file_path', required=True, type=click.Path(exists=True),
|
|
help='Path to markdown file')
|
|
@click.option('--format', 'output_format', default='json', type=click.Choice(['json', 'text']),
|
|
help='Output format (json or text)')
|
|
def content_stats(file_path, output_format):
|
|
"""Calculate content statistics."""
|
|
try:
|
|
file_path = Path(file_path)
|
|
with open(file_path, 'r', encoding='utf-8') as f:
|
|
text = f.read()
|
|
|
|
parser = ContentParser()
|
|
content = parser.extract_content(text)
|
|
stats = parser.calculate_stats(content)
|
|
|
|
if output_format == 'json':
|
|
click.echo(json.dumps(stats.to_dict(), indent=2))
|
|
else:
|
|
click.echo(f"Word count: {stats.word_count}")
|
|
click.echo(f"Line count: {stats.line_count}")
|
|
click.echo(f"Paragraph count: {stats.paragraph_count}")
|
|
click.echo(f"Character count: {stats.character_count}")
|
|
|
|
except Exception as e:
|
|
click.echo(f"Error: {e}", err=True)
|
|
raise click.ClickException(f"Failed to calculate stats for {file_path}") |