Files
testdrive-jsui/STANDALONE_PLAN.md
tegwick 6a6543228a docs: add cleanup report and standalone reusability plan
Added comprehensive documentation for post-migration cleanup and future
standalone development:

- CLEANUP_REPORT.md: Identifies 6 cleanup opportunities after migration
  completion (empty dirs, legacy wrappers, relicts, documentation updates)

- STANDALONE_PLAN.md: 5-phase plan to achieve 95% standalone maturity
  (move rendering engine to capability, create examples, update docs,
  testing, PyPI distribution)

- CLAUDE.md: Updated with migration completion status

These documents provide clear roadmap for making testdrive-jsui truly
pip-installable and reusable independently from MarkiTect.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-16 11:10:56 +01:00

21 KiB

TestDrive-JSUI Standalone Reusability Plan

Date: 2025-12-16 Goal: Make testdrive-jsui truly reusable independently from MarkiTect Current Maturity: 60% → Target: 95%


Executive Summary

TestDrive-JSUI has excellent JavaScript architecture and testing infrastructure, but its Python rendering engine lives in the MarkiTect codebase, preventing true standalone reuse. This plan outlines how to make it a fully independent, pip-installable package that works in any Python project.

Key Problem: Cannot pip install testdrive-jsui and use it in non-MarkiTect projects.

Solution: Move rendering engine and dependencies into the capability package.


Current State Analysis

What Works

  • JavaScript components are self-contained
  • Testing infrastructure is independent
  • Asset structure is clean
  • Documentation is comprehensive

What Doesn't

  • Rendering engine in /markitect/plugins/testdrive_jsui.py
  • Depends on markitect.plugins.rendering.RenderingConfig
  • Python package (src/testdrive_jsui/) is empty shells
  • Not pip-installable for standalone use

Phase 1: Move Core Rendering Engine

Objective

Move the rendering engine from MarkiTect plugins into the capability package.

Current Location

/markitect/plugins/testdrive_jsui.py       (242 lines)
/markitect/plugins/rendering.py            (316 lines - base classes)
/markitect/plugins/base.py                 (Plugin metadata)

Target Location

src/testdrive_jsui/
├── __init__.py                 # Export main classes
├── engine.py                   # TestDriveJSUIEngine (moved)
├── rendering.py                # RenderingEnginePlugin, RenderingConfig (extracted)
├── models.py                   # PluginMetadata, etc.
└── testing/                    # ✅ Already independent

Implementation Steps

Step 1.1: Extract Base Classes

Create: src/testdrive_jsui/models.py

"""
Data models and metadata for TestDrive-JSUI.
"""
from dataclasses import dataclass
from enum import Enum
from typing import Optional

class PluginType(Enum):
    """Plugin type enumeration."""
    RENDERING = "rendering"
    TESTING = "testing"

@dataclass
class PluginMetadata:
    """Plugin metadata information."""
    name: str
    version: str
    description: str
    author: str
    plugin_type: PluginType

Why: Remove dependency on MarkiTect's plugin system.


Step 1.2: Create Standalone Rendering Base

Create: src/testdrive_jsui/rendering.py

Extract and adapt from /markitect/plugins/rendering.py:

  • RenderingEnginePlugin (abstract base)
  • RenderingConfig (configuration)
  • Remove MarkiTect-specific integrations
  • Make it generic for any Python project
"""
Rendering engine plugin architecture for TestDrive-JSUI.

This module provides a standalone rendering system that can be used
independently of MarkiTect or integrated into any Python project.
"""
from abc import ABC, abstractmethod
from typing import Dict, List, Optional, Any
from pathlib import Path
import json

class RenderingEnginePlugin(ABC):
    """Base class for rendering engine plugins."""

    @abstractmethod
    def get_supported_modes(self) -> List[str]:
        """Return supported rendering modes (e.g., ['edit', 'view'])."""
        pass

    @abstractmethod
    def get_required_assets(self) -> Dict[str, List[str]]:
        """Return required assets by type (js, css, images)."""
        pass

    @abstractmethod
    def render_document(self, content: str, mode: str,
                       config: 'RenderingConfig') -> str:
        """Render markdown content to HTML."""
        pass

    # ... rest of interface

