vovk-rust 0.0.1-beta.14 → 0.0.1-beta.16
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.
- package/client-templates/rsSrc/http_request.rs +22 -4
- package/client-templates/rsSrc/lib.rs.ejs +18 -4
- package/index.js +96 -14
- package/package.json +1 -1
|
@@ -46,6 +46,8 @@ fn prepare_request<B, Q, P>(
|
|
|
46
46
|
handler_name: &str,
|
|
47
47
|
body: Option<&B>,
|
|
48
48
|
form: Option<multipart::Form>,
|
|
49
|
+
text_body: Option<String>,
|
|
50
|
+
binary_body: Option<(Vec<u8>, String)>,
|
|
49
51
|
query: Option<&Q>,
|
|
50
52
|
params: Option<&P>,
|
|
51
53
|
headers: Option<&HashMap<String, String>>,
|
|
@@ -111,8 +113,8 @@ where
|
|
|
111
113
|
.transpose()
|
|
112
114
|
.map_err(|e| format!("Failed to serialize params: {}", e))?;
|
|
113
115
|
|
|
114
|
-
// Perform JSON validation if not disabled and no form data is provided
|
|
115
|
-
if !disable_client_validation && form.is_none() {
|
|
116
|
+
// Perform JSON validation if not disabled and no form/text/binary data is provided
|
|
117
|
+
if !disable_client_validation && form.is_none() && text_body.is_none() && binary_body.is_none() {
|
|
116
118
|
if let Some(body_schema) = validation.get("body") {
|
|
117
119
|
if let Some(ref body_val) = body_value {
|
|
118
120
|
let schema =
|
|
@@ -189,8 +191,12 @@ where
|
|
|
189
191
|
// Set up request headers
|
|
190
192
|
let mut headers_map = reqwest::header::HeaderMap::new();
|
|
191
193
|
headers_map.insert("Accept", "application/jsonl, application/json".parse().unwrap());
|
|
192
|
-
if body_value.is_some() && form.is_none() {
|
|
194
|
+
if body_value.is_some() && form.is_none() && text_body.is_none() && binary_body.is_none() {
|
|
193
195
|
headers_map.insert("Content-Type", "application/json".parse().unwrap());
|
|
196
|
+
} else if text_body.is_some() {
|
|
197
|
+
headers_map.insert("Content-Type", "text/plain".parse().unwrap());
|
|
198
|
+
} else if let Some((_, ref content_type)) = binary_body {
|
|
199
|
+
headers_map.insert("Content-Type", content_type.parse().unwrap());
|
|
194
200
|
}
|
|
195
201
|
|
|
196
202
|
// Merge with user-provided headers if any
|
|
@@ -220,9 +226,13 @@ where
|
|
|
220
226
|
let client = Client::new();
|
|
221
227
|
let mut request = client.request(method, &url).headers(headers_map);
|
|
222
228
|
|
|
223
|
-
// Apply form data or JSON body to the request
|
|
229
|
+
// Apply form data, text body, binary body, or JSON body to the request
|
|
224
230
|
if let Some(form_data) = form {
|
|
225
231
|
request = request.multipart(form_data);
|
|
232
|
+
} else if let Some(text) = text_body {
|
|
233
|
+
request = request.body(text);
|
|
234
|
+
} else if let Some((bytes, _)) = binary_body {
|
|
235
|
+
request = request.body(bytes);
|
|
226
236
|
} else if let Some(body_val) = body_value {
|
|
227
237
|
request = request.json(&body_val);
|
|
228
238
|
}
|
|
@@ -239,6 +249,8 @@ pub async fn http_request<T, B, Q, P>(
|
|
|
239
249
|
handler_name: &str,
|
|
240
250
|
body: Option<&B>,
|
|
241
251
|
form: Option<multipart::Form>,
|
|
252
|
+
text_body: Option<String>,
|
|
253
|
+
binary_body: Option<(Vec<u8>, String)>,
|
|
242
254
|
query: Option<&Q>,
|
|
243
255
|
params: Option<&P>,
|
|
244
256
|
headers: Option<&HashMap<String, String>>,
|
|
@@ -258,6 +270,8 @@ where
|
|
|
258
270
|
handler_name,
|
|
259
271
|
body,
|
|
260
272
|
form,
|
|
273
|
+
text_body,
|
|
274
|
+
binary_body,
|
|
261
275
|
query,
|
|
262
276
|
params,
|
|
263
277
|
headers,
|
|
@@ -344,6 +358,8 @@ pub async fn http_request_stream<T, B, Q, P>(
|
|
|
344
358
|
handler_name: &str,
|
|
345
359
|
body: Option<&B>,
|
|
346
360
|
form: Option<multipart::Form>,
|
|
361
|
+
text_body: Option<String>,
|
|
362
|
+
binary_body: Option<(Vec<u8>, String)>,
|
|
347
363
|
query: Option<&Q>,
|
|
348
364
|
params: Option<&P>,
|
|
349
365
|
headers: Option<&HashMap<String, String>>,
|
|
@@ -363,6 +379,8 @@ where
|
|
|
363
379
|
handler_name,
|
|
364
380
|
body,
|
|
365
381
|
form,
|
|
382
|
+
text_body,
|
|
383
|
+
binary_body,
|
|
366
384
|
query,
|
|
367
385
|
params,
|
|
368
386
|
headers,
|
|
@@ -45,8 +45,20 @@ vars.convertJSONSchemasToRustTypes({
|
|
|
45
45
|
validation?.query?.description ? `Query: ${validation?.query?.description}`: '',
|
|
46
46
|
validation?.output?.description ? `Returns: ${validation?.output?.description}`: ''
|
|
47
47
|
]).filter(Boolean).map((s) => s.split('\n')).flat().map((s) => ' '.repeat(4) + '/// ' + s).join('\n') %>
|
|
48
|
+
<%
|
|
49
|
+
// Determine body kind: 'none', 'form', 'binary', 'text', or 'json'
|
|
50
|
+
const bodyKind = (() => {
|
|
51
|
+
if (!validation?.body) return 'none';
|
|
52
|
+
const ct = validation.body['x-contentType'];
|
|
53
|
+
if (ct?.includes('multipart/form-data') || ct?.includes('application/x-www-form-urlencoded')) return 'form';
|
|
54
|
+
if (validation.body.format === 'binary' || validation.body.contentEncoding === 'binary') return 'binary';
|
|
55
|
+
if (ct?.some(c => c.startsWith('text/'))) return 'text';
|
|
56
|
+
return 'json';
|
|
57
|
+
})();
|
|
58
|
+
const firstContentType = validation?.body?.['x-contentType']?.[0] || 'application/octet-stream';
|
|
59
|
+
%>
|
|
48
60
|
pub async fn <%= handlerName %>(
|
|
49
|
-
body: <%-
|
|
61
|
+
body: <%- bodyKind === 'form' ? 'reqwest::multipart::Form' : bodyKind !== 'none' ? `${handlerName}_::body` : '()' %>,
|
|
50
62
|
query: <%- validation?.query ? `${handlerName}_::query` : '()' %>,
|
|
51
63
|
params: <%- validation?.params ? `${handlerName}_::params` : '()' %>,
|
|
52
64
|
headers: Option<&HashMap<String, String>>,
|
|
@@ -56,7 +68,7 @@ vars.convertJSONSchemasToRustTypes({
|
|
|
56
68
|
let result = <%= validation?.iteration ? 'http_request_stream' : 'http_request' %>::<
|
|
57
69
|
<%- [
|
|
58
70
|
validation?.output ? `${handlerName}_::output` : validation?.iteration ? `${handlerName}_::iteration` : 'serde_json::Value',
|
|
59
|
-
|
|
71
|
+
bodyKind === 'json' ? `${handlerName}_::body` : '()',
|
|
60
72
|
validation?.query ? `${handlerName}_::query` : '()',
|
|
61
73
|
validation?.params ? `${handlerName}_::params` : '()'
|
|
62
74
|
].filter(Boolean).map((s) => ' '.repeat(12) + s).join(',\n') %>
|
|
@@ -65,8 +77,10 @@ vars.convertJSONSchemasToRustTypes({
|
|
|
65
77
|
"<%= segmentName %>",
|
|
66
78
|
"<%= controllerSchema.rpcModuleName %>",
|
|
67
79
|
"<%= handlerNameOriginal %>",
|
|
68
|
-
<%-
|
|
69
|
-
<%-
|
|
80
|
+
<%- bodyKind === 'json' ? 'Some(&body)' : 'None' %>,
|
|
81
|
+
<%- bodyKind === 'form' ? 'Some(body)' : 'None' %>,
|
|
82
|
+
<%- bodyKind === 'text' ? 'Some(body)' : 'None' %>,
|
|
83
|
+
<%- bodyKind === 'binary' ? `Some((body, "${firstContentType}".to_string()))` : 'None' %>,
|
|
70
84
|
Some(&query),
|
|
71
85
|
Some(¶ms),
|
|
72
86
|
headers,
|
package/index.js
CHANGED
|
@@ -1,3 +1,58 @@
|
|
|
1
|
+
// Rust reserved keywords that cannot be used as identifiers
|
|
2
|
+
const RUST_KEYWORDS = new Set([
|
|
3
|
+
'as',
|
|
4
|
+
'break',
|
|
5
|
+
'const',
|
|
6
|
+
'continue',
|
|
7
|
+
'crate',
|
|
8
|
+
'else',
|
|
9
|
+
'enum',
|
|
10
|
+
'extern',
|
|
11
|
+
'false',
|
|
12
|
+
'fn',
|
|
13
|
+
'for',
|
|
14
|
+
'if',
|
|
15
|
+
'impl',
|
|
16
|
+
'in',
|
|
17
|
+
'let',
|
|
18
|
+
'loop',
|
|
19
|
+
'match',
|
|
20
|
+
'mod',
|
|
21
|
+
'move',
|
|
22
|
+
'mut',
|
|
23
|
+
'pub',
|
|
24
|
+
'ref',
|
|
25
|
+
'return',
|
|
26
|
+
'self',
|
|
27
|
+
'Self',
|
|
28
|
+
'static',
|
|
29
|
+
'struct',
|
|
30
|
+
'super',
|
|
31
|
+
'trait',
|
|
32
|
+
'true',
|
|
33
|
+
'type',
|
|
34
|
+
'unsafe',
|
|
35
|
+
'use',
|
|
36
|
+
'where',
|
|
37
|
+
'while',
|
|
38
|
+
'async',
|
|
39
|
+
'await',
|
|
40
|
+
'dyn',
|
|
41
|
+
'abstract',
|
|
42
|
+
'become',
|
|
43
|
+
'box',
|
|
44
|
+
'do',
|
|
45
|
+
'final',
|
|
46
|
+
'macro',
|
|
47
|
+
'override',
|
|
48
|
+
'priv',
|
|
49
|
+
'typeof',
|
|
50
|
+
'unsized',
|
|
51
|
+
'virtual',
|
|
52
|
+
'yield',
|
|
53
|
+
'try',
|
|
54
|
+
'union',
|
|
55
|
+
]);
|
|
1
56
|
// Helper function for indentation
|
|
2
57
|
export function indent(level, pad = 0) {
|
|
3
58
|
return ' '.repeat(pad + level * 2);
|
|
@@ -90,6 +145,10 @@ export function toRustType(schema, path, rootSchema = schema) {
|
|
|
90
145
|
}
|
|
91
146
|
}
|
|
92
147
|
if (schema.type === 'string') {
|
|
148
|
+
// Binary format maps to Vec<u8>
|
|
149
|
+
if (schema.format === 'binary' || schema.contentEncoding === 'binary') {
|
|
150
|
+
return 'Vec<u8>';
|
|
151
|
+
}
|
|
93
152
|
return 'String';
|
|
94
153
|
}
|
|
95
154
|
else if (schema.type === 'number' || schema.type === 'integer') {
|
|
@@ -153,7 +212,7 @@ export function toRustType(schema, path, rootSchema = schema) {
|
|
|
153
212
|
return '()';
|
|
154
213
|
}
|
|
155
214
|
else if (schema.type === 'array') {
|
|
156
|
-
if (schema.items) {
|
|
215
|
+
if (schema.items && typeof schema.items !== 'boolean') {
|
|
157
216
|
// Check if array items are objects that need special handling
|
|
158
217
|
if (schema.items.type === 'object' || schema.items.properties || schema.items.$ref) {
|
|
159
218
|
// For array of objects, reference the item type with proper module path
|
|
@@ -225,8 +284,8 @@ export function generateVariantEnum(schema, name, path, level, rootSchema, pad =
|
|
|
225
284
|
// If it's an object type, we need to create a separate struct
|
|
226
285
|
if (variant.type === 'object' || variant.properties) {
|
|
227
286
|
code += `${indentFn(level + 1)}${variantName}(${name}_::${variantName}),\n`;
|
|
228
|
-
// Create a nested type definition to be added
|
|
229
|
-
nestedTypes += processObject(variant, variantPath, level, rootSchema, pad);
|
|
287
|
+
// Create a nested type definition to be added inside a sub-module
|
|
288
|
+
nestedTypes += processObject(variant, variantPath, level + 1, rootSchema, pad);
|
|
230
289
|
}
|
|
231
290
|
else {
|
|
232
291
|
// For simple types, we can include them directly in the enum
|
|
@@ -235,9 +294,13 @@ export function generateVariantEnum(schema, name, path, level, rootSchema, pad =
|
|
|
235
294
|
}
|
|
236
295
|
});
|
|
237
296
|
code += `${indentFn(level)}}\n\n`;
|
|
238
|
-
// Add nested type definitions
|
|
297
|
+
// Add nested type definitions wrapped in a sub-module
|
|
239
298
|
if (nestedTypes) {
|
|
299
|
+
code += `${indentFn(level)}#[allow(non_snake_case)]\n`;
|
|
300
|
+
code += `${indentFn(level)}pub mod ${name}_ {\n`;
|
|
301
|
+
code += `${indentFn(level + 1)}use serde::{Serialize, Deserialize};\n\n`;
|
|
240
302
|
code += nestedTypes;
|
|
303
|
+
code += `${indentFn(level)}}\n`;
|
|
241
304
|
}
|
|
242
305
|
return code;
|
|
243
306
|
}
|
|
@@ -288,7 +351,9 @@ export function processObject(schema, path, level, rootSchema = schema, pad = 0)
|
|
|
288
351
|
let code = '';
|
|
289
352
|
// Add documentation comments for the struct
|
|
290
353
|
code += generateDocComment(schema, level, pad);
|
|
291
|
-
if (schema.type === 'object' &&
|
|
354
|
+
if (schema.type === 'object' &&
|
|
355
|
+
(schema['x-contentType']?.includes('multipart/form-data') ||
|
|
356
|
+
schema['x-contentType']?.includes('application/x-www-form-urlencoded'))) {
|
|
292
357
|
code += `${indentFn(level)}pub use reqwest::multipart::Form as ${currentName};\n`;
|
|
293
358
|
return code;
|
|
294
359
|
}
|
|
@@ -337,7 +402,13 @@ export function processObject(schema, path, level, rootSchema = schema, pad = 0)
|
|
|
337
402
|
if (!isRequired) {
|
|
338
403
|
propType = `Option<${propType}>`;
|
|
339
404
|
}
|
|
340
|
-
|
|
405
|
+
if (RUST_KEYWORDS.has(propName)) {
|
|
406
|
+
code += `${indentFn(level + 1)}#[serde(rename = "${propName}")]\n`;
|
|
407
|
+
code += `${indentFn(level + 1)}pub r#${propName}: ${propType},\n`;
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
code += `${indentFn(level + 1)}pub ${propName}: ${propType},\n`;
|
|
411
|
+
}
|
|
341
412
|
});
|
|
342
413
|
code += `${indentFn(level)}}\n\n`;
|
|
343
414
|
// Check if any properties require nested types before generating the sub-module
|
|
@@ -352,6 +423,7 @@ export function processObject(schema, path, level, rootSchema = schema, pad = 0)
|
|
|
352
423
|
((propSchema.type === 'string' || !propSchema.type) && propSchema.enum) ||
|
|
353
424
|
(propSchema.type === 'array' &&
|
|
354
425
|
propSchema.items &&
|
|
426
|
+
typeof propSchema.items !== 'boolean' &&
|
|
355
427
|
(propSchema.items.type === 'object' || propSchema.items.properties || propSchema.items.$ref)) ||
|
|
356
428
|
propSchema.anyOf ||
|
|
357
429
|
propSchema.oneOf ||
|
|
@@ -379,7 +451,7 @@ export function processObject(schema, path, level, rootSchema = schema, pad = 0)
|
|
|
379
451
|
code += generateEnum(propSchema, propName, level + 1, pad);
|
|
380
452
|
}
|
|
381
453
|
// Generate types for array items if they're objects
|
|
382
|
-
else if (propSchema.type === 'array' && propSchema.items) {
|
|
454
|
+
else if (propSchema.type === 'array' && propSchema.items && typeof propSchema.items !== 'boolean') {
|
|
383
455
|
// Check if items has a $ref
|
|
384
456
|
if (propSchema.items.$ref) {
|
|
385
457
|
const resolved = resolveRef(propSchema.items.$ref, rootSchema);
|
|
@@ -409,7 +481,13 @@ export function processPrimitive(schema, name, level, pad = 0) {
|
|
|
409
481
|
// For primitive types, create a type alias
|
|
410
482
|
code += `${indentFn(level)}pub type ${name} = `;
|
|
411
483
|
if (schema.type === 'string') {
|
|
412
|
-
|
|
484
|
+
// Binary format maps to Vec<u8>
|
|
485
|
+
if (schema.format === 'binary' || schema.contentEncoding === 'binary') {
|
|
486
|
+
code += 'Vec<u8>';
|
|
487
|
+
}
|
|
488
|
+
else {
|
|
489
|
+
code += 'String';
|
|
490
|
+
}
|
|
413
491
|
}
|
|
414
492
|
else if (schema.type === 'number') {
|
|
415
493
|
code += 'f64';
|
|
@@ -441,7 +519,9 @@ export function convertJSONSchemasToRustTypes({ schemas, pad = 0, rootName, }) {
|
|
|
441
519
|
}
|
|
442
520
|
const indentFn = (level) => ' '.repeat(pad + level * 2);
|
|
443
521
|
// Start code generation
|
|
444
|
-
let result = `${indentFn(0)}
|
|
522
|
+
let result = `${indentFn(0)}#[allow(non_camel_case_types)]\n`;
|
|
523
|
+
result += `${indentFn(0)}pub mod ${rootName}_ {\n`;
|
|
524
|
+
result += `${indentFn(1)}#[allow(unused_imports)]\n`;
|
|
445
525
|
result += `${indentFn(1)}use serde::{Serialize, Deserialize};\n`;
|
|
446
526
|
// Process each schema in the schemas object
|
|
447
527
|
Object.entries(schemas).forEach(([schemaName, schemaObj]) => {
|
|
@@ -460,7 +540,7 @@ export function convertJSONSchemasToRustTypes({ schemas, pad = 0, rootName, }) {
|
|
|
460
540
|
required: defSchema.required || [],
|
|
461
541
|
title: defSchema.title,
|
|
462
542
|
description: defSchema.description,
|
|
463
|
-
'x-
|
|
543
|
+
'x-contentType': defSchema['x-contentType'],
|
|
464
544
|
};
|
|
465
545
|
result += processObject(rootDefObject, [defName], 1, schemaObj, pad);
|
|
466
546
|
}
|
|
@@ -470,7 +550,8 @@ export function convertJSONSchemasToRustTypes({ schemas, pad = 0, rootName, }) {
|
|
|
470
550
|
else if (defSchema.anyOf || defSchema.oneOf || defSchema.allOf) {
|
|
471
551
|
result += generateVariantEnum(defSchema, defName, [defName], 1, schemaObj, pad);
|
|
472
552
|
}
|
|
473
|
-
else if (defSchema.type
|
|
553
|
+
else if (typeof defSchema.type === 'string' &&
|
|
554
|
+
['string', 'number', 'integer', 'boolean', 'null'].includes(defSchema.type)) {
|
|
474
555
|
// Handle primitive types in $defs
|
|
475
556
|
result += processPrimitive(defSchema, defName, 1, pad);
|
|
476
557
|
}
|
|
@@ -486,11 +567,12 @@ export function convertJSONSchemasToRustTypes({ schemas, pad = 0, rootName, }) {
|
|
|
486
567
|
required: schemaObj.required || [],
|
|
487
568
|
title: schemaObj.title,
|
|
488
569
|
description: schemaObj.description,
|
|
489
|
-
'x-
|
|
570
|
+
'x-contentType': schemaObj['x-contentType'],
|
|
490
571
|
};
|
|
491
572
|
result += processObject(rootObject, [schemaName], 1, schemaObj, pad);
|
|
492
573
|
}
|
|
493
|
-
else if (
|
|
574
|
+
else if (typeof schemaObj.type === 'string' &&
|
|
575
|
+
['string', 'number', 'integer', 'boolean', 'null'].includes(schemaObj.type)) {
|
|
494
576
|
// Handle primitive schema
|
|
495
577
|
result += processPrimitive(schemaObj, schemaName, 1, pad);
|
|
496
578
|
}
|
|
@@ -505,7 +587,7 @@ export function convertJSONSchemasToRustTypes({ schemas, pad = 0, rootName, }) {
|
|
|
505
587
|
else if (schemaObj.type === 'array') {
|
|
506
588
|
// For array as root type, create a type alias to Vec<ItemType>
|
|
507
589
|
let itemType = 'String'; // Default if no items specified
|
|
508
|
-
if (schemaObj.items) {
|
|
590
|
+
if (schemaObj.items && typeof schemaObj.items !== 'boolean') {
|
|
509
591
|
if (schemaObj.items.type === 'object' || schemaObj.items.properties) {
|
|
510
592
|
// Create the item type
|
|
511
593
|
const itemSchema = {
|