Add commands and formatters modules
Some checks failed
CI / test (3.11) (push) Has been cancelled
CI / test (3.12) (push) Has been cancelled
CI / test (3.8) (push) Has been cancelled
CI / test (3.9) (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / typecheck (push) Has been cancelled
CI / build-package (push) Has been cancelled
CI / test (3.10) (push) Has been cancelled
Some checks failed
CI / test (3.11) (push) Has been cancelled
CI / test (3.12) (push) Has been cancelled
CI / test (3.8) (push) Has been cancelled
CI / test (3.9) (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / typecheck (push) Has been cancelled
CI / build-package (push) Has been cancelled
CI / test (3.10) (push) Has been cancelled
This commit is contained in:
94
configforge/commands/generate.py
Normal file
94
configforge/commands/generate.py
Normal file
@@ -0,0 +1,94 @@
|
||||
"""Generate command for ConfigForge."""
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
import click
|
||||
|
||||
from configforge.exceptions import (
|
||||
FileOperationError,
|
||||
InvalidConfigFormatError,
|
||||
SchemaGenerationError,
|
||||
)
|
||||
from configforge.formatters import JSONHandler, TypeScriptHandler, YAMLHandler
|
||||
from configforge.utils.file_parser import detect_format
|
||||
|
||||
|
||||
@click.command("generate")
|
||||
@click.argument("input_file", type=click.Path(exists=True))
|
||||
@click.option(
|
||||
"--output",
|
||||
"-o",
|
||||
type=click.Path(),
|
||||
help="Output file path (default: stdout)",
|
||||
)
|
||||
@click.option(
|
||||
"--interface-name",
|
||||
"-n",
|
||||
default="Config",
|
||||
help="Name for the generated TypeScript interface",
|
||||
)
|
||||
@click.option(
|
||||
"--from-data",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help="Generate TypeScript interface from sample data instead of schema",
|
||||
)
|
||||
def generate(
|
||||
input_file: str,
|
||||
output: Optional[str],
|
||||
interface_name: str,
|
||||
from_data: bool,
|
||||
) -> None:
|
||||
"""Generate TypeScript interfaces from JSON Schema or config data."""
|
||||
try:
|
||||
format_type = detect_format(input_file)
|
||||
|
||||
if format_type not in ("json", "yaml", "yml"):
|
||||
raise InvalidConfigFormatError(
|
||||
f"Unsupported format: {format_type}. Use JSON or YAML."
|
||||
)
|
||||
|
||||
if from_data:
|
||||
data = _read_data(input_file, format_type)
|
||||
ts_output = TypeScriptHandler.generate_from_data(data, interface_name)
|
||||
else:
|
||||
schema = _read_schema(input_file, format_type)
|
||||
ts_output = TypeScriptHandler.generate_from_schema(schema, interface_name)
|
||||
|
||||
if output:
|
||||
_write_output(output, ts_output)
|
||||
click.echo(f"Generated TypeScript interface -> {output}")
|
||||
else:
|
||||
click.echo(ts_output)
|
||||
|
||||
except (InvalidConfigFormatError, FileOperationError, SchemaGenerationError) as e:
|
||||
click.echo(f"Error: {e.message}", err=True)
|
||||
click.get_current_context().exit(1)
|
||||
|
||||
|
||||
def _read_data(filepath: str, format_type: str) -> dict:
|
||||
"""Read configuration data from file."""
|
||||
if format_type == "json":
|
||||
return JSONHandler.read(filepath)
|
||||
else:
|
||||
return YAMLHandler.read(filepath)
|
||||
|
||||
|
||||
def _read_schema(filepath: str, format_type: str) -> dict:
|
||||
"""Read JSON Schema from file."""
|
||||
if format_type == "json":
|
||||
return JSONHandler.read(filepath)
|
||||
else:
|
||||
return YAMLHandler.read(filepath)
|
||||
|
||||
|
||||
def _write_output(filepath: str, content: str) -> None:
|
||||
"""Write content to output file."""
|
||||
try:
|
||||
with open(filepath, "w", encoding="utf-8") as f:
|
||||
f.write(content)
|
||||
except PermissionError:
|
||||
raise FileOperationError(f"Permission denied: {filepath}", filepath=filepath)
|
||||
except OSError as e:
|
||||
raise FileOperationError(f"Failed to write {filepath}: {str(e)}", filepath=filepath)
|
||||
Reference in New Issue
Block a user