class RenderingConfig:
    """Configuration for rendering engine."""

    def __init__(self,
                 asset_base_url: str = "_static",
                 development_mode: bool = False,
                 plugin_source_dirs: Optional[Dict[str, Path]] = None,
                 output_directory: Optional[Path] = None):
        """Initialize configuration for standalone use."""
        self.asset_base_url = asset_base_url
        self.development_mode = development_mode
        self.plugin_source_dirs = plugin_source_dirs or {}
        self.output_directory = output_directory

    # ... rest of implementation

Why: Standalone projects shouldn't import markitect.plugins.rendering.


Step 1.3: Move Engine Implementation

Create: src/testdrive_jsui/engine.py

Move from /markitect/plugins/testdrive_jsui.py:

"""
TestDrive-JSUI Rendering Engine.

Standalone JavaScript UI rendering engine for markdown content.
Can be used independently or integrated into any Python application.
"""
from pathlib import Path
from typing import Dict, List, Optional
import json

from .models import PluginMetadata, PluginType
from .rendering import RenderingEnginePlugin, RenderingConfig


class TestDriveJSUIEngine(RenderingEnginePlugin):
    """
    TestDrive JavaScript UI rendering engine.

    Usage:
        >>> from testdrive_jsui import TestDriveJSUIEngine, RenderingConfig
        >>> engine = TestDriveJSUIEngine()
        >>> config = RenderingConfig(development_mode=True)
        >>> html = engine.render_document("# Hello", "edit", config)
    """

    def __init__(self):
        super().__init__()
        self._metadata = PluginMetadata(
            name="testdrive-jsui",
            version="1.0.0",
            description="Independent JavaScript UI engine for markdown",
            author="MarkiTect Team",
            plugin_type=PluginType.RENDERING
        )

    # ... full implementation from markitect/plugins/testdrive_jsui.py

Why: Makes the engine part of the testdrive-jsui package, not MarkiTect.


Step 1.4: Update Package init.py

Update: src/testdrive_jsui/__init__.py

"""
TestDrive-JSUI: Standalone JavaScript UI Rendering Engine and Testing Framework

A self-contained capability providing:
- Interactive JavaScript UI for markdown editing and viewing
- Python-JavaScript test integration bridge
- Standalone rendering engine for any Python project
"""

__version__ = "1.0.0"
__author__ = "MarkiTect Team"

# Core rendering engine
from .engine import TestDriveJSUIEngine
from .rendering import RenderingEnginePlugin, RenderingConfig
from .models import PluginMetadata, PluginType

# Testing infrastructure
from .testing.js_test_runner import JavaScriptTestRunner, JSTestResult
from .testing.integration import PythonJSBridge

__all__ = [
    # Engine
    "TestDriveJSUIEngine",
    "RenderingEnginePlugin",
    "RenderingConfig",

    # Models
    "PluginMetadata",
    "PluginType",

    # Testing
    "JavaScriptTestRunner",
    "JSTestResult",
    "PythonJSBridge",
]

Why: Clean, documented public API for standalone use.


Step 1.5: Maintain MarkiTect Compatibility

Update: /markitect/plugins/testdrive_jsui.py

"""
TestDrive-JSUI Plugin Integration for MarkiTect.

This is a thin compatibility wrapper that imports the standalone
TestDrive-JSUI engine and integrates it with MarkiTect's plugin system.
"""
from pathlib import Path

# Import from standalone package
from testdrive_jsui import TestDriveJSUIEngine as StandaloneEngine
from testdrive_jsui import RenderingConfig as StandaloneConfig

# Re-export for MarkiTect compatibility
TestDriveJSUIEngine = StandaloneEngine
RenderingConfig = StandaloneConfig

# MarkiTect-specific plugin system integration
from .base import PluginMetadata, PluginType
from .rendering import RenderingEnginePlugin as MarkitectRenderingPlugin

# Adapter if needed for MarkiTect's plugin system
class MarkitectTestDriveJSUIAdapter(MarkitectRenderingPlugin):
    """Adapter to integrate standalone engine with MarkiTect plugin system."""

    def __init__(self):
        self._engine = StandaloneEngine()

    def __getattr__(self, name):
        # Delegate all calls to standalone engine
        return getattr(self._engine, name)

