-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgenerate_js_to_td_code.cjs
197 lines (191 loc) · 7.62 KB
/
generate_js_to_td_code.cjs
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
/** @type {typeof import("./parsing_tl").TD_API} */
const {
constructors,
functions,
classes,
} = require("./td_api.json");
let result = `\
#ifndef _TdNode_JS_TO_TD_CODE
#define _TdNode_JS_TO_TD_CODE
#include "libraries.h"
#include "js-to-td.h"
inline const bool TdNode::ToTelegram::IsNotNullish(const Napi::Value value) {
return !value.IsNull() && !value.IsUndefined();
}
inline TdNode::ToTelegram::double_t TdNode::ToTelegram::double_(const Napi::Value value) {
return value.As<const Napi::Number>().DoubleValue();
}
inline TdNode::ToTelegram::string_t TdNode::ToTelegram::string_(const Napi::Value value) {
return value.As<const Napi::String>().Utf8Value();
}
TdNode::ToTelegram::int64_t TdNode::ToTelegram::int64_(const Napi::Value value) {
switch (value.Type()) {
case napi_valuetype::napi_bigint:
return std::stoll(value.ToString());
case napi_valuetype::napi_number:
return value.As<const Napi::Number>().Int64Value();
case napi_valuetype::napi_string:
return std::stoll(value.As<const Napi::String>());
default:
throw std::runtime_error("Cannot coerce JS value of such type to int64");
}
}
TdNode::ToTelegram::int53_t TdNode::ToTelegram::int53_(const Napi::Value value) {
switch (value.Type()) {
case napi_valuetype::napi_bigint:
return std::stoll(value.ToString());
case napi_valuetype::napi_number:
return value.As<const Napi::Number>().Int64Value();
case napi_valuetype::napi_string:
return std::stoll(value.As<const Napi::String>());
default:
throw std::runtime_error("Cannot coerce JS value of such type to int53");
}
}
TdNode::ToTelegram::int32_t TdNode::ToTelegram::int32_(const Napi::Value value) {
switch (value.Type()) {
case napi_valuetype::napi_bigint:
return std::stoi(value.ToString());
case napi_valuetype::napi_number:
return value.As<const Napi::Number>().Int32Value();
case napi_valuetype::napi_string:
return std::stoi(value.As<const Napi::String>());
default:
throw std::runtime_error("Cannot coerce JS value of such type to int32");
}
}
TdNode::ToTelegram::boolFalse_t TdNode::ToTelegram::boolFalse_(const Napi::Value value) {
if (value.As<const Napi::Boolean>().Value() == boolFalse) {
return boolFalse;
} else {
throw std::runtime_error("Value is not false");
}
}
TdNode::ToTelegram::boolTrue_t TdNode::ToTelegram::boolTrue_(const Napi::Value value) {
if (value.As<const Napi::Boolean>().Value() == boolTrue) {
return boolTrue;
} else {
throw std::runtime_error("Value is not true");
}
}
inline TdNode::ToTelegram::Bool_t TdNode::ToTelegram::Bool_(const Napi::Value value) {
return value.As<Napi::Boolean>().Value();
}
TdNode::ToTelegram::bytes_t TdNode::ToTelegram::bytes_(const Napi::Value value) {
if (value.IsBuffer()) {
const Napi::Buffer<const unsigned char> data = value.As<const Napi::Buffer<const unsigned char>>();
const unsigned char *bytes = data.Data();
return base64_encode(bytes, (unsigned int) data.Length());
} else if (value.IsTypedArray()) {
Napi::ArrayBuffer data = value.As<const Napi::TypedArray>().ArrayBuffer();
return base64_encode((const unsigned char *) data.Data(), (unsigned int) data.ByteLength());
} else if (value.IsArrayBuffer()) {
Napi::ArrayBuffer data = value.As<Napi::ArrayBuffer>();
return base64_encode((const unsigned char *)data.Data(), (unsigned int) data.ByteLength());
} else {
return value.As<Napi::String>().Utf8Value();
}
}
namespace TdNode {
namespace ToTelegram {
template<auto (*Callback)(Napi::Value)>
vector_t<std::invoke_result_t<decltype(Callback), const Napi::Value>>
vector_(Napi::Value value) {
const Napi::Array array = value.As<const Napi::Array>();
const uint32_t size = array.Length();
vector_t<std::invoke_result_t<decltype(Callback), const Napi::Value>> result(size);
for (uint32_t i = 0; i < size; i++) {
result[i] = std::move(Callback(array[i]));
}
return result;
}
template <auto Callback(const Napi::Value)>
constexpr auto &&Vector_ = vector_<Callback>;
}
}
`;
/** @param {import("./parsing_tl").TD_API.classParamType | import("./parsing_tl").TD_API.constructorParamType | import("./parsing_tl").TD_API.vectorParamType} type */
function GetFunctionForTransformation(type) {
"use strict";
if (type["@type"] === "classParamType") {
return type.className + "_";
} else if (type["@type"] === "constructorParamType") {
return type.constructorName + "_";
} else if (type["@type"] === "vectorParamType") {
return `vector_<&${GetFunctionForTransformation(type.of_type)}>`;
} else {
throw new Error("Invalid type");
}
}
for (const i of constructors) {
result += `
td::td_api::object_ptr<TdNode::ToTelegram::${i.name}_t> TdNode::ToTelegram::${i.name}_(const Napi::Value value) {
const Napi::Object object = value.As<const Napi::Object>();
td::td_api::object_ptr<${i.name}_t> result = td::td_api::make_object<${i.name}_t>();`;
for (const j of i.parameters) {
result += `
if (const Napi::Value field = object.Get("${j.name}"); IsNotNullish(field)) {
result->${j.name}_ = std::move(${GetFunctionForTransformation(j.type)}(object.Get("${j.name}")));
}`;
}
result += `
return result;
}`
}
for (const i of functions) {
result += `
td::td_api::object_ptr<TdNode::ToTelegram::${i.name}_t> TdNode::ToTelegram::${i.name}_(const Napi::Value value) {
const Napi::Object object = value.As<const Napi::Object>();
td::td_api::object_ptr<${i.name}_t> result = td::td_api::make_object<${i.name}_t>();`;
for (const j of i.parameters) {
result += `
if (const Napi::Value field = object.Get("${j.name}"); IsNotNullish(field)) {
result->${j.name}_ = std::move(${GetFunctionForTransformation(j.type)}(object.Get("${j.name}")));
}`;
}
result += `
return result;
}`
}
for (const i of classes) {
if (i.constructors.length <= 1) continue;
result += `
td::td_api::object_ptr<TdNode::ToTelegram::${i.name}_t> TdNode::ToTelegram::${i.name}_(const Napi::Value value) {
const Napi::Object object = value.As<const Napi::Object>();
std::string type = object.Get("@type").As<const Napi::String>().Utf8Value();`;
for (const j of i.constructors) {
result += `
if (type == "${j}") {
return std::move(${j}_(value));
}`
}
result += `
throw std::runtime_error("Invalid @type for ${i.name}");
}`
}
result += `
td::td_api::object_ptr<td::td_api::Function> TdNode::ToTelegram::AnyUnknownFunction(const Napi::Value value) {
const std::string type = value.As<const Napi::Object>().Get("@type").As<const Napi::String>().Utf8Value();`;
for (const i of functions) {
result += `
if (type == "${i.name}") {
return std::move(TdNode::ToTelegram::${i.name}_(value));
}`
}
result += `
throw std::runtime_error("No valid @type for function");
}
td::td_api::object_ptr<td::td_api::Object> TdNode::ToTelegram::AnyUnknownObject(const Napi::Value value) {
const std::string type = value.As<const Napi::Object>().Get("@type").As<const Napi::String>().Utf8Value();`;
for (const i of constructors) {
result += `
if (type == "${i.name}") {
return std::move(${i.name}_(value));
}`
}
result += `
throw std::runtime_error("No valid @type for object");
}
#endif
`;
require("fs").writeFileSync("./src/js-to-td.cpp", result);