reproto 0.0.7__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 +11 -26
- .git/FETCH_HEAD +2 -0
- .git/index +0 -0
- .git/logs/HEAD +6 -0
- .git/logs/refs/heads/iyue +6 -0
- .git/logs/refs/remotes/gitlab/iyue +6 -0
- .git/logs/refs/remotes/origin/iyue +6 -0
- .git/objects/15/eb3f02479e633439ec83c143e703f8448043a1 +0 -0
- .git/objects/26/1f67f3b731b32f6d77de9dd7be2d61e2a14ace +0 -0
- .git/objects/29/4708b82b343e04e7a6685f5cd1287f3d17f7a9 +0 -0
- .git/objects/2c/fcddd7eebeb4eee0562dc384a79366bc7b04bb +0 -0
- .git/objects/2e/2c1c42f5ac5d665cc672d3792078b756d9ab0e +0 -0
- .git/objects/34/192f0df5f5b694c881d086019eda349608d222 +0 -0
- .git/objects/35/8bace20b731ff1bbb256d2a0158dfc84720978 +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/4d/6d457bfabc4af842e5ddc2d56eb059d5dfdc9d +0 -0
- .git/objects/55/6723fdd4f525eed41c52fa80defca3f0c81c47 +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/65/a4f0ada7519f8b1e6a7c7e287541b8effde9fd +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/8d/44142ae2d6dbb59d4ebed8587bccd051e5766b +0 -0
- .git/objects/8d/4a5767bef0c342f1660526f9671c0944922c40 +0 -0
- .git/objects/94/ce01b61b90d1fb21d2d339fbeb22e821b6f413 +0 -0
- .git/objects/95/295a15779ebefd563ec777c3d3cced7e8d0209 +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/db/beedb30613f79ae3ff67df1428cf8ade223711 +0 -0
- .git/objects/df/f8f64cee2b97df7d86f73207c5e690f98f0208 +0 -0
- .git/objects/eb/528f06c622d54e411e9e05b3a200b4ac624a90 +0 -0
- .git/objects/fc/e15b9dbffd9f37b1f2d46944ee2d0394df6565 +2 -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 +122 -200
- generation/proto_generator.py +19 -68
- parsing/java_parser.py +219 -46
- pyproject.toml +1 -1
- reproto-0.0.9.dist-info/METADATA +295 -0
- reproto-0.0.9.dist-info/RECORD +132 -0
- utils/file_cache.py +165 -0
- utils/type_index.py +341 -0
- utils/type_utils.py +414 -0
- reproto-0.0.7.dist-info/METADATA +0 -174
- reproto-0.0.7.dist-info/RECORD +0 -87
- {reproto-0.0.7.dist-info → reproto-0.0.9.dist-info}/WHEEL +0 -0
- {reproto-0.0.7.dist-info → reproto-0.0.9.dist-info}/entry_points.txt +0 -0
utils/type_utils.py
ADDED
@@ -0,0 +1,414 @@
|
|
1
|
+
"""
|
2
|
+
类型工具类 - 统一处理类型映射和命名转换
|
3
|
+
"""
|
4
|
+
|
5
|
+
import re
|
6
|
+
from typing import Dict, Optional, Set
|
7
|
+
|
8
|
+
|
9
|
+
class TypeMapper:
|
10
|
+
"""统一的类型映射器"""
|
11
|
+
|
12
|
+
# Java基础类型到Protobuf类型的映射(基于语言规范,合理的硬编码)
|
13
|
+
_JAVA_TO_PROTO_MAPPING = {
|
14
|
+
# Java基础类型
|
15
|
+
'int': 'int32',
|
16
|
+
'long': 'int64',
|
17
|
+
'float': 'float',
|
18
|
+
'double': 'double',
|
19
|
+
'boolean': 'bool',
|
20
|
+
'byte': 'int32',
|
21
|
+
'short': 'int32',
|
22
|
+
'char': 'int32',
|
23
|
+
|
24
|
+
# Java包装类型
|
25
|
+
'Integer': 'int32',
|
26
|
+
'Long': 'int64',
|
27
|
+
'Boolean': 'bool',
|
28
|
+
'Float': 'float',
|
29
|
+
'Double': 'double',
|
30
|
+
'Byte': 'int32',
|
31
|
+
'Short': 'int32',
|
32
|
+
'Character': 'int32',
|
33
|
+
'String': 'string',
|
34
|
+
|
35
|
+
# Java完整类名
|
36
|
+
'java.lang.String': 'string',
|
37
|
+
'java.lang.Integer': 'int32',
|
38
|
+
'java.lang.Long': 'int64',
|
39
|
+
'java.lang.Float': 'float',
|
40
|
+
'java.lang.Double': 'double',
|
41
|
+
'java.lang.Boolean': 'bool',
|
42
|
+
'java.lang.Byte': 'int32',
|
43
|
+
'java.lang.Short': 'int32',
|
44
|
+
'java.lang.Character': 'int32',
|
45
|
+
|
46
|
+
# 特殊类型
|
47
|
+
'byte[]': 'bytes',
|
48
|
+
'ByteString': 'bytes',
|
49
|
+
'com.google.protobuf.ByteString': 'bytes',
|
50
|
+
|
51
|
+
# Google Protobuf Well-Known Types
|
52
|
+
'com.google.protobuf.Any': 'google.protobuf.Any',
|
53
|
+
'com.google.protobuf.Timestamp': 'google.protobuf.Timestamp',
|
54
|
+
'com.google.protobuf.Duration': 'google.protobuf.Duration',
|
55
|
+
'com.google.protobuf.Empty': 'google.protobuf.Empty',
|
56
|
+
'com.google.protobuf.Struct': 'google.protobuf.Struct',
|
57
|
+
'com.google.protobuf.Value': 'google.protobuf.Value',
|
58
|
+
'com.google.protobuf.ListValue': 'google.protobuf.ListValue',
|
59
|
+
'com.google.protobuf.FieldMask': 'google.protobuf.FieldMask',
|
60
|
+
|
61
|
+
# Protobuf Wrapper Types (现在已过时,但仍需支持)
|
62
|
+
'com.google.protobuf.BoolValue': 'google.protobuf.BoolValue',
|
63
|
+
'com.google.protobuf.Int32Value': 'google.protobuf.Int32Value',
|
64
|
+
'com.google.protobuf.Int64Value': 'google.protobuf.Int64Value',
|
65
|
+
'com.google.protobuf.UInt32Value': 'google.protobuf.UInt32Value',
|
66
|
+
'com.google.protobuf.UInt64Value': 'google.protobuf.UInt64Value',
|
67
|
+
'com.google.protobuf.FloatValue': 'google.protobuf.FloatValue',
|
68
|
+
'com.google.protobuf.DoubleValue': 'google.protobuf.DoubleValue',
|
69
|
+
'com.google.protobuf.StringValue': 'google.protobuf.StringValue',
|
70
|
+
'com.google.protobuf.BytesValue': 'google.protobuf.BytesValue',
|
71
|
+
}
|
72
|
+
|
73
|
+
# Protobuf标准类型集合
|
74
|
+
_PROTO_BASIC_TYPES = {
|
75
|
+
'string', 'int32', 'int64', 'uint32', 'uint64', 'sint32', 'sint64',
|
76
|
+
'fixed32', 'fixed64', 'sfixed32', 'sfixed64', 'bool', 'float', 'double', 'bytes'
|
77
|
+
}
|
78
|
+
|
79
|
+
# Java系统包前缀(用于过滤)
|
80
|
+
_SYSTEM_PACKAGES = {
|
81
|
+
'java.', 'javax.', 'android.', 'androidx.',
|
82
|
+
'kotlin.', 'kotlinx.', 'com.google.common.',
|
83
|
+
'org.apache.', 'org.junit.', 'junit.'
|
84
|
+
}
|
85
|
+
|
86
|
+
# 泛型容器类型模式(基于Protobuf实现规律,可配置)
|
87
|
+
_GENERIC_TYPE_PATTERNS = {
|
88
|
+
# Map类型模式
|
89
|
+
'map_patterns': ['MapFieldLite<', 'Map<', 'java.util.Map<'],
|
90
|
+
# List类型模式
|
91
|
+
'list_patterns': ['Internal.ProtobufList<', 'List<', 'ArrayList<',
|
92
|
+
'java.util.List<', 'java.util.ArrayList<'],
|
93
|
+
# 特殊列表类型
|
94
|
+
'special_lists': {'Internal.IntList': 'int32'}
|
95
|
+
}
|
96
|
+
|
97
|
+
@classmethod
|
98
|
+
def java_to_proto_type(cls, java_type: str) -> str:
|
99
|
+
"""
|
100
|
+
将Java类型转换为Protobuf类型
|
101
|
+
|
102
|
+
Args:
|
103
|
+
java_type: Java类型名
|
104
|
+
|
105
|
+
Returns:
|
106
|
+
对应的Protobuf类型名
|
107
|
+
"""
|
108
|
+
# 处理特殊列表类型(无泛型)
|
109
|
+
if java_type in cls._GENERIC_TYPE_PATTERNS['special_lists']:
|
110
|
+
return cls._GENERIC_TYPE_PATTERNS['special_lists'][java_type]
|
111
|
+
|
112
|
+
# 处理Map类型(通用模式匹配)
|
113
|
+
for pattern in cls._GENERIC_TYPE_PATTERNS['map_patterns']:
|
114
|
+
if java_type.startswith(pattern) and java_type.endswith('>'):
|
115
|
+
# 提取泛型参数
|
116
|
+
generic_part = java_type[len(pattern):-1]
|
117
|
+
|
118
|
+
# 解析键值类型,处理嵌套的尖括号
|
119
|
+
key_type, value_type = cls._parse_map_generic_types(generic_part)
|
120
|
+
|
121
|
+
# 递归转换键值类型
|
122
|
+
proto_key_type = cls.java_to_proto_type(key_type.strip())
|
123
|
+
proto_value_type = cls.java_to_proto_type(value_type.strip())
|
124
|
+
|
125
|
+
return f"map<{proto_key_type}, {proto_value_type}>"
|
126
|
+
|
127
|
+
# 处理List类型(通用模式匹配)
|
128
|
+
for pattern in cls._GENERIC_TYPE_PATTERNS['list_patterns']:
|
129
|
+
if java_type.startswith(pattern) and java_type.endswith('>'):
|
130
|
+
# 提取元素类型
|
131
|
+
start_pos = len(pattern)
|
132
|
+
element_type = java_type[start_pos:-1]
|
133
|
+
# 递归转换元素类型
|
134
|
+
return cls.java_to_proto_type(element_type.strip())
|
135
|
+
|
136
|
+
# 直接映射
|
137
|
+
if java_type in cls._JAVA_TO_PROTO_MAPPING:
|
138
|
+
return cls._JAVA_TO_PROTO_MAPPING[java_type]
|
139
|
+
|
140
|
+
# 如果是完整的类名,提取简单类名
|
141
|
+
if '.' in java_type:
|
142
|
+
return java_type.split('.')[-1]
|
143
|
+
|
144
|
+
# 默认返回原类型名
|
145
|
+
return java_type
|
146
|
+
|
147
|
+
@classmethod
|
148
|
+
def is_basic_proto_type(cls, type_name: str) -> bool:
|
149
|
+
"""检查是否为Protobuf基础类型"""
|
150
|
+
return type_name in cls._PROTO_BASIC_TYPES
|
151
|
+
|
152
|
+
@classmethod
|
153
|
+
def is_java_basic_type(cls, type_name: str) -> bool:
|
154
|
+
"""检查是否为Java基础类型"""
|
155
|
+
return type_name in cls._JAVA_TO_PROTO_MAPPING
|
156
|
+
|
157
|
+
@classmethod
|
158
|
+
def is_system_package(cls, class_name: str) -> bool:
|
159
|
+
"""检查是否为系统包"""
|
160
|
+
return any(class_name.startswith(pkg) for pkg in cls._SYSTEM_PACKAGES)
|
161
|
+
|
162
|
+
@classmethod
|
163
|
+
def is_well_known_type(cls, type_name: str) -> bool:
|
164
|
+
"""检查是否为Google Protobuf Well-Known Type"""
|
165
|
+
return type_name.startswith('google.protobuf.')
|
166
|
+
|
167
|
+
@classmethod
|
168
|
+
def get_required_imports(cls, proto_type: str) -> list:
|
169
|
+
"""获取类型所需的导入语句"""
|
170
|
+
imports = []
|
171
|
+
if cls.is_well_known_type(proto_type):
|
172
|
+
# 提取具体的well-known type名称
|
173
|
+
type_name = proto_type.split('.')[-1].lower()
|
174
|
+
imports.append(f"google/protobuf/{type_name}.proto")
|
175
|
+
return imports
|
176
|
+
|
177
|
+
@classmethod
|
178
|
+
def add_generic_pattern(cls, category: str, pattern: str):
|
179
|
+
"""动态添加泛型类型模式(用于扩展性)"""
|
180
|
+
if category in cls._GENERIC_TYPE_PATTERNS:
|
181
|
+
if isinstance(cls._GENERIC_TYPE_PATTERNS[category], list):
|
182
|
+
if pattern not in cls._GENERIC_TYPE_PATTERNS[category]:
|
183
|
+
cls._GENERIC_TYPE_PATTERNS[category].append(pattern)
|
184
|
+
|
185
|
+
@classmethod
|
186
|
+
def add_special_mapping(cls, java_type: str, proto_type: str):
|
187
|
+
"""动态添加特殊类型映射(用于扩展性)"""
|
188
|
+
cls._GENERIC_TYPE_PATTERNS['special_lists'][java_type] = proto_type
|
189
|
+
|
190
|
+
@classmethod
|
191
|
+
def _parse_map_generic_types(cls, generic_part: str) -> tuple:
|
192
|
+
"""
|
193
|
+
解析map泛型参数,处理嵌套的尖括号
|
194
|
+
|
195
|
+
Args:
|
196
|
+
generic_part: 泛型部分,如 "String, Contact" 或 "String, List<Contact>"
|
197
|
+
|
198
|
+
Returns:
|
199
|
+
(key_type, value_type) 元组
|
200
|
+
"""
|
201
|
+
# 简单情况:没有嵌套的尖括号
|
202
|
+
if '<' not in generic_part:
|
203
|
+
parts = [part.strip() for part in generic_part.split(',', 1)]
|
204
|
+
if len(parts) == 2:
|
205
|
+
return parts[0], parts[1]
|
206
|
+
|
207
|
+
# 复杂情况:处理嵌套的尖括号
|
208
|
+
bracket_count = 0
|
209
|
+
for i, char in enumerate(generic_part):
|
210
|
+
if char == '<':
|
211
|
+
bracket_count += 1
|
212
|
+
elif char == '>':
|
213
|
+
bracket_count -= 1
|
214
|
+
elif char == ',' and bracket_count == 0:
|
215
|
+
# 找到分隔符
|
216
|
+
key_type = generic_part[:i].strip()
|
217
|
+
value_type = generic_part[i+1:].strip()
|
218
|
+
return key_type, value_type
|
219
|
+
|
220
|
+
# 如果解析失败,返回默认值
|
221
|
+
return 'string', 'string'
|
222
|
+
|
223
|
+
|
224
|
+
class NamingConverter:
|
225
|
+
"""统一的命名转换器"""
|
226
|
+
|
227
|
+
@staticmethod
|
228
|
+
def to_snake_case(camel_str: str) -> str:
|
229
|
+
"""
|
230
|
+
将CamelCase转换为snake_case
|
231
|
+
|
232
|
+
Args:
|
233
|
+
camel_str: 驼峰命名字符串
|
234
|
+
|
235
|
+
Returns:
|
236
|
+
蛇形命名字符串
|
237
|
+
"""
|
238
|
+
if not camel_str:
|
239
|
+
return camel_str
|
240
|
+
|
241
|
+
# 处理连续大写字母:XMLParser -> XML_Parser
|
242
|
+
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', camel_str)
|
243
|
+
# 处理小写字母后跟大写字母:userId -> user_Id
|
244
|
+
s2 = re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1)
|
245
|
+
return s2.lower()
|
246
|
+
|
247
|
+
@staticmethod
|
248
|
+
def to_pascal_case(snake_str: str) -> str:
|
249
|
+
"""
|
250
|
+
将snake_case转换为PascalCase
|
251
|
+
|
252
|
+
Args:
|
253
|
+
snake_str: 蛇形命名字符串
|
254
|
+
|
255
|
+
Returns:
|
256
|
+
帕斯卡命名字符串
|
257
|
+
"""
|
258
|
+
if not snake_str:
|
259
|
+
return snake_str
|
260
|
+
|
261
|
+
components = snake_str.split('_')
|
262
|
+
return ''.join(word.capitalize() for word in components if word)
|
263
|
+
|
264
|
+
@staticmethod
|
265
|
+
def to_camel_case(snake_str: str) -> str:
|
266
|
+
"""
|
267
|
+
将snake_case转换为camelCase
|
268
|
+
|
269
|
+
Args:
|
270
|
+
snake_str: 蛇形命名字符串
|
271
|
+
|
272
|
+
Returns:
|
273
|
+
驼峰命名字符串
|
274
|
+
"""
|
275
|
+
if not snake_str:
|
276
|
+
return snake_str
|
277
|
+
|
278
|
+
components = snake_str.split('_')
|
279
|
+
if not components:
|
280
|
+
return snake_str
|
281
|
+
|
282
|
+
# 第一个单词保持小写,其余单词首字母大写
|
283
|
+
return components[0].lower() + ''.join(word.capitalize() for word in components[1:] if word)
|
284
|
+
|
285
|
+
|
286
|
+
class FieldNameProcessor:
|
287
|
+
"""字段名处理器 - 基于规律的智能处理"""
|
288
|
+
|
289
|
+
@staticmethod
|
290
|
+
def generate_type_name_from_field(field_name: str, target_type: str = 'message') -> str:
|
291
|
+
"""
|
292
|
+
基于字段名生成类型名(使用规律而非硬编码)
|
293
|
+
|
294
|
+
Args:
|
295
|
+
field_name: 字段名
|
296
|
+
target_type: 目标类型 ('enum' 或 'message')
|
297
|
+
|
298
|
+
Returns:
|
299
|
+
生成的类型名
|
300
|
+
"""
|
301
|
+
# 清理字段名
|
302
|
+
name = field_name.rstrip('_')
|
303
|
+
|
304
|
+
# 应用智能后缀转换(基于英语语言规律)
|
305
|
+
name = FieldNameProcessor._apply_suffix_transformation(name, target_type)
|
306
|
+
|
307
|
+
# 处理复数形式(仅对枚举类型)
|
308
|
+
if target_type == 'enum' and FieldNameProcessor._is_plural(name):
|
309
|
+
name = FieldNameProcessor._to_singular(name)
|
310
|
+
|
311
|
+
return NamingConverter.to_pascal_case(name)
|
312
|
+
|
313
|
+
@staticmethod
|
314
|
+
def _apply_suffix_transformation(name: str, target_type: str) -> str:
|
315
|
+
"""
|
316
|
+
应用后缀转换(基于英语语言规律,无硬编码)
|
317
|
+
|
318
|
+
Args:
|
319
|
+
name: 原始名称
|
320
|
+
target_type: 目标类型
|
321
|
+
|
322
|
+
Returns:
|
323
|
+
转换后的名称
|
324
|
+
"""
|
325
|
+
# 检查是否以下划线+单词结尾的模式
|
326
|
+
suffix_pattern = re.search(r'_([a-z]+)$', name)
|
327
|
+
if suffix_pattern:
|
328
|
+
suffix = suffix_pattern.group(1)
|
329
|
+
prefix = name[:suffix_pattern.start()]
|
330
|
+
|
331
|
+
# 特殊情况:如果后缀本身就是有意义的类型名,进行转换
|
332
|
+
if FieldNameProcessor._is_meaningful_type_suffix(suffix, target_type):
|
333
|
+
# 应用英语首字母大写规律(这是语言规律,不是硬编码)
|
334
|
+
capitalized_suffix = suffix.capitalize()
|
335
|
+
return prefix + capitalized_suffix
|
336
|
+
|
337
|
+
return name
|
338
|
+
|
339
|
+
@staticmethod
|
340
|
+
def _is_meaningful_type_suffix(suffix: str, target_type: str) -> bool:
|
341
|
+
"""
|
342
|
+
判断后缀是否为有意义的类型后缀(基于语义分析)
|
343
|
+
|
344
|
+
Args:
|
345
|
+
suffix: 后缀
|
346
|
+
target_type: 目标类型
|
347
|
+
|
348
|
+
Returns:
|
349
|
+
是否为有意义的类型后缀
|
350
|
+
"""
|
351
|
+
# 常见的类型相关词汇(基于英语语义,不是应用特定的)
|
352
|
+
enum_words = {'type', 'status', 'state', 'mode', 'level', 'kind', 'category', 'code'}
|
353
|
+
message_words = {'info', 'data', 'details', 'config', 'setting', 'metadata', 'stats', 'profile'}
|
354
|
+
|
355
|
+
if target_type == 'enum':
|
356
|
+
return suffix in enum_words
|
357
|
+
else: # message
|
358
|
+
return suffix in message_words
|
359
|
+
|
360
|
+
@staticmethod
|
361
|
+
def _is_plural(name: str) -> bool:
|
362
|
+
"""
|
363
|
+
判断名称是否为复数形式(基于英语语法规律)
|
364
|
+
|
365
|
+
Args:
|
366
|
+
name: 名称
|
367
|
+
|
368
|
+
Returns:
|
369
|
+
是否为复数
|
370
|
+
"""
|
371
|
+
if len(name) <= 1:
|
372
|
+
return False
|
373
|
+
|
374
|
+
# 简单的英语复数规则检查
|
375
|
+
if name.endswith('s') and not name.endswith('ss'):
|
376
|
+
# 排除一些明显不是复数的情况
|
377
|
+
non_plural_endings = {'class', 'pass', 'address', 'access', 'process', 'status'}
|
378
|
+
return name not in non_plural_endings
|
379
|
+
|
380
|
+
return False
|
381
|
+
|
382
|
+
@staticmethod
|
383
|
+
def _to_singular(name: str) -> str:
|
384
|
+
"""
|
385
|
+
将复数转换为单数(基于英语语法规律)
|
386
|
+
|
387
|
+
Args:
|
388
|
+
name: 复数名称
|
389
|
+
|
390
|
+
Returns:
|
391
|
+
单数名称
|
392
|
+
"""
|
393
|
+
if not name.endswith('s') or len(name) <= 1:
|
394
|
+
return name
|
395
|
+
|
396
|
+
# 简单的英语单数转换规则
|
397
|
+
if name.endswith('ies') and len(name) > 3:
|
398
|
+
# categories -> category
|
399
|
+
return name[:-3] + 'y'
|
400
|
+
elif name.endswith('es') and len(name) > 2:
|
401
|
+
# boxes -> box, but not "types" -> "typ"
|
402
|
+
if name.endswith(('ches', 'shes', 'xes', 'zes')):
|
403
|
+
return name[:-2]
|
404
|
+
else:
|
405
|
+
return name[:-1]
|
406
|
+
else:
|
407
|
+
# 一般情况:直接去掉s
|
408
|
+
return name[:-1]
|
409
|
+
|
410
|
+
|
411
|
+
# 全局实例,方便使用
|
412
|
+
type_mapper = TypeMapper()
|
413
|
+
naming_converter = NamingConverter()
|
414
|
+
field_name_processor = FieldNameProcessor()
|
reproto-0.0.7.dist-info/METADATA
DELETED
@@ -1,174 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.3
|
2
|
-
Name: reproto
|
3
|
-
Version: 0.0.7
|
4
|
-
Summary: 一个强大的逆向工程工具, 能够从任何使用Google Protobuf Lite的Android应用中自动重构出完整的.proto文件结构.
|
5
|
-
License: Proprietary
|
6
|
-
Keywords: protobuf,reverse-engineering,android,jadx,proto
|
7
|
-
Author: iyue
|
8
|
-
Author-email: ys1231@126.com
|
9
|
-
Requires-Python: >=3.12,<4.0
|
10
|
-
Classifier: Development Status :: 4 - Beta
|
11
|
-
Classifier: Intended Audience :: Developers
|
12
|
-
Classifier: License :: Other/Proprietary License
|
13
|
-
Classifier: Programming Language :: Python :: 3
|
14
|
-
Classifier: Programming Language :: Python :: 3.12
|
15
|
-
Classifier: Programming Language :: Python :: 3.13
|
16
|
-
Classifier: Topic :: Software Development :: Code Generators
|
17
|
-
Classifier: Topic :: Software Development :: Disassemblers
|
18
|
-
Requires-Dist: loguru (>=0.7.3)
|
19
|
-
Project-URL: Homepage, https://github.com/ys1231/reproto
|
20
|
-
Project-URL: Repository, https://github.com/ys1231/reproto.git
|
21
|
-
Description-Content-Type: text/markdown
|
22
|
-
|
23
|
-
# Protobuf Reconstructor
|
24
|
-
|
25
|
-
🔧 **从JADX反编译的Java源码自动重构Protobuf .proto文件**
|
26
|
-
|
27
|
-
一个强大的逆向工程工具,能够从任何使用Google Protobuf Lite的Android应用中自动重构出完整的.proto文件结构。
|
28
|
-
|
29
|
-
## ✨ 特性
|
30
|
-
|
31
|
-
- 🎯 **精准解析**: 基于Google Protobuf Lite字节码的逆向工程
|
32
|
-
- 🔄 **递归依赖**: 自动发现和处理所有依赖的消息和枚举类型
|
33
|
-
- 📦 **完整支持**: 支持oneof、repeated、map、枚举等所有Protobuf特性
|
34
|
-
- 🌐 **通用性**: 适用于任何Android应用,无需硬编码映射
|
35
|
-
- 🧠 **智能推断**: 从Java源码直接读取类型信息,确保高准确性
|
36
|
-
- 📝 **标准输出**: 严格遵循Google Proto Style Guide
|
37
|
-
|
38
|
-
## 🛠️ 安装
|
39
|
-
|
40
|
-
```bash
|
41
|
-
# 克隆项目
|
42
|
-
git clone https://github.com/ys1231/reproto.git
|
43
|
-
cd reproto
|
44
|
-
|
45
|
-
# 安装依赖
|
46
|
-
pip install -r requirements.txt
|
47
|
-
```
|
48
|
-
|
49
|
-
## 📖 使用方法
|
50
|
-
|
51
|
-
### 基本用法
|
52
|
-
```bash
|
53
|
-
python main.py <java_sources_dir> <root_class> <output_dir> [--verbose]
|
54
|
-
```
|
55
|
-
|
56
|
-
### 参数说明
|
57
|
-
- `java_sources_dir`: JADX反编译的Java源码目录路径
|
58
|
-
- `root_class`: 要重构的根类完整类名(如:com.example.Model)
|
59
|
-
- `output_dir`: 生成的proto文件输出目录路径
|
60
|
-
- `--verbose`: 显示详细处理信息
|
61
|
-
|
62
|
-
### 示例
|
63
|
-
```bash
|
64
|
-
# 重构消息应用的数据模型
|
65
|
-
python main.py ./out_jadx/sources com.example.messaging.v1.models.MessageData ./protos_generated --verbose
|
66
|
-
|
67
|
-
# 重构内部类
|
68
|
-
python main.py ./out_jadx/sources 'com.truecaller.accountonboarding.v1.Models$Onboarded' ./output --verbose
|
69
|
-
```
|
70
|
-
|
71
|
-
## 🔍 工作原理
|
72
|
-
|
73
|
-
### 核心技术
|
74
|
-
1. **字节码解析**: 逆向工程Google Protobuf Lite的`newMessageInfo`调用
|
75
|
-
2. **依赖发现**: 递归分析Java文件中的类型引用
|
76
|
-
3. **智能推断**: 基于字段名和对象数组推断枚举和消息类型
|
77
|
-
4. **源码分析**: 直接从Java源码读取真实的字段类型声明
|
78
|
-
|
79
|
-
### 解析流程
|
80
|
-
```
|
81
|
-
Java源码 → 字节码提取 → 类型解码 → 依赖发现 → 源码验证 → Proto生成
|
82
|
-
```
|
83
|
-
|
84
|
-
## 📁 项目结构
|
85
|
-
|
86
|
-
```
|
87
|
-
reproto/
|
88
|
-
├── main.py # 主程序入口
|
89
|
-
├── core/ # 核心组件
|
90
|
-
│ ├── reconstructor.py # 主协调器
|
91
|
-
│ └── info_decoder.py # 字节码解码器
|
92
|
-
├── parsing/ # 解析模块
|
93
|
-
│ ├── java_parser.py # Java文件解析器
|
94
|
-
│ └── java_source_analyzer.py # Java源码分析器
|
95
|
-
├── generation/ # 生成模块
|
96
|
-
│ └── proto_generator.py # Proto文件生成器
|
97
|
-
├── models/ # 数据模型
|
98
|
-
└── utils/ # 工具函数
|
99
|
-
```
|
100
|
-
|
101
|
-
## 📊 输出示例
|
102
|
-
|
103
|
-
### 输入:Java源码
|
104
|
-
```java
|
105
|
-
public final class MessageData extends GeneratedMessageLite {
|
106
|
-
public static final int TEXT_MESSAGE_FIELD_NUMBER = 1;
|
107
|
-
public static final int MEDIA_MESSAGE_FIELD_NUMBER = 2;
|
108
|
-
|
109
|
-
private int dataCase_;
|
110
|
-
private Object data_;
|
111
|
-
|
112
|
-
public enum DataCase {
|
113
|
-
TEXT_MESSAGE(1),
|
114
|
-
MEDIA_MESSAGE(2),
|
115
|
-
DATA_NOT_SET(0);
|
116
|
-
}
|
117
|
-
}
|
118
|
-
```
|
119
|
-
|
120
|
-
### 输出:Proto文件
|
121
|
-
```protobuf
|
122
|
-
syntax = "proto3";
|
123
|
-
|
124
|
-
package com.example.messaging.v1.models;
|
125
|
-
|
126
|
-
option java_package = "com.example.messaging.v1.models";
|
127
|
-
option java_multiple_files = true;
|
128
|
-
|
129
|
-
message MessageData {
|
130
|
-
oneof data {
|
131
|
-
TextMessage text_message = 1;
|
132
|
-
MediaMessage media_message = 2;
|
133
|
-
}
|
134
|
-
}
|
135
|
-
```
|
136
|
-
|
137
|
-
## 🚀 工作流程
|
138
|
-
|
139
|
-
1. 使用JADX反编译Android应用:`jadx -d out_jadx app.apk`
|
140
|
-
2. 运行ReProto指定根Protobuf类
|
141
|
-
3. 自动解析所有相关类和依赖
|
142
|
-
4. 生成完整的.proto文件结构
|
143
|
-
|
144
|
-
## 📝 配置选项
|
145
|
-
|
146
|
-
### 日志配置
|
147
|
-
- 日志文件自动保存到 `./logs/` 目录
|
148
|
-
- 文件格式: `reproto-YYYY-MM-DD-HH-MM-SS.log`
|
149
|
-
- 使用 `--verbose` 参数查看详细处理过程
|
150
|
-
|
151
|
-
### 输出格式
|
152
|
-
生成的proto文件遵循Google Protobuf Style Guide:
|
153
|
-
- 文件名:`snake_case.proto`
|
154
|
-
- 字段名:`snake_case`
|
155
|
-
- 消息名:`PascalCase`
|
156
|
-
- 枚举值:`UPPER_SNAKE_CASE`
|
157
|
-
|
158
|
-
## 🔧 开发
|
159
|
-
|
160
|
-
```bash
|
161
|
-
# 使用Poetry管理依赖
|
162
|
-
poetry install
|
163
|
-
poetry shell
|
164
|
-
|
165
|
-
# 运行测试
|
166
|
-
python main.py ../out_jadx/sources 'com.example.TestClass' ../test_output --verbose
|
167
|
-
```
|
168
|
-
|
169
|
-
## 📄 许可证
|
170
|
-
|
171
|
-
本项目为私有项目,仅供授权用户使用。
|
172
|
-
|
173
|
-
---
|
174
|
-
|
reproto-0.0.7.dist-info/RECORD
DELETED
@@ -1,87 +0,0 @@
|
|
1
|
-
.git/COMMIT_EDITMSG,sha256=vWBgg8c4nJUTpGorLmdBiJ660gt2AqgexEmYUvl51Aw,1153
|
2
|
-
.git/HEAD,sha256=ly8yuQLWQE8njkYAapHLPJ1xVg6_fMgQjCoHqKvFIdw,21
|
3
|
-
.git/config,sha256=9ZAySfDWBdI-K9eOXyrEQOhiX68AiaP0Z4CLzH07H10,399
|
4
|
-
.git/description,sha256=hatsFj1DoX6pz3eIMIvKFGbxsKjRzJLibpv2PaQGKu4,73
|
5
|
-
.git/hooks/applypatch-msg.sample,sha256=AiNJeguLAzqlijpSG4YphpOGz3qw4vEBlj0yiqYhk_c,478
|
6
|
-
.git/hooks/commit-msg.sample,sha256=H3TV6SkpebVz69WXQdRsuT_zkazdCD00C5Q3B1PZJDc,896
|
7
|
-
.git/hooks/fsmonitor-watchman.sample,sha256=4FSZZOk4l7UZvY4zPAN-Uf_w-IuhPghqMxWSv4AfodA,4726
|
8
|
-
.git/hooks/post-update.sample,sha256=gXZa8trvMjBh3LxeYfwWSBy3SzusmtihdLGGUjWG9sU,189
|
9
|
-
.git/hooks/pre-applypatch.sample,sha256=4VxbRp6j4KaVvqbyyCvPjmKCEHSTnd2Ft34AB_8WVHU,424
|
10
|
-
.git/hooks/pre-commit.sample,sha256=Vxhbe58FI516tS2wRfW4nrMTSNeyF36rIU9euHLhlxs,1649
|
11
|
-
.git/hooks/pre-merge-commit.sample,sha256=04JacDN5QOu9ClwHKYThMkWSDN-ImL0iXI0npt_Jy1M,416
|
12
|
-
.git/hooks/pre-push.sample,sha256=7M6cfgTT9d2ditqBdT3R1UmpY0smdwBCtY3aACF9CGo,1374
|
13
|
-
.git/hooks/pre-rebase.sample,sha256=T-vOhneQBSM4B29OZsxH77FIedGAl9HWHIJhhZ6qp7M,4898
|
14
|
-
.git/hooks/pre-receive.sample,sha256=pMPSuce7P9jRRBwxvU7nGlldZrRPz0ndsxAlIyAWmYk,544
|
15
|
-
.git/hooks/prepare-commit-msg.sample,sha256=6d3KpBif3dJe2X_Ix4nsp7bKFjkLI5KuMnbwyOGqRhk,1492
|
16
|
-
.git/hooks/push-to-checkout.sample,sha256=pT0HQXmLKHxt16-mSu5HPzBeZdP0lGO7nXQI7DsSv18,2783
|
17
|
-
.git/hooks/sendemail-validate.sample,sha256=ROv8kj3FRmvACWAvDs8Ge5xlRZq_6IaN3Em3jmztepI,2308
|
18
|
-
.git/hooks/update.sample,sha256=jV8vqD4QPPCLV-qmdSHfkZT0XL28s32lKtWGCXoU0QY,3650
|
19
|
-
.git/index,sha256=nckmwqmC8EqH_vLPAej3d-XaBtUVlxCzKL8Qt6yYvz8,1991
|
20
|
-
.git/info/exclude,sha256=ZnH-g7egfIky7okWTR8nk7IxgFjri5jcXAbuClo7DsE,240
|
21
|
-
.git/logs/HEAD,sha256=T-dzLHXLLB7bROtDGZibbNa290si245Rh_CjOspA7GQ,726
|
22
|
-
.git/logs/refs/heads/iyue,sha256=T-dzLHXLLB7bROtDGZibbNa290si245Rh_CjOspA7GQ,726
|
23
|
-
.git/logs/refs/remotes/gitlab/iyue,sha256=VcwPRaWPyufhVnQ-14cf2KAMQR70LHcxgpuhcJauhYY,408
|
24
|
-
.git/logs/refs/remotes/origin/HEAD,sha256=4vCPTgC0N80jhmkFXNUlYvHtGllYJkQTGZEn6LlqZgs,163
|
25
|
-
.git/logs/refs/remotes/origin/iyue,sha256=p6LGJyJ8YWca4RQ6etXUQ3DjwoYp7oN3aBz1vYIa8fw,408
|
26
|
-
.git/objects/09/a92517fe9eeb33d2fd7c979e01d163665f7abc,sha256=wyFL5jJ16f0xCpL1MB5EiJvs2opieE0hMEmyDpUV3ps,9356
|
27
|
-
.git/objects/14/d323d58fb90c209a730c17e23fd82a6c735fc1,sha256=rTCuhPM5LYusLIMDv7CLC557SlRFvvbBzgr4jwrjMVg,426
|
28
|
-
.git/objects/18/89a4fb55eb3abdc528ce87f0cea039278c06fd,sha256=Uz8TPtDNnPWR5pfsIx7tMDCDFBdWLIkaPcnYPIJ12oM,2880
|
29
|
-
.git/objects/20/cf56ec106bcd66420dd000279f983571b918b6,sha256=0dwZwG7CpR7yYYNvgYDxHLPj2P7eRLK7fTW_En419pk,166
|
30
|
-
.git/objects/21/55b64d52922c88527c102d62f23e5c2abbae79,sha256=6LLW2HrSfqqVwvO59yc-EcUp6MHw6zfHwu8TB775dII,13853
|
31
|
-
.git/objects/23/bfbca38e177bcbb423dd782c35b19d127a5ab0,sha256=hYW2b3t3bVGNh4pqyyA7DMlyF4LfNZco5NwedWMwwuI,3700
|
32
|
-
.git/objects/33/181441ab38eded005db356da89b54c7d29f452,sha256=iIM6a2aGs_TGZjxHKnkYYyZj_hA77nAF7r2lMOtN1VA,2021
|
33
|
-
.git/objects/33/52dfa8f5d9eb46cc98ea7ccecf02e4d9df95f7,sha256=KNAvQNdSalt8CxCZVVb8e6KBC4zqVtusT5MriFLPbIQ,4409
|
34
|
-
.git/objects/3c/6f0120229cc2cd8123efbeb7f186eb0a485f29,sha256=iyh7Xt-m7vou3slm58k8xSl3Cn2yYXTuv5WziSWHrW0,802
|
35
|
-
.git/objects/40/84f4567d983a977c49598b7d886e46b13ff50b,sha256=R3w6EvxpJRcVuJvbCslrGDK07kcOjECGGosj5tO-JBo,426
|
36
|
-
.git/objects/48/369b05749e384be9be58e5f943f3a0040d0f37,sha256=KP9dXx-XniZuIEXESlrL_MWWi55zGiFr7xtmp3oD67o,8551
|
37
|
-
.git/objects/76/311aa8e59d780763e0d66787067cc5d9613a67,sha256=J9Xy8ESXbWUbC_4sA0KumGVKm09tzlqA8C5oJ63a_b4,2167
|
38
|
-
.git/objects/7c/00eec7ae9ef5f94fc337e5c8f9793a2a48810d,sha256=Ju-Yuy5EARcIThU4vkHrZuHQWu3MjXSZYGtBDTWR18c,96
|
39
|
-
.git/objects/8c/809c42c7ae13007fd885ee7bcffae7acf2c520,sha256=HYoU3_cZUGur3rWrgRvzHRAv0JfrXgc34R8UeGbC5Bc,14180
|
40
|
-
.git/objects/97/56fe0931216a7c40cbf250e1ab8a6dfd589f13,sha256=Su7Q-bXO0K9QKEGC249NVuUS62xmQs5TgWfEmdbauaI,97
|
41
|
-
.git/objects/9a/e313cdf64cd82416c1238eb493e6396f799f12,sha256=9bPRhebwMVqtGqJUxfVq-TEUxceuOdSvicWe1H8F7Ks,876
|
42
|
-
.git/objects/a3/cedc28e563a1845a7860161b39b0fe58d5f0d3,sha256=Vee0H8dhSj4ERNDSAnRU6vebs0tbY1-lgYr1Nz5X7bc,122
|
43
|
-
.git/objects/a5/b7e4e1b63bfb65288f6553687aaabcfb4d51b1,sha256=9tl9xb48EdvQk9GIg6mEzXSwqUgD6yEVZx-sVxaQVKw,1064
|
44
|
-
.git/objects/cd/2d6c229438c6b1c694b9392a85888d89ef49c1,sha256=IW9iGk3Eb-i_Ht64HQcltVp27ziQHz5IP6k5p57YFtY,122
|
45
|
-
.git/objects/d0/9c84ad2142a187bf26a1714b7041b62e404c8f,sha256=twhhaZbfU_mgu5LIlt9ZeGjp_PT_gri_9H231H5nrNc,2172
|
46
|
-
.git/objects/d9/6d7456245232b3e159dcf691f11e51224c557a,sha256=3w45hxiT2rn6ljSdgo36fHMMWZt30r5C1FPvbnjq9tc,597
|
47
|
-
.git/objects/e8/1433b6ad92206cdadbee1f474b4f99383314cb,sha256=mRMdmx6wCs6b-63QL72Iutm2AUVCOIYs7J5XbAsLluc,426
|
48
|
-
.git/objects/e8/2f42ea26b8bf4f0bc92c0648ac8f190f14226d,sha256=xtbEwloZnqXdNdViAevzyprosfPQ1P--xAu6URGlaYI,155
|
49
|
-
.git/objects/e9/a15996cb55ac72aeb6611d26e8d22246589943,sha256=sTn6X3xMp3_WYpj1CmP2hDqviX86aJHTCzzi_ZTpBKw,4643
|
50
|
-
.git/objects/ed/fb5bbf938de738d1f658f80e23c675bb8b3fae,sha256=MOYiuXKTxnd9YcqU3-HUVUq2g9fPU1-AKZOQ-3xsWCk,4237
|
51
|
-
.git/objects/ef/4844af55f7f64b8dd24b81b5a8322a8c80208e,sha256=hO8yllVMOtIE4HeOvwKSqQUByH6lvaA4L-RYrSU4vlg,167
|
52
|
-
.git/objects/f2/2bfffda9fb6a7f37bed04b7c40c9466ef09454,sha256=goQNyEV3NqzS28mMXuus1SWzwb8yXnvEPef14Ugzh5Q,750
|
53
|
-
.git/objects/f5/18c69a6e1bf3052b79da01502b2837ea58f0f4,sha256=r98SFbCvw7yeAYTjzkw-2VMhOVbpm79FLZQiC5A1-pw,123
|
54
|
-
.git/objects/f7/25a430eb3364460ba854dbc8809edc21dc6c70,sha256=LdyMmAWGLWbn5G5fC7eAPi4NFOboKcJ6iJJdxENSUCk,2505
|
55
|
-
.git/objects/pack/pack-289f7bb06603881c49190e6036de6390223baf77.idx,sha256=KRv1SBEe9bYL9d5V301LwPOBqFs3tMnB0dl4PriMMIw,2416
|
56
|
-
.git/objects/pack/pack-289f7bb06603881c49190e6036de6390223baf77.pack,sha256=R4oMXhr-NcPAUBXStCbAaUvGUDW_SBECmPIbiB9Gy48,42003
|
57
|
-
.git/objects/pack/pack-289f7bb06603881c49190e6036de6390223baf77.rev,sha256=22_3sqyTNB5IbwAK5oCqNz0UxDDqoZ5jcF7p_44Lalo,244
|
58
|
-
.git/packed-refs,sha256=4H0m4wd6q98wZkBk7WfvVeTBuuxQdTE65XxsswYP-oQ,112
|
59
|
-
.git/refs/heads/iyue,sha256=uNzTlIGt4yrSLvXubuKKl8nJyDrxCK3ADGlq4CVVWTM,41
|
60
|
-
.git/refs/remotes/gitlab/iyue,sha256=uNzTlIGt4yrSLvXubuKKl8nJyDrxCK3ADGlq4CVVWTM,41
|
61
|
-
.git/refs/remotes/origin/HEAD,sha256=G8pFPTbCqnJ2IkCzz9J-STqOXWU6TrlXfpt1wx5bUWE,30
|
62
|
-
.git/refs/remotes/origin/iyue,sha256=uNzTlIGt4yrSLvXubuKKl8nJyDrxCK3ADGlq4CVVWTM,41
|
63
|
-
.gitignore,sha256=ThRUL1E38Z_Q4Lww0xYYl9ziFaPUvvwwqxbmp2cuwco,2068
|
64
|
-
.python-version,sha256=NxOs_9lT1XG8y-FjlRru-YinX5RcBJt_ulPwgDESZ_o,7
|
65
|
-
ARCHITECTURE.md,sha256=JALnUdREwdLRAmcUit5CGAPLpeZ6UfoYpAQkxil3NJc,8322
|
66
|
-
README.md,sha256=1EC39Oeth4evP26KNWEMFG-hSrFNhJIAVOSSOBhc9cY,4244
|
67
|
-
core/__init__.py,sha256=ajz1GSNU9xYVrFEDSz6Xwg7amWQ_yvW75tQa1ZvRIWc,3
|
68
|
-
core/bytecode_parser.py,sha256=87ZGhnyBNGP-gRjIyRUcGfWS2HR1YA_e1OBKafLEEDc,11532
|
69
|
-
core/info_decoder.py,sha256=wQMZoiQ7adK1xrAhZ0GOIqeLzvf3-TO7_EAERy4EX6g,52682
|
70
|
-
core/reconstructor.py,sha256=jm7XvZ3IcQosM42yG4Q-GVcQBaFtqABQ4-O63dJGRZA,51705
|
71
|
-
generation/__init__.py,sha256=ajz1GSNU9xYVrFEDSz6Xwg7amWQ_yvW75tQa1ZvRIWc,3
|
72
|
-
generation/proto_generator.py,sha256=KQjSxy8CGIwMEUJhEypa1xXbJ97yoGu_NIAYDf8sMLQ,16863
|
73
|
-
main.py,sha256=3G649-aTByEjMS4tb1A9wcO9NVUxXVSvdwGTq9hXxBI,7081
|
74
|
-
models/__init__.py,sha256=WScv63rvEl65y5CWjpb6__hvjNvjpCkl6lz1Z2u0IYc,811
|
75
|
-
models/message_definition.py,sha256=AszUZnNPSBn9SMXne5ORDBiGZz1W2pcYmU8ftGC3Mks,4873
|
76
|
-
parsing/__init__.py,sha256=ajz1GSNU9xYVrFEDSz6Xwg7amWQ_yvW75tQa1ZvRIWc,3
|
77
|
-
parsing/enum_parser.py,sha256=4BjMk1NIYgt2FDZUjTZyOvFfC1uJp_MBZipVdk1tqes,6175
|
78
|
-
parsing/java_parser.py,sha256=ECaiU9cZMNUZqoV1mrKRvaSFjZXha-lVgB59w6MuwxY,14761
|
79
|
-
pyproject.toml,sha256=J5gcdLZazkYd26QZJRYQ0VK3vXcEtfvdgEJQ9VkU4Fc,1378
|
80
|
-
requirements.txt,sha256=cQGj3IS6Kj88jbwj_jeKkokMnG-fEezWve91mfW4CJs,96
|
81
|
-
utils/__init__.py,sha256=ajz1GSNU9xYVrFEDSz6Xwg7amWQ_yvW75tQa1ZvRIWc,3
|
82
|
-
utils/file_utils.py,sha256=N1Ei7hmyeOkIyZJFEXyNbtTrfeVF2hP-U8evXAVW2MA,4085
|
83
|
-
utils/logger.py,sha256=473DfzFVXzdGpiRTJGY6bBd-V5G80_P07gQqcvDChpQ,2447
|
84
|
-
reproto-0.0.7.dist-info/METADATA,sha256=0x4j3WCrdeg5DO7oDV9wi9-kNaoBJTgj-NvWlFEpATg,5193
|
85
|
-
reproto-0.0.7.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
86
|
-
reproto-0.0.7.dist-info/entry_points.txt,sha256=6Oro9lK_2DXDgHiB3andNuIE78wxfooqacqp8yY1C-g,37
|
87
|
-
reproto-0.0.7.dist-info/RECORD,,
|
File without changes
|
File without changes
|