From 4a705d233fc93bcf974ef23d562cbd1b98c357c0 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Sun, 1 Feb 2026 17:04:00 +0000 Subject: [PATCH] fix: resolve CI test failures --- app/localapi-docs/src/cli.py | 92 ++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 app/localapi-docs/src/cli.py diff --git a/app/localapi-docs/src/cli.py b/app/localapi-docs/src/cli.py new file mode 100644 index 0000000..8332624 --- /dev/null +++ b/app/localapi-docs/src/cli.py @@ -0,0 +1,92 @@ +import click +from pathlib import Path +import json +from src.core.parser import parse_openapi_spec, _basic_validate +from src.utils.templates import generate_html, generate_markdown, generate_json, serve_docs +from src.utils.search import create_search_index, search_index + + +@click.group() +def main(): + """LocalAPI Docs - Privacy-First OpenAPI Documentation CLI""" + pass + + +@main.command("serve") +@click.argument("spec_path", type=click.Path(exists=True)) +@click.option("--host", default="127.0.0.1", help="Host to bind the server to") +@click.option("--port", default=8080, type=int, help="Port to bind the server to") +def serve(spec_path: str, host: str, port: int): + """Serve interactive API documentation locally""" + serve_docs(spec_path, host=host, port=port) + + +@main.command("generate") +@click.argument("spec_path", type=click.Path(exists=True)) +@click.option("--output", "-o", type=click.Path(), help="Output file path") +@click.option("--format", "fmt", type=click.Choice(["html", "markdown", "json"]), default="html", help="Output format") +@click.option("--template", type=click.Path(exists=True), help="Custom template file path") +def generate(spec_path: str, output: str | None, fmt: str, template: str | None): + """Generate documentation in various formats""" + if output is None: + if fmt == "html": + output = "docs.html" + elif fmt == "markdown": + output = "docs.md" + else: + output = "docs.json" + try: + if fmt == "html": + generate_html(spec_path, output, template_path=template) + elif fmt == "markdown": + generate_markdown(spec_path, output, template_path=template) + else: + generate_json(spec_path, output, template_path=template) + click.echo(f"Documentation generated: {output}") + except Exception as e: + click.echo(f"Error generating documentation: {e}", err=True) + + +@main.command("validate") +@click.argument("spec_path", type=click.Path(exists=True)) +def validate(spec_path: str): + """Validate an OpenAPI specification file""" + try: + spec = parse_openapi_spec(spec_path) + click.echo(f"Valid OpenAPI spec: {spec.info['title']} v{spec.info['version']}") + return True + except ValueError as e: + click.echo(f"Validation failed: {e}", err=True) + return False + + +@main.command("search") +@click.argument("spec_path", type=click.Path(exists=True)) +@click.argument("query", nargs=-1) +def search(spec_path: str, query: tuple): + """Search for endpoints in an OpenAPI specification""" + query_str = " ".join(query) + if not query_str: + click.echo("Please provide a search query") + return + try: + try: + spec = parse_openapi_spec(spec_path) + spec_dict = spec.model_dump() + except Exception: + content = Path(spec_path).read_text() + if spec_path.endswith(('.yaml', '.yml')): + import yaml + spec_dict = yaml.safe_load(content) + else: + spec_dict = json.loads(content) + index = create_search_index(spec_dict) + results = search_index(index, query_str) + if results: + click.echo(f"Found {len(results)} results for '{query_str}':") + for r in results: + click.echo(f" [{r.method}] {r.path} - {r.summary or ''}") + else: + click.echo(f"No results found for '{query_str}'") + except Exception as e: + click.echo(f"Search failed: {e}", err=True)