Skip to content

Commit 1e5bc12

Browse files
authored
bug fixes to add 4 more azure_svc crates (#505)
1 parent 8ea32f9 commit 1e5bc12

File tree

113 files changed

+159354
-4656
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

113 files changed

+159354
-4656
lines changed

services/autorust/codegen/examples/gen_mgmt.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const SKIP_SERVICE_TAGS: &[(&str, &str)] = &[
4242
("datamigration", "package-2021-06"),
4343
("deploymentmanager", "package-2018-09-01-preview"), // identifiers are bound more than once in param list. https://github.com/Azure/azure-sdk-for-rust/issues/415
4444
("iothub", "package-preview-2021-07"), // duplicate tag https://github.com/Azure/azure-rest-api-specs/issues/16692
45+
("iothub", "package-2021-07"), // duplicate tag https://github.com/Azure/azure-rest-api-specs/issues/16692
4546
("mediaservices", "package-2019-05-preview"), // invalid unicode character of a dash instead of a hyphen https://github.com/Azure/azure-rest-api-specs/pull/11576
4647
("marketplace", "package-2020-01-01"),
4748
("marketplace", "package-2020-12-01"),

services/autorust/codegen/examples/gen_svc.rs

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,20 @@ const OUTPUT_FOLDER: &str = "../svc";
88
const ONLY_SERVICES: &[&str] = &[];
99

1010
const SKIP_SERVICES: &[&str] = &[
11-
"deviceupdate", // missing field `authorizationUrl`
12-
"digitaltwins", // missing field `scopes`
13-
"machinelearningservices", // untagged enum
14-
"servicefabric", // currently generates `async` member names
15-
"hdinsight", // job_id appears multiple times?
11+
"machinelearningservices", // need to box inner errors
12+
"hdinsight", // job_id appears multiple times https://github.com/Azure/azure-sdk-for-rust/issues/503
1613
"videoanalyzer", // no operations
1714
"mediaservices", // no operations
18-
"marketplacecatalog", // BadRequest400 uses models::String?
1915
];
2016

2117
const SKIP_SERVICE_TAGS: &[(&str, &str)] = &[
22-
("agrifood", "package-2021-03-31-preview"), // untagged enum?
23-
("attestation", "package-2018-09-01"), // uses models::String?
24-
("containerregistry", "package-2019-08"), // untagged enum
25-
("containerregistry", "package-2019-07"), // untagged enum
26-
("purview", "package-2021-05-01-preview"), // untagged enum
27-
("maps", "package-preview-2.0"), // string \"200Async\", expected length 3"
28-
("maps", "package-1.0-preview"), // "invalid value: string \"201Async\"
18+
("agrifood", "package-2021-03-31-preview"), // duplicate params https://github.com/Azure/azure-sdk-for-rust/issues/501
19+
("purview", "package-2021-05-01-preview"), // need to box types
20+
("maps", "package-preview-2.0"), // global responses https://github.com/Azure/azure-sdk-for-rust/issues/502
21+
("maps", "package-1.0-preview"), // global responses https://github.com/Azure/azure-sdk-for-rust/issues/502
22+
("servicefabric", "6.2"), // invalid model TimeBasedBackupScheduleDescription
23+
("servicefabric", "6.3"), // invalid model TimeBasedBackupScheduleDescription
24+
("servicefabric", "6.4"), // invalid model TimeBasedBackupScheduleDescription
2925
("storagedatalake", "package-2018-11"), // "invalid value: string \"ErrorResponse\", expected length 3"
3026
("storagedatalake", "package-2018-06-preview"),
3127
("storagedatalake", "package-2019-10"),
@@ -98,7 +94,39 @@ const BOX_PROPERTIES: &[(&str, &str, &str)] = &[
9894
"../../../azure-rest-api-specs/specification/datalake-analytics/data-plane/Microsoft.DataLakeAnalytics/preview/2017-09-01-preview/job.json",
9995
"JobInnerError",
10096
"innerError"
101-
)
97+
),
98+
// deviceupdate
99+
(
100+
"../../../azure-rest-api-specs/specification/deviceupdate/data-plane/Microsoft.DeviceUpdate/preview/2020-09-01/deviceupdate.json",
101+
"Error",
102+
"innerError"
103+
),
104+
(
105+
"../../../azure-rest-api-specs/specification/deviceupdate/data-plane/Microsoft.DeviceUpdate/preview/2020-09-01/deviceupdate.json",
106+
"InnerError",
107+
"innerError"
108+
),
109+
// digitaltwins
110+
(
111+
"../../../azure-rest-api-specs/specification/digitaltwins/data-plane/Microsoft.DigitalTwins/preview/2020-05-31-preview/digitaltwins.json",
112+
"Error",
113+
"innererror"
114+
),
115+
(
116+
"../../../azure-rest-api-specs/specification/digitaltwins/data-plane/Microsoft.DigitalTwins/preview/2020-05-31-preview/digitaltwins.json",
117+
"InnerError",
118+
"innererror"
119+
),
120+
(
121+
"../../../azure-rest-api-specs/specification/digitaltwins/data-plane/Microsoft.DigitalTwins/stable/2020-10-31/digitaltwins.json",
122+
"Error",
123+
"innererror"
124+
),
125+
(
126+
"../../../azure-rest-api-specs/specification/digitaltwins/data-plane/Microsoft.DigitalTwins/stable/2020-10-31/digitaltwins.json",
127+
"InnerError",
128+
"innererror"
129+
),
102130
];
103131

104132
pub type Result<T, E = Error> = std::result::Result<T, E>;

services/autorust/codegen/src/codegen_models.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@ use crate::{
33
create_generated_by_header, enum_values_as_strings, get_schema_array_items, get_type_name_for_schema, get_type_name_for_schema_ref,
44
is_array, is_basic_type, is_local_enum, is_local_struct, is_vec, require, Error,
55
},
6-
identifier::{ident, CamelCaseIdent},
6+
identifier::{CamelCaseIdent, SnakeCaseIdent},
77
spec, CodeGen, PropertyName, ResolvedSchema,
88
};
99
use autorust_openapi::Reference;
10-
use heck::{CamelCase, SnakeCase};
1110
use indexmap::IndexMap;
1211
use proc_macro2::TokenStream;
1312
use quote::quote;
@@ -85,7 +84,7 @@ pub fn create_models(cg: &CodeGen) -> Result<TokenStream, Error> {
8584
}
8685

8786
fn create_basic_type_alias(property_name: &str, property: &ResolvedSchema) -> Result<(TokenStream, TokenStream), Error> {
88-
let id = ident(&property_name.to_camel_case()).map_err(Error::StructName)?;
87+
let id = property_name.to_camel_case_ident().map_err(Error::StructName)?;
8988
let value = get_type_name_for_schema(&property.schema.common)?.to_token_stream(false, false)?;
9089
Ok((id, value))
9190
}
@@ -117,7 +116,7 @@ fn create_enum(
117116
lowercase_workaround: bool,
118117
) -> Result<(TokenStream, TokenStream), Error> {
119118
let enum_values = enum_values_as_strings(&property.schema.common.enum_);
120-
let id = ident(&property_name.to_camel_case()).map_err(|source| Error::EnumName {
119+
let id = &property_name.to_camel_case_ident().map_err(|source| Error::EnumName {
121120
source,
122121
property: property_name.to_owned(),
123122
})?;
@@ -141,7 +140,7 @@ fn create_enum(
141140
};
142141
values.extend(value);
143142
}
144-
let nm = ident(&property_name.to_camel_case()).map_err(|source| Error::EnumName {
143+
let nm = property_name.to_camel_case_ident().map_err(|source| Error::EnumName {
145144
source,
146145
property: property_name.to_owned(),
147146
})?;
@@ -157,7 +156,7 @@ fn create_enum(
157156

158157
fn create_vec_alias(alias_name: &str, schema: &ResolvedSchema) -> Result<TokenStream, Error> {
159158
let items = get_schema_array_items(&schema.schema.common)?;
160-
let typ = ident(&alias_name.to_camel_case()).map_err(Error::VecAliasName)?;
159+
let typ = &alias_name.to_camel_case_ident().map_err(Error::VecAliasName)?;
161160
let items_typ = get_type_name_for_schema_ref(items)?.to_token_stream(false, false)?;
162161
Ok(quote! { pub type #typ = Vec<#items_typ>; })
163162
}
@@ -167,13 +166,13 @@ fn create_struct(cg: &CodeGen, doc_file: &Path, struct_name: &str, schema: &Reso
167166
let mut streams = Vec::new();
168167
let mut local_types = Vec::new();
169168
let mut props = TokenStream::new();
170-
let ns = ident(&struct_name.to_snake_case()).map_err(Error::StructName)?;
171-
let nm = ident(&struct_name.to_camel_case()).map_err(Error::StructName)?;
169+
let ns = struct_name.to_snake_case_ident().map_err(Error::StructName)?;
170+
let nm = struct_name.to_camel_case_ident().map_err(Error::StructName)?;
172171
let required: HashSet<&str> = schema.schema.required.iter().map(String::as_str).collect();
173172

174173
for schema in &schema.schema.all_of {
175174
let type_name = get_type_name_for_schema_ref(schema)?.to_token_stream(false, false)?;
176-
let field_name = ident(&type_name.to_string().to_snake_case()).map_err(Error::StructFieldName)?;
175+
let field_name = type_name.to_string().to_snake_case_ident().map_err(Error::StructFieldName)?;
177176
props.extend(quote! {
178177
#[serde(flatten)]
179178
pub #field_name: #type_name,
@@ -182,7 +181,7 @@ fn create_struct(cg: &CodeGen, doc_file: &Path, struct_name: &str, schema: &Reso
182181

183182
let properties = cg.spec.resolve_schema_map(doc_file, &schema.schema.properties)?;
184183
for (property_name, property) in &properties {
185-
let nm = ident(&property_name.to_snake_case()).map_err(Error::StructName)?;
184+
let nm = property_name.to_snake_case_ident().map_err(Error::StructName)?;
186185
let prop_nm = &PropertyName {
187186
file_path: PathBuf::from(doc_file),
188187
schema_name: struct_name.to_owned(),
@@ -271,15 +270,15 @@ fn create_struct_field_type(
271270
) -> Result<(TokenStream, Vec<TokenStream>), Error> {
272271
match &property.ref_key {
273272
Some(ref_key) => {
274-
let tp = ident(&ref_key.name.to_camel_case()).map_err(Error::PropertyName)?;
273+
let tp = ref_key.name.to_camel_case_ident().map_err(Error::PropertyName)?;
275274
Ok((tp, Vec::new()))
276275
}
277276
None => {
278277
if is_local_enum(property) {
279278
let (tp_name, tp) = create_enum(namespace, property_name, property, lowercase_workaround)?;
280279
Ok((tp_name, vec![tp]))
281280
} else if is_local_struct(property) {
282-
let id = ident(&property_name.to_camel_case()).map_err(Error::PropertyName)?;
281+
let id = property_name.to_camel_case_ident().map_err(Error::PropertyName)?;
283282
let tp_name = quote! {#namespace::#id};
284283
let tps = create_struct(cg, doc_file, property_name, property)?;
285284
// println!("creating local struct {:?} {}", tp_name, tps.len());

services/autorust/codegen/src/codegen_operations.rs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::{
22
codegen::{create_generated_by_header, get_type_name_for_schema, get_type_name_for_schema_ref, is_array, is_string, require, Error},
33
codegen::{parse_params, PARAM_RE},
44
identifier::ident,
5+
identifier::SnakeCaseIdent,
56
spec::{WebOperation, WebVerb},
67
status_codes::{get_error_responses, get_response_type_name, get_success_responses, has_default_response},
78
status_codes::{get_response_type_ident, get_status_code_ident},
@@ -110,7 +111,7 @@ fn create_function(cg: &CodeGen, operation: &WebOperation) -> Result<TokenStream
110111

111112
let params = parse_params(&operation.path);
112113
// println!("path params {:#?}", params);
113-
let params: Result<Vec<_>, Error> = params.iter().map(|s| ident(&s.to_snake_case()).map_err(Error::ParamName)).collect();
114+
let params: Result<Vec<_>, Error> = params.iter().map(|s| s.to_snake_case_ident().map_err(Error::ParamName)).collect();
114115
let params = params?;
115116
let url_str_args = quote! { #(#params),* };
116117

@@ -281,18 +282,22 @@ fn create_function(cg: &CodeGen, operation: &WebOperation) -> Result<TokenStream
281282
});
282283
}
283284
}
284-
ParameterType::Form => {
285-
if required {
286-
ts_request_builder.extend(quote! {
287-
req_builder = req_builder.form(#param_name_var);
288-
});
289-
} else {
290-
ts_request_builder.extend(quote! {
291-
if let Some(#param_name_var) = #param_name_var {
292-
req_builder = req_builder.form(#param_name_var);
293-
}
294-
});
295-
}
285+
ParameterType::FormData => {
286+
ts_request_builder.extend(quote! {
287+
unimplemented!("form data not yet supported");
288+
});
289+
// https://github.com/Azure/azure-sdk-for-rust/issues/500
290+
// if required {
291+
// cargo run --example gen_svc --release
292+
// req_builder = req_builder.form(#param_name_var);
293+
// });
294+
// } else {
295+
// ts_request_builder.extend(quote! {
296+
// if let Some(#param_name_var) = #param_name_var {
297+
// req_builder = req_builder.form(#param_name_var);
298+
// }
299+
// });
300+
// }
296301
}
297302
}
298303
}
@@ -558,7 +563,7 @@ fn create_function_params(_cg: &CodeGen, _doc_file: &Path, parameters: &[Paramet
558563
}
559564

560565
fn get_param_name(param: &Parameter) -> Result<TokenStream, Error> {
561-
ident(&param.name.to_snake_case()).map_err(Error::ParamName)
566+
param.name.to_snake_case_ident().map_err(Error::ParamName)
562567
}
563568

564569
fn get_param_type(param: &Parameter) -> Result<TokenStream, Error> {

services/autorust/codegen/src/identifier.rs

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use heck::CamelCase;
1+
use heck::{CamelCase, SnakeCase};
22
use proc_macro2::TokenStream;
33
use quote::ToTokens;
44

@@ -15,7 +15,8 @@ pub trait CamelCaseIdent: ToOwned {
1515
impl CamelCaseIdent for str {
1616
fn to_camel_case_ident(&self) -> Result<TokenStream, Error> {
1717
let is_number = starts_with_number(self);
18-
let mut txt = replace_first(self, true);
18+
let mut txt = replace_first(self, true, true);
19+
txt = replace_first(&txt, true, false);
1920
txt = replace_special_chars(&txt);
2021
if !is_number {
2122
// heck::CamelCase::to_camel_case will remove underscores
@@ -29,8 +30,26 @@ impl CamelCaseIdent for str {
2930
}
3031
}
3132

33+
pub trait SnakeCaseIdent: ToOwned {
34+
fn to_snake_case_ident(&self) -> Result<TokenStream, Error>;
35+
}
36+
37+
impl SnakeCaseIdent for str {
38+
fn to_snake_case_ident(&self) -> Result<TokenStream, Error> {
39+
let mut txt = replace_first(self, false, true);
40+
txt = replace_special_chars(&txt);
41+
txt = txt.to_snake_case();
42+
txt = suffix_keyword(&txt);
43+
let idt = syn::parse_str::<syn::Ident>(&txt).map_err(|source| Error::ParseIdentError {
44+
source,
45+
text: self.to_owned(),
46+
})?;
47+
Ok(idt.into_token_stream())
48+
}
49+
}
50+
3251
pub fn ident(text: &str) -> Result<TokenStream, Error> {
33-
let mut txt = replace_first(text, false);
52+
let mut txt = replace_first(text, false, false);
3453
txt = replace_special_chars(&txt);
3554
txt = remove_spaces(&txt);
3655
txt = suffix_keyword(&txt);
@@ -52,6 +71,7 @@ fn replace_special_chars(text: &str) -> String {
5271
txt = txt.replace("-", "_");
5372
txt = txt.replace("/", "_");
5473
txt = txt.replace("*", "_");
74+
txt = txt.replace(":", "_");
5575
txt
5676
}
5777

@@ -68,14 +88,18 @@ fn unicode(c: char, uppercase: bool) -> String {
6888
format!("{}{}", u, &s[3..s.len() - 1])
6989
}
7090

71-
fn replace_first(text: &str, uppercase: bool) -> String {
91+
fn replace_first(text: &str, uppercase: bool, remove: bool) -> String {
7292
let first = text.chars().next().unwrap_or_default();
7393
if first.is_numeric() {
7494
let n = if uppercase { 'N' } else { 'n' };
7595
format!("{}{}", n, text)
7696
} else if !first.is_ascii_alphanumeric() {
7797
if text.len() > 1 {
78-
format!("{}{}", unicode(first, uppercase), &text[1..])
98+
if remove {
99+
text[1..].to_owned()
100+
} else {
101+
format!("{}{}", unicode(first, uppercase), &text[1..])
102+
}
79103
} else {
80104
unicode(first, uppercase)
81105
}
@@ -100,6 +124,7 @@ fn is_keyword(word: &str) -> bool {
100124
"abstract"
101125
| "alignof"
102126
| "as"
127+
| "async"
103128
| "become"
104129
| "box"
105130
| "break"
@@ -165,9 +190,9 @@ mod tests {
165190

166191
#[test]
167192
fn test_replace_first() -> Result<(), Error> {
168-
assert_eq!(replace_first(".", false), "u2e");
169-
assert_eq!(replace_first("/", false), "u2f");
170-
assert_eq!(replace_first("", false), "u0");
193+
assert_eq!(replace_first(".", false, false), "u2e");
194+
assert_eq!(replace_first("/", false, false), "u2f");
195+
assert_eq!(replace_first("", false, false), "u0");
171196
Ok(())
172197
}
173198

@@ -249,4 +274,34 @@ mod tests {
249274
assert_eq!("1.0".to_camel_case_ident()?.to_string(), "N1_0");
250275
Ok(())
251276
}
277+
278+
#[test]
279+
fn test_async() -> Result<(), Error> {
280+
assert_eq!("Async".to_snake_case_ident()?.to_string(), "async_");
281+
Ok(())
282+
}
283+
284+
#[test]
285+
fn test_attr_qualified_name() -> Result<(), Error> {
286+
assert_eq!("attr:qualifiedName".to_snake_case_ident()?.to_string(), "attr_qualified_name");
287+
Ok(())
288+
}
289+
290+
#[test]
291+
fn test_filter() -> Result<(), Error> {
292+
assert_eq!("$filter".to_snake_case_ident()?.to_string(), "filter");
293+
Ok(())
294+
}
295+
296+
#[test]
297+
fn test_odata_type() -> Result<(), Error> {
298+
assert_eq!("@odata.type".to_camel_case_ident()?.to_string(), "OdataType");
299+
Ok(())
300+
}
301+
302+
#[test]
303+
fn test_10minutely() -> Result<(), Error> {
304+
assert_eq!("_10minutely".to_camel_case_ident()?.to_string(), "N10minutely");
305+
Ok(())
306+
}
252307
}

services/autorust/openapi/src/parameter.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ pub enum ParameterType {
5757
Query,
5858
Header,
5959
Body,
60-
Form,
60+
/// https://swagger.io/docs/specification/2-0/describing-parameters/#form-parameters
61+
FormData,
6162
}
6263

6364
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]

services/autorust/openapi/tests/azure_rest_api_specs.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ mod common;
66
use common::*;
77

88
const PATHS: &[&str] = &[
9+
// empty tags[] & consumes[]
10+
// "../../../../azure-rest-api-specs/specification/machinelearningservices/data-plane/Microsoft.MachineLearningServices/preview/2019-09-30/execution.json",
911
"../../../../azure-rest-api-specs/specification/vmware/resource-manager/Microsoft.AVS/stable/2020-03-20/vmware.json",
1012
"../../../../azure-rest-api-specs/specification/batch/data-plane/Microsoft.Batch/stable/2020-03-01.11.0/BatchService.json",
1113
"../../../../azure-rest-api-specs/specification/security/resource-manager/common/v1/types.json",

services/mgmt/appplatform/src/package_2019_05_01_preview/models.rs

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)