Why: Existing MarkiTect code continues to work without changes.


Step 1.6: Update Dependencies

Update: pyproject.toml

[project]
name = "testdrive-jsui"
version = "1.0.0"
description = "Standalone JavaScript UI rendering engine and testing framework"
dependencies = [
    # Minimal dependencies for standalone use
    "pathlib2>=2.3.0;python_version<'3.4'",
]

[project.optional-dependencies]
# Testing remains same
testing = [
    "pytest>=7.0.0",
    "pytest-xvfb>=3.0.0",
    "selenium>=4.0.0",
]

# Development tools
dev = [
    "pytest-cov>=4.0.0",
    "black>=23.0.0",
    "flake8>=6.0.0",
    "mypy>=1.0.0",
]

# MarkiTect integration (optional)
markitect = [
    # Only needed if using with MarkiTect plugin system
]

Why: Minimal dependencies for standalone use.


Phase 2: Create Standalone Examples

Objective

Provide working examples showing standalone usage without MarkiTect.

Implementation

Create: examples/standalone_basic.py

"""
Basic standalone usage of TestDrive-JSUI.

This example shows how to use TestDrive-JSUI in any Python project
without MarkiTect.
"""
from pathlib import Path
from testdrive_jsui import TestDriveJSUIEngine, RenderingConfig

# Create engine instance
engine = TestDriveJSUIEngine()

# Configure for standalone use
config = RenderingConfig(
    asset_base_url=".",  # Serve from current directory
    development_mode=True,
    plugin_source_dirs={
        'testdrive-jsui': engine.get_plugin_source_dir()
    }
)

# Markdown content to render
markdown_content = """
# TestDrive-JSUI Standalone Demo

This document demonstrates **TestDrive-JSUI** running standalone,
without any MarkiTect dependencies.

## Features

- Interactive markdown editing
- Section management
- Debug controls
- Keyboard shortcuts

Try editing this content in the browser!
"""

# Render to HTML
html = engine.render_document(
    content=markdown_content,
    mode='edit',  # or 'view' for read-only
    config=config
)

# Save to file
output_path = Path('output.html')
output_path.write_text(html, encoding='utf-8')

print(f"✅ Rendered to: {output_path.absolute()}")
print(f"📂 Open in browser: file://{output_path.absolute()}")

Create: examples/flask_integration.py

"""
Flask integration example.

Shows how to integrate TestDrive-JSUI into a Flask web application.
"""
from flask import Flask, render_template_string
from testdrive_jsui import TestDriveJSUIEngine, RenderingConfig
from pathlib import Path

app = Flask(__name__)

# Initialize engine once
engine = TestDriveJSUIEngine()
config = RenderingConfig(
    asset_base_url="/static",
    development_mode=False
)

@app.route('/')
def index():
    """Render markdown with TestDrive-JSUI."""
    markdown = """
# Flask + TestDrive-JSUI

Edit this markdown content in your browser!
    """

    html = engine.render_document(markdown, 'edit', config)
    return html

@app.route('/view/<document_id>')
def view_document(document_id):
    """View a document in read-only mode."""
    # Load markdown from database/file
    markdown = load_document(document_id)

    html = engine.render_document(markdown, 'view', config)
    return html

if __name__ == '__main__':
    app.run(debug=True)

Create: examples/django_integration.py

"""
Django integration example.

Shows how to use TestDrive-JSUI in Django views.
"""
from django.http import HttpResponse
from django.views import View
from testdrive_jsui import TestDriveJSUIEngine, RenderingConfig

class MarkdownEditorView(View):
    """View for editing markdown with TestDrive-JSUI."""

    def __init__(self):
        self.engine = TestDriveJSUIEngine()
        self.config = RenderingConfig(
            asset_base_url="/static",
            development_mode=False
        )

    def get(self, request, document_id=None):
        """Render markdown editor."""
        # Load markdown content
        markdown = self.load_markdown(document_id)

        # Render with TestDrive-JSUI
        html = self.engine.render_document(
            markdown,
            'edit',
            self.config
        )

        return HttpResponse(html)

    def post(self, request, document_id):
        """Save markdown content."""
        markdown = request.POST.get('content')
        self.save_markdown(document_id, markdown)
        return HttpResponse(status=200)

Create: examples/README.md

# TestDrive-JSUI Examples

## Standalone Usage

### Basic Example
```bash
python examples/standalone_basic.py

Opens output.html with an interactive markdown editor.

Flask Integration

pip install flask
python examples/flask_integration.py

Visit http://localhost:5000 to see TestDrive-JSUI in Flask.

Django Integration

See django_integration.py for integration with Django views.

Requirements

All examples work with just:

pip install testdrive-jsui

No MarkiTect required!


---

## Phase 3: Update Documentation

### Update README.md

**Section to Add**: "Standalone Installation"

```markdown
## Standalone Installation

TestDrive-JSUI can be used completely independently:

```bash
# Install from PyPI
pip install testdrive-jsui

# Or install from source
pip install -e ./capabilities/testdrive-jsui

Quick Start (Standalone)

from testdrive_jsui import TestDriveJSUIEngine, RenderingConfig

engine = TestDriveJSUIEngine()
config = RenderingConfig(development_mode=True)
html = engine.render_document("# Hello World", "edit", config)

See examples/ directory for Flask, Django, and other integrations.


---

### Create: `docs/STANDALONE_GUIDE.md`

Comprehensive guide covering:
- Installation in non-MarkiTect projects
- Configuration options
- Asset deployment strategies
- Framework integrations (Flask, Django, FastAPI)
- Production deployment
- Customization options

---

## Phase 4: Testing and Validation

### Create Standalone Tests

**Create**: `tests/test_standalone.py`

```python
"""
Test standalone usage without MarkiTect dependencies.

These tests verify the package works independently.
"""
import pytest
from pathlib import Path

def test_import_without_markitect():
    """Verify imports work without MarkiTect."""
    # Should not raise ImportError
    from testdrive_jsui import TestDriveJSUIEngine
    from testdrive_jsui import RenderingConfig
    from testdrive_jsui import JavaScriptTestRunner

    assert TestDriveJSUIEngine is not None
    assert RenderingConfig is not None
    assert JavaScriptTestRunner is not None

def test_engine_initialization():
    """Test engine can be initialized standalone."""
    from testdrive_jsui import TestDriveJSUIEngine

    engine = TestDriveJSUIEngine()
    assert engine is not None
    assert engine.metadata.name == "testdrive-jsui"

def test_render_document_standalone():
    """Test document rendering works standalone."""
    from testdrive_jsui import TestDriveJSUIEngine, RenderingConfig

    engine = TestDriveJSUIEngine()
    config = RenderingConfig(development_mode=True)

    html = engine.render_document("# Test", "edit", config)

    assert html is not None
    assert "Test" in html
    assert "<html" in html

def test_no_markitect_imports():
    """Verify no MarkiTect imports in standalone code."""
    import testdrive_jsui
    import inspect

    # Get all source code
    source = inspect.getsource(testdrive_jsui)

    # Should not import from markitect
    assert "from markitect" not in source
    assert "import markitect" not in source

Create Isolated Test Environment

# Create clean virtual environment
python -m venv test_standalone
source test_standalone/bin/activate

# Install ONLY testdrive-jsui (not MarkiTect)
pip install -e ./capabilities/testdrive-jsui

# Run standalone tests
pytest capabilities/testdrive-jsui/tests/test_standalone.py -v

# Try examples
python capabilities/testdrive-jsui/examples/standalone_basic.py

Success Criteria: All tests pass without MarkiTect installed.


Phase 5: Distribution and Packaging

Prepare for PyPI

Update pyproject.toml

[project]
name = "testdrive-jsui"
version = "1.0.0"
description = "Standalone JavaScript UI rendering engine for markdown content"
readme = "README.md"
license = {text = "MIT"}
authors = [
    {name = "MarkiTect Team", email = "team@markitect.dev"}
]

keywords = [
    "markdown", "editor", "javascript", "ui", "rendering",
    "testing", "jest", "pytest", "standalone"
]

classifiers = [
    "Development Status :: 4 - Beta",
    "Intended Audience :: Developers",
    "License :: OSI Approved :: MIT License",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.8",
    "Programming Language :: Python :: 3.9",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    "Topic :: Software Development :: Libraries",
    "Topic :: Text Editors",
    "Framework :: Flask",
    "Framework :: Django",
]

[project.urls]
Homepage = "https://github.com/markitect/testdrive-jsui"
Documentation = "https://docs.markitect.com/testdrive-jsui"
Repository = "https://github.com/markitect/testdrive-jsui"
"Bug Tracker" = "https://github.com/markitect/testdrive-jsui/issues"

Include Assets in Package

Create: MANIFEST.in

# Include JavaScript, CSS, and templates
recursive-include src/testdrive_jsui/js *.js
recursive-include src/testdrive_jsui/static *.css *.html *.png *.jpg *.svg

# Include documentation
include README.md
include LICENSE
include CLAUDE.md
recursive-include docs *.md

# Include examples
recursive-include examples *.py *.md

# Exclude development files
exclude MIGRATION_STATUS.md
exclude CLEANUP_REPORT.md
recursive-exclude * __pycache__
recursive-exclude * *.py[co]
recursive-exclude * .DS_Store

Update: pyproject.toml

[tool.setuptools]
packages = ["testdrive_jsui"]
package-dir = {"" = "src"}

[tool.setuptools.package-data]
testdrive_jsui = [
    "js/**/*.js",
    "static/**/*",
    "templates/**/*",
]

Build and Test Distribution

cd capabilities/testdrive-jsui

# Install build tools
pip install build twine

# Build distribution
python -m build

# Test installation in clean environment
python -m venv test_dist
source test_dist/bin/activate
pip install dist/testdrive_jsui-1.0.0-py3-none-any.whl

# Verify it works
python -c "from testdrive_jsui import TestDriveJSUIEngine; print('✅ Success')"

# Run example
python examples/standalone_basic.py

Publish to PyPI (when ready)

# Test PyPI first
python -m twine upload --repository testpypi dist/*

# Verify installation from Test PyPI
pip install --index-url https://test.pypi.org/simple/ testdrive-jsui

# If all good, publish to real PyPI
python -m twine upload dist/*

Success Criteria

Standalone Usability Checklist

  • Can pip install testdrive-jsui in empty environment
  • Can from testdrive_jsui import TestDriveJSUIEngine works
  • No MarkiTect imports in standalone code
  • Examples work without MarkiTect
  • All tests pass in isolated environment
  • Documentation covers standalone usage
  • Package includes all necessary assets
  • Works with Flask/Django/FastAPI
  • MarkiTect integration still works
  • Published to PyPI (optional)

Maturity Assessment After Implementation

Aspect Before After Target
Python API 60% 95% 95%
Standalone Use 30% 95% 95%
Documentation 80% 95% 95%
Distribution 40% 90% 90%
Examples 20% 90% 90%
Overall 60% 94% 95%

Implementation Timeline

Week 1: Core Infrastructure

  • Day 1-2: Extract base classes (Phase 1.1, 1.2)
  • Day 3-4: Move engine implementation (Phase 1.3, 1.4)
  • Day 5: Update dependencies and compatibility (Phase 1.5, 1.6)

Week 2: Examples and Documentation

  • Day 1-2: Create standalone examples (Phase 2)
  • Day 3-4: Update documentation (Phase 3)
  • Day 5: Testing and validation (Phase 4)

Week 3: Distribution

  • Day 1-2: Prepare packaging (Phase 5)
  • Day 3: Test distribution
  • Day 4-5: Buffer for issues and polish

Total Effort: ~15 days


Risks and Mitigation

Risk 1: Breaking MarkiTect Integration

Mitigation:

  • Keep compatibility wrapper in /markitect/plugins/
  • Run MarkiTect tests after each change
  • Maintain adapter pattern

Risk 2: Missing Assets in Package

Mitigation:

  • Comprehensive MANIFEST.in
  • Test wheel installation
  • Verify assets accessible

Risk 3: Complex Dependencies

Mitigation:

  • Keep dependencies minimal
  • Optional dependencies for advanced features
  • Document requirements clearly

Next Steps

  1. Review this plan with team
  2. Create feature branch: feature/standalone-reusability
  3. Implement Phase 1: Core infrastructure
  4. Validate: Test in isolated environment
  5. Continue phases: Examples, docs, distribution
  6. Release v1.0.0: First standalone release

End of Standalone Reusability Plan