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.
- {code2logic-1.0.30 → code2logic-1.0.35}/PKG-INFO +17 -14
- {code2logic-1.0.30 → code2logic-1.0.35}/README.md +9 -1
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/__init__.py +1 -1
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/cli.py +114 -58
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/config.py +8 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/generators.py +23 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/parsers.py +122 -24
- code2logic-1.0.35/code2logic/project_comparison.md +16 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/pyproject.toml +8 -18
- {code2logic-1.0.30 → code2logic-1.0.35}/LICENSE +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/__main__.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/adaptive.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/analyzer.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/base.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/benchmark.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/benchmarks/__init__.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/benchmarks/common.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/benchmarks/results.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/benchmarks/runner.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/chunked_reproduction.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/code_review.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/core/__init__.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/dependency.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/errors.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/file_formats.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/formats/__init__.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/function_logic.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/gherkin.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/integrations/__init__.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/intent.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/llm/__init__.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/llm.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/llm_clients.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/llm_clients_new.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/llm_profiler.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/logicml.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/markdown_format.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/mcp_server.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/metrics.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/models.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/project_reproducer.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/prompts.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/py.typed +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/quality.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/refactor.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/reproducer.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/reproduction.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/schemas/__init__.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/schemas/json_schema.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/schemas/logicml_schema.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/schemas/markdown_schema.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/schemas/yaml_schema.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/shared_utils.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/similarity.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/terminal.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/tools/__init__.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/toon_format.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/universal.py +0 -0
- {code2logic-1.0.30 → code2logic-1.0.35}/code2logic/utils.py +0 -0
|
@@ -1,30 +1,25 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: code2logic
|
|
3
|
-
Version: 1.0.
|
|
4
|
-
Summary:
|
|
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:
|
|
9
|
+
Author-email: tom@sapletta.com
|
|
9
10
|
Maintainer: Softreck
|
|
10
|
-
Maintainer-email:
|
|
11
|
+
Maintainer-email: tom@sapletta.com
|
|
11
12
|
Requires-Python: >=3.9,<4.0
|
|
12
|
-
Classifier: Development Status ::
|
|
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:
|
|
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
|
[](https://badge.fury.io/py/code2logic)
|
|
59
54
|
[](https://www.python.org/downloads/)
|
|
60
|
-
[](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
|
[](https://badge.fury.io/py/code2logic)
|
|
8
8
|
[](https://www.python.org/downloads/)
|
|
9
|
-
[](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)
|
|
@@ -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
|
-
|
|
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
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
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
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
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
|
-
#
|
|
996
|
+
# Determine path for function logic file
|
|
942
997
|
if args.function_logic == 'auto':
|
|
943
|
-
if
|
|
944
|
-
#
|
|
945
|
-
|
|
946
|
-
|
|
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
|
-
#
|
|
952
|
-
|
|
953
|
-
|
|
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
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
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
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
os.makedirs(
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
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
|
-
|
|
1001
|
-
except
|
|
1002
|
-
|
|
1003
|
-
|
|
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
|
-
|
|
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+)?
|
|
2130
|
+
for m in re.finditer(r'^(?:pub\s+)?type\s+(\w+)\s*=', content, re.MULTILINE):
|
|
2062
2131
|
name = m.group(1)
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
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.
|
|
8
|
-
description = "
|
|
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 = [
|
|
12
|
-
|
|
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 ::
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|