Skip to content

Commit f8ee8a1

Browse files
committed
update codegen integration in main cli
1 parent c6735b1 commit f8ee8a1

4 files changed

Lines changed: 54 additions & 152 deletions

File tree

json_explorer/cli.py

Lines changed: 7 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
from .stats import DataStatsAnalyzer
66
from .visualizer import JSONVisualizer
77
from .filter_parser import FilterExpressionParser
8-
from .analyzer import analyze_json
9-
from .codegen import MultiTargetGenerator, parse_config_string
108

119

1210
class CLIHandler:
@@ -28,7 +26,7 @@ def set_data(self, data, source):
2826
def run(self, args):
2927
"""Run CLI mode operations based on arguments."""
3028
if not self.data:
31-
self.console.print(" [red]No data loaded[/red]")
29+
self.console.print(" [red]No data loaded[/red]")
3230
return 1
3331

3432
self.console.print(f"📄 Loaded: {self.source}")
@@ -49,9 +47,8 @@ def run(self, args):
4947
if args.plot:
5048
self._handle_visualization(args)
5149

52-
# Code generation
53-
if args.codegen:
54-
self._handle_codegen(args)
50+
# Note: Code generation is handled by main.py -> handle_codegen_command()
51+
# This keeps the CLI focused on core analysis features
5552

5653
return 0
5754

@@ -86,7 +83,7 @@ def _handle_search(self, args):
8683
elif args.search_type == "pair":
8784
if not args.search_value:
8885
self.console.print(
89-
" [red]--search-value required for pair search[/red]"
86+
" [red]--search-value required for pair search[/red]"
9087
)
9188
return
9289
results = self.searcher.search_key_value_pairs(
@@ -97,10 +94,10 @@ def _handle_search(self, args):
9794
filter_func = FilterExpressionParser.parse_filter(search_term)
9895
results = self.searcher.search_with_filter(self.data, filter_func)
9996
except Exception as e:
100-
self.console.print(f" [red]Filter error: {e}[/red]")
97+
self.console.print(f" [red]Filter error: {e}[/red]")
10198
return
10299
else:
103-
self.console.print(f" [red]Unknown search type: {args.search_type}[/red]")
100+
self.console.print(f" [red]Unknown search type: {args.search_type}[/red]")
104101
return
105102

106103
# Display results
@@ -140,72 +137,4 @@ def _handle_visualization(self, args):
140137
"✅ [green]Visualizations generated successfully[/green]"
141138
)
142139
except Exception as e:
143-
self.console.print(f"⌛ [red]Visualization error: {e}[/red]")
144-
145-
def _handle_codegen(self, args):
146-
"""Handle code generation."""
147-
self.console.print("\n🔧 Generating code from JSON schema...")
148-
149-
try:
150-
# Analyze JSON to generate schema
151-
schema = analyze_json(self.data)
152-
153-
# Create generator
154-
root_name = getattr(args, "codegen_root", "Root")
155-
generator = MultiTargetGenerator(schema, root_name=root_name)
156-
157-
# Parse configuration if provided
158-
config_dict = {}
159-
if hasattr(args, "codegen_config") and args.codegen_config:
160-
config_dict = parse_config_string(args.codegen_config)
161-
162-
# Handle target selection
163-
if args.codegen == "all":
164-
# Generate all targets
165-
self.console.print("📝 Generating code for all supported targets...")
166-
results = generator.generate_all(config_dict)
167-
168-
for target, code in results.items():
169-
self.console.print(f"\n{'='*60}")
170-
self.console.print(
171-
f"🎯 [bold cyan]TARGET: {target.upper()}[/bold cyan]"
172-
)
173-
self.console.print("=" * 60)
174-
print(code)
175-
176-
self.console.print(
177-
f"\n✅ [green]Generated code for {len(results)} targets[/green]"
178-
)
179-
180-
elif args.codegen in generator.list_targets():
181-
# Generate specific target
182-
self.console.print(f"📝 Generating {args.codegen.upper()} code...")
183-
code = generator.generate(args.codegen, config_dict)
184-
185-
self.console.print(
186-
f"\n🎯 [bold cyan]{args.codegen.upper()} Code:[/bold cyan]"
187-
)
188-
self.console.print("-" * 50)
189-
print(code)
190-
191-
self.console.print(f"\n✅ [green]Code generated successfully[/green]")
192-
193-
else:
194-
available = ", ".join(generator.list_targets())
195-
self.console.print(f"⌛ [red]Unknown target: {args.codegen}[/red]")
196-
self.console.print(
197-
f"[yellow]Available targets: {available}, all[/yellow]"
198-
)
199-
200-
except Exception as e:
201-
self.console.print(f"⌛ [red]Code generation error: {e}[/red]")
202-
203-
def list_codegen_targets(self):
204-
"""List available code generation targets."""
205-
generator = MultiTargetGenerator({})
206-
targets = generator.list_targets()
207-
208-
self.console.print("\n🎯 [bold]Available Code Generation Targets:[/bold]")
209-
for target in targets:
210-
self.console.print(f" • [cyan]{target}[/cyan]")
211-
self.console.print(" • [cyan]all[/cyan] - Generate code for all targets")
140+
self.console.print(f"❌ [red]Visualization error: {e}[/red]")

json_explorer/codegen/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
list_supported_languages,
1111
register_generator,
1212
get_language_info,
13+
list_all_language_info,
1314
)
1415
from .core import (
1516
CodeGenerator,
@@ -148,6 +149,7 @@ def create_config(language="go", **kwargs) -> GeneratorConfig:
148149
"register_generator",
149150
"registry",
150151
"get_language_info",
152+
"list_all_language_info",
151153
# Core interfaces
152154
"CodeGenerator",
153155
"GeneratorError",

json_explorer/codegen/cli_integration.py

Lines changed: 11 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import sys
99
import json
1010
from pathlib import Path
11+
from rich.console import Console
1112

1213
from . import (
1314
generate_from_analysis,
@@ -98,6 +99,12 @@ def add_codegen_args(parser: argparse.ArgumentParser):
9899
help="Case style for field names",
99100
)
100101

102+
common_group.add_argument(
103+
"--verbose",
104+
action="store_true",
105+
help="Show generation result metadata",
106+
)
107+
101108
# Go-specific options
102109
go_group = parser.add_argument_group("Go-specific options")
103110
go_group.add_argument(
@@ -394,9 +401,9 @@ def _get_input_data(args: argparse.Namespace):
394401
"""Get JSON input data from various sources."""
395402
try:
396403
if hasattr(args, "file") and args.file:
397-
return load_json(args.file)
404+
return load_json(args.file)[1]
398405
elif hasattr(args, "url") and args.url:
399-
return load_json(args.url)
406+
return load_json(args.url)[1]
400407
else:
401408
# Try to read from stdin
402409
return json.load(sys.stdin)
@@ -412,9 +419,9 @@ def _get_subcommand_input(args: argparse.Namespace):
412419
"""Get input data for subcommand."""
413420
try:
414421
if args.file:
415-
return load_json(args.file)
422+
return load_json(args.file)[1]
416423
elif args.url:
417-
return load_json(args.url)
424+
return load_json(args.url)[1]
418425
elif args.stdin:
419426
return json.load(sys.stdin)
420427
else:
@@ -604,38 +611,3 @@ def validate_cli_config(args: argparse.Namespace) -> bool:
604611
return False
605612

606613
return True
607-
608-
609-
def get_cli_help_text() -> str:
610-
"""Get formatted help text for CLI integration."""
611-
return """
612-
Code Generation Options:
613-
614-
--generate LANGUAGE Generate code in specified language
615-
--output FILE Save generated code to file
616-
--config FILE Load configuration from JSON file
617-
--package-name NAME Set package/namespace name
618-
--root-name NAME Set name for root structure
619-
--list-languages List all supported languages
620-
--language-info LANG Show detailed language information
621-
622-
Common Generation Options:
623-
624-
--no-comments Don't add comments to generated code
625-
--struct-case CASE Naming case for structs (pascal/camel/snake)
626-
--field-case CASE Naming case for fields (pascal/camel/snake)
627-
628-
Go-Specific Options:
629-
630-
--no-pointers Don't use pointers for optional fields
631-
--no-json-tags Don't generate JSON struct tags
632-
--no-omitempty Don't add omitempty to JSON tags
633-
--json-tag-case CASE Case style for JSON tags (original/snake/camel)
634-
635-
Examples:
636-
637-
json_explorer --generate go --package main data.json
638-
json_explorer --generate go --no-pointers --output types.go data.json
639-
json_explorer --list-languages
640-
json_explorer --language-info go
641-
""".strip()

json_explorer/main.py

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from .cli import CLIHandler
1919
from .interactive import InteractiveHandler
2020
from .utils import load_json
21+
from .codegen.cli_integration import add_codegen_args, handle_codegen_command
2122
from rich.console import Console
2223

2324

@@ -37,16 +38,23 @@ def load_data(self, file_path=None, url=None):
3738
self.source, self.data = load_json(file_path, url)
3839
return True
3940
except Exception as e:
40-
self.console.print(f" [red]Error loading data: {e}[/red]")
41+
self.console.print(f" [red]Error loading data: {e}[/red]")
4142
return False
4243

4344
def run(self, args):
4445
"""Main execution method."""
45-
# Handle special commands that don't require data
46-
if args.list_codegen_targets:
47-
self.cli_handler.list_codegen_targets()
48-
return 0
49-
46+
# Handle codegen commands (which may not require data for --list-languages)
47+
if hasattr(args, "generate") or hasattr(args, "list_languages"):
48+
if args.list_languages:
49+
# List languages doesn't need data
50+
return handle_codegen_command(args)
51+
elif args.generate:
52+
# Code generation needs data
53+
if not self.load_data(args.file, args.url):
54+
return 1
55+
return handle_codegen_command(args)
56+
57+
# For other operations, load data first
5058
if not self.load_data(args.file, args.url):
5159
return 1
5260

@@ -60,7 +68,7 @@ def run(self, args):
6068

6169
def _has_cli_actions(self, args) -> bool:
6270
"""Check if any CLI-specific actions are requested."""
63-
return any([args.tree, args.search, args.stats, args.plot, args.codegen])
71+
return any([args.tree, args.search, args.stats, args.plot])
6472

6573

6674
def create_parser():
@@ -75,8 +83,12 @@ def create_parser():
7583
%(prog)s data.json --search "name" --search-type key
7684
%(prog)s data.json --search "isinstance(value, int) and value > 10" --search-type filter
7785
%(prog)s --url https://api.example.com/data --plot --tree-results
78-
%(prog)s data.json --codegen java --codegen-root User --codegen-config "lombok=true,jackson=true"
79-
%(prog)s data.json --codegen all --codegen-root ApiResponse
86+
87+
Code Generation:
88+
%(prog)s data.json --generate go --output user.go --root-name User
89+
%(prog)s data.json --generate go --package-name models --no-pointers
90+
%(prog)s data.json --generate go --config my-config.json
91+
%(prog)s --list-languages
8092
""",
8193
)
8294

@@ -157,29 +169,8 @@ def create_parser():
157169
help="Don't open browser for HTML visualizations",
158170
)
159171

160-
# Code generation options
161-
codegen_group = parser.add_argument_group("code generation options")
162-
codegen_group.add_argument(
163-
"--codegen",
164-
type=str,
165-
help="Generate code for target language (java, python, typescript, go, rust, openapi, graphql, all)",
166-
)
167-
codegen_group.add_argument(
168-
"--codegen-root",
169-
type=str,
170-
default="Root",
171-
help="Root class/type name for generated code (default: Root)",
172-
)
173-
codegen_group.add_argument(
174-
"--codegen-config",
175-
type=str,
176-
help="Code generation configuration (key=value,key2=value2). Example: lombok=true,jackson=true,package=com.example",
177-
)
178-
codegen_group.add_argument(
179-
"--list-codegen-targets",
180-
action="store_true",
181-
help="List all available code generation targets",
182-
)
172+
# Add codegen arguments from the dedicated module
173+
add_codegen_args(parser)
183174

184175
return parser
185176

@@ -194,12 +185,20 @@ def main():
194185
return 1
195186

196187
# Handle special commands that don't need file/url
197-
if args.list_codegen_targets:
188+
if hasattr(args, "list_languages") and args.list_languages:
198189
explorer = JSONExplorer()
199190
return explorer.run(args)
200191

201-
if not (args.file or args.url):
202-
print("⌛ Error: You must provide a file path or --url")
192+
# For codegen, we need either file or url (unless just listing languages)
193+
if hasattr(args, "generate") and args.generate:
194+
if not (args.file or args.url):
195+
print("❌ Error: Code generation requires a file path or --url")
196+
parser.print_help()
197+
return 1
198+
199+
# For other operations, file or url is required
200+
if not hasattr(args, "generate") and not (args.file or args.url):
201+
print("❌ Error: You must provide a file path or --url")
203202
parser.print_help()
204203
return 1
205204

0 commit comments

Comments
 (0)