generated from coulomb/repo-seed
Added deterministic function layer
This commit is contained in:
@@ -37,6 +37,13 @@ from markitect_tool.contract import (
|
||||
load_contract_file,
|
||||
validate_contract,
|
||||
)
|
||||
from markitect_tool.document_function import (
|
||||
DocumentFunctionError,
|
||||
default_document_function_registry,
|
||||
render_document_functions,
|
||||
validate_document_functions,
|
||||
)
|
||||
from markitect_tool.extension import ProcessingContext
|
||||
from markitect_tool.explode import (
|
||||
ExplodeError,
|
||||
explode_markdown_file,
|
||||
@@ -858,6 +865,77 @@ def policy_resource_manifest(manifest_file: Path, output_format: str) -> None:
|
||||
_emit_resource_manifest_result({"manifest": manifest.to_dict()}, output_format)
|
||||
|
||||
|
||||
@main.group("function")
|
||||
def function_group() -> None:
|
||||
"""Inspect and execute deterministic document functions."""
|
||||
|
||||
|
||||
@function_group.command("list")
|
||||
@click.option("--namespace", help="Only list functions in one namespace.")
|
||||
@click.option(
|
||||
"--format",
|
||||
"output_format",
|
||||
type=click.Choice(["json", "yaml", "text"], case_sensitive=False),
|
||||
default="text",
|
||||
show_default=True,
|
||||
)
|
||||
def function_list(namespace: str | None, output_format: str) -> None:
|
||||
"""List registered document functions."""
|
||||
|
||||
registry = default_document_function_registry()
|
||||
functions = [descriptor.to_dict() for descriptor in registry.list(namespace=namespace)]
|
||||
_emit_function_catalog({"count": len(functions), "functions": functions}, output_format)
|
||||
|
||||
|
||||
@function_group.command("render")
|
||||
@click.argument("file", type=click.Path(exists=True, dir_okay=False, path_type=Path))
|
||||
@click.option(
|
||||
"--format",
|
||||
"output_format",
|
||||
type=click.Choice(["json", "yaml", "text"], case_sensitive=False),
|
||||
default="text",
|
||||
show_default=True,
|
||||
)
|
||||
def function_render(file: Path, output_format: str) -> None:
|
||||
"""Render deterministic document function calls in a Markdown file."""
|
||||
|
||||
try:
|
||||
text = file.read_text(encoding="utf-8")
|
||||
result = render_document_functions(text, context=ProcessingContext(source_path=file))
|
||||
except DocumentFunctionError as exc:
|
||||
raise click.ClickException(str(exc)) from exc
|
||||
_emit_function_result(result.to_dict(), output_format)
|
||||
raise click.exceptions.Exit(0 if result.valid else 1)
|
||||
|
||||
|
||||
@function_group.command("check")
|
||||
@click.argument("file", type=click.Path(exists=True, dir_okay=False, path_type=Path))
|
||||
@click.option("--allow", "allowed", multiple=True, help="Only allow this function id. May be repeated.")
|
||||
@click.option("--forbid", "forbidden", multiple=True, help="Forbid this function id. May be repeated.")
|
||||
@click.option(
|
||||
"--format",
|
||||
"output_format",
|
||||
type=click.Choice(["json", "yaml", "text"], case_sensitive=False),
|
||||
default="text",
|
||||
show_default=True,
|
||||
)
|
||||
def function_check(
|
||||
file: Path,
|
||||
allowed: tuple[str, ...],
|
||||
forbidden: tuple[str, ...],
|
||||
output_format: str,
|
||||
) -> None:
|
||||
"""Validate document function calls without rendering."""
|
||||
|
||||
try:
|
||||
text = file.read_text(encoding="utf-8")
|
||||
result = validate_document_functions(text, allowed=list(allowed), forbidden=list(forbidden))
|
||||
except DocumentFunctionError as exc:
|
||||
raise click.ClickException(str(exc)) from exc
|
||||
_emit_function_check_result(result.to_dict(), output_format)
|
||||
raise click.exceptions.Exit(0 if result.valid else 1)
|
||||
|
||||
|
||||
@main.group("class")
|
||||
def class_group() -> None:
|
||||
"""Resolve deterministic content classes."""
|
||||
@@ -1831,6 +1909,39 @@ def _emit_resource_manifest_result(data: dict, output_format: str) -> None:
|
||||
click.echo(f"actions: {actions}")
|
||||
|
||||
|
||||
def _emit_function_catalog(data: dict, output_format: str) -> None:
|
||||
if output_format == "json":
|
||||
click.echo(json.dumps(data, indent=2, ensure_ascii=False))
|
||||
elif output_format == "yaml":
|
||||
click.echo(yaml.safe_dump(data, sort_keys=False))
|
||||
else:
|
||||
for function in data.get("functions", []):
|
||||
click.echo(f"{function['id']}: {function.get('summary', '')}")
|
||||
|
||||
|
||||
def _emit_function_result(data: dict, output_format: str) -> None:
|
||||
if output_format == "json":
|
||||
click.echo(json.dumps(data, indent=2, ensure_ascii=False))
|
||||
elif output_format == "yaml":
|
||||
click.echo(yaml.safe_dump(data, sort_keys=False))
|
||||
else:
|
||||
click.echo(data.get("content", ""))
|
||||
for diagnostic in data.get("diagnostics", []):
|
||||
click.echo(f"[{diagnostic['severity']}] {diagnostic['code']}: {diagnostic['message']}")
|
||||
|
||||
|
||||
def _emit_function_check_result(data: dict, output_format: str) -> None:
|
||||
if output_format == "json":
|
||||
click.echo(json.dumps(data, indent=2, ensure_ascii=False))
|
||||
elif output_format == "yaml":
|
||||
click.echo(yaml.safe_dump(data, sort_keys=False))
|
||||
else:
|
||||
click.echo("valid" if data.get("valid") else "invalid")
|
||||
click.echo(f"functions: {len(data.get('calls', []))}")
|
||||
for diagnostic in data.get("diagnostics", []):
|
||||
click.echo(f"- [{diagnostic['severity']}] {diagnostic['code']}: {diagnostic['message']}")
|
||||
|
||||
|
||||
def _emit_metrics(data: dict, output_format: str) -> None:
|
||||
if output_format == "json":
|
||||
click.echo(json.dumps(data, indent=2, ensure_ascii=False))
|
||||
|
||||
Reference in New Issue
Block a user