reproto 0.0.8__py3-none-any.whl → 0.0.9__py3-none-any.whl
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.
- .git/COMMIT_EDITMSG +14 -1
- .git/FETCH_HEAD +2 -0
- .git/index +0 -0
- .git/logs/HEAD +4 -0
- .git/logs/refs/heads/iyue +4 -0
- .git/logs/refs/remotes/gitlab/iyue +4 -0
- .git/logs/refs/remotes/origin/iyue +4 -0
- .git/objects/29/4708b82b343e04e7a6685f5cd1287f3d17f7a9 +0 -0
- .git/objects/2c/fcddd7eebeb4eee0562dc384a79366bc7b04bb +0 -0
- .git/objects/34/192f0df5f5b694c881d086019eda349608d222 +0 -0
- .git/objects/3e/d953d5ed2c66722045f5e39d068696a0853b4f +0 -0
- .git/objects/44/4af3a0d68ba81976f67c7b638c9b0db4640709 +0 -0
- .git/objects/4b/43f5f577e1cdc35f8e06d178d8f5c892034061 +0 -0
- .git/objects/4c/16984be6ef7b24d01604821e9728cb579acd69 +0 -0
- .git/objects/56/79064a3138031d3a92d60aa629b82009fd0d1d +0 -0
- .git/objects/58/0d8f872aa869e42ba608f64888b1349f8b3ff4 +0 -0
- .git/objects/5a/11f9d70791e06a0570e01d3dcbbae39cde55db +0 -0
- .git/objects/5c/715dcb05e32db7a7a3b030f07524bdd8a56849 +0 -0
- .git/objects/5d/e2e9d536c2c0b78e8f9b3b61daa531a55332dc +0 -0
- .git/objects/66/7291e131d4769e7d028346a0cc7a0c05d500e5 +0 -0
- .git/objects/67/f54a4a3ede6749acc7c718ad97a86634215b5e +0 -0
- .git/objects/70/ded03ee69f30850c938a8129be308cb30772d9 +0 -0
- .git/objects/78/3e7e252c20e73e33615c703174766036546ff6 +3 -0
- .git/objects/94/ce01b61b90d1fb21d2d339fbeb22e821b6f413 +0 -0
- .git/objects/97/71dd4958faa94d3db229c129f6af35b508905a +0 -0
- .git/objects/9e/9978522bc8ca79133d7c11ef8ca3fe3c7eed0a +0 -0
- .git/objects/9f/b57064e0c53ed80af8507acaab718a1e80184e +0 -0
- .git/objects/b3/28dc445ee33220db9359370fc0089a77174101 +0 -0
- .git/objects/b3/d2b3037bede44e7e4d18dc99419f8c712c9c62 +0 -0
- .git/objects/c3/93db4841dbbb8acf54e9af12b6705c9f5ecde9 +0 -0
- .git/objects/c3/c8594874dd9ff9c21662fd06cac9b5baadbba0 +0 -0
- .git/objects/c9/a6ca8f8efee4a5632e9a655ced29f1b708f35e +0 -0
- .git/objects/c9/cdef9ab627b874ffe6455a47583a75bf16496d +0 -0
- .git/objects/df/f8f64cee2b97df7d86f73207c5e690f98f0208 +0 -0
- .git/objects/eb/528f06c622d54e411e9e05b3a200b4ac624a90 +0 -0
- .git/objects/fd/267d9de63212db235135fa6834f62572224fc6 +0 -0
- .git/refs/heads/iyue +1 -1
- .git/refs/remotes/gitlab/iyue +1 -1
- .git/refs/remotes/origin/iyue +1 -1
- .gitignore +4 -1
- ARCHITECTURE.md +146 -48
- README.md +145 -24
- core/bytecode_parser.py +2 -5
- core/info_decoder.py +9 -83
- core/reconstructor.py +91 -211
- generation/proto_generator.py +6 -61
- parsing/java_parser.py +219 -46
- pyproject.toml +1 -1
- reproto-0.0.9.dist-info/METADATA +295 -0
- {reproto-0.0.8.dist-info → reproto-0.0.9.dist-info}/RECORD +53 -22
- utils/type_utils.py +414 -0
- reproto-0.0.8.dist-info/METADATA +0 -174
- {reproto-0.0.8.dist-info → reproto-0.0.9.dist-info}/WHEEL +0 -0
- {reproto-0.0.8.dist-info → reproto-0.0.9.dist-info}/entry_points.txt +0 -0
core/reconstructor.py
CHANGED
@@ -12,7 +12,7 @@ Author: AI Assistant
|
|
12
12
|
import re
|
13
13
|
from pathlib import Path
|
14
14
|
from collections import deque
|
15
|
-
from typing import Set, Dict, List, Optional
|
15
|
+
from typing import Set, Dict, List, Optional, Tuple
|
16
16
|
|
17
17
|
from parsing.java_parser import JavaParser
|
18
18
|
from parsing.enum_parser import EnumParser
|
@@ -20,6 +20,8 @@ from core.info_decoder import InfoDecoder
|
|
20
20
|
from generation.proto_generator import ProtoGenerator
|
21
21
|
from models.message_definition import MessageDefinition, EnumDefinition, EnumValueDefinition
|
22
22
|
from utils.logger import get_logger
|
23
|
+
from utils.file_cache import get_file_cache
|
24
|
+
from utils.type_utils import type_mapper, naming_converter
|
23
25
|
|
24
26
|
|
25
27
|
class JavaSourceAnalyzer:
|
@@ -32,7 +34,6 @@ class JavaSourceAnalyzer:
|
|
32
34
|
# 初始化JavaParser用于字段类型解析
|
33
35
|
self.java_parser = JavaParser()
|
34
36
|
# 使用文件缓存系统优化I/O性能
|
35
|
-
from utils.file_cache import get_file_cache
|
36
37
|
self.file_cache = get_file_cache()
|
37
38
|
|
38
39
|
def set_current_class(self, class_name: str):
|
@@ -186,41 +187,9 @@ class JavaSourceAnalyzer:
|
|
186
187
|
java_type: Java类型名
|
187
188
|
|
188
189
|
Returns:
|
189
|
-
protobuf类型名
|
190
|
+
对应的protobuf类型名
|
190
191
|
"""
|
191
|
-
|
192
|
-
return 'string'
|
193
|
-
|
194
|
-
# 基础类型映射
|
195
|
-
basic_types = {
|
196
|
-
'int': 'int32',
|
197
|
-
'long': 'int64',
|
198
|
-
'float': 'float',
|
199
|
-
'double': 'double',
|
200
|
-
'boolean': 'bool',
|
201
|
-
'String': 'string',
|
202
|
-
'java.lang.String': 'string',
|
203
|
-
'java.lang.Integer': 'int32',
|
204
|
-
'java.lang.Long': 'int64',
|
205
|
-
'java.lang.Float': 'float',
|
206
|
-
'java.lang.Double': 'double',
|
207
|
-
'java.lang.Boolean': 'bool',
|
208
|
-
'byte[]': 'bytes',
|
209
|
-
'ByteString': 'bytes',
|
210
|
-
'com.google.protobuf.ByteString': 'bytes',
|
211
|
-
}
|
212
|
-
|
213
|
-
# 检查是否为基础类型
|
214
|
-
if java_type in basic_types:
|
215
|
-
return basic_types[java_type]
|
216
|
-
|
217
|
-
# 如果是完整的类名,提取简单类名
|
218
|
-
if '.' in java_type:
|
219
|
-
simple_name = java_type.split('.')[-1]
|
220
|
-
return simple_name
|
221
|
-
|
222
|
-
# 默认返回原类型名
|
223
|
-
return java_type
|
192
|
+
return type_mapper.java_to_proto_type(java_type)
|
224
193
|
|
225
194
|
def _get_type_from_setter(self, field_name: str) -> Optional[str]:
|
226
195
|
"""
|
@@ -351,9 +320,9 @@ class ProtoReconstructor:
|
|
351
320
|
self.java_source_analyzer = JavaSourceAnalyzer(sources_dir)
|
352
321
|
self.info_decoder.java_source_analyzer = self.java_source_analyzer
|
353
322
|
|
354
|
-
#
|
355
|
-
|
356
|
-
|
323
|
+
# 🚀 性能优化:移除未使用的索引系统,简化代码
|
324
|
+
# 索引系统在实际使用中被基础类型检测绕过,且构建耗时
|
325
|
+
# 改为使用直接的文件路径构造和智能包名推断
|
357
326
|
|
358
327
|
# 任务调度状态
|
359
328
|
self.processed_classes: Set[str] = set() # 已处理的类
|
@@ -397,8 +366,7 @@ class ProtoReconstructor:
|
|
397
366
|
file_cache = get_file_cache()
|
398
367
|
file_cache.print_stats()
|
399
368
|
|
400
|
-
#
|
401
|
-
self.type_index.print_stats()
|
369
|
+
# 🚀 性能优化:索引系统已移除,无需统计
|
402
370
|
|
403
371
|
# 6. 返回统计信息
|
404
372
|
# 报告未知类型统计
|
@@ -633,7 +601,7 @@ class ProtoReconstructor:
|
|
633
601
|
|
634
602
|
def _should_skip_class(self, class_name: str) -> bool:
|
635
603
|
"""
|
636
|
-
|
604
|
+
判断是否应该跳过某个类的处理
|
637
605
|
|
638
606
|
Args:
|
639
607
|
class_name: 类名
|
@@ -641,27 +609,15 @@ class ProtoReconstructor:
|
|
641
609
|
Returns:
|
642
610
|
是否应该跳过
|
643
611
|
"""
|
644
|
-
#
|
612
|
+
# 已处理过的类
|
645
613
|
if class_name in self.processed_classes:
|
646
614
|
return True
|
647
|
-
|
648
|
-
# 跳过基础类型(包括Java基础类型和常见的系统类型)
|
649
|
-
basic_types = {
|
650
|
-
# Java基础类型
|
651
|
-
'int', 'long', 'float', 'double', 'boolean', 'byte', 'short', 'char',
|
652
|
-
'String', 'Object', 'Integer', 'Long', 'Float', 'Double', 'Boolean',
|
653
|
-
'Byte', 'Short', 'Character',
|
654
|
-
# Java系统类型
|
655
|
-
'java.lang.String', 'java.lang.Integer', 'java.lang.Long',
|
656
|
-
'java.lang.Boolean', 'java.lang.Float', 'java.lang.Double',
|
657
|
-
'java.lang.Object', 'java.util.List', 'java.util.Map',
|
658
|
-
'com.google.protobuf.ByteString', 'com.google.protobuf.MessageLite'
|
659
|
-
}
|
660
615
|
|
661
|
-
|
616
|
+
# 使用TypeMapper判断基础类型和系统包
|
617
|
+
if type_mapper.is_java_basic_type(class_name) or type_mapper.is_system_package(class_name):
|
662
618
|
return True
|
663
619
|
|
664
|
-
#
|
620
|
+
# 跳过明显不是protobuf类的包
|
665
621
|
if self._is_system_or_internal_type(class_name):
|
666
622
|
return True
|
667
623
|
|
@@ -764,12 +720,7 @@ class ProtoReconstructor:
|
|
764
720
|
return None
|
765
721
|
|
766
722
|
# 检查是否为基础类型
|
767
|
-
|
768
|
-
'string', 'int32', 'int64', 'uint32', 'uint64', 'sint32', 'sint64',
|
769
|
-
'fixed32', 'fixed64', 'sfixed32', 'sfixed64', 'bool', 'float', 'double', 'bytes'
|
770
|
-
}
|
771
|
-
|
772
|
-
if type_name in basic_proto_types:
|
723
|
+
if type_mapper.is_basic_proto_type(type_name):
|
773
724
|
return None
|
774
725
|
|
775
726
|
# 如果已经是完整类名,直接返回
|
@@ -794,7 +745,7 @@ class ProtoReconstructor:
|
|
794
745
|
|
795
746
|
def _find_java_file(self, class_name: str) -> Optional[Path]:
|
796
747
|
"""
|
797
|
-
根据类名查找对应的Java
|
748
|
+
根据类名查找对应的Java文件(优化版本)
|
798
749
|
|
799
750
|
Args:
|
800
751
|
class_name: 完整的Java类名
|
@@ -802,6 +753,7 @@ class ProtoReconstructor:
|
|
802
753
|
Returns:
|
803
754
|
Java文件路径,如果找不到则返回None
|
804
755
|
"""
|
756
|
+
# 🚀 优化1:直接根据包名和类名构造文件路径(你的建议)
|
805
757
|
# 标准路径:com.example.Model -> com/example/Model.java
|
806
758
|
file_path = class_name.replace('.', '/') + '.java'
|
807
759
|
full_path = self.sources_dir / file_path
|
@@ -809,31 +761,43 @@ class ProtoReconstructor:
|
|
809
761
|
if full_path.exists():
|
810
762
|
return full_path
|
811
763
|
|
812
|
-
#
|
813
|
-
# com.example.Models$Inner$Deep -> com/example/Models$Inner$Deep.java
|
764
|
+
# 🚀 优化2:处理内部类,但避免全目录扫描
|
814
765
|
if '$' in class_name:
|
815
|
-
#
|
766
|
+
# 内部类处理:com.example.Models$Inner -> com/example/Models.java
|
816
767
|
last_dot_index = class_name.rfind('.')
|
817
768
|
if last_dot_index != -1:
|
818
|
-
package_path = class_name[:last_dot_index].replace('.', '/')
|
819
|
-
class_part = class_name[last_dot_index + 1:]
|
820
|
-
inner_class_file_path = f"{package_path}/{class_part}.java"
|
821
|
-
inner_class_full_path = self.sources_dir / inner_class_file_path
|
769
|
+
package_path = class_name[:last_dot_index].replace('.', '/')
|
770
|
+
class_part = class_name[last_dot_index + 1:]
|
822
771
|
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
772
|
+
# 提取外部类名($之前的部分)
|
773
|
+
outer_class = class_part.split('$')[0]
|
774
|
+
outer_class_file_path = f"{package_path}/{outer_class}.java"
|
775
|
+
outer_class_full_path = self.sources_dir / outer_class_file_path
|
776
|
+
|
777
|
+
if outer_class_full_path.exists():
|
778
|
+
return outer_class_full_path
|
779
|
+
|
780
|
+
# 🚀 优化3:简化文件查找逻辑,移除索引依赖
|
781
|
+
|
782
|
+
# 🚀 优化4:最后的备选方案 - 限制搜索范围
|
783
|
+
# 只在当前包及其父包中搜索,避免全目录扫描
|
784
|
+
package_parts = class_name.split('.')[:-1] # 获取包名部分
|
785
|
+
simple_name = class_name.split('.')[-1].split('$')[0] # 提取简单类名
|
786
|
+
|
787
|
+
# 构造搜索路径列表,限制搜索范围
|
788
|
+
search_paths = []
|
789
|
+
for i in range(len(package_parts), 0, -1):
|
790
|
+
package_path = '/'.join(package_parts[:i])
|
791
|
+
search_paths.append(self.sources_dir / package_path)
|
792
|
+
|
793
|
+
# 在限定范围内搜索
|
794
|
+
for search_path in search_paths:
|
795
|
+
if search_path.exists():
|
796
|
+
for java_file in search_path.rglob(f"{simple_name}.java"):
|
797
|
+
# 验证找到的文件是否匹配
|
798
|
+
relative_path = java_file.relative_to(self.sources_dir)
|
799
|
+
if relative_path.stem == simple_name:
|
800
|
+
return java_file
|
837
801
|
|
838
802
|
return None
|
839
803
|
|
@@ -857,7 +821,7 @@ class ProtoReconstructor:
|
|
857
821
|
return candidate
|
858
822
|
|
859
823
|
return None
|
860
|
-
|
824
|
+
|
861
825
|
def _generate_candidate_packages(self, current_package: str) -> List[str]:
|
862
826
|
"""
|
863
827
|
动态生成候选包名列表
|
@@ -930,7 +894,7 @@ class ProtoReconstructor:
|
|
930
894
|
|
931
895
|
def _find_best_matching_class(self, type_name: str, current_package: str, current_class: str = None) -> Optional[str]:
|
932
896
|
"""
|
933
|
-
|
897
|
+
查找最佳匹配的类(高性能版本)
|
934
898
|
|
935
899
|
Args:
|
936
900
|
type_name: 类型名(如 IdData)
|
@@ -940,27 +904,20 @@ class ProtoReconstructor:
|
|
940
904
|
Returns:
|
941
905
|
最佳匹配的完整类名
|
942
906
|
"""
|
943
|
-
#
|
944
|
-
if current_class:
|
945
|
-
actual_type = self._extract_actual_field_type(current_class, type_name)
|
946
|
-
if actual_type:
|
947
|
-
self.logger.info(f" 🔍 源码分析: {type_name} -> {actual_type}")
|
948
|
-
return actual_type
|
949
|
-
|
950
|
-
# 预检查:如果是基础字段名,可能不需要创建单独的类
|
907
|
+
# 🚀 性能优化:优先进行基础类型检测,避免不必要的文件IO
|
951
908
|
if self._is_basic_field_type(type_name, current_class):
|
952
|
-
self.logger.
|
909
|
+
self.logger.debug(f" 🔍 基础字段类型检测: {type_name} -> 跳过类匹配")
|
953
910
|
return None
|
954
911
|
|
955
|
-
#
|
956
|
-
|
957
|
-
|
958
|
-
if
|
959
|
-
self.logger.info(f" 🔍
|
960
|
-
return
|
912
|
+
# 🚀 性能优化:直接使用智能包名推断,避免索引开销
|
913
|
+
# 1. 首先尝试推断完整类名
|
914
|
+
inferred_name = self._infer_full_class_name(type_name, current_package)
|
915
|
+
if inferred_name:
|
916
|
+
self.logger.info(f" 🔍 包名推断: {type_name} -> {inferred_name}")
|
917
|
+
return inferred_name
|
961
918
|
|
962
|
-
#
|
963
|
-
self.logger.debug(f"
|
919
|
+
# 2. 如果推断失败,使用限制范围的目录搜索
|
920
|
+
self.logger.debug(f" 🔍 启用目录搜索: {type_name}")
|
964
921
|
return self._fallback_directory_search(type_name, current_package)
|
965
922
|
|
966
923
|
def _fallback_directory_search(self, type_name: str, current_package: str) -> Optional[str]:
|
@@ -1004,7 +961,7 @@ class ProtoReconstructor:
|
|
1004
961
|
|
1005
962
|
def _is_basic_field_type(self, type_name: str, current_class: str = None) -> bool:
|
1006
963
|
"""
|
1007
|
-
|
964
|
+
快速检查是否为基础字段类型(高性能版本)
|
1008
965
|
|
1009
966
|
Args:
|
1010
967
|
type_name: 类型名
|
@@ -1013,61 +970,11 @@ class ProtoReconstructor:
|
|
1013
970
|
Returns:
|
1014
971
|
是否为基础字段类型
|
1015
972
|
"""
|
1016
|
-
#
|
1017
|
-
|
1018
|
-
'int', 'long', 'float', 'double', 'boolean', 'byte', 'short', 'char',
|
1019
|
-
'String', 'Object', 'Integer', 'Long', 'Float', 'Double', 'Boolean',
|
1020
|
-
'Byte', 'Short', 'Character'
|
1021
|
-
}
|
1022
|
-
|
1023
|
-
if type_name in basic_java_types:
|
1024
|
-
return True
|
1025
|
-
|
1026
|
-
# 常见的基础字段名模式
|
1027
|
-
basic_patterns = [
|
1028
|
-
'tags', # tags_ 字段通常是 repeated string
|
1029
|
-
'ids', # ids_ 字段通常是 repeated string 或 repeated int64
|
1030
|
-
'values', # values_ 字段通常是基础类型数组
|
1031
|
-
'names', # names_ 字段通常是 repeated string
|
1032
|
-
'urls', # urls_ 字段通常是 repeated string
|
1033
|
-
'emails', # emails_ 字段通常是 repeated string
|
1034
|
-
]
|
1035
|
-
|
1036
|
-
type_lower = type_name.lower()
|
1037
|
-
|
1038
|
-
# 检查是否匹配基础模式
|
1039
|
-
if type_lower in basic_patterns:
|
1040
|
-
return True
|
1041
|
-
|
1042
|
-
# 如果有当前类,尝试从Java源码中验证
|
1043
|
-
if current_class:
|
1044
|
-
try:
|
1045
|
-
java_file = self._find_java_file(current_class)
|
1046
|
-
if java_file:
|
1047
|
-
content = java_file.read_text(encoding='utf-8')
|
1048
|
-
|
1049
|
-
# 查找对应的字段声明,检查是否为基础类型
|
1050
|
-
field_name_pattern = type_lower.rstrip('s') + 's?_' # tags -> tags?_
|
1051
|
-
import re
|
1052
|
-
|
1053
|
-
# 查找字段声明:private List<String> tags_; 或 private Internal.ProtobufList<String> tags_;
|
1054
|
-
patterns = [
|
1055
|
-
rf'private\s+(?:Internal\.)?ProtobufList<String>\s+{field_name_pattern}',
|
1056
|
-
rf'private\s+List<String>\s+{field_name_pattern}',
|
1057
|
-
rf'private\s+(?:Internal\.)?ProtobufList<Integer>\s+{field_name_pattern}',
|
1058
|
-
rf'private\s+List<Integer>\s+{field_name_pattern}',
|
1059
|
-
rf'private\s+(?:Internal\.)?ProtobufList<Long>\s+{field_name_pattern}',
|
1060
|
-
rf'private\s+List<Long>\s+{field_name_pattern}',
|
1061
|
-
]
|
1062
|
-
|
1063
|
-
for pattern in patterns:
|
1064
|
-
if re.search(pattern, content, re.IGNORECASE):
|
1065
|
-
return True
|
1066
|
-
|
1067
|
-
except Exception as e:
|
1068
|
-
self.logger.debug(f" 检查基础字段类型时出错: {e}")
|
973
|
+
# 🚀 性能优化:使用缓存的类型检查器,避免重复计算
|
974
|
+
from utils.type_utils import TypeMapper
|
1069
975
|
|
1070
|
-
|
976
|
+
# 直接使用统一的基础类型检查,无需额外逻辑
|
977
|
+
return TypeMapper.is_java_basic_type(type_name)
|
1071
978
|
|
1072
979
|
def _is_valid_package_for_matching(self, candidate_package: str, current_package: str) -> bool:
|
1073
980
|
"""
|
@@ -1138,7 +1045,7 @@ class ProtoReconstructor:
|
|
1138
1045
|
|
1139
1046
|
def _extract_actual_field_type(self, class_name: str, inferred_type: str) -> Optional[str]:
|
1140
1047
|
"""
|
1141
|
-
从Java
|
1048
|
+
从Java源码中提取字段的实际类型(优化版本)
|
1142
1049
|
|
1143
1050
|
Args:
|
1144
1051
|
class_name: 当前类的完整名称
|
@@ -1147,61 +1054,36 @@ class ProtoReconstructor:
|
|
1147
1054
|
Returns:
|
1148
1055
|
实际的完整类型名
|
1149
1056
|
"""
|
1150
|
-
#
|
1151
|
-
|
1152
|
-
'int', 'long', 'float', 'double', 'boolean', 'byte', 'short', 'char',
|
1153
|
-
'String', 'Object', 'Integer', 'Long', 'Float', 'Double', 'Boolean',
|
1154
|
-
'Byte', 'Short', 'Character'
|
1155
|
-
}
|
1057
|
+
# 🚀 优化:使用统一的类型检查器
|
1058
|
+
from utils.type_utils import TypeMapper
|
1156
1059
|
|
1157
|
-
if inferred_type
|
1060
|
+
if TypeMapper.is_java_basic_type(inferred_type):
|
1158
1061
|
self.logger.debug(f" 跳过基础类型: {inferred_type}")
|
1159
1062
|
return None
|
1160
1063
|
|
1064
|
+
# 🚀 性能优化:简化源码分析,避免复杂的正则表达式匹配
|
1065
|
+
# 对于大多数情况,索引系统已经能够提供足够准确的匹配
|
1066
|
+
# 这里只做最基本的检查,避免耗时的文件IO和正则匹配
|
1067
|
+
|
1161
1068
|
try:
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
# 使用缓存读取Java源码
|
1167
|
-
from utils.file_cache import get_file_cache
|
1168
|
-
file_cache = get_file_cache()
|
1169
|
-
content = file_cache.get_content(java_file)
|
1170
|
-
if not content:
|
1171
|
-
return None
|
1172
|
-
|
1173
|
-
# 查找字段声明模式:private SomeType fieldName_;
|
1174
|
-
# 我们要找的是以inferred_type结尾的类型声明
|
1175
|
-
import re
|
1069
|
+
# 使用索引系统进行快速查找,避免文件IO
|
1070
|
+
from utils.type_index import get_type_index
|
1071
|
+
type_index = get_type_index(self.sources_dir)
|
1176
1072
|
|
1177
|
-
#
|
1178
|
-
|
1179
|
-
|
1073
|
+
# 构造可能的完整类名
|
1074
|
+
package_name = '.'.join(class_name.split('.')[:-1])
|
1075
|
+
possible_full_name = f"{package_name}.{inferred_type}"
|
1180
1076
|
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
if actual_type_simple in basic_types:
|
1187
|
-
self.logger.debug(f" 匹配到基础类型,跳过: {actual_type_simple}")
|
1188
|
-
return None
|
1189
|
-
|
1190
|
-
# 检查是否有import语句
|
1191
|
-
import_pattern = rf'import\s+([^;]*\.{re.escape(actual_type_simple)});'
|
1192
|
-
import_matches = re.findall(import_pattern, content)
|
1193
|
-
|
1194
|
-
if import_matches:
|
1195
|
-
return import_matches[0] # 返回完整的包名.类名
|
1196
|
-
else:
|
1197
|
-
# 如果没有import,假设在同一个包中
|
1198
|
-
package_name = '.'.join(class_name.split('.')[:-1])
|
1199
|
-
return f"{package_name}.{actual_type_simple}"
|
1077
|
+
# 使用索引快速检查
|
1078
|
+
result = type_index.find_best_match(inferred_type, package_name)
|
1079
|
+
if result:
|
1080
|
+
self.logger.debug(f" 索引快速匹配: {inferred_type} -> {result}")
|
1081
|
+
return result
|
1200
1082
|
|
1201
1083
|
return None
|
1202
1084
|
|
1203
1085
|
except Exception as e:
|
1204
|
-
self.logger.
|
1086
|
+
self.logger.debug(f" ⚠️ 快速类型匹配失败: {e}")
|
1205
1087
|
return None
|
1206
1088
|
|
1207
1089
|
def _create_enum_definition(self, class_name: str, enum_values: List[tuple]) -> EnumDefinition:
|
@@ -1334,7 +1216,7 @@ class ProtoReconstructor:
|
|
1334
1216
|
@staticmethod
|
1335
1217
|
def _to_snake_case(camel_str: str) -> str:
|
1336
1218
|
"""
|
1337
|
-
将CamelCase转换为snake_case
|
1219
|
+
将CamelCase转换为snake_case(使用统一的命名转换器)
|
1338
1220
|
|
1339
1221
|
Args:
|
1340
1222
|
camel_str: 驼峰命名字符串
|
@@ -1342,8 +1224,6 @@ class ProtoReconstructor:
|
|
1342
1224
|
Returns:
|
1343
1225
|
蛇形命名字符串
|
1344
1226
|
"""
|
1345
|
-
#
|
1346
|
-
|
1347
|
-
|
1348
|
-
s2 = re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1)
|
1349
|
-
return s2.lower()
|
1227
|
+
# 🚀 优化:使用统一的命名转换器,避免重复实现
|
1228
|
+
from utils.type_utils import NamingConverter
|
1229
|
+
return NamingConverter.to_snake_case(camel_str)
|
generation/proto_generator.py
CHANGED
@@ -11,6 +11,7 @@ Author: AI Assistant
|
|
11
11
|
import re
|
12
12
|
from typing import Dict, Set, List, Union
|
13
13
|
from models.message_definition import MessageDefinition, FieldDefinition, EnumDefinition, EnumValueDefinition
|
14
|
+
from utils.type_utils import type_mapper, naming_converter, field_name_processor
|
14
15
|
|
15
16
|
|
16
17
|
class ProtoGenerator:
|
@@ -410,16 +411,7 @@ class ProtoGenerator:
|
|
410
411
|
Returns:
|
411
412
|
基础proto类型,如果不是基础类型则返回None
|
412
413
|
"""
|
413
|
-
|
414
|
-
'string': 'string',
|
415
|
-
'int32': 'int32',
|
416
|
-
'int64': 'int64',
|
417
|
-
'bool': 'bool',
|
418
|
-
'float': 'float',
|
419
|
-
'double': 'double',
|
420
|
-
'bytes': 'bytes',
|
421
|
-
}
|
422
|
-
return basic_type_mapping.get(type_name)
|
414
|
+
return type_mapper.java_to_proto_type(type_name) if type_mapper.is_java_basic_type(type_name) else None
|
423
415
|
|
424
416
|
def _generate_enum_type_name(self, field_name: str) -> str:
|
425
417
|
"""
|
@@ -431,33 +423,7 @@ class ProtoGenerator:
|
|
431
423
|
Returns:
|
432
424
|
枚举类型名(PascalCase)
|
433
425
|
"""
|
434
|
-
|
435
|
-
|
436
|
-
# 特殊字段名修正
|
437
|
-
field_name_corrections = {
|
438
|
-
'access': 'Access', # 修正拼写
|
439
|
-
}
|
440
|
-
|
441
|
-
if name in field_name_corrections:
|
442
|
-
return field_name_corrections[name]
|
443
|
-
|
444
|
-
# 处理常见的枚举后缀
|
445
|
-
suffix_mappings = {
|
446
|
-
'_type': 'Type',
|
447
|
-
'_status': 'Status',
|
448
|
-
'_code': 'Code'
|
449
|
-
}
|
450
|
-
|
451
|
-
for suffix, replacement in suffix_mappings.items():
|
452
|
-
if name.endswith(suffix):
|
453
|
-
name = name[:-len(suffix)] + replacement
|
454
|
-
break
|
455
|
-
|
456
|
-
# 处理复数形式:badges -> badge
|
457
|
-
if name.endswith('s') and len(name) > 1:
|
458
|
-
name = name[:-1]
|
459
|
-
|
460
|
-
return self._to_pascal_case(name)
|
426
|
+
return field_name_processor.generate_type_name_from_field(field_name, 'enum')
|
461
427
|
|
462
428
|
def _generate_message_type_name(self, field_name: str) -> str:
|
463
429
|
"""
|
@@ -469,23 +435,7 @@ class ProtoGenerator:
|
|
469
435
|
Returns:
|
470
436
|
消息类型名(PascalCase)
|
471
437
|
"""
|
472
|
-
|
473
|
-
|
474
|
-
# 处理常见的消息后缀
|
475
|
-
suffix_mappings = {
|
476
|
-
'_info': 'Info',
|
477
|
-
'_data': 'Data',
|
478
|
-
'_stats': 'Stats',
|
479
|
-
'_profile': 'Profile',
|
480
|
-
'_config': 'Config'
|
481
|
-
}
|
482
|
-
|
483
|
-
for suffix, replacement in suffix_mappings.items():
|
484
|
-
if name.endswith(suffix):
|
485
|
-
name = name[:-len(suffix)] + replacement
|
486
|
-
break
|
487
|
-
|
488
|
-
return self._to_pascal_case(name)
|
438
|
+
return field_name_processor.generate_type_name_from_field(field_name, 'message')
|
489
439
|
|
490
440
|
@staticmethod
|
491
441
|
def _to_pascal_case(snake_str: str) -> str:
|
@@ -498,8 +448,7 @@ class ProtoGenerator:
|
|
498
448
|
Returns:
|
499
449
|
帕斯卡命名字符串
|
500
450
|
"""
|
501
|
-
|
502
|
-
return ''.join(word.capitalize() for word in components)
|
451
|
+
return naming_converter.to_pascal_case(snake_str)
|
503
452
|
|
504
453
|
@staticmethod
|
505
454
|
def _to_snake_case(camel_str: str) -> str:
|
@@ -512,8 +461,4 @@ class ProtoGenerator:
|
|
512
461
|
Returns:
|
513
462
|
蛇形命名字符串
|
514
463
|
"""
|
515
|
-
|
516
|
-
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', camel_str)
|
517
|
-
# 处理小写字母后跟大写字母:userId -> user_Id
|
518
|
-
s2 = re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1)
|
519
|
-
return s2.lower()
|
464
|
+
return naming_converter.to_snake_case(camel_str)
|