Skip to content

Commit 298b98c

Browse files
refactoring
1 parent 338640f commit 298b98c

File tree

2 files changed

+120
-81
lines changed

2 files changed

+120
-81
lines changed

code2logic/cli.py

Lines changed: 104 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -605,8 +605,9 @@ def _maybe_print_pretty_help() -> bool:
605605
help='Detail level - columns to include (default: standard)'
606606
)
607607
parser.add_argument(
608-
'-o', '--output',
609-
help='Output file path (default: stdout)'
608+
'-o', '--output-dir',
609+
dest='output_dir',
610+
help='Output directory for all generated files. If specified, files are saved instead of stdout. File names are derived from --name and format flags: {name}.{format}, {name}.functions.{ext}, {name}.{format}-schema.json'
610611
)
611612
parser.add_argument(
612613
'--name',
@@ -643,7 +644,12 @@ def _maybe_print_pretty_help() -> bool:
643644
parser.add_argument(
644645
'--with-schema',
645646
action='store_true',
646-
help='Generate JSON schema alongside output'
647+
help='Generate JSON schema file alongside output (uses project name for filename)'
648+
)
649+
parser.add_argument(
650+
'--stdout',
651+
action='store_true',
652+
help='Write all output to stdout instead of files (including schema and function-logic). Useful for piping.'
647653
)
648654
parser.add_argument(
649655
'--no-install',
@@ -853,26 +859,37 @@ def _maybe_print_pretty_help() -> bool:
853859

854860
log.separator()
855861

856-
# Get default project name from config
857-
project_name = config.get_project_name()
858-
859-
# Determine default output path when using --function-logic or --with-schema without -o
860-
default_output = None
861-
if (args.function_logic or args.with_schema) and not args.output:
862-
# Use project name from config with appropriate extension
863-
ext_map = {
864-
'markdown': 'md',
865-
'compact': 'txt',
866-
'json': 'json',
867-
'yaml': 'yaml',
868-
'hybrid': 'yaml',
869-
'csv': 'csv',
870-
'gherkin': 'feature',
871-
'toon': 'toon',
872-
'logicml': 'logicml',
873-
}
874-
ext = ext_map.get(args.format, args.format)
875-
default_output = f"{project_name}.{ext}"
862+
# Get project name: CLI arg > env var > default
863+
project_name = args.project_name if args.project_name else config.get_project_name()
864+
865+
# Determine output mode:
866+
# - --stdout: all requested output to stdout (with section markers)
867+
# - -o ./dir with --function-logic or --with-schema: only generate flagged files
868+
# - -o ./dir without aux flags: generate main file only
869+
# - no -o: main to stdout (auxiliary files require explicit path)
870+
use_stdout = args.stdout
871+
output_dir = args.output_dir
872+
873+
# When using output_dir with aux flags, only generate those files (not main)
874+
has_aux_flags = args.function_logic or args.with_schema
875+
generate_main = not has_aux_flags or use_stdout
876+
877+
# Build output paths based on output_dir
878+
ext_map = {
879+
'markdown': 'md',
880+
'compact': 'txt',
881+
'json': 'json',
882+
'yaml': 'yaml',
883+
'hybrid': 'yaml',
884+
'csv': 'csv',
885+
'gherkin': 'feature',
886+
'toon': 'toon',
887+
'logicml': 'logicml',
888+
}
889+
ext = ext_map.get(args.format, args.format)
890+
main_output_path = None
891+
if output_dir and generate_main:
892+
main_output_path = os.path.join(output_dir, f"{project_name}.{ext}")
876893

877894
# Generate output
878895
if args.verbose:
@@ -913,16 +930,19 @@ def _maybe_print_pretty_help() -> bool:
913930
schema = generator.generate_schema('hybrid')
914931
else:
915932
schema = generator.generate_schema('compact' if compact else 'full')
916-
effective_output = args.output or default_output
917-
base_name = os.path.splitext(effective_output)[0] if effective_output else project_name
918-
schema_path = f"{base_name}.yaml-schema.json"
919-
parent_dir = os.path.dirname(schema_path)
920-
if parent_dir:
921-
os.makedirs(parent_dir, exist_ok=True)
922-
with open(schema_path, 'w', encoding='utf-8') as f:
923-
f.write(schema)
924-
if args.verbose:
925-
log.success(f"Schema written to: {schema_path}")
933+
934+
if use_stdout:
935+
# Write to stdout with section marker
936+
print(f"\n=== SCHEMA ===")
937+
print(schema)
938+
elif output_dir:
939+
# Write to file in output directory
940+
schema_path = os.path.join(output_dir, f"{project_name}.yaml-schema.json")
941+
os.makedirs(output_dir, exist_ok=True)
942+
with open(schema_path, 'w', encoding='utf-8') as f:
943+
f.write(schema)
944+
if args.verbose:
945+
log.success(f"Schema written to: {schema_path}")
926946

927947
elif args.format == 'toon':
928948
generator = TOONGenerator()
@@ -947,16 +967,19 @@ def _maybe_print_pretty_help() -> bool:
947967
if args.with_schema:
948968
schema_type = 'ultra_compact' if use_ultra_compact else 'standard'
949969
schema = generator.generate_schema(schema_type)
950-
effective_output = args.output or default_output
951-
base_name = os.path.splitext(effective_output)[0] if effective_output else project_name
952-
schema_path = f"{base_name}.toon-schema.json"
953-
parent_dir = os.path.dirname(schema_path)
954-
if parent_dir:
955-
os.makedirs(parent_dir, exist_ok=True)
956-
with open(schema_path, 'w', encoding='utf-8') as f:
957-
f.write(schema)
958-
if args.verbose:
959-
log.success(f"Schema written to: {schema_path}")
970+
971+
if use_stdout:
972+
# Write to stdout with section marker
973+
print(f"\n=== SCHEMA ===")
974+
print(schema)
975+
elif output_dir:
976+
# Write to file in output directory
977+
schema_path = os.path.join(output_dir, f"{project_name}.toon-schema.json")
978+
os.makedirs(output_dir, exist_ok=True)
979+
with open(schema_path, 'w', encoding='utf-8') as f:
980+
f.write(schema)
981+
if args.verbose:
982+
log.success(f"Schema written to: {schema_path}")
960983

961984
elif args.format == 'logicml':
962985
generator = LogicMLGenerator()
@@ -970,21 +993,16 @@ def _maybe_print_pretty_help() -> bool:
970993
if args.function_logic:
971994
logic_gen = FunctionLogicGenerator()
972995

973-
# Auto-generate path if 'auto' was specified (--function-logic without argument)
996+
# Determine path for function logic file
974997
if args.function_logic == 'auto':
975-
effective_output = args.output or default_output
976-
if effective_output:
977-
# Derive from output file: project.c2l.yaml -> project.functions.yaml
978-
base = effective_output.rsplit('.', 1)[0]
979-
if base.endswith('.c2l'):
980-
base = base[:-4]
981-
ext = effective_output.rsplit('.', 1)[-1] if '.' in effective_output else 'logicml'
982-
logic_path = f"{base}.functions.{ext}"
998+
if output_dir:
999+
# Use output directory with project name
1000+
logic_ext = ext_map.get(args.format, 'logicml')
1001+
logic_path = os.path.join(output_dir, f"{project_name}.functions.{logic_ext}")
9831002
else:
984-
# Default path based on format using project name from config
985-
ext_map = {'json': 'json', 'yaml': 'yaml', 'toon': 'toon'}
986-
ext = ext_map.get(args.format, 'logicml')
987-
logic_path = f"{project_name}.functions.{ext}"
1003+
# No output dir - use project name in current directory
1004+
logic_ext = ext_map.get(args.format, 'logicml')
1005+
logic_path = f"{project_name}.functions.{logic_ext}"
9881006
else:
9891007
logic_path = str(args.function_logic)
9901008

@@ -998,13 +1016,17 @@ def _maybe_print_pretty_help() -> bool:
9981016
else:
9991017
logic_out = logic_gen.generate(project, detail=args.detail)
10001018

1001-
parent_dir = os.path.dirname(logic_path)
1002-
if parent_dir:
1003-
os.makedirs(parent_dir, exist_ok=True)
1004-
with open(logic_path, 'w', encoding='utf-8') as f:
1005-
f.write(logic_out)
1006-
if args.verbose:
1007-
log.success(f"Function logic written to: {logic_path}")
1019+
if use_stdout:
1020+
# Write to stdout with section marker
1021+
print(f"\n=== FUNCTION_LOGIC ===")
1022+
print(logic_out)
1023+
elif output_dir:
1024+
# Write to file in output directory
1025+
os.makedirs(output_dir, exist_ok=True)
1026+
with open(logic_path, 'w', encoding='utf-8') as f:
1027+
f.write(logic_out)
1028+
if args.verbose:
1029+
log.success(f"Function logic written to: {logic_path}")
10081030

10091031
gen_time = time.time() - gen_start
10101032

@@ -1015,25 +1037,26 @@ def _maybe_print_pretty_help() -> bool:
10151037
log.stats("Size", f"{output_size:,} chars (~{tokens_approx:,} tokens)")
10161038
log.stats("Lines", output.count('\n') + 1)
10171039

1018-
# Write output
1019-
if args.output:
1020-
parent_dir = os.path.dirname(args.output)
1021-
if parent_dir:
1022-
os.makedirs(parent_dir, exist_ok=True)
1023-
with open(args.output, 'w', encoding='utf-8') as f:
1024-
f.write(output)
1025-
if args.verbose:
1026-
log.success(f"Output written to: {args.output}")
1027-
else:
1028-
if not args.quiet:
1029-
try:
1030-
print(output, flush=True)
1031-
except BrokenPipeError:
1040+
# Write main output (only if generate_main is True)
1041+
if generate_main:
1042+
if output_dir:
1043+
# Write to file in output directory
1044+
os.makedirs(output_dir, exist_ok=True)
1045+
with open(main_output_path, 'w', encoding='utf-8') as f:
1046+
f.write(output)
1047+
if args.verbose:
1048+
log.success(f"Output written to: {main_output_path}")
1049+
else:
1050+
# Write to stdout
1051+
if not args.quiet:
10321052
try:
1033-
sys.stdout.close()
1034-
except Exception:
1035-
pass
1036-
os._exit(0)
1053+
print(output, flush=True)
1054+
except BrokenPipeError:
1055+
try:
1056+
sys.stdout.close()
1057+
except Exception:
1058+
pass
1059+
os._exit(0)
10371060

10381061
# Final summary
10391062
if args.verbose:

code2logic/project_comparison.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Project Comparison Analysis
2+
3+
Generated on: $(date)
4+
5+
## Project Statistics
6+
7+
| Project | Modules | Functions | Total Items | Main Language |
8+
|---------|---------|-----------|-------------|---------------|
9+
10+
## Detailed Analysis
11+
12+
### Projects by Size (Total Items)
13+
14+
15+
### Projects by Language Distribution
16+

0 commit comments

Comments
 (0)