code2logic 1.0.30__tar.gz → 1.0.35__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. {code2logic-1.0.30 → code2logic-1.0.35}/PKG-INFO +17 -14
  2. {code2logic-1.0.30 → code2logic-1.0.35}/README.md +9 -1
  3. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/__init__.py +1 -1
  4. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/cli.py +114 -58
  5. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/config.py +8 -0
  6. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/generators.py +23 -0
  7. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/parsers.py +122 -24
  8. code2logic-1.0.35/code2logic/project_comparison.md +16 -0
  9. {code2logic-1.0.30 → code2logic-1.0.35}/pyproject.toml +8 -18
  10. {code2logic-1.0.30 → code2logic-1.0.35}/LICENSE +0 -0
  11. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/__main__.py +0 -0
  12. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/adaptive.py +0 -0
  13. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/analyzer.py +0 -0
  14. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/base.py +0 -0
  15. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/benchmark.py +0 -0
  16. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/benchmarks/__init__.py +0 -0
  17. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/benchmarks/common.py +0 -0
  18. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/benchmarks/results.py +0 -0
  19. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/benchmarks/runner.py +0 -0
  20. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/chunked_reproduction.py +0 -0
  21. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/code_review.py +0 -0
  22. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/core/__init__.py +0 -0
  23. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/dependency.py +0 -0
  24. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/errors.py +0 -0
  25. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/file_formats.py +0 -0
  26. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/formats/__init__.py +0 -0
  27. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/function_logic.py +0 -0
  28. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/gherkin.py +0 -0
  29. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/integrations/__init__.py +0 -0
  30. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/intent.py +0 -0
  31. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/llm/__init__.py +0 -0
  32. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/llm.py +0 -0
  33. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/llm_clients.py +0 -0
  34. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/llm_clients_new.py +0 -0
  35. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/llm_profiler.py +0 -0
  36. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/logicml.py +0 -0
  37. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/markdown_format.py +0 -0
  38. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/mcp_server.py +0 -0
  39. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/metrics.py +0 -0
  40. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/models.py +0 -0
  41. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/project_reproducer.py +0 -0
  42. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/prompts.py +0 -0
  43. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/py.typed +0 -0
  44. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/quality.py +0 -0
  45. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/refactor.py +0 -0
  46. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/reproducer.py +0 -0
  47. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/reproduction.py +0 -0
  48. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/schemas/__init__.py +0 -0
  49. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/schemas/json_schema.py +0 -0
  50. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/schemas/logicml_schema.py +0 -0
  51. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/schemas/markdown_schema.py +0 -0
  52. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/schemas/yaml_schema.py +0 -0
  53. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/shared_utils.py +0 -0
  54. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/similarity.py +0 -0
  55. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/terminal.py +0 -0
  56. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/tools/__init__.py +0 -0
  57. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/toon_format.py +0 -0
  58. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/universal.py +0 -0
  59. {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/utils.py +0 -0
@@ -1,30 +1,25 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: code2logic
3
- Version: 1.0.30
4
- Summary: Convert source code to logical representation for LLM analysis
3
+ Version: 1.0.35
4
+ Summary: Code2Logic - Source code to logical representation converter for LLM analysis, featuring Tree-sitter parsing, dependency graph analysis, and multi-language support.
5
5
  License: Apache-2.0
6
+ License-File: LICENSE
6
7
  Keywords: code-analysis,llm,ast,static-analysis,tree-sitter,code-understanding,documentation,dependency-graph,nlp
7
8
  Author: Softreck
8
- Author-email: info@softreck.dev
9
+ Author-email: tom@sapletta.com
9
10
  Maintainer: Softreck
10
- Maintainer-email: info@softreck.dev
11
+ Maintainer-email: tom@sapletta.com
11
12
  Requires-Python: >=3.9,<4.0
12
- Classifier: Development Status :: 4 - Beta
13
- Classifier: Environment :: Console
13
+ Classifier: Development Status :: 3 - Alpha
14
14
  Classifier: Intended Audience :: Developers
15
15
  Classifier: License :: OSI Approved :: Apache Software License
16
- Classifier: Operating System :: OS Independent
17
16
  Classifier: Programming Language :: Python :: 3
18
17
  Classifier: Programming Language :: Python :: 3.9
19
18
  Classifier: Programming Language :: Python :: 3.10
20
19
  Classifier: Programming Language :: Python :: 3.11
21
20
  Classifier: Programming Language :: Python :: 3.12
22
21
  Classifier: Programming Language :: Python :: 3.13
23
- Classifier: Topic :: Software Development :: Documentation
24
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
- Classifier: Topic :: Software Development :: Quality Assurance
26
- Classifier: Topic :: Text Processing :: Linguistic
27
- Classifier: Typing :: Typed
22
+ Classifier: Programming Language :: Python :: 3.14
28
23
  Provides-Extra: full
29
24
  Provides-Extra: graph
30
25
  Provides-Extra: llm
@@ -57,7 +52,7 @@ Description-Content-Type: text/markdown
57
52
 
58
53
  [![PyPI version](https://badge.fury.io/py/code2logic.svg)](https://badge.fury.io/py/code2logic)
59
54
  [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
60
- [![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-yellow.svg)](https://www.apache.org/licenses/LICENSE-2.0)
55
+ [![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
61
56
 
62
57
 
63
58
  **Convert source code to logical representation for LLM analysis.**
@@ -561,3 +556,11 @@ python -m logic2code out/code2logic/project.c2l.yaml -o out/logic2code/generated
561
556
  - [GitHub](https://github.com/wronai/code2logic)
562
557
  - [Issues](https://github.com/wronai/code2logic/issues)
563
558
 
559
+ ## License
560
+
561
+ Apache License 2.0 - see [LICENSE](LICENSE) for details.
562
+
563
+ ## Author
564
+
565
+ Created by **Tom Sapletta** - [tom@sapletta.com](mailto:tom@sapletta.com)
566
+
@@ -6,7 +6,7 @@
6
6
 
7
7
  [![PyPI version](https://badge.fury.io/py/code2logic.svg)](https://badge.fury.io/py/code2logic)
8
8
  [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
9
- [![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-yellow.svg)](https://www.apache.org/licenses/LICENSE-2.0)
9
+ [![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
10
10
 
11
11
 
12
12
  **Convert source code to logical representation for LLM analysis.**
@@ -509,3 +509,11 @@ python -m logic2code out/code2logic/project.c2l.yaml -o out/logic2code/generated
509
509
  - [PyPI](https://pypi.org/project/code2logic/)
510
510
  - [GitHub](https://github.com/wronai/code2logic)
511
511
  - [Issues](https://github.com/wronai/code2logic/issues)
512
+
513
+ ## License
514
+
515
+ Apache License 2.0 - see [LICENSE](LICENSE) for details.
516
+
517
+ ## Author
518
+
519
+ Created by **Tom Sapletta** - [tom@sapletta.com](mailto:tom@sapletta.com)
@@ -18,7 +18,7 @@ Example:
18
18
  >>> print(output)
19
19
  """
20
20
 
21
- __version__ = "1.0.30"
21
+ __version__ = "1.0.35"
22
22
  __author__ = "Softreck"
23
23
  __email__ = "info@softreck.dev"
24
24
  __license__ = "MIT"
@@ -605,8 +605,14 @@ code2logic [path] [options]
605
605
  help='Detail level - columns to include (default: standard)'
606
606
  )
607
607
  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'
611
+ )
612
+ parser.add_argument(
613
+ '--name',
614
+ dest='project_name',
615
+ help='Project name for output files (default: from CODE2LOGIC_PROJECT_NAME env or "project"). Used for auto-generating output, schema, and function-logic file names.'
610
616
  )
611
617
  parser.add_argument(
612
618
  '--function-logic',
@@ -638,7 +644,12 @@ code2logic [path] [options]
638
644
  parser.add_argument(
639
645
  '--with-schema',
640
646
  action='store_true',
641
- 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.'
642
653
  )
643
654
  parser.add_argument(
644
655
  '--no-install',
@@ -725,6 +736,7 @@ code2logic [path] [options]
725
736
 
726
737
  # Import after potential installation
727
738
  from .analyzer import ProjectAnalyzer, get_library_status
739
+ from .config import Config
728
740
  from .function_logic import FunctionLogicGenerator
729
741
  from .generators import (
730
742
  CSVGenerator,
@@ -736,6 +748,9 @@ code2logic [path] [options]
736
748
  from .logicml import LogicMLGenerator
737
749
  from .toon_format import TOONGenerator
738
750
 
751
+ # Load config to get project name
752
+ config = Config()
753
+
739
754
  # Status check
740
755
  if args.status:
741
756
  status = get_library_status()
@@ -844,6 +859,38 @@ code2logic [path] [options]
844
859
 
845
860
  log.separator()
846
861
 
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}")
893
+
847
894
  # Generate output
848
895
  if args.verbose:
849
896
  log.step(f"Generating {args.format} output (detail: {args.detail})")
@@ -883,15 +930,19 @@ code2logic [path] [options]
883
930
  schema = generator.generate_schema('hybrid')
884
931
  else:
885
932
  schema = generator.generate_schema('compact' if compact else 'full')
886
- base_name = os.path.splitext(args.output)[0] if args.output else 'output'
887
- schema_path = f"{base_name}.yaml-schema.json"
888
- parent_dir = os.path.dirname(schema_path)
889
- if parent_dir:
890
- os.makedirs(parent_dir, exist_ok=True)
891
- with open(schema_path, 'w', encoding='utf-8') as f:
892
- f.write(schema)
893
- if args.verbose:
894
- 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}")
895
946
 
896
947
  elif args.format == 'toon':
897
948
  generator = TOONGenerator()
@@ -916,15 +967,19 @@ code2logic [path] [options]
916
967
  if args.with_schema:
917
968
  schema_type = 'ultra_compact' if use_ultra_compact else 'standard'
918
969
  schema = generator.generate_schema(schema_type)
919
- base_name = os.path.splitext(args.output)[0] if args.output else 'output'
920
- schema_path = f"{base_name}.toon-schema.json"
921
- parent_dir = os.path.dirname(schema_path)
922
- if parent_dir:
923
- os.makedirs(parent_dir, exist_ok=True)
924
- with open(schema_path, 'w', encoding='utf-8') as f:
925
- f.write(schema)
926
- if args.verbose:
927
- 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}")
928
983
 
929
984
  elif args.format == 'logicml':
930
985
  generator = LogicMLGenerator()
@@ -938,20 +993,16 @@ code2logic [path] [options]
938
993
  if args.function_logic:
939
994
  logic_gen = FunctionLogicGenerator()
940
995
 
941
- # Auto-generate path if 'auto' was specified (--function-logic without argument)
996
+ # Determine path for function logic file
942
997
  if args.function_logic == 'auto':
943
- if args.output:
944
- # Derive from output file: project.c2l.yaml -> project.functions.yaml
945
- base = args.output.rsplit('.', 1)[0]
946
- if base.endswith('.c2l'):
947
- base = base[:-4]
948
- ext = args.output.rsplit('.', 1)[-1] if '.' in args.output else 'logicml'
949
- 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}")
950
1002
  else:
951
- # Default path based on format
952
- ext_map = {'json': 'json', 'yaml': 'yaml', 'toon': 'toon'}
953
- ext = ext_map.get(args.format, 'logicml')
954
- logic_path = f"project.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}"
955
1006
  else:
956
1007
  logic_path = str(args.function_logic)
957
1008
 
@@ -965,13 +1016,17 @@ code2logic [path] [options]
965
1016
  else:
966
1017
  logic_out = logic_gen.generate(project, detail=args.detail)
967
1018
 
968
- parent_dir = os.path.dirname(logic_path)
969
- if parent_dir:
970
- os.makedirs(parent_dir, exist_ok=True)
971
- with open(logic_path, 'w', encoding='utf-8') as f:
972
- f.write(logic_out)
973
- if args.verbose:
974
- 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}")
975
1030
 
976
1031
  gen_time = time.time() - gen_start
977
1032
 
@@ -982,25 +1037,26 @@ code2logic [path] [options]
982
1037
  log.stats("Size", f"{output_size:,} chars (~{tokens_approx:,} tokens)")
983
1038
  log.stats("Lines", output.count('\n') + 1)
984
1039
 
985
- # Write output
986
- if args.output:
987
- parent_dir = os.path.dirname(args.output)
988
- if parent_dir:
989
- os.makedirs(parent_dir, exist_ok=True)
990
- with open(args.output, 'w', encoding='utf-8') as f:
991
- f.write(output)
992
- if args.verbose:
993
- log.success(f"Output written to: {args.output}")
994
- else:
995
- if not args.quiet:
996
- try:
997
- print(output, flush=True)
998
- 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:
999
1052
  try:
1000
- sys.stdout.close()
1001
- except Exception:
1002
- pass
1003
- 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)
1004
1060
 
1005
1061
  # Final summary
1006
1062
  if args.verbose:
@@ -153,6 +153,14 @@ class Config:
153
153
  """Check if verbose mode is enabled."""
154
154
  return os.environ.get('CODE2LOGIC_VERBOSE', '').lower() in ('true', '1', 'yes')
155
155
 
156
+ def get_project_name(self) -> str:
157
+ """Get default project name for output files.
158
+
159
+ Returns:
160
+ Project name (default: 'project')
161
+ """
162
+ return os.environ.get('CODE2LOGIC_PROJECT_NAME', 'project')
163
+
156
164
  def get_cache_dir(self) -> Path:
157
165
  """Get cache directory path."""
158
166
  cache_dir = os.environ.get('CODE2LOGIC_CACHE_DIR', '~/.code2logic/cache')
@@ -329,6 +329,18 @@ class CompactGenerator:
329
329
  if hubs:
330
330
  lines.append(f"HUBS: {' '.join(hubs[:5])}")
331
331
 
332
+ # Dependency edges (compact call flow for LLM)
333
+ deps = {k: v for k, v in project.dependency_graph.items() if v}
334
+ if deps:
335
+ lines.append("")
336
+ lines.append("DEPS:")
337
+ for src, targets in sorted(deps.items())[:20]:
338
+ short_src = Path(src).stem
339
+ short_targets = ','.join(Path(t).stem for t in targets[:5])
340
+ if len(targets) > 5:
341
+ short_targets += f"+{len(targets)-5}"
342
+ lines.append(f" {short_src}->{short_targets}")
343
+
332
344
  lines.append("")
333
345
 
334
346
  curr_dir = None
@@ -350,6 +362,17 @@ class CompactGenerator:
350
362
  if fn_s:
351
363
  parts.append(f"F:{fn_s}")
352
364
 
365
+ # Add method signatures with return types for classes
366
+ for c in m.classes[:3]:
367
+ pub_methods = [mt for mt in c.methods if not mt.is_private or mt.name == '__init__']
368
+ if pub_methods:
369
+ sigs = []
370
+ for mt in pub_methods[:6]:
371
+ p = ','.join(remove_self_from_params(mt.params or [])[:3])
372
+ ret = f"->{mt.return_type}" if mt.return_type else ""
373
+ sigs.append(f"{mt.name}({p}){ret}")
374
+ parts.append(f"{c.name}:{{{';'.join(sigs)}}}")
375
+
353
376
  content = ' | '.join(parts) if parts else '-'
354
377
  lines.append(f" {fn} ({m.lines_code}L) {content}")
355
378
 
@@ -2039,12 +2039,81 @@ class UniversalParser:
2039
2039
  constants: List[str] = []
2040
2040
  exports: List[str] = []
2041
2041
 
2042
+ def _get_or_create_class(name: str) -> ClassInfo:
2043
+ for c in classes:
2044
+ if c.name == name:
2045
+ return c
2046
+ c = ClassInfo(name=name)
2047
+ classes.append(c)
2048
+ return c
2049
+
2050
+ def _find_matching_brace(src: str, start_idx: int) -> int:
2051
+ depth = 0
2052
+ in_str = False
2053
+ str_ch = ''
2054
+ i = start_idx
2055
+ while i < len(src):
2056
+ ch = src[i]
2057
+ if in_str:
2058
+ if ch == '\\' and i + 1 < len(src):
2059
+ i += 2
2060
+ continue
2061
+ if ch == str_ch:
2062
+ in_str = False
2063
+ str_ch = ''
2064
+ i += 1
2065
+ continue
2066
+ if ch in ('\"', "'"):
2067
+ in_str = True
2068
+ str_ch = ch
2069
+ i += 1
2070
+ continue
2071
+ if ch == '{':
2072
+ depth += 1
2073
+ elif ch == '}':
2074
+ depth -= 1
2075
+ if depth == 0:
2076
+ return i
2077
+ i += 1
2078
+ return -1
2079
+
2080
+ def _parse_rust_fn(match: re.Match, *, is_method: bool) -> FunctionInfo:
2081
+ name = match.group('name')
2082
+ params_raw = (match.group('params') or '').strip()
2083
+ ret = (match.group('ret') or '').strip()
2084
+ sig = (match.group(0) or '')
2085
+
2086
+ params = [p.strip() for p in params_raw.split(',') if p.strip()]
2087
+ params = params[:8]
2088
+
2089
+ is_pub = bool(re.search(r'\bpub\b', sig))
2090
+ return FunctionInfo(
2091
+ name=name,
2092
+ params=params,
2093
+ return_type=ret,
2094
+ docstring=None,
2095
+ docstring_full=None,
2096
+ calls=[],
2097
+ raises=[],
2098
+ decorators=[],
2099
+ complexity=1,
2100
+ lines=1,
2101
+ is_async=False,
2102
+ is_static=False,
2103
+ is_classmethod=False,
2104
+ is_property=False,
2105
+ intent=self.intent_gen.generate(name),
2106
+ start_line=0,
2107
+ end_line=0,
2108
+ is_private=not is_pub,
2109
+ )
2110
+
2042
2111
  for m in re.finditer(r'^use\s+([^;]+);', content, re.MULTILINE):
2043
2112
  imports.append(m.group(1).strip())
2044
2113
 
2045
2114
  for m in re.finditer(r'^(?:pub\s+)?struct\s+(\w+)', content, re.MULTILINE):
2046
2115
  name = m.group(1)
2047
- classes.append(ClassInfo(name=name))
2116
+ _get_or_create_class(name)
2048
2117
  types.append(TypeInfo(name=name, kind='struct', definition=''))
2049
2118
  exports.append(name)
2050
2119
 
@@ -2058,35 +2127,64 @@ class UniversalParser:
2058
2127
  types.append(TypeInfo(name=name, kind='trait', definition=''))
2059
2128
  exports.append(name)
2060
2129
 
2061
- for m in re.finditer(r'^(?:pub\s+)?fn\s+(\w+)\s*\(([^)]*)\)\s*(?:->\s*([^\s{]+))?', content, re.MULTILINE):
2130
+ for m in re.finditer(r'^(?:pub\s+)?type\s+(\w+)\s*=', content, re.MULTILINE):
2062
2131
  name = m.group(1)
2063
- params = [p.strip() for p in (m.group(2) or '').split(',') if p.strip()][:8]
2064
- ret = (m.group(3) or '').strip()
2065
- functions.append(FunctionInfo(
2066
- name=name,
2067
- params=params,
2068
- return_type=ret,
2069
- docstring=None,
2070
- docstring_full=None,
2071
- calls=[],
2072
- raises=[],
2073
- decorators=[],
2074
- complexity=1,
2075
- lines=1,
2076
- is_async='async' in m.group(0),
2077
- is_static=False,
2078
- is_classmethod=False,
2079
- is_property=False,
2080
- intent=self.intent_gen.generate(name),
2081
- start_line=0,
2082
- end_line=0,
2083
- is_private=False,
2084
- ))
2132
+ types.append(TypeInfo(name=name, kind='type', definition=''))
2133
+ exports.append(name)
2134
+
2135
+ for m in re.finditer(r'^(?:pub\s+)?mod\s+(\w+)\s*;', content, re.MULTILINE):
2136
+ name = m.group(1)
2137
+ types.append(TypeInfo(name=name, kind='module', definition=''))
2085
2138
  exports.append(name)
2086
2139
 
2140
+ fn_pat = re.compile(
2141
+ r'^\s*(?P<sig>(?:pub(?:\([^)]*\))?\s+)?fn)\s+(?P<name>\w+)\s*\((?P<params>[^)]*)\)\s*(?:->\s*(?P<ret>[^\s{]+))?',
2142
+ re.MULTILINE,
2143
+ )
2144
+
2145
+ for m in fn_pat.finditer(content):
2146
+ functions.append(_parse_rust_fn(m, is_method=False))
2147
+ exports.append(m.group('name'))
2148
+
2149
+ impl_pat = re.compile(
2150
+ r'^impl\b[^\{]*\{',
2151
+ re.MULTILINE,
2152
+ )
2153
+
2154
+ for m in impl_pat.finditer(content):
2155
+ hdr = content[m.start():m.end()]
2156
+ type_name = ''
2157
+ m_for = re.search(r'\bfor\s+(\w+)\b', hdr)
2158
+ if m_for:
2159
+ type_name = m_for.group(1)
2160
+ else:
2161
+ m_type = re.search(r'^impl\b[^\{]*?\b(\w+)\b\s*\{', hdr)
2162
+ if m_type:
2163
+ type_name = m_type.group(1)
2164
+
2165
+ if not type_name:
2166
+ continue
2167
+
2168
+ open_idx = content.find('{', m.start(), m.end())
2169
+ if open_idx < 0:
2170
+ continue
2171
+ close_idx = _find_matching_brace(content, open_idx)
2172
+ if close_idx < 0:
2173
+ continue
2174
+
2175
+ body = content[open_idx + 1:close_idx]
2176
+ cls = _get_or_create_class(type_name)
2177
+ for fm in fn_pat.finditer(body):
2178
+ cls.methods.append(_parse_rust_fn(fm, is_method=True))
2179
+
2180
+ exports.append(type_name)
2181
+
2087
2182
  for m in re.finditer(r'^(?:pub\s+)?const\s+([A-Z][A-Z0-9_]*)\b', content, re.MULTILINE):
2088
2183
  constants.append(m.group(1))
2089
2184
 
2185
+ for m in re.finditer(r'^(?:pub\s+)?static\s+(?:mut\s+)?([A-Z][A-Z0-9_]*)\b', content, re.MULTILINE):
2186
+ constants.append(m.group(1))
2187
+
2090
2188
  lines = content.split('\n')
2091
2189
  return ModuleInfo(
2092
2190
  path=filepath,
@@ -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
+
@@ -4,12 +4,15 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [tool.poetry]
6
6
  name = "code2logic"
7
- version = "1.0.30"
8
- description = "Convert source code to logical representation for LLM analysis"
7
+ version = "1.0.35"
8
+ description = "Code2Logic - Source code to logical representation converter for LLM analysis, featuring Tree-sitter parsing, dependency graph analysis, and multi-language support."
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
11
- authors = ["Softreck <info@softreck.dev>"]
12
- maintainers = ["Softreck <info@softreck.dev>"]
11
+ authors = [
12
+ "Softreck <tom@sapletta.com>",
13
+ "Tom Sapletta <tom@sapletta.com>",
14
+ ]
15
+ maintainers = ["Softreck <tom@sapletta.com>"]
13
16
  keywords = [
14
17
  "code-analysis",
15
18
  "llm",
@@ -22,21 +25,8 @@ keywords = [
22
25
  "nlp",
23
26
  ]
24
27
  classifiers = [
25
- "Development Status :: 4 - Beta",
26
- "Environment :: Console",
28
+ "Development Status :: 3 - Alpha",
27
29
  "Intended Audience :: Developers",
28
- "License :: OSI Approved :: Apache Software License",
29
- "Operating System :: OS Independent",
30
- "Programming Language :: Python :: 3",
31
- "Programming Language :: Python :: 3.9",
32
- "Programming Language :: Python :: 3.10",
33
- "Programming Language :: Python :: 3.11",
34
- "Programming Language :: Python :: 3.12",
35
- "Topic :: Software Development :: Documentation",
36
- "Topic :: Software Development :: Libraries :: Python Modules",
37
- "Topic :: Software Development :: Quality Assurance",
38
- "Topic :: Text Processing :: Linguistic",
39
- "Typing :: Typed",
40
30
  ]
41
31
  packages = [{ include = "code2logic" }]
42
32
 
File without changes