-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathprogenitor_fixes.py
More file actions
197 lines (164 loc) · 8.24 KB
/
progenitor_fixes.py
File metadata and controls
197 lines (164 loc) · 8.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
import json
import re
import itertools
import sys
import os
def reconstructAllOfOneOf(schema):
# return
print('reconstructing allOf to oneOf. only for testing with progenitor')
all_of = schema["allOf"]
# Check if all elements in allOf have oneOf
one_of_lists = []
for item in all_of:
if "oneOf" in item:
one_of_lists.append(item["oneOf"])
else:
# If there's an element in allOf that doesn't have oneOf,
# we'll treat it as a oneOf with a single element
one_of_lists.append([item])
# Generate all combinations of the elements from all oneOf arrays
combinations = list(itertools.product(*one_of_lists))
# Create a new oneOf array with allOf entries for each combination
new_one_of = []
for combo in combinations:
combined = {
"allOf": list(combo)
}
new_one_of.append(combined)
# Replace the allOf with oneOf in the schema
schema.pop("allOf")
schema["oneOf"] = new_one_of
def iterate_nested_json_for_loop(json_obj):
if isinstance(json_obj, dict):
if 'allOf' in json_obj:
oneOfs = 0
for item in json_obj['allOf']:
if 'oneOf' in item:
oneOfs += 1
if oneOfs >= 2:
reconstructAllOfOneOf(json_obj)
for key, value in json_obj.items():
iterate_nested_json_for_loop(value)
if isinstance(json_obj, list):
for item in json_obj:
iterate_nested_json_for_loop(item)
filename = 'openapi.json'
f = open(filename, 'r')
spec = json.load(f)
if 'anyOf' in spec['components']['schemas']['GlobalContractIdentifierView']:
spec['components']['schemas']['GlobalContractIdentifierView']['oneOf'] = spec['components']['schemas']['GlobalContractIdentifierView'].pop('anyOf')
f.close()
if len(sys.argv) == 2 and sys.argv[1] == '--spec-fix':
iterate_nested_json_for_loop(spec)
print('spec fixed')
f = open(filename, 'w')
json.dump(spec, f, indent=4)
f.close()
if len(sys.argv) == 2 and sys.argv[1] == '--lib-fix':
all_lib_rs_file = open('./near-openapi/src/lib.rs', 'r')
lib_rs = all_lib_rs_file.read()
all_lib_rs_file.close()
types_start = """#[doc = r" Types used as operation parameters and responses."]
#[allow(clippy::all)]
pub mod types {"""
types_index = lib_rs.find(types_start)
client_index = lib_rs.find("""#[derive(Clone, Debug)]
#[doc = "Client for NEAR Protocol JSON RPC API""")
print(types_index, client_index)
dependencies = lib_rs[:types_index]
types = lib_rs[types_index:client_index]
client = lib_rs[client_index:]
types = 'pub use near_account_id::AccountId;\npub use near_gas::NearGas;\npub use near_token::NearToken;\n' + types[len(types_start):-2]
types = types.replace('super::NearToken("0".to_string())', 'super::NearToken::from_yoctonear(0)')
account_id_start = types.find('#[doc = "NEAR Account Identifier')
account_id_validity_start = types.find('#[doc = "`AccountIdValidityRulesVersion`"]')
types = types[:account_id_start] + types[account_id_validity_start:]
near_gas_start = types.find('#[doc = "`NearGas`"]')
network_info_view_start = types.find('#[doc = "`NetworkInfoView`"]') # remove NearGas and NearToken
types = types[:near_gas_start] + types[network_info_view_start:]
# Remove inline error module
error_start = types.find('#[doc = r" Error types."]')
access_key_start = types.find('#[doc = "Access key provides limited access')
types = types[:error_start] + types[access_key_start:]
# Remove CryptoHash definition
crypto_hash_start = types.find('#[doc = "`CryptoHash`"]')
current_epoch_start = types.find('#[doc = "Describes information about the current epoch validator"]')
types = types[:crypto_hash_start] + types[current_epoch_start:]
# Add thiserror::Error and strum_macros::Display derives for error types
# Match RpcRequestValidationErrorKind and types ending with Error (but not JsonRpcResponseFor*)
# First find all types that already have Display impl
types_with_display = set(re.findall(r'impl ::std::fmt::Display for (\w+)', types))
def add_error_derives(m):
if m.group(4).startswith('JsonRpcResponseFor'):
return m.group(0)
derives = m.group(1).rstrip().rstrip(',') # Remove trailing whitespace and comma
type_name = m.group(4)
# Only add strum_macros::Display if type doesn't already have Display impl
if type_name in types_with_display:
new_derives = f'{derives}, thiserror::Error'
else:
new_derives = f'{derives}, thiserror::Error, strum_macros::Display'
return f'#[derive({new_derives})]{m.group(2)}{m.group(3)}pub enum {type_name}'
types = re.sub(
r'#\[derive\(([^)]+)\)\](\n(?:\s*#\[[^\n]+\n)*)(\s*)pub enum (RpcRequestValidationErrorKind|[A-Z][a-zA-Z0-9]*Error)\b',
add_error_derives,
types
)
types_lib_rs = """//! This crate provides types for the Near OpenAPI specification.
//!
//! Used in [near-openapi-client](https://docs.rs/near-openapi-client/latest/near_openapi_client/)
pub mod error;
mod util;
pub use util::CryptoHash;
""" + types
client_lib_rs = dependencies + client
client_lib_rs = 'pub use near_openapi_types as types;\n' + client_lib_rs
client_lib_rs = re.sub('"{}/\w*', '"{}/', client_lib_rs)
readme_md = open('./README.md', 'r')
client_docs = readme_md.readlines()
index_of_finish = client_docs.index('### Generate libraries and test:\n')
client_docs = ['//!' + line for line in client_docs[:index_of_finish]]
client_lib_rs = '\n'.join(client_docs) + client_lib_rs
if not os.path.isdir('./near-openapi-client/src'):
os.makedirs('./near-openapi-client/src')
client_lib_rs_file = open('./near-openapi-client/src/lib.rs', 'w')
client_lib_rs_file.write(client_lib_rs)
client_lib_rs_file.close()
if not os.path.isdir('./near-openapi-types/src'):
os.makedirs('./near-openapi-types/src')
types_lib_rs_file = open('./near-openapi-types/src/lib.rs', 'w')
types_lib_rs_file.write(types_lib_rs)
types_lib_rs_file.close()
all_cargo_toml_file = open('./near-openapi/Cargo.toml', 'r')
cargo_toml = all_cargo_toml_file.read()
all_cargo_toml_file.close()
cargo_toml = re.sub('\[workspace\]', '', cargo_toml)
client_cargo_toml = re.sub('near-openapi', 'near-openapi-client', cargo_toml)
client_cargo_toml = re.sub('version = "0.0.0"\nedition = "2021"\nlicense = "SPECIFY A LICENSE BEFORE PUBLISHING"', """version.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
description = "Progenitor-generated client of NEAR JSON RPC API"
""", client_cargo_toml)
client_cargo_toml += 'near-openapi-types.workspace = true\n'
types_cargo_toml = re.sub('near-openapi', 'near-openapi-types', cargo_toml)
types_cargo_toml = re.sub('version = "0.0.0"\nedition = "2021"\nlicense = "SPECIFY A LICENSE BEFORE PUBLISHING"', """version.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
description = "Types for progenitor-generated client of NEAR JSON RPC API"
""", types_cargo_toml)
# Remove client-specific dependencies not needed for types crate
types_cargo_toml = re.sub(r'bytes = "[^"]+"\n', '', types_cargo_toml)
types_cargo_toml = re.sub(r'futures-core = "[^"]+"\n', '', types_cargo_toml)
types_cargo_toml = re.sub(r'progenitor-client = "[^"]+"\n', '', types_cargo_toml)
types_cargo_toml = re.sub(r'reqwest = \{[^}]+\}\n', '', types_cargo_toml)
types_cargo_toml = re.sub(r'serde_urlencoded = "[^"]+"\n', '', types_cargo_toml)
types_cargo_toml += 'near-account-id = { version = "2.0", features = ["serde"] }\nnear-gas = { version = "0.3.2", features = ["serde"] }\nnear-token = { version = "0.3.1", features = ["serde"] }\nthiserror = "2.0.17"\nstrum_macros = "0.27.2"\nbs58 = "0.5.1"\n'
client_cargo_toml_file = open('./near-openapi-client/Cargo.toml', 'w')
client_cargo_toml_file.write(client_cargo_toml)
client_cargo_toml_file.close()
types_cargo_toml_file = open('./near-openapi-types/Cargo.toml', 'w')
types_cargo_toml_file.write(types_cargo_toml)
types_cargo_toml_file.close()
print('lib fixed')