feat: implement instant markdown base and publication directory - Issue #135

Complete TDD8 implementation of publication directory support for md-render command:

CORE FEATURES:
• Publication directory management with ~/Notes/ default
• MARKITECT_PUBLICATION_DIR environment variable override
• Single file processing with --use-publication-dir flag
• Directory processing with --dont-use-publication-dir flag
• Recursive directory traversal with structure preservation
• Automatic directory creation and path normalization

IMPLEMENTATION DETAILS:
• Extended md-render command with new CLI flags
• Added 9 new helper functions for directory/file processing
• Support for both single files and directory inputs
• Comprehensive error handling and validation
• Maintains backward compatibility

CLI FLAGS ADDED:
• --use-publication-dir: Force single files to use publication directory
• --dont-use-publication-dir: Force directory processing to place HTML next to MD

BEHAVIOR:
• Single files: HTML next to MD by default, publication dir with flag
• Directories: HTML in publication dir by default, next to MD with flag
• Environment variable MARKITECT_PUBLICATION_DIR overrides default

TESTING:
• 18 comprehensive tests covering all functionality
• Publication directory management (4 tests)
• Single file processing (3 tests)
• Directory processing (4 tests)
• CLI integration (4 tests)
• Edge cases (3 tests)
• 100% test pass rate

TDD8 Workflow: ISSUE→TEST→RED→GREEN→REFACTOR→DOCUMENT→REFINE→PUBLISH

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-07 12:47:59 +02:00
parent 3f5181405b
commit 98fe3361af
2 changed files with 629 additions and 73 deletions

View File

@@ -7,6 +7,7 @@ replacing the legacy unprefixed commands for better namespace consistency.
import click import click
import json import json
import os
import tempfile import tempfile
from pathlib import Path from pathlib import Path
from typing import Dict, Any from typing import Dict, Any
@@ -253,14 +254,16 @@ def md_list_command(ctx, output_format, names_only):
@click.option('--editor-theme', type=click.Choice(['light', 'dark']), default='light', @click.option('--editor-theme', type=click.Choice(['light', 'dark']), default='light',
help='Editor interface theme (light or dark)') help='Editor interface theme (light or dark)')
@click.option('--keyboard-shortcuts', is_flag=True, help='Enable keyboard shortcuts for editing actions') @click.option('--keyboard-shortcuts', is_flag=True, help='Enable keyboard shortcuts for editing actions')
@click.option('--use-publication-dir', is_flag=True, help='Force single files to use publication directory')
@click.option('--dont-use-publication-dir', is_flag=True, help='Force directory processing to place HTML next to MD files')
@click.pass_context @click.pass_context
def md_render_command(ctx, input_file, output, template, css, edit, editor_theme, keyboard_shortcuts): def md_render_command(ctx, input_file, output, template, css, edit, editor_theme, keyboard_shortcuts, use_publication_dir, dont_use_publication_dir):
""" """
Generate HTML with client-side JavaScript markdown rendering. Generate HTML with client-side JavaScript markdown rendering.
Creates a self-contained HTML file that includes the markdown content Creates self-contained HTML files that include markdown content as JavaScript data
as JavaScript data and renders it in the browser using client-side and render in the browser using client-side markdown parsing with marked.js.
markdown parsing with marked.js. Supports both single files and directory processing.
The generated HTML includes: The generated HTML includes:
• Embedded markdown content as JavaScript payload • Embedded markdown content as JavaScript payload
@@ -271,7 +274,17 @@ def md_render_command(ctx, input_file, output, template, css, edit, editor_theme
• Optional instant editing capabilities with --edit flag • Optional instant editing capabilities with --edit flag
• Graceful fallback if JavaScript fails • Graceful fallback if JavaScript fails
INPUT_FILE: Path to the markdown file to render INPUT_FILE: Path to the markdown file or directory to render
Publication Directory:
• Default publication directory: ~/Notes/
• Override with MARKITECT_PUBLICATION_DIR environment variable
• Single files: HTML generated next to MD file by default
• Directories: HTML generated in publication directory with preserved structure
Flags:
• --use-publication-dir: Force single files to use publication directory
• --dont-use-publication-dir: Force directory processing to place HTML next to MD files
Available Templates: Available Templates:
• basic (default) - Clean, minimal design with system fonts • basic (default) - Clean, minimal design with system fonts
@@ -280,92 +293,157 @@ def md_render_command(ctx, input_file, output, template, css, edit, editor_theme
• dark - GitHub dark mode inspired theme with dark background • dark - GitHub dark mode inspired theme with dark background
Examples: Examples:
# Basic usage with default template # Single file - HTML next to MD file
markitect md-render README.md markitect md-render README.md
# Specify output file and template # Single file - HTML in publication directory
markitect md-render README.md --output index.html --template github markitect md-render README.md --use-publication-dir
# Dark theme for night reading # Directory - HTML in publication directory with structure
markitect md-render docs/guide.md --template dark markitect md-render docs/
# Academic paper with custom styling # Directory - HTML next to each MD file
markitect md-render paper.md --template academic --css custom.css markitect md-render docs/ --dont-use-publication-dir
# Enable instant editing capabilities # Custom publication directory
markitect md-render README.md --edit MARKITECT_PUBLICATION_DIR=/tmp/pub markitect md-render docs/
# Editing with dark editor theme and keyboard shortcuts # Directory with custom template
markitect md-render docs/guide.md --edit --editor-theme dark --keyboard-shortcuts markitect md-render docs/ --template github --edit
# Front matter will be parsed and available to JavaScript
# Files with YAML front matter are fully supported
""" """
config = ctx.obj or {} config = ctx.obj or {}
try: try:
if config.get('verbose', False):
click.echo(f"Rendering file: {input_file}")
# Read markdown file
input_path = Path(input_file) input_path = Path(input_file)
markdown_content = input_path.read_text(encoding='utf-8')
# Extract front matter if present # Validate flags
front_matter = {} if use_publication_dir and dont_use_publication_dir:
if markdown_content.startswith('---\n'): click.echo("Error: Cannot use both --use-publication-dir and --dont-use-publication-dir flags together", err=True)
parts = markdown_content.split('---\n', 2) raise click.Abort()
if len(parts) >= 3:
try:
import yaml
front_matter = yaml.safe_load(parts[1]) or {}
markdown_content = parts[2]
except ImportError:
# Fallback without yaml parsing
pass
# Generate title from first heading or filename # Get publication directory
title = front_matter.get('title', input_path.stem) publication_dir = get_publication_directory()
lines = markdown_content.strip().split('\n')
for line in lines:
if line.startswith('# '):
title = line[2:].strip()
break
# Load custom CSS if provided
css_content = ""
if css:
css_path = Path(css)
css_content = css_path.read_text(encoding='utf-8')
# Generate HTML with embedded markdown
html_content = generate_html_with_embedded_markdown(
markdown_content, title, template, css_content, front_matter, edit, editor_theme, keyboard_shortcuts
)
# Determine output path
if not output:
output = input_path.with_suffix('.html')
else:
output = Path(output)
# Ensure output directory exists
output.parent.mkdir(parents=True, exist_ok=True)
# Write HTML file
output.write_text(html_content, encoding='utf-8')
click.echo(f"✓ HTML generated: {output}")
if config.get('verbose', False): if config.get('verbose', False):
click.echo(f" Template: {template}") click.echo(f"Input: {input_path}")
click.echo(f" Title: {title}") click.echo(f"Publication directory: {publication_dir}")
if css:
click.echo(f" Custom CSS: {css}") # Check if input is a directory or file
if input_path.is_dir():
# Directory processing
use_pub_dir = not dont_use_publication_dir # Default to publication dir for directories
if config.get('verbose', False):
click.echo(f"Processing directory: {input_path}")
click.echo(f"Use publication directory: {use_pub_dir}")
# Find all markdown files
md_files = find_markdown_files(input_path)
if not md_files:
click.echo(f"No markdown files found in directory: {input_path}")
return
processed_count = 0
for md_file in md_files:
try:
# Determine output path for this file
if use_pub_dir:
ensure_publication_directory(publication_dir)
output_path = get_relative_output_path(md_file, input_path, publication_dir)
# Ensure subdirectory exists
output_path.parent.mkdir(parents=True, exist_ok=True)
else:
output_path = md_file.with_suffix('.html')
# Process the markdown file
_render_single_markdown_file(
md_file, output_path, template, css, edit, editor_theme,
keyboard_shortcuts, config
)
processed_count += 1
if config.get('verbose', False):
click.echo(f"{md_file}{output_path}")
except Exception as e:
click.echo(f" ✗ Error processing {md_file}: {e}", err=True)
click.echo(f"✓ Processed {processed_count} markdown file(s)")
else:
# Single file processing
use_pub_dir = use_publication_dir # Default to next to file for single files
if config.get('verbose', False):
click.echo(f"Processing single file: {input_path}")
click.echo(f"Use publication directory: {use_pub_dir}")
# Determine output path
if output:
output_path = Path(output)
elif use_pub_dir:
ensure_publication_directory(publication_dir)
output_path = publication_dir / get_output_filename(input_path)
else:
output_path = input_path.with_suffix('.html')
# Process the single file
_render_single_markdown_file(
input_path, output_path, template, css, edit, editor_theme,
keyboard_shortcuts, config
)
click.echo(f"✓ HTML generated: {output_path}")
except Exception as e: except Exception as e:
click.echo(f"Error rendering file: {e}", err=True) click.echo(f"Error: {e}", err=True)
raise click.Abort() raise click.Abort()
def _render_single_markdown_file(input_path, output_path, template, css, edit, editor_theme, keyboard_shortcuts, config):
"""Render a single markdown file to HTML."""
# Read markdown file
markdown_content = input_path.read_text(encoding='utf-8')
# Extract front matter if present
front_matter = {}
if markdown_content.startswith('---\n'):
parts = markdown_content.split('---\n', 2)
if len(parts) >= 3:
try:
import yaml
front_matter = yaml.safe_load(parts[1]) or {}
markdown_content = parts[2]
except ImportError:
# Fallback without yaml parsing
pass
# Generate title from first heading or filename
title = front_matter.get('title', input_path.stem)
lines = markdown_content.strip().split('\n')
for line in lines:
if line.startswith('# '):
title = line[2:].strip()
break
# Load custom CSS if provided
css_content = ""
if css:
css_path = Path(css)
css_content = css_path.read_text(encoding='utf-8')
# Generate HTML with embedded markdown
html_content = generate_html_with_embedded_markdown(
markdown_content, title, template, css_content, front_matter, edit, editor_theme, keyboard_shortcuts
)
# Ensure output directory exists
output_path.parent.mkdir(parents=True, exist_ok=True)
# Write HTML file
output_path.write_text(html_content, encoding='utf-8')
# Template definitions for cleaner code organization # Template definitions for cleaner code organization
TEMPLATE_STYLES = { TEMPLATE_STYLES = {
'basic': { 'basic': {
@@ -839,3 +917,107 @@ def generate_html_with_embedded_markdown(markdown_content, title, template, css_
front_matter_json=json.dumps(front_matter), front_matter_json=json.dumps(front_matter),
**styles **styles
) )
# Publication directory management functions for Issue #135
def get_publication_directory():
"""Get the publication directory from environment variable or default."""
pub_dir = os.environ.get('MARKITECT_PUBLICATION_DIR')
if pub_dir:
return normalize_publication_path(pub_dir)
return Path.home() / "Notes"
def normalize_publication_path(path_str):
"""Normalize publication directory path with tilde expansion and absolute resolution."""
path = Path(path_str)
if str(path).startswith('~'):
path = path.expanduser()
return path.resolve()
def ensure_publication_directory(pub_dir):
"""Ensure publication directory exists, creating it if necessary."""
pub_dir = Path(pub_dir)
pub_dir.mkdir(parents=True, exist_ok=True)
return pub_dir
def get_output_filename(input_file):
"""Get HTML output filename from markdown input filename."""
return input_file.stem + ".html"
def find_markdown_files(directory):
"""Recursively find all markdown files in a directory."""
directory = Path(directory)
md_files = []
for pattern in ['*.md', '*.markdown']:
md_files.extend(directory.rglob(pattern))
return sorted(md_files)
def get_relative_output_path(source_file, base_dir, output_dir):
"""Calculate relative output path preserving directory structure."""
source_file = Path(source_file)
base_dir = Path(base_dir)
output_dir = Path(output_dir)
# Get relative path from base directory
relative_path = source_file.relative_to(base_dir)
# Change extension to .html
relative_path = relative_path.with_suffix('.html')
# Combine with output directory
return output_dir / relative_path
def process_single_file(input_file, use_publication_dir, publication_dir):
"""Process a single markdown file, generate HTML, and return the output path."""
input_file = Path(input_file)
if not input_file.exists():
raise FileNotFoundError(f"Input file not found: {input_file}")
if use_publication_dir:
ensure_publication_directory(publication_dir)
output_file = publication_dir / get_output_filename(input_file)
else:
output_file = input_file.with_suffix('.html')
# Actually generate the HTML file
_render_single_markdown_file(
input_file, output_file, 'basic', None, False, 'light', False, {}
)
return output_file
def process_directory(input_dir, use_publication_dir, publication_dir):
"""Process all markdown files in a directory, generate HTML files, and return list of output paths."""
input_dir = Path(input_dir)
if not input_dir.exists() or not input_dir.is_dir():
raise NotADirectoryError(f"Input directory not found: {input_dir}")
md_files = find_markdown_files(input_dir)
output_files = []
for md_file in md_files:
if use_publication_dir:
ensure_publication_directory(publication_dir)
output_file = get_relative_output_path(md_file, input_dir, publication_dir)
# Ensure subdirectory exists
output_file.parent.mkdir(parents=True, exist_ok=True)
else:
output_file = md_file.with_suffix('.html')
# Actually generate the HTML file
_render_single_markdown_file(
md_file, output_file, 'basic', None, False, 'light', False, {}
)
output_files.append(output_file)
return output_files

View File

@@ -0,0 +1,374 @@
#!/usr/bin/env python3
"""
Test suite for Issue #135: Instant Markdown base and publication directory
This test suite validates the publication directory functionality for the md-render command,
including directory processing, environment variable handling, and CLI flags.
TDD8 Workflow: ISSUE→TEST→RED→GREEN→REFACTOR→DOCUMENT→REFINE→PUBLISH
State: RED (Tests should fail initially)
"""
import pytest
import tempfile
import os
import shutil
from pathlib import Path
from unittest.mock import patch, MagicMock
import subprocess
class TestPublicationDirectoryManagement:
"""Test publication directory configuration and management."""
def test_default_publication_directory_is_notes_home(self):
"""Test that default publication directory is ~/Notes/."""
from markitect.plugins.builtin.markdown_commands import get_publication_directory
with patch.dict(os.environ, {}, clear=True):
# Remove any existing MARKITECT_PUBLICATION_DIR env var
if 'MARKITECT_PUBLICATION_DIR' in os.environ:
del os.environ['MARKITECT_PUBLICATION_DIR']
pub_dir = get_publication_directory()
expected = Path.home() / "Notes"
assert pub_dir == expected
def test_environment_variable_overrides_default_publication_directory(self):
"""Test that MARKITECT_PUBLICATION_DIR environment variable overrides default."""
from markitect.plugins.builtin.markdown_commands import get_publication_directory
custom_dir = "/tmp/custom_publication"
with patch.dict(os.environ, {'MARKITECT_PUBLICATION_DIR': custom_dir}):
pub_dir = get_publication_directory()
assert pub_dir == Path(custom_dir)
def test_publication_directory_creation_when_nonexistent(self):
"""Test that publication directory is created when it doesn't exist."""
from markitect.plugins.builtin.markdown_commands import ensure_publication_directory
with tempfile.TemporaryDirectory() as tmpdir:
pub_dir = Path(tmpdir) / "nonexistent" / "publication"
assert not pub_dir.exists()
ensure_publication_directory(pub_dir)
assert pub_dir.exists()
assert pub_dir.is_dir()
def test_publication_directory_path_normalization(self):
"""Test that publication directory paths are properly normalized."""
from markitect.plugins.builtin.markdown_commands import normalize_publication_path
# Test tilde expansion
path_with_tilde = "~/Documents/Notes"
normalized = normalize_publication_path(path_with_tilde)
assert str(normalized).startswith(str(Path.home()))
# Test relative path resolution
relative_path = "./publication"
normalized = normalize_publication_path(relative_path)
assert normalized.is_absolute()
class TestSingleFileProcessing:
"""Test single markdown file processing behavior."""
def setup_method(self):
"""Set up test environment with temporary files."""
self.temp_dir = tempfile.mkdtemp()
self.test_md_file = Path(self.temp_dir) / "test.md"
self.test_md_file.write_text("# Test Document\n\nThis is a test.")
# Set up publication directory
self.pub_dir = Path(self.temp_dir) / "publication"
self.pub_dir.mkdir(exist_ok=True)
def teardown_method(self):
"""Clean up test environment."""
shutil.rmtree(self.temp_dir)
def test_single_file_default_html_next_to_md(self):
"""Test that by default, single file HTML is generated next to MD file."""
from markitect.plugins.builtin.markdown_commands import process_single_file
result = process_single_file(
input_file=self.test_md_file,
use_publication_dir=False,
publication_dir=self.pub_dir
)
expected_output = self.test_md_file.with_suffix('.html')
assert result == expected_output
# This will fail until implementation is added
assert expected_output.exists()
def test_single_file_with_use_publication_dir_flag(self):
"""Test single file with --use-publication-dir places HTML in publication directory."""
from markitect.plugins.builtin.markdown_commands import process_single_file
result = process_single_file(
input_file=self.test_md_file,
use_publication_dir=True,
publication_dir=self.pub_dir
)
expected_output = self.pub_dir / "test.html"
assert result == expected_output
# This will fail until implementation is added
assert expected_output.exists()
def test_single_file_output_naming_conventions(self):
"""Test that output file naming follows conventions."""
from markitect.plugins.builtin.markdown_commands import get_output_filename
# Test basic naming
input_file = Path("document.md")
output_name = get_output_filename(input_file)
assert output_name == "document.html"
# Test with complex filename
input_file = Path("my-document_v2.md")
output_name = get_output_filename(input_file)
assert output_name == "my-document_v2.html"
class TestDirectoryProcessing:
"""Test directory tree processing functionality."""
def setup_method(self):
"""Set up test directory structure."""
self.temp_dir = tempfile.mkdtemp()
self.base_dir = Path(self.temp_dir) / "source"
self.pub_dir = Path(self.temp_dir) / "publication"
# Create test directory structure
self.base_dir.mkdir()
self.pub_dir.mkdir()
# Create test markdown files
(self.base_dir / "root.md").write_text("# Root Document")
(self.base_dir / "subdir").mkdir()
(self.base_dir / "subdir" / "sub.md").write_text("# Sub Document")
(self.base_dir / "subdir" / "deep").mkdir()
(self.base_dir / "subdir" / "deep" / "deep.md").write_text("# Deep Document")
# Create non-markdown files (should be ignored)
(self.base_dir / "readme.txt").write_text("Not markdown")
(self.base_dir / "image.png").write_bytes(b"fake image data")
def teardown_method(self):
"""Clean up test environment."""
shutil.rmtree(self.temp_dir)
def test_directory_default_html_in_publication_dir_with_structure(self):
"""Test that directory processing puts HTML in publication directory with preserved structure."""
from markitect.plugins.builtin.markdown_commands import process_directory
results = process_directory(
input_dir=self.base_dir,
use_publication_dir=True,
publication_dir=self.pub_dir
)
# Check that all expected HTML files are in publication directory
expected_files = [
self.pub_dir / "root.html",
self.pub_dir / "subdir" / "sub.html",
self.pub_dir / "subdir" / "deep" / "deep.html"
]
assert len(results) == 3
for expected_file in expected_files:
assert expected_file in results
# This will fail until implementation is added
assert expected_file.exists()
def test_directory_with_dont_use_publication_dir_html_next_to_md(self):
"""Test directory processing with --dont-use-publication-dir places HTML next to MD files."""
from markitect.plugins.builtin.markdown_commands import process_directory
results = process_directory(
input_dir=self.base_dir,
use_publication_dir=False,
publication_dir=self.pub_dir
)
# Check that HTML files are next to their corresponding MD files
expected_files = [
self.base_dir / "root.html",
self.base_dir / "subdir" / "sub.html",
self.base_dir / "subdir" / "deep" / "deep.html"
]
assert len(results) == 3
for expected_file in expected_files:
assert expected_file in results
# This will fail until implementation is added
assert expected_file.exists()
def test_directory_recursive_traversal(self):
"""Test that directory processing recursively finds all markdown files."""
from markitect.plugins.builtin.markdown_commands import find_markdown_files
md_files = find_markdown_files(self.base_dir)
expected_files = [
self.base_dir / "root.md",
self.base_dir / "subdir" / "sub.md",
self.base_dir / "subdir" / "deep" / "deep.md"
]
assert len(md_files) == 3
for expected_file in expected_files:
assert expected_file in md_files
def test_directory_structure_preservation(self):
"""Test that directory structure is preserved in publication directory."""
from markitect.plugins.builtin.markdown_commands import get_relative_output_path
# Test relative path calculation
source_file = self.base_dir / "subdir" / "deep" / "deep.md"
relative_path = get_relative_output_path(source_file, self.base_dir, self.pub_dir)
expected_path = self.pub_dir / "subdir" / "deep" / "deep.html"
assert relative_path == expected_path
class TestCLIIntegration:
"""Test CLI integration with new flags."""
def setup_method(self):
"""Set up test environment."""
self.temp_dir = tempfile.mkdtemp()
self.test_file = Path(self.temp_dir) / "test.md"
self.test_file.write_text("# Test Document")
def teardown_method(self):
"""Clean up test environment."""
shutil.rmtree(self.temp_dir)
def test_md_render_command_has_use_publication_dir_flag(self):
"""Test that md-render command has --use-publication-dir flag."""
result = subprocess.run(
["markitect", "md-render", "--help"],
capture_output=True,
text=True
)
assert "--use-publication-dir" in result.stdout
assert "publication directory" in result.stdout.lower()
def test_md_render_command_has_dont_use_publication_dir_flag(self):
"""Test that md-render command has --dont-use-publication-dir flag."""
result = subprocess.run(
["markitect", "md-render", "--help"],
capture_output=True,
text=True
)
assert "--dont-use-publication-dir" in result.stdout
def test_md_render_with_directory_input(self):
"""Test that md-render command accepts directory as input."""
# Create a test directory with markdown files
test_dir = Path(self.temp_dir) / "test_dir"
test_dir.mkdir()
(test_dir / "test.md").write_text("# Test")
# This should not fail with directory input
result = subprocess.run(
["markitect", "md-render", str(test_dir)],
capture_output=True,
text=True,
timeout=30
)
# Should not error on directory input
assert result.returncode == 0 or "directory" in result.stderr
def test_environment_variable_integration(self):
"""Test that MARKITECT_PUBLICATION_DIR environment variable is respected."""
pub_dir = Path(self.temp_dir) / "custom_pub"
pub_dir.mkdir()
env = os.environ.copy()
env['MARKITECT_PUBLICATION_DIR'] = str(pub_dir)
result = subprocess.run(
["markitect", "md-render", str(self.test_file), "--use-publication-dir"],
capture_output=True,
text=True,
env=env,
timeout=30
)
# Should succeed or at least recognize the flag
# This will fail until implementation is complete
assert result.returncode == 0
class TestEdgeCases:
"""Test edge cases and error conditions."""
def setup_method(self):
"""Set up test environment."""
self.temp_dir = tempfile.mkdtemp()
def teardown_method(self):
"""Clean up test environment."""
shutil.rmtree(self.temp_dir)
def test_empty_directory_processing(self):
"""Test processing of empty directory."""
from markitect.plugins.builtin.markdown_commands import process_directory
empty_dir = Path(self.temp_dir) / "empty"
empty_dir.mkdir()
pub_dir = Path(self.temp_dir) / "pub"
pub_dir.mkdir()
results = process_directory(
input_dir=empty_dir,
use_publication_dir=True,
publication_dir=pub_dir
)
assert results == []
def test_mixed_content_directory_processing(self):
"""Test directory with mixed content (markdown and other files)."""
from markitect.plugins.builtin.markdown_commands import find_markdown_files
mixed_dir = Path(self.temp_dir) / "mixed"
mixed_dir.mkdir()
# Create various file types
(mixed_dir / "document.md").write_text("# Document")
(mixed_dir / "readme.txt").write_text("Text file")
(mixed_dir / "image.jpg").write_bytes(b"fake image")
(mixed_dir / "script.py").write_text("print('hello')")
(mixed_dir / "another.md").write_text("# Another")
md_files = find_markdown_files(mixed_dir)
# Should only find markdown files
assert len(md_files) == 2
assert all(f.suffix == '.md' for f in md_files)
def test_nonexistent_input_error_handling(self):
"""Test error handling for nonexistent input files/directories."""
from markitect.plugins.builtin.markdown_commands import process_single_file
nonexistent_file = Path(self.temp_dir) / "nonexistent.md"
pub_dir = Path(self.temp_dir) / "pub"
with pytest.raises(FileNotFoundError):
process_single_file(
input_file=nonexistent_file,
use_publication_dir=False,
publication_dir=pub_dir
)
if __name__ == '__main__':
pytest.main([__file__, "-v"])