@azure-tools/typespec-rust 0.41.5-20260810.2 → 0.42.0
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/README.md +39 -0
- package/dist/src/codegen/cargotoml.d.ts.map +1 -1
- package/dist/src/codegen/cargotoml.js +13 -3
- package/dist/src/codegen/cargotoml.js.map +1 -1
- package/dist/src/codegen/clients.d.ts.map +1 -1
- package/dist/src/codegen/clients.js +84 -186
- package/dist/src/codegen/clients.js.map +1 -1
- package/dist/src/codegen/codeGenerator.d.ts.map +1 -1
- package/dist/src/codegen/codeGenerator.js +8 -2
- package/dist/src/codegen/codeGenerator.js.map +1 -1
- package/dist/src/codegen/context.d.ts.map +1 -1
- package/dist/src/codegen/context.js +3 -2
- package/dist/src/codegen/context.js.map +1 -1
- package/dist/src/codegen/errors.d.ts.map +1 -1
- package/dist/src/codegen/fakes.d.ts +11 -0
- package/dist/src/codegen/fakes.d.ts.map +1 -0
- package/dist/src/codegen/fakes.js +431 -0
- package/dist/src/codegen/fakes.js.map +1 -0
- package/dist/src/codegen/headerTraits.js.map +1 -1
- package/dist/src/codegen/helpers.d.ts +3 -1
- package/dist/src/codegen/helpers.d.ts.map +1 -1
- package/dist/src/codegen/helpers.js.map +1 -1
- package/dist/src/codegen/mod.d.ts +3 -1
- package/dist/src/codegen/mod.d.ts.map +1 -1
- package/dist/src/codegen/mod.js +11 -5
- package/dist/src/codegen/mod.js.map +1 -1
- package/dist/src/codegen/models.js +3 -5
- package/dist/src/codegen/models.js.map +1 -1
- package/dist/src/codegen/parameters.d.ts +13 -0
- package/dist/src/codegen/parameters.d.ts.map +1 -0
- package/dist/src/codegen/parameters.js +64 -0
- package/dist/src/codegen/parameters.js.map +1 -0
- package/dist/src/codegen/use.d.ts.map +1 -1
- package/dist/src/codegen/use.js.map +1 -1
- package/dist/src/codemodel/client.d.ts +12 -0
- package/dist/src/codemodel/client.d.ts.map +1 -1
- package/dist/src/codemodel/client.js +1 -0
- package/dist/src/codemodel/client.js.map +1 -1
- package/dist/src/codemodel/crate.d.ts +2 -0
- package/dist/src/codemodel/crate.d.ts.map +1 -1
- package/dist/src/codemodel/crate.js +1 -0
- package/dist/src/codemodel/crate.js.map +1 -1
- package/dist/src/codemodel/customizations.d.ts.map +1 -1
- package/dist/src/codemodel/method.d.ts.map +1 -1
- package/dist/src/codemodel/types.d.ts.map +1 -1
- package/dist/src/codemodel/types.js +1 -1
- package/dist/src/codemodel/types.js.map +1 -1
- package/dist/src/lib.d.ts +2 -0
- package/dist/src/lib.d.ts.map +1 -1
- package/dist/src/lib.js +6 -0
- package/dist/src/lib.js.map +1 -1
- package/dist/src/tcgcadapter/adapter.d.ts +8 -0
- package/dist/src/tcgcadapter/adapter.d.ts.map +1 -1
- package/dist/src/tcgcadapter/adapter.js +137 -53
- package/dist/src/tcgcadapter/adapter.js.map +1 -1
- package/dist/src/utils/utils.js.map +1 -1
- package/package.json +36 -41
package/README.md
CHANGED
|
@@ -1,6 +1,45 @@
|
|
|
1
1
|
# TypeSpec Rust Generator
|
|
2
2
|
|
|
3
3
|
The TypeSpec Rust generator is intended to be used with the TypeSpec compiler.
|
|
4
|
+
Generated crates should forward their `default` feature to `azure_core/default`
|
|
5
|
+
by setting `default = ["azure_core/default"]` in the `[features]` section of
|
|
6
|
+
`Cargo.toml`. Declare the `azure_core` dependency with `default-features = false`,
|
|
7
|
+
including in `[workspace.dependencies]` when inherited from a workspace.
|
|
8
|
+
Together, these settings enable the default HTTP transport while allowing callers
|
|
9
|
+
to disable it with `--no-default-features`.
|
|
10
|
+
|
|
11
|
+
## Azure Resource Manager
|
|
12
|
+
|
|
13
|
+
ARM services are detected from TypeSpec metadata. Generated crates enable
|
|
14
|
+
`azure_core/unstable_resource_manager` and use Public cloud by default.
|
|
15
|
+
For other clouds, pass the same cloud configuration to the credential and client.
|
|
16
|
+
See the [default-cloud][default-cloud] and [custom-cloud][custom-cloud] examples.
|
|
17
|
+
|
|
18
|
+
Generated pagers and pollers use shared Azure Core helpers, keeping paging and
|
|
19
|
+
long-running operation behavior consistent with ARM conventions.
|
|
20
|
+
|
|
21
|
+
[default-cloud]: test/other/resource_manager/examples/default_cloud.rs
|
|
22
|
+
[custom-cloud]: test/other/resource_manager/examples/custom_cloud.rs
|
|
23
|
+
|
|
24
|
+
## Fake servers
|
|
25
|
+
|
|
26
|
+
Fake server generation is disabled by default. Opt in for data-plane or Resource
|
|
27
|
+
Manager clients with the emitter option:
|
|
28
|
+
|
|
29
|
+
```yaml
|
|
30
|
+
options:
|
|
31
|
+
"@azure-tools/typespec-rust":
|
|
32
|
+
generate-fakes: true
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Enable the generated crate's `unstable_fake` Cargo feature (which also enables
|
|
36
|
+
`test`), implement its `clients::fake::<Name>Server` trait, and construct the client
|
|
37
|
+
with `with_fake()`. No credential is needed. Fakes use the normal client pipeline,
|
|
38
|
+
pagers, and pollers. See the offline [Key Vault secrets example][secrets-fake] and
|
|
39
|
+
[Resource Manager LRO example][arm-fake].
|
|
40
|
+
|
|
41
|
+
[secrets-fake]: test/sdk/keyvault_secrets/examples/secret_client_fake.rs
|
|
42
|
+
[arm-fake]: test/other/resource_manager/examples/fake.rs
|
|
4
43
|
|
|
5
44
|
## Contributing
|
|
6
45
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cargotoml.d.ts","sourceRoot":"","sources":["../../../src/codegen/cargotoml.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,IAAI,MAAM,uBAAuB,CAAC;AAE9C;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"cargotoml.d.ts","sourceRoot":"","sources":["../../../src/codegen/cargotoml.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,IAAI,MAAM,uBAAuB,CAAC;AAE9C;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,MAAM,CA4BvD"}
|
|
@@ -14,15 +14,25 @@ export function emitCargoToml(crate) {
|
|
|
14
14
|
content += 'edition.workspace = true\n';
|
|
15
15
|
content += 'license.workspace = true\n';
|
|
16
16
|
content += 'repository.workspace = true\n';
|
|
17
|
-
content += 'rust-version.workspace = true\n
|
|
17
|
+
content += 'rust-version.workspace = true\n';
|
|
18
|
+
content += 'exclude.workspace = true\n\n';
|
|
18
19
|
content += '[features]\n';
|
|
19
20
|
content += 'default = ["azure_core/default"]\n';
|
|
21
|
+
if (crate.generateFakes) {
|
|
22
|
+
content += 'test = ["azure_core/test"]\n';
|
|
23
|
+
content += 'unstable_fake = ["test", "azure_core/unstable_fake"]\n';
|
|
24
|
+
}
|
|
20
25
|
if (crate.dependencies.length > 0) {
|
|
21
26
|
content += '\n[dependencies]\n';
|
|
22
27
|
for (const dependency of crate.dependencies) {
|
|
23
28
|
// dependency versions are managed by the workspace's Cargo.toml file
|
|
24
|
-
const
|
|
25
|
-
|
|
29
|
+
const featureNames = new Set(dependency.features);
|
|
30
|
+
if (dependency.name === 'azure_core' && crate.type === 'azure-arm') {
|
|
31
|
+
featureNames.add('unstable_resource_manager');
|
|
32
|
+
}
|
|
33
|
+
const features = featureNames.size > 0 ? `, features = [${[...featureNames].sort().map(f => `"${f}"`).join(', ')}]` : '';
|
|
34
|
+
const defaults = dependency.name === 'azure_core' ? ', default-features = false' : '';
|
|
35
|
+
content += `${dependency.name} = { workspace = true${defaults}${features} }\n`;
|
|
26
36
|
}
|
|
27
37
|
}
|
|
28
38
|
return content;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cargotoml.js","sourceRoot":"","sources":["../../../src/codegen/cargotoml.ts"],"names":[],"mappings":"AAAA;;;+FAG+F;AAI/F;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC7C,IAAI,OAAO,GAAG,sBAAsB,KAAK,CAAC,IAAI,iBAAiB,KAAK,CAAC,OAAO,KAAK,CAAC;IAClF,OAAO,IAAI,4BAA4B,CAAC;IACxC,OAAO,IAAI,4BAA4B,CAAC;IACxC,OAAO,IAAI,4BAA4B,CAAC;IACxC,OAAO,IAAI,+BAA+B,CAAC;IAC3C,OAAO,IAAI,
|
|
1
|
+
{"version":3,"file":"cargotoml.js","sourceRoot":"","sources":["../../../src/codegen/cargotoml.ts"],"names":[],"mappings":"AAAA;;;+FAG+F;AAI/F;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC7C,IAAI,OAAO,GAAG,sBAAsB,KAAK,CAAC,IAAI,iBAAiB,KAAK,CAAC,OAAO,KAAK,CAAC;IAClF,OAAO,IAAI,4BAA4B,CAAC;IACxC,OAAO,IAAI,4BAA4B,CAAC;IACxC,OAAO,IAAI,4BAA4B,CAAC;IACxC,OAAO,IAAI,+BAA+B,CAAC;IAC3C,OAAO,IAAI,iCAAiC,CAAC;IAC7C,OAAO,IAAI,8BAA8B,CAAC;IAC1C,OAAO,IAAI,cAAc,CAAC;IAC1B,OAAO,IAAI,oCAAoC,CAAC;IAChD,IAAI,KAAK,CAAC,aAAa,EAAE,CAAC;QACxB,OAAO,IAAI,8BAA8B,CAAC;QAC1C,OAAO,IAAI,wDAAwD,CAAC;IACtE,CAAC;IACD,IAAI,KAAK,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,OAAO,IAAI,oBAAoB,CAAC;QAChC,KAAK,MAAM,UAAU,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;YAC5C,qEAAqE;YACrE,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YAClD,IAAI,UAAU,CAAC,IAAI,KAAK,YAAY,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBACnE,YAAY,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;YAChD,CAAC;YACD,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,GAAG,YAAY,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACzH,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,EAAE,CAAC;YACtF,OAAO,IAAI,GAAG,UAAU,CAAC,IAAI,wBAAwB,QAAQ,GAAG,QAAQ,MAAM,CAAC;QACjF,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clients.d.ts","sourceRoot":"","sources":["../../../src/codegen/clients.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AAGxC,OAAO,KAAK,IAAI,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"clients.d.ts","sourceRoot":"","sources":["../../../src/codegen/clients.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AAGxC,OAAO,KAAK,IAAI,MAAM,uBAAuB,CAAC;AAK9C,yBAAyB;AACzB,MAAM,WAAW,aAAa;IAC5B,iCAAiC;IACjC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAE/B,uCAAuC;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,eAAe,GAAG,aAAa,GAAG,SAAS,CA0VnF"}
|
|
@@ -10,6 +10,8 @@ import queryString from 'query-string';
|
|
|
10
10
|
import { Use } from './use.js';
|
|
11
11
|
import * as rust from '../codemodel/index.js';
|
|
12
12
|
import * as utils from '../utils/utils.js';
|
|
13
|
+
import { emitFakeCapture } from './fakes.js';
|
|
14
|
+
import { methodParameters, requiredConstructorParameters, supplementalEndpoint } from './parameters.js';
|
|
13
15
|
/**
|
|
14
16
|
* emits the content for all client files
|
|
15
17
|
*
|
|
@@ -88,46 +90,13 @@ export function emitClients(module) {
|
|
|
88
90
|
if (crate.type === 'azure-arm') {
|
|
89
91
|
use.add('azure_core', 'Error');
|
|
90
92
|
use.add('azure_core::error', 'ErrorKind');
|
|
91
|
-
use.add('
|
|
92
|
-
// for ARM, derive endpoint and scope from cloud config
|
|
93
|
-
use.add('azure_core::cloud', 'CloudConfiguration');
|
|
93
|
+
use.add('azure_core::cloud::resource_manager', 'CloudConfigurationExt as _');
|
|
94
94
|
use.add('azure_core::http::policies', 'auth::BearerTokenAuthorizationPolicy', 'Policy');
|
|
95
|
-
body += `${indent.push().get()}let
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
+ `\n${indent.get()}"https://management.azure.com/.default".to_string(),`
|
|
101
|
-
+ `\n${indent.pop().get()})\n`
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
pattern: 'Some(CloudConfiguration::AzureGovernment)',
|
|
105
|
-
body: (indent) => `${indent.get()}`
|
|
106
|
-
+ `(\n${indent.push().get()}"https://management.usgovcloudapi.net".to_string(),`
|
|
107
|
-
+ `\n${indent.get()}"https://management.usgovcloudapi.net/.default".to_string(),`
|
|
108
|
-
+ `\n${indent.pop().get()})\n`
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
pattern: 'Some(CloudConfiguration::AzureChina)',
|
|
112
|
-
body: (indent) => `${indent.get()}`
|
|
113
|
-
+ `(\n${indent.push().get()}"https://management.chinacloudapi.cn".to_string(),`
|
|
114
|
-
+ `\n${indent.get()}"https://management.chinacloudapi.cn/.default".to_string(),`
|
|
115
|
-
+ `\n${indent.pop().get()})\n`
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
pattern: 'Some(CloudConfiguration::Custom(custom))',
|
|
119
|
-
body: (indent) => `${indent.get()}{\n`
|
|
120
|
-
+ `${indent.push().get()}let audience = custom.audiences.get::<Audience>().ok_or_else(|| { Error::new(ErrorKind::Credential, "missing custom cloud configuration audience")})?;\n`
|
|
121
|
-
+ `${indent.get()}(audience.to_string(), format!("{}/.default", audience))\n`
|
|
122
|
-
+ `${indent.pop().get()}}\n`
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
pattern: '_',
|
|
126
|
-
body: (indent) => `${indent.get()}unreachable!()\n`
|
|
127
|
-
},
|
|
128
|
-
])};\n`;
|
|
129
|
-
body += `${indent.get()}let endpoint = Url::parse(&endpoint)?;\n`;
|
|
130
|
-
body += `${indent.get()}let auth_policy: Arc<dyn Policy> = Arc::new(BearerTokenAuthorizationPolicy::new(credential, vec![scope]));\n`;
|
|
95
|
+
body += `${indent.push().get()}let cloud = options.client_options.cloud.as_deref().unwrap_or_default();\n`;
|
|
96
|
+
body += `${indent.get()}let endpoint = cloud.endpoint().ok_or_else(|| Error::new(ErrorKind::Other, "missing Resource Manager endpoint"))?;\n`;
|
|
97
|
+
body += `${indent.get()}let endpoint = Url::parse(endpoint)?;\n`;
|
|
98
|
+
body += `${indent.get()}let scope = cloud.default_scope()?.into_owned();\n`;
|
|
99
|
+
body += `${indent.get()}let auth_policy: Arc<dyn Policy> = Arc::new(BearerTokenAuthorizationPolicy::new(credential, vec![scope]).with_options((&options.client_options).into()));\n`;
|
|
131
100
|
hasAuthPolicy = true;
|
|
132
101
|
}
|
|
133
102
|
else {
|
|
@@ -138,21 +107,7 @@ export function emitClients(module) {
|
|
|
138
107
|
condition: `!${endpointParamName}.scheme().starts_with("http")`,
|
|
139
108
|
body: (indent) => `${indent.get()}return Err(azure_core::Error::with_message(azure_core::error::ErrorKind::Other, format!("{${endpointParamName}} must use http(s)")));\n`,
|
|
140
109
|
})}`;
|
|
141
|
-
|
|
142
|
-
if (client.constructable.endpoint) {
|
|
143
|
-
const supplementalEndpoint = client.constructable.endpoint;
|
|
144
|
-
if (supplementalEndpoint.parameters.length > 0) {
|
|
145
|
-
body += `${indent.get()}let mut host = String::from("${supplementalEndpoint.path}");\n`;
|
|
146
|
-
for (const param of supplementalEndpoint.parameters) {
|
|
147
|
-
body += `${indent.get()}host = host.replace("{${param.segment}}", ${getClientSupplementalEndpointParamValue(param)});\n`;
|
|
148
|
-
}
|
|
149
|
-
body += `${indent.push().get()}${endpointParamName} = ${endpointParamName}.join(&host)?;\n`;
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
// there are no params for the supplemental host, so just append it
|
|
153
|
-
body += `${indent.push().get()}${endpointParamName} = ${endpointParamName}.join("${supplementalEndpoint.path}")?;\n`;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
110
|
+
body += supplementalEndpoint(indent, endpointParamName, client.constructable.endpoint);
|
|
156
111
|
// if there's a credential param, create the necessary auth policy
|
|
157
112
|
const authPolicy = getAuthPolicy(constructor, use);
|
|
158
113
|
if (authPolicy) {
|
|
@@ -548,11 +503,7 @@ function getParamsBlockDocComment(indent, callable) {
|
|
|
548
503
|
*/
|
|
549
504
|
function getConstructorParamsSig(params, options, use) {
|
|
550
505
|
const paramsSig = new Array();
|
|
551
|
-
for (const param of params) {
|
|
552
|
-
if (param.optional) {
|
|
553
|
-
// optional params will be in the client options type
|
|
554
|
-
continue;
|
|
555
|
-
}
|
|
506
|
+
for (const param of requiredConstructorParameters(params)) {
|
|
556
507
|
use.addForType(param.type);
|
|
557
508
|
paramsSig.push(`${param.name}: ${helpers.getTypeDeclaration(param.type)}`);
|
|
558
509
|
}
|
|
@@ -582,34 +533,18 @@ function getMethodParamsCountAndSig(method, use) {
|
|
|
582
533
|
}
|
|
583
534
|
}
|
|
584
535
|
else {
|
|
585
|
-
const emittedGroups = new Set();
|
|
586
536
|
for (const param of method.params) {
|
|
587
|
-
if (param.group) {
|
|
588
|
-
if (!emittedGroups.has(param.group.name)) {
|
|
589
|
-
emittedGroups.add(param.group.name);
|
|
590
|
-
// required parameter group appears as a single struct parameter in the method signature
|
|
591
|
-
paramsSig.push(`${param.group.name}: ${helpers.getTypeDeclaration(param.group.type, 'anonymous')}`);
|
|
592
|
-
++count;
|
|
593
|
-
}
|
|
594
|
-
continue;
|
|
595
|
-
}
|
|
596
537
|
const paramType = helpers.unwrapType(param.type);
|
|
597
|
-
if (paramType.kind === '
|
|
598
|
-
// literal params are embedded directly in the code (e.g. accept header param)
|
|
599
|
-
continue;
|
|
600
|
-
}
|
|
601
|
-
else if (paramType.kind === 'enumValue') {
|
|
602
|
-
// enum values are treated like literals, we just need to use their type
|
|
538
|
+
if (!param.group && paramType.kind === 'enumValue') {
|
|
603
539
|
use.addForType(paramType.type);
|
|
604
|
-
continue;
|
|
605
|
-
}
|
|
606
|
-
// don't add client or optional params to the method param sig
|
|
607
|
-
if (param.location === 'method' && !param.optional) {
|
|
608
|
-
use.addForType(param.kind === 'partialBody' ? param.paramType : param.type);
|
|
609
|
-
paramsSig.push(`${param.name}: ${formatParamTypeName(param)}`);
|
|
610
|
-
++count;
|
|
611
540
|
}
|
|
612
541
|
}
|
|
542
|
+
for (const param of methodParameters(method)) {
|
|
543
|
+
use.addForType(param.type);
|
|
544
|
+
const grouped = method.params.some(p => { var _a; return ((_a = p.group) === null || _a === void 0 ? void 0 : _a.name) === param.name; });
|
|
545
|
+
paramsSig.push(`${param.name}: ${param.mut ? 'mut ' : ''}${helpers.getTypeDeclaration(param.type, grouped ? 'anonymous' : undefined)}`);
|
|
546
|
+
++count;
|
|
547
|
+
}
|
|
613
548
|
paramsSig.push(`${method.options.name}: ${helpers.getTypeDeclaration(method.options.type, 'anonymous')}`);
|
|
614
549
|
++count;
|
|
615
550
|
}
|
|
@@ -673,7 +608,7 @@ function getAuthPolicy(ctor, use) {
|
|
|
673
608
|
for (const scope of arcTokenCred.scopes) {
|
|
674
609
|
scopes.push(`"${scope}"`);
|
|
675
610
|
}
|
|
676
|
-
return `let auth_policy: Arc<dyn Policy> = Arc::new(BearerTokenAuthorizationPolicy::new(credential, vec![${scopes.join(', ')}]));`;
|
|
611
|
+
return `let auth_policy: Arc<dyn Policy> = Arc::new(BearerTokenAuthorizationPolicy::new(credential, vec![${scopes.join(', ')}]).with_options((&options.client_options).into()));`;
|
|
677
612
|
}
|
|
678
613
|
}
|
|
679
614
|
return undefined;
|
|
@@ -812,10 +747,10 @@ function getMethodParamGroup(method) {
|
|
|
812
747
|
};
|
|
813
748
|
}
|
|
814
749
|
/**
|
|
815
|
-
* wraps the
|
|
750
|
+
* wraps the code emitted by setter in a presence check
|
|
816
751
|
* if the parameter is optional, else the value of setter is returned.
|
|
817
752
|
*
|
|
818
|
-
* NOTE: for optional params,
|
|
753
|
+
* NOTE: for optional non-constant params, we'll create a local named param.name.
|
|
819
754
|
* setter MUST reference by param.name so it works for optional and required params.
|
|
820
755
|
*
|
|
821
756
|
* @param indent the indentation helper currently in scope
|
|
@@ -834,8 +769,9 @@ function getParamValueHelper(indent, param, setter, optionsPrefix = 'options.')
|
|
|
834
769
|
asRefOrClone = '.as_ref()';
|
|
835
770
|
}
|
|
836
771
|
// optional params are in the unwrapped options local var
|
|
772
|
+
const paramRef = `${param.location === 'client' ? 'self.' : optionsPrefix}${param.name}`;
|
|
837
773
|
const op = indent.get() + helpers.buildIfBlock(indent, {
|
|
838
|
-
condition:
|
|
774
|
+
condition: param.type.kind === 'enumValue' ? `${paramRef}.is_some()` : `let Some(${param.name}) = ${paramRef}${asRefOrClone}`,
|
|
839
775
|
body: setter,
|
|
840
776
|
});
|
|
841
777
|
return op + '\n';
|
|
@@ -1280,6 +1216,7 @@ function getAsyncMethodBody(indent, use, client, method) {
|
|
|
1280
1216
|
const paramGroups = getMethodParamGroup(method);
|
|
1281
1217
|
let body = checkEmptyRequiredPathParams(indent, paramGroups.path);
|
|
1282
1218
|
body += 'let options = options.unwrap_or_default();\n';
|
|
1219
|
+
body += emitFakeCapture(client, method);
|
|
1283
1220
|
body += `${indent.get()}let ctx = options.method_options.context.to_borrowed();\n`;
|
|
1284
1221
|
body += `${indent.get()}let ${urlVarNeedsMut(paramGroups, method)}${urlVarName} = self.${client.endpoint.name}.clone();\n`;
|
|
1285
1222
|
body += constructUrl(indent, use, method, paramGroups, urlVarName);
|
|
@@ -1412,7 +1349,8 @@ function getLroMonitorHelperStruct(indent: helpers.indentation, client: rust.Cli
|
|
|
1412
1349
|
* @returns the contents of the method body
|
|
1413
1350
|
*/
|
|
1414
1351
|
function getPageableMethodBody(indent, use, client, method) {
|
|
1415
|
-
var _a, _b
|
|
1352
|
+
var _a, _b;
|
|
1353
|
+
var _c;
|
|
1416
1354
|
use.add('azure_core::http', 'Method', 'Request', 'Url');
|
|
1417
1355
|
use.add('azure_core::http::pager', 'PagerResult', 'PagerState');
|
|
1418
1356
|
use.add('azure_core', 'Result');
|
|
@@ -1423,6 +1361,7 @@ function getPageableMethodBody(indent, use, client, method) {
|
|
|
1423
1361
|
const pageableResponseHelperStruct = getPageableResponseHelperStruct(indent, client, method);
|
|
1424
1362
|
let body = checkEmptyRequiredPathParams(indent, paramGroups.path);
|
|
1425
1363
|
body += 'let options = options.unwrap_or_default().into_owned();\n';
|
|
1364
|
+
body += emitFakeCapture(client, method);
|
|
1426
1365
|
body += `${indent.get()}let pipeline = self.pipeline.clone();\n`;
|
|
1427
1366
|
body += `${indent.get()}let ${urlVarNeedsMut(paramGroups, method)}${urlVar} = self.${client.endpoint.name}.clone();\n`;
|
|
1428
1367
|
body += constructUrl(indent, use, method, paramGroups, urlVar);
|
|
@@ -1547,7 +1486,7 @@ function getPageableMethodBody(indent, use, client, method) {
|
|
|
1547
1486
|
use.add('azure_core', bodyFormat, 'http::RawResponse');
|
|
1548
1487
|
body += `${indent.get()}let (status, headers, body) = rsp.deconstruct();\n`;
|
|
1549
1488
|
const deserialize = `${bodyFormat}::from_${bodyFormat}`;
|
|
1550
|
-
body += `${indent.get()}let res: ${(
|
|
1489
|
+
body += `${indent.get()}let res: ${(_c = pageableResponseHelperStruct === null || pageableResponseHelperStruct === void 0 ? void 0 : pageableResponseHelperStruct.typeName) !== null && _c !== void 0 ? _c : helpers.getTypeDeclaration(helpers.unwrapType(method.returns.type))} = ${deserialize}(&body)?;\n`;
|
|
1551
1490
|
body += `${indent.get()}let rsp = RawResponse::from_bytes(status, headers, body).into();\n`;
|
|
1552
1491
|
}
|
|
1553
1492
|
if (method.strategy) {
|
|
@@ -1615,7 +1554,7 @@ function getPageableMethodBody(indent, use, client, method) {
|
|
|
1615
1554
|
// non-continuation case, so we don't need to worry about next links, continuation tokens, etc...
|
|
1616
1555
|
body += `${indent.get()}Ok(PagerResult::Done { response: rsp.into() })\n`;
|
|
1617
1556
|
}
|
|
1618
|
-
if (((
|
|
1557
|
+
if (((_b = method.strategy) === null || _b === void 0 ? void 0 : _b.kind) === 'nextLink') {
|
|
1619
1558
|
body += `${indent.pop().get()}}\n`;
|
|
1620
1559
|
}
|
|
1621
1560
|
body += `${indent.pop().get()}})\n`; // end Box::pin(async move {
|
|
@@ -1633,8 +1572,60 @@ function getPageableMethodBody(indent, use, client, method) {
|
|
|
1633
1572
|
* @param method the method for the body to build
|
|
1634
1573
|
* @returns the contents of the method body
|
|
1635
1574
|
*/
|
|
1575
|
+
function getResourceManagerLroMethodBody(crate, indent, use, client, method) {
|
|
1576
|
+
use.add('azure_core::http', 'Method', 'Request');
|
|
1577
|
+
use.addForType(helpers.unwrapType(method.returns.type));
|
|
1578
|
+
use.add('azure_core::http::poller::resource_manager', 'new_poller');
|
|
1579
|
+
const params = getMethodParamGroup(method);
|
|
1580
|
+
const url = helpers.getUniqueVarName(method.params, ['url', 'url_var']);
|
|
1581
|
+
let body = 'let options = options.unwrap_or_default().into_owned();\n';
|
|
1582
|
+
body += emitFakeCapture(client, method);
|
|
1583
|
+
body += `${indent.get()}let ${urlVarNeedsMut(params, method)}${url} = self.${client.endpoint.name}.clone();\n`;
|
|
1584
|
+
body += constructUrl(indent, use, method, params, url);
|
|
1585
|
+
const request = constructRequest(indent, use, method, params, false, url, false, params.body !== undefined || params.partialBody.length > 0);
|
|
1586
|
+
body += request.content;
|
|
1587
|
+
let finalState = 'None';
|
|
1588
|
+
const selection = method.resourceManagerFinalState;
|
|
1589
|
+
if (selection) {
|
|
1590
|
+
use.add('azure_core::http::poller::resource_manager', 'FinalStateVia');
|
|
1591
|
+
let callback = '';
|
|
1592
|
+
if (selection.selector === 'OperationLocation') {
|
|
1593
|
+
const path = selection.resultPath;
|
|
1594
|
+
callback = '( |response| {\n';
|
|
1595
|
+
if (path.length > 0) {
|
|
1596
|
+
crate.addDependency(new rust.CrateDependency('serde_json', ['raw_value']));
|
|
1597
|
+
use.add('azure_core', 'Bytes');
|
|
1598
|
+
use.add('azure_core::http', 'RawResponse');
|
|
1599
|
+
indent.push();
|
|
1600
|
+
for (let i = 0; i < path.length; ++i) {
|
|
1601
|
+
callback += `${indent.get()}#[derive(serde::Deserialize)]\n`;
|
|
1602
|
+
callback += `${indent.get()}struct ResultEnvelope${i}<'a> {\n`;
|
|
1603
|
+
callback += `${indent.push().get()}#[serde(borrow, rename = ${JSON.stringify(path[i])})]\n`;
|
|
1604
|
+
callback += `${indent.get()}value: ${i === path.length - 1 ? "&'a serde_json::value::RawValue" : `ResultEnvelope${i + 1}<'a>`},\n`;
|
|
1605
|
+
callback += `${indent.pop().get()}}\n`;
|
|
1606
|
+
}
|
|
1607
|
+
callback += `${indent.get()}let (status, headers, body) = response.deconstruct();\n`;
|
|
1608
|
+
callback += `${indent.get()}let bytes = Bytes::from(body);\n`;
|
|
1609
|
+
callback += `${indent.get()}let envelope: ResultEnvelope0<'_> = serde_json::from_slice(&bytes)?;\n`;
|
|
1610
|
+
callback += `${indent.get()}let result = bytes.slice_ref(envelope${'.value'.repeat(path.length)}.get().as_bytes());\n`;
|
|
1611
|
+
callback += `${indent.get()}Ok(RawResponse::from_bytes(status, headers, result).into())\n`;
|
|
1612
|
+
indent.pop();
|
|
1613
|
+
}
|
|
1614
|
+
else {
|
|
1615
|
+
callback += `${indent.get()}Ok(response.to_raw_response().into())\n`;
|
|
1616
|
+
}
|
|
1617
|
+
callback += `${indent.get()}})`;
|
|
1618
|
+
}
|
|
1619
|
+
finalState = `Some(FinalStateVia::${selection.selector}${callback})`;
|
|
1620
|
+
}
|
|
1621
|
+
body += `${indent.get()}Ok(new_poller(self.pipeline.clone(), ${request.requestVarName}, ${finalState}, Some(options.method_options)))\n`;
|
|
1622
|
+
return body;
|
|
1623
|
+
}
|
|
1636
1624
|
function getLroMethodBody(crate, indent, use, client, method) {
|
|
1637
1625
|
var _a;
|
|
1626
|
+
if (crate.type === 'azure-arm') {
|
|
1627
|
+
return getResourceManagerLroMethodBody(crate, indent, use, client, method);
|
|
1628
|
+
}
|
|
1638
1629
|
let pollingStepHeaderName = undefined;
|
|
1639
1630
|
for (const header of ['operation-location', 'azure-asyncoperation', 'location']) {
|
|
1640
1631
|
if ((_a = method.responseHeaders) === null || _a === void 0 ? void 0 : _a.headers.some(h => h.header.toLowerCase() === header)) {
|
|
@@ -1654,6 +1645,7 @@ function getLroMethodBody(crate, indent, use, client, method) {
|
|
|
1654
1645
|
const paramGroups = getMethodParamGroup(method);
|
|
1655
1646
|
const urlVar = helpers.getUniqueVarName(method.params, ['url', 'url_var']);
|
|
1656
1647
|
let body = 'let options = options.unwrap_or_default().into_owned();\n';
|
|
1648
|
+
body += emitFakeCapture(client, method);
|
|
1657
1649
|
body += `${indent.get()}let pipeline = self.pipeline.clone();\n`;
|
|
1658
1650
|
body += `${indent.get()}let ${urlVarNeedsMut(paramGroups, method)}${urlVar} = self.${client.endpoint.name}.clone();\n`;
|
|
1659
1651
|
body += constructUrl(indent, use, method, paramGroups, urlVar);
|
|
@@ -1730,64 +1722,13 @@ function getLroMethodBody(crate, indent, use, client, method) {
|
|
|
1730
1722
|
}
|
|
1731
1723
|
}
|
|
1732
1724
|
}
|
|
1733
|
-
// Match an ARM PUT operation ("create or update"), which may have immediate 200 OK response with no headers and no poller status
|
|
1734
|
-
const isArmPutLro = bodyFormat === 'json'
|
|
1735
|
-
&& method.httpMethod === 'put'
|
|
1736
|
-
&& method.returns.type.resultType !== undefined
|
|
1737
|
-
&& method.finalResultStrategy.kind === 'header'
|
|
1738
|
-
&& method.finalResultStrategy.headerName === 'azure-asyncoperation'
|
|
1739
|
-
&& pollingStepHeaderName === 'azure-asyncoperation'
|
|
1740
|
-
&& method.statusCodes.some(sc => sc == 200)
|
|
1741
|
-
&& method.statusCodes.some(sc => sc == 201);
|
|
1742
|
-
// Match an ARM PATCH operation ("update"), which may have immediate 200 OK response with no headers and no poller status
|
|
1743
|
-
const isArmPatchLro = bodyFormat === 'json'
|
|
1744
|
-
&& method.httpMethod === 'patch'
|
|
1745
|
-
&& method.returns.type.resultType !== undefined
|
|
1746
|
-
&& method.finalResultStrategy.kind === 'header'
|
|
1747
|
-
&& method.finalResultStrategy.headerName === 'location'
|
|
1748
|
-
&& pollingStepHeaderName === 'location'
|
|
1749
|
-
&& method.statusCodes.some(sc => sc == 200)
|
|
1750
|
-
&& method.statusCodes.some(sc => sc == 202);
|
|
1751
|
-
// Match an ARM POST operation ("export"), which may have empty initial response
|
|
1752
|
-
const isArmPostLro = bodyFormat === 'json'
|
|
1753
|
-
&& method.httpMethod === 'post'
|
|
1754
|
-
&& method.returns.type.resultType !== undefined
|
|
1755
|
-
&& method.finalResultStrategy.kind === 'header'
|
|
1756
|
-
&& method.finalResultStrategy.headerName === 'location'
|
|
1757
|
-
&& pollingStepHeaderName === 'azure-asyncoperation'
|
|
1758
|
-
&& method.statusCodes.some(sc => sc == 200)
|
|
1759
|
-
&& method.statusCodes.some(sc => sc == 202);
|
|
1760
|
-
// Match an ARM DELETE operation, which may have empty responses and only communicate via status codes
|
|
1761
|
-
const isArmDeleteLro = bodyFormat === 'json'
|
|
1762
|
-
&& method.httpMethod === 'delete'
|
|
1763
|
-
&& method.returns.type.resultType === undefined
|
|
1764
|
-
&& method.finalResultStrategy.kind === 'header'
|
|
1765
|
-
&& method.finalResultStrategy.headerName === 'location'
|
|
1766
|
-
&& pollingStepHeaderName === 'location'
|
|
1767
|
-
&& method.statusCodes.some(sc => sc == 200)
|
|
1768
|
-
&& method.statusCodes.some(sc => sc == 202)
|
|
1769
|
-
&& method.statusCodes.some(sc => sc == 204);
|
|
1770
|
-
if (isArmPutLro || isArmPatchLro) {
|
|
1771
|
-
body += 'let original_url = url.clone();\n';
|
|
1772
|
-
}
|
|
1773
1725
|
body += `${indent.get()}Box::pin(async move {\n`;
|
|
1774
1726
|
if (fallibleInitialPollerRequest) {
|
|
1775
1727
|
body += `${indent.push().get()}let (mut ${initialRequestResult.requestVarName}, continuation) = poller_request?;\n`;
|
|
1776
1728
|
indent.pop();
|
|
1777
1729
|
}
|
|
1778
1730
|
body += `${indent.push().get()}let rsp = pipeline.send(&ctx, &mut ${initialRequestResult.requestVarName}, ${getPipelineOptions(indent, use, method)}).await?;\n`;
|
|
1779
|
-
|
|
1780
|
-
body += `${indent.get()}let (status, headers, ${needsMutBody ? 'mut' : ''} body) = rsp.deconstruct();\n`;
|
|
1781
|
-
if (isArmPostLro || isArmDeleteLro) {
|
|
1782
|
-
body += `${indent.get()}if body.is_empty() {\n`;
|
|
1783
|
-
let emptyBodyExpr = '"{}"';
|
|
1784
|
-
if (isArmDeleteLro) {
|
|
1785
|
-
use.add('azure_core::http', 'StatusCode');
|
|
1786
|
-
emptyBodyExpr = `if status == StatusCode::NoContent { "{\\"status\\":\\"Succeeded\\"}" } else { "{}" }`;
|
|
1787
|
-
}
|
|
1788
|
-
body += `${indent.push().get()}body = azure_core::http::response::ResponseBody::from_bytes(${emptyBodyExpr});\n`;
|
|
1789
|
-
body += `${indent.pop().get()}}\n`;
|
|
1790
|
-
}
|
|
1731
|
+
body += `${indent.get()}let (status, headers, body) = rsp.deconstruct();\n`;
|
|
1791
1732
|
if (pollingStepHeaderName !== undefined) {
|
|
1792
1733
|
body += `${indent.get()}let continuation = ${helpers.buildIfBlock(indent, {
|
|
1793
1734
|
condition: `let Some(operation_location) = headers.get_optional_string(&HeaderName::from_static("${pollingStepHeaderName}"))`,
|
|
@@ -1806,21 +1747,6 @@ function getLroMethodBody(crate, indent, use, client, method) {
|
|
|
1806
1747
|
body: (indent) => `${indent.get()}continuation\n`
|
|
1807
1748
|
})};\n`;
|
|
1808
1749
|
}
|
|
1809
|
-
if (isArmPutLro || isArmPatchLro) {
|
|
1810
|
-
use.add('azure_core::http', 'StatusCode');
|
|
1811
|
-
body += `${indent.get()}let next_link = ${helpers.buildMatch(indent, '&continuation', [{
|
|
1812
|
-
pattern: 'PollerContinuation::Links { next_link, .. }',
|
|
1813
|
-
body: (indent) => `${indent.get()}next_link\n`,
|
|
1814
|
-
}, {
|
|
1815
|
-
pattern: '_',
|
|
1816
|
-
body: (indent) => `${indent.get()}unreachable!()\n`,
|
|
1817
|
-
}])};\n`;
|
|
1818
|
-
body += `${indent.get()}let mut final_body = None;\n`;
|
|
1819
|
-
body += `${indent.get()}if status == StatusCode::Ok && next_link.as_str() == original_url.as_str() {\n`;
|
|
1820
|
-
body += `${indent.push().get()}final_body = Some(body);\n`;
|
|
1821
|
-
body += `${indent.get()}body = azure_core::http::response::ResponseBody::from_bytes("{\\"status\\":\\"Succeeded\\"}");\n`;
|
|
1822
|
-
body += `${indent.pop().get()}}\n`;
|
|
1823
|
-
}
|
|
1824
1750
|
if (method.finalResultStrategy.kind === 'header' && method.finalResultStrategy.headerName !== pollingStepHeaderName) { // separate link for picking up the result
|
|
1825
1751
|
body += `${indent.get()}let continuation = ${helpers.buildIfBlock(indent, {
|
|
1826
1752
|
condition: `let Some(final_link) = headers.get_optional_string(&HeaderName::from_static("${method.finalResultStrategy.headerName}"))`,
|
|
@@ -1854,10 +1780,7 @@ function getLroMethodBody(crate, indent, use, client, method) {
|
|
|
1854
1780
|
body += `${indent.get()}let mut final_rsp: Option<RawResponse> = None;\n`;
|
|
1855
1781
|
body += `if res.status() == PollerStatus::Succeeded {\n`;
|
|
1856
1782
|
let responseBodyExpr = 'body.clone()';
|
|
1857
|
-
if (
|
|
1858
|
-
responseBodyExpr = 'if let Some(final_body) = final_body { final_body } else { body.clone() }';
|
|
1859
|
-
}
|
|
1860
|
-
else if (method.finalResultStrategy.propertyName !== undefined) {
|
|
1783
|
+
if (method.finalResultStrategy.propertyName !== undefined) {
|
|
1861
1784
|
responseBodyExpr = 'body';
|
|
1862
1785
|
if (bodyFormat === 'json') {
|
|
1863
1786
|
crate.addDependency(new rust.CrateDependency('serde_json'));
|
|
@@ -1912,32 +1835,6 @@ function getLroMethodBody(crate, indent, use, client, method) {
|
|
|
1912
1835
|
body += `${indent.pop().get()} Some(options.method_options),))`; // end Ok/Poller::new
|
|
1913
1836
|
return body;
|
|
1914
1837
|
}
|
|
1915
|
-
/**
|
|
1916
|
-
* contains the code to use when populating a client endpoint parameter value
|
|
1917
|
-
* from a parameter of that type.
|
|
1918
|
-
* @param param the param for which to get the value
|
|
1919
|
-
* @returns the code to use for the param's value
|
|
1920
|
-
*/
|
|
1921
|
-
function getClientSupplementalEndpointParamValue(param) {
|
|
1922
|
-
let paramName = param.name;
|
|
1923
|
-
if (param.optional) {
|
|
1924
|
-
paramName = 'options.' + paramName;
|
|
1925
|
-
}
|
|
1926
|
-
const unwrappedType = helpers.unwrapType(param.type);
|
|
1927
|
-
switch (unwrappedType.kind) {
|
|
1928
|
-
case 'String':
|
|
1929
|
-
return `&${paramName}`;
|
|
1930
|
-
case 'enum':
|
|
1931
|
-
return `${paramName}.as_ref()`;
|
|
1932
|
-
case 'offsetDateTime':
|
|
1933
|
-
case 'scalar':
|
|
1934
|
-
return `&${paramName}.to_string()`;
|
|
1935
|
-
case 'str':
|
|
1936
|
-
return paramName;
|
|
1937
|
-
default:
|
|
1938
|
-
throw new CodegenError('InternalError', `unhandled ${param.kind} param type kind ${param.type.kind}`);
|
|
1939
|
-
}
|
|
1940
|
-
}
|
|
1941
1838
|
/**
|
|
1942
1839
|
* returns the code to use when populating a header/path/query value
|
|
1943
1840
|
* from a parameter of that type. this will include any borrowing of
|
|
@@ -2058,6 +1955,7 @@ function getHeaderPathQueryParamValue(use, param, fromSelf, neverBorrow, overrid
|
|
|
2058
1955
|
break;
|
|
2059
1956
|
case 'literal':
|
|
2060
1957
|
paramValue = `"${paramType.value}"`;
|
|
1958
|
+
mustBorrow = false;
|
|
2061
1959
|
break;
|
|
2062
1960
|
case 'offsetDateTime':
|
|
2063
1961
|
paramValue = encodeDateTime(paramType, paramName);
|