@azure-tools/typespec-rust 0.41.5 → 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 -36
|
@@ -90,11 +90,17 @@ export class Adapter {
|
|
|
90
90
|
serviceType = 'azure-arm';
|
|
91
91
|
}
|
|
92
92
|
this.crate = new rust.Crate(this.options['crate-name'], (_a = this.options['crate-version']) !== null && _a !== void 0 ? _a : '0.1.0', serviceType);
|
|
93
|
+
this.crate.generateFakes = this.options['generate-fakes'] === true;
|
|
93
94
|
}
|
|
94
95
|
/** performs all the steps to convert tcgc to a crate */
|
|
95
96
|
tcgcToCrate() {
|
|
96
97
|
this.adaptTypes();
|
|
97
98
|
this.adaptClients();
|
|
99
|
+
// Register before CodeGenerator sorts dependencies, including nested clients.
|
|
100
|
+
const hasClients = (module) => module.clients.length > 0 || module.subModules.some(hasClients);
|
|
101
|
+
if (this.crate.generateFakes && hasClients(this.crate)) {
|
|
102
|
+
this.crate.addDependency(new rust.CrateDependency('async-trait'));
|
|
103
|
+
}
|
|
98
104
|
return this.crate;
|
|
99
105
|
}
|
|
100
106
|
/** converts tcgc docs to formatted rust.Docs */
|
|
@@ -269,7 +275,8 @@ export class Adapter {
|
|
|
269
275
|
* @returns a Rust enum
|
|
270
276
|
*/
|
|
271
277
|
getEnum(sdkEnum) {
|
|
272
|
-
var _a, _b
|
|
278
|
+
var _a, _b;
|
|
279
|
+
var _c;
|
|
273
280
|
const enumName = utils.deconstruct(sdkEnum.name).map((each) => utils.capitalize(each)).join('');
|
|
274
281
|
let rustEnum = this.types.get(enumName);
|
|
275
282
|
if (rustEnum) {
|
|
@@ -485,7 +492,8 @@ export class Adapter {
|
|
|
485
492
|
* @returns a Rust union
|
|
486
493
|
*/
|
|
487
494
|
getDiscriminatedUnion(src) {
|
|
488
|
-
var _a, _b, _c, _d, _e, _f, _g, _h
|
|
495
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
496
|
+
var _j;
|
|
489
497
|
if (src.name.length === 0) {
|
|
490
498
|
throw new AdapterError('InternalError', 'unnamed union', (_a = src.__raw) === null || _a === void 0 ? void 0 : _a.node);
|
|
491
499
|
}
|
|
@@ -547,9 +555,9 @@ export class Adapter {
|
|
|
547
555
|
rustUnion.unionKind = new rust.DiscriminatedUnionBase(baseModel);
|
|
548
556
|
}
|
|
549
557
|
// we need to handle the case where src is a root with no child types
|
|
550
|
-
for (const subType of Object.values((
|
|
558
|
+
for (const subType of Object.values((_j = src.discriminatedSubtypes) !== null && _j !== void 0 ? _j : {})) {
|
|
551
559
|
if (!subType.discriminatorValue) {
|
|
552
|
-
throw new AdapterError('InternalError', `model ${subType.name} has no discriminator value`, (
|
|
560
|
+
throw new AdapterError('InternalError', `model ${subType.name} has no discriminator value`, (_e = subType.__raw) === null || _e === void 0 ? void 0 : _e.node);
|
|
553
561
|
}
|
|
554
562
|
const unionMemberType = subType.discriminatedSubtypes ? this.getDiscriminatedUnion(subType) : this.getModel(subType);
|
|
555
563
|
const rustUnionMember = new rust.DiscriminatedUnionMember(unionMemberType, subType.discriminatorValue);
|
|
@@ -562,7 +570,7 @@ export class Adapter {
|
|
|
562
570
|
// we should have verified this earlier.
|
|
563
571
|
// having this check means the compiler won't bark
|
|
564
572
|
// at us when accessing src.discriminatedOptions
|
|
565
|
-
throw new AdapterError('InternalError', 'getDiscriminatedUnion called for non-discriminated union', (
|
|
573
|
+
throw new AdapterError('InternalError', 'getDiscriminatedUnion called for non-discriminated union', (_f = src.__raw) === null || _f === void 0 ? void 0 : _f.node);
|
|
566
574
|
}
|
|
567
575
|
rustUnion = new rust.DiscriminatedUnion(unionName, adaptAccessFlags(src.access), src.discriminatedOptions.discriminatorPropertyName, this.adaptNamespace(src.namespace));
|
|
568
576
|
if (src.discriminatedOptions.envelopePropertyName) {
|
|
@@ -585,12 +593,12 @@ export class Adapter {
|
|
|
585
593
|
// END WORKAROUND
|
|
586
594
|
for (const unionMember of src.variantTypes) {
|
|
587
595
|
if (unionMember.kind !== 'model') {
|
|
588
|
-
throw new AdapterError('UnsupportedTsp', `non-model union member kind ${unionMember.kind}`, (
|
|
596
|
+
throw new AdapterError('UnsupportedTsp', `non-model union member kind ${unionMember.kind}`, (_g = unionMember.__raw) === null || _g === void 0 ? void 0 : _g.node);
|
|
589
597
|
}
|
|
590
598
|
// TODO: use unionMember.discriminatorValue
|
|
591
599
|
const discriminatorValue = discriminatorValues.get(unionMember.name);
|
|
592
600
|
if (!discriminatorValue) {
|
|
593
|
-
throw new AdapterError('InternalError', `didn't find discriminant value for type ${unionMember.name}`, (
|
|
601
|
+
throw new AdapterError('InternalError', `didn't find discriminant value for type ${unionMember.name}`, (_h = unionMember.__raw) === null || _h === void 0 ? void 0 : _h.node);
|
|
594
602
|
}
|
|
595
603
|
const unionMemberType = this.getModel(unionMember);
|
|
596
604
|
const rustUnionMember = new rust.DiscriminatedUnionMember(unionMemberType, discriminatorValue);
|
|
@@ -605,8 +613,9 @@ export class Adapter {
|
|
|
605
613
|
return rustUnion;
|
|
606
614
|
}
|
|
607
615
|
getSerializedPropertyName(property) {
|
|
608
|
-
var _a, _b, _c
|
|
609
|
-
|
|
616
|
+
var _a, _b, _c;
|
|
617
|
+
var _d, _e;
|
|
618
|
+
return property.kind === 'property' ? (_e = (_d = (_a = property.serializationOptions.json) === null || _a === void 0 ? void 0 : _a.name) !== null && _d !== void 0 ? _d : (_b = property.serializationOptions.xml) === null || _b === void 0 ? void 0 : _b.name) !== null && _e !== void 0 ? _e : (_c = property.serializationOptions.multipart) === null || _c === void 0 ? void 0 : _c.name : undefined;
|
|
610
619
|
}
|
|
611
620
|
/**
|
|
612
621
|
* converts a non-discriminated tcgc union to either a flat merged Rust Enum (union-of-enums)
|
|
@@ -805,7 +814,8 @@ export class Adapter {
|
|
|
805
814
|
* @returns a Rust model field
|
|
806
815
|
*/
|
|
807
816
|
getModelField(modelFlags, property, modelVisibility, stack) {
|
|
808
|
-
var _a, _b, _c
|
|
817
|
+
var _a, _b, _c;
|
|
818
|
+
var _d, _e, _f, _g;
|
|
809
819
|
const fieldNeedsBoxing = function (fieldType) {
|
|
810
820
|
if (fieldType.kind === 'model' && (stack.includes(fieldType))) {
|
|
811
821
|
// if the field's type is a model and it's in the type stack then
|
|
@@ -834,7 +844,7 @@ export class Adapter {
|
|
|
834
844
|
if (notSpreadOnly || property.optional) {
|
|
835
845
|
fieldType = this.getOptionType(fieldType.kind === 'box' ? fieldType : this.typeToWireType(fieldType));
|
|
836
846
|
}
|
|
837
|
-
const serializedName = (
|
|
847
|
+
const serializedName = (_d = this.getSerializedPropertyName(property)) !== null && _d !== void 0 ? _d : property.name;
|
|
838
848
|
const modelField = new rust.ModelField(naming.getEscapedReservedName(utils.snakeCaseName(property.name), 'prop'), serializedName, modelVisibility, fieldType, property.optional);
|
|
839
849
|
modelField.docs = this.adaptDocs(property.summary, property.doc);
|
|
840
850
|
// append visibility info as a doc comment when visibility is restricted
|
|
@@ -901,7 +911,7 @@ export class Adapter {
|
|
|
901
911
|
code: 'DuplicateClientOption',
|
|
902
912
|
severity: 'warning',
|
|
903
913
|
message: `duplicate client option ${optionName} on model field ${property.name} will be ignored`,
|
|
904
|
-
target: (
|
|
914
|
+
target: (_e = (_a = property.__raw) === null || _a === void 0 ? void 0 : _a.node) !== null && _e !== void 0 ? _e : tsp.NoTarget,
|
|
905
915
|
});
|
|
906
916
|
continue;
|
|
907
917
|
}
|
|
@@ -914,7 +924,7 @@ export class Adapter {
|
|
|
914
924
|
code: 'DuplicateClientOption',
|
|
915
925
|
severity: 'warning',
|
|
916
926
|
message: `duplicate client option ${optionName} on model field ${property.name} will be ignored`,
|
|
917
|
-
target: (
|
|
927
|
+
target: (_f = (_b = property.__raw) === null || _b === void 0 ? void 0 : _b.node) !== null && _f !== void 0 ? _f : tsp.NoTarget,
|
|
918
928
|
});
|
|
919
929
|
continue;
|
|
920
930
|
}
|
|
@@ -925,7 +935,7 @@ export class Adapter {
|
|
|
925
935
|
code: 'InvalidClientOption',
|
|
926
936
|
severity: 'warning',
|
|
927
937
|
message: `invalid client option ${optionName} on model field ${property.name}`,
|
|
928
|
-
target: (_g = (
|
|
938
|
+
target: (_g = (_c = property.__raw) === null || _c === void 0 ? void 0 : _c.node) !== null && _g !== void 0 ? _g : tsp.NoTarget,
|
|
929
939
|
});
|
|
930
940
|
}
|
|
931
941
|
}
|
|
@@ -1343,7 +1353,8 @@ export class Adapter {
|
|
|
1343
1353
|
* @returns a Rust client
|
|
1344
1354
|
*/
|
|
1345
1355
|
recursiveAdaptClient(client, parent) {
|
|
1346
|
-
var _a, _b, _c, _d, _e, _f
|
|
1356
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1357
|
+
var _g, _h;
|
|
1347
1358
|
let clientName = client.name;
|
|
1348
1359
|
// NOTE: if the client has the @clientName decorator applied then use that verbatim
|
|
1349
1360
|
if (parent && !hasClientNameDecorator(client.decorators)) {
|
|
@@ -1416,7 +1427,8 @@ export class Adapter {
|
|
|
1416
1427
|
* @returns the AuthTypes enum for the credential that was handled, or AuthTypes.Default if none were
|
|
1417
1428
|
*/
|
|
1418
1429
|
const processCredential = (rustClient, param, cred, constructable) => {
|
|
1419
|
-
var _a
|
|
1430
|
+
var _a;
|
|
1431
|
+
var _b;
|
|
1420
1432
|
switch (cred.type) {
|
|
1421
1433
|
case 'noAuth':
|
|
1422
1434
|
return AuthTypes.NoAuth;
|
|
@@ -1439,7 +1451,7 @@ export class Adapter {
|
|
|
1439
1451
|
return AuthTypes.WithAuth;
|
|
1440
1452
|
}
|
|
1441
1453
|
};
|
|
1442
|
-
const ctorParams =
|
|
1454
|
+
const ctorParams = rustClient.constructable.parameters;
|
|
1443
1455
|
for (const param of client.clientInitialization.parameters) {
|
|
1444
1456
|
switch (param.kind) {
|
|
1445
1457
|
case 'credential':
|
|
@@ -1512,6 +1524,10 @@ export class Adapter {
|
|
|
1512
1524
|
break;
|
|
1513
1525
|
}
|
|
1514
1526
|
case 'method': {
|
|
1527
|
+
if (isRequiredFixedInput(param)) {
|
|
1528
|
+
// Operations serialize the constant directly, without stored client state.
|
|
1529
|
+
continue;
|
|
1530
|
+
}
|
|
1515
1531
|
if (param.isApiVersionParam && param.optional && !param.clientDefaultValue) {
|
|
1516
1532
|
if (!parent && client.children && client.methods.length === 0) {
|
|
1517
1533
|
// this is the top-level client for a multi-client scenario.
|
|
@@ -1536,6 +1552,7 @@ export class Adapter {
|
|
|
1536
1552
|
rustClient.constructable.constructors.push(ctorWithNoCredential);
|
|
1537
1553
|
}
|
|
1538
1554
|
// propagate ctor params to all client ctors
|
|
1555
|
+
helpers.sortClientParameters(ctorParams);
|
|
1539
1556
|
for (const constructor of rustClient.constructable.constructors) {
|
|
1540
1557
|
constructor.params.push(...ctorParams);
|
|
1541
1558
|
// ensure param order of endpoint, credential, other
|
|
@@ -1548,6 +1565,9 @@ export class Adapter {
|
|
|
1548
1565
|
// to create a child client that will need to inherit our client params.
|
|
1549
1566
|
rustClient.endpoint = parent.endpoint;
|
|
1550
1567
|
for (const prop of client.clientInitialization.parameters) {
|
|
1568
|
+
if (prop.kind === 'method' && isRequiredFixedInput(prop)) {
|
|
1569
|
+
continue;
|
|
1570
|
+
}
|
|
1551
1571
|
const name = utils.snakeCaseName(prop.name);
|
|
1552
1572
|
const parentField = parent.fields.find((v) => v.name === name);
|
|
1553
1573
|
if (parentField) {
|
|
@@ -1581,6 +1601,7 @@ export class Adapter {
|
|
|
1581
1601
|
const field = new rust.StructField(clientParam.name, 'pubCrate', clientParam.type);
|
|
1582
1602
|
cur.fields.push(field);
|
|
1583
1603
|
// propagate this param to all client constructors
|
|
1604
|
+
constructable.parameters.push(clientParam);
|
|
1584
1605
|
for (const constructor of constructable.constructors) {
|
|
1585
1606
|
constructor.params.push(clientParam);
|
|
1586
1607
|
}
|
|
@@ -1593,7 +1614,7 @@ export class Adapter {
|
|
|
1593
1614
|
else {
|
|
1594
1615
|
throw new AdapterError('InternalError', `uninstantiatable client ${client.name} has no parent`);
|
|
1595
1616
|
}
|
|
1596
|
-
for (const child of (
|
|
1617
|
+
for (const child of (_g = client.children) !== null && _g !== void 0 ? _g : []) {
|
|
1597
1618
|
const subClient = this.recursiveAdaptClient(child, rustClient);
|
|
1598
1619
|
this.adaptClientAccessor(client, child, rustClient, subClient);
|
|
1599
1620
|
}
|
|
@@ -1605,7 +1626,7 @@ export class Adapter {
|
|
|
1605
1626
|
code: 'LroPagingNotSupported',
|
|
1606
1627
|
severity: 'warning',
|
|
1607
1628
|
message: `skip emitting Paging LRO ${method.name}`,
|
|
1608
|
-
target: (_h = (
|
|
1629
|
+
target: (_h = (_f = method.__raw) === null || _f === void 0 ? void 0 : _f.node) !== null && _h !== void 0 ? _h : tsp.NoTarget,
|
|
1609
1630
|
});
|
|
1610
1631
|
continue;
|
|
1611
1632
|
}
|
|
@@ -1642,6 +1663,16 @@ export class Adapter {
|
|
|
1642
1663
|
tokenCredParam.docs.summary = `An implementation of [\`TokenCredential\`](azure_core::credentials::TokenCredential) that can provide an Entra ID token to use when authenticating.`;
|
|
1643
1664
|
ctorTokenCredential.params.push(tokenCredParam);
|
|
1644
1665
|
ctorTokenCredential.docs.summary = `Creates a new ${rustClient.name}, using Entra ID authentication.`;
|
|
1666
|
+
if (this.crate.type === 'azure-arm') {
|
|
1667
|
+
ctorTokenCredential.docs.description = 'Public cloud is used when no cloud configuration is supplied. For a custom cloud,\n'
|
|
1668
|
+
+ 'set [`CustomConfiguration::endpoint`](azure_core::cloud::CustomConfiguration::endpoint)\n'
|
|
1669
|
+
+ 'and register its authentication audience using the shared\n'
|
|
1670
|
+
+ '[`Audience`](azure_core::cloud::resource_manager::Audience) marker.\n'
|
|
1671
|
+
+ "Configure the credential's cloud separately to use its identity authority.\n\n"
|
|
1672
|
+
+ '# Errors\n\n'
|
|
1673
|
+
+ 'Returns an error if a custom cloud has no endpoint or Resource Manager audience,\n'
|
|
1674
|
+
+ 'or if its endpoint URL is invalid.';
|
|
1675
|
+
}
|
|
1645
1676
|
return ctorTokenCredential;
|
|
1646
1677
|
}
|
|
1647
1678
|
/**
|
|
@@ -1695,6 +1726,9 @@ export class Adapter {
|
|
|
1695
1726
|
const clientAccessor = new rust.ClientAccessor(`get_${utils.snakeCaseName(subClient.name)}`, rustClient, subClient);
|
|
1696
1727
|
clientAccessor.docs.summary = `Returns a new instance of ${subClient.name}.`;
|
|
1697
1728
|
for (const param of childClient.clientInitialization.parameters) {
|
|
1729
|
+
if (param.kind === 'method' && isRequiredFixedInput(param)) {
|
|
1730
|
+
continue;
|
|
1731
|
+
}
|
|
1698
1732
|
// check if the client's initializer already has this parameter.
|
|
1699
1733
|
// if it does then omit it from the method sig as we'll populate
|
|
1700
1734
|
// the child client's value from the parent.
|
|
@@ -1721,7 +1755,8 @@ export class Adapter {
|
|
|
1721
1755
|
* @param rustClient the client to which the method belongs
|
|
1722
1756
|
*/
|
|
1723
1757
|
adaptMethod(method, rustClient) {
|
|
1724
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x
|
|
1758
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
|
|
1759
|
+
var _y, _z;
|
|
1725
1760
|
let srcMethodName = method.name;
|
|
1726
1761
|
// NOTE: if the method has the @clientName decorator applied then skip fixing up the name
|
|
1727
1762
|
if (!hasClientNameDecorator(method.decorators)) {
|
|
@@ -1738,7 +1773,7 @@ export class Adapter {
|
|
|
1738
1773
|
code: 'PagingMethodRename',
|
|
1739
1774
|
severity: 'warning',
|
|
1740
1775
|
message: `renamed paging method from ${method.name} to ${srcMethodName}`,
|
|
1741
|
-
target: (
|
|
1776
|
+
target: (_y = (_a = method.__raw) === null || _a === void 0 ? void 0 : _a.node) !== null && _y !== void 0 ? _y : tsp.NoTarget,
|
|
1742
1777
|
});
|
|
1743
1778
|
}
|
|
1744
1779
|
else if ((method.kind === 'lro' || method.kind === 'lropaging') && !srcMethodName.match(/^begin/i)) {
|
|
@@ -1749,7 +1784,7 @@ export class Adapter {
|
|
|
1749
1784
|
code: 'PollingMethodRename',
|
|
1750
1785
|
severity: 'warning',
|
|
1751
1786
|
message: `renamed polling method from ${method.name} to ${srcMethodName}`,
|
|
1752
|
-
target: (
|
|
1787
|
+
target: (_z = (_b = method.__raw) === null || _b === void 0 ? void 0 : _b.node) !== null && _z !== void 0 ? _z : tsp.NoTarget,
|
|
1753
1788
|
});
|
|
1754
1789
|
}
|
|
1755
1790
|
}
|
|
@@ -1760,7 +1795,7 @@ export class Adapter {
|
|
|
1760
1795
|
// if the method was renamed then ensure it doesn't collide
|
|
1761
1796
|
for (const existingMethod of rustClient.methods) {
|
|
1762
1797
|
if (existingMethod.name === methodName) {
|
|
1763
|
-
throw new AdapterError('NameCollision', `renamed method ${srcMethodName} collides with an existing method`, (
|
|
1798
|
+
throw new AdapterError('NameCollision', `renamed method ${srcMethodName} collides with an existing method`, (_c = method.__raw) === null || _c === void 0 ? void 0 : _c.node);
|
|
1764
1799
|
}
|
|
1765
1800
|
}
|
|
1766
1801
|
}
|
|
@@ -1814,28 +1849,31 @@ export class Adapter {
|
|
|
1814
1849
|
lroFinalResultStrategy = new rust.LroFinalResultStrategyHeader('operation-location');
|
|
1815
1850
|
break;
|
|
1816
1851
|
case FinalStateValue.customLink:
|
|
1817
|
-
if (((
|
|
1852
|
+
if (((_d = method.lroMetadata.statusMonitorStep) === null || _d === void 0 ? void 0 : _d.kind) === "nextOperationLink") {
|
|
1818
1853
|
const customHeaderName = method.lroMetadata.statusMonitorStep.target.property.name;
|
|
1819
1854
|
if (customHeaderName.trim() === '') {
|
|
1820
|
-
throw new AdapterError('UnsupportedTsp', `lroMetadata.finalStateVia === customLink && customHeaderName === "${customHeaderName}"`, (
|
|
1855
|
+
throw new AdapterError('UnsupportedTsp', `lroMetadata.finalStateVia === customLink && customHeaderName === "${customHeaderName}"`, (_e = method.__raw) === null || _e === void 0 ? void 0 : _e.node);
|
|
1821
1856
|
}
|
|
1822
1857
|
lroFinalResultStrategy = new rust.LroFinalResultStrategyHeader(customHeaderName);
|
|
1823
1858
|
}
|
|
1824
1859
|
else {
|
|
1825
|
-
throw new AdapterError('UnsupportedTsp', `lroMetadata.finalStateVia === customLink && lroMetadata.statusMonitorStep?.kind === "${(
|
|
1860
|
+
throw new AdapterError('UnsupportedTsp', `lroMetadata.finalStateVia === customLink && lroMetadata.statusMonitorStep?.kind === "${(_f = method.lroMetadata.statusMonitorStep) === null || _f === void 0 ? void 0 : _f.kind}"`, (_g = method.__raw) === null || _g === void 0 ? void 0 : _g.node);
|
|
1826
1861
|
}
|
|
1827
1862
|
break;
|
|
1828
1863
|
default:
|
|
1829
1864
|
/* eslint-disable-next-line @typescript-eslint/restrict-template-expressions */
|
|
1830
|
-
throw new AdapterError('UnsupportedTsp', `lroMetadata.finalStateVia ${method.lroMetadata.finalStateVia} NYI`, (
|
|
1865
|
+
throw new AdapterError('UnsupportedTsp', `lroMetadata.finalStateVia ${method.lroMetadata.finalStateVia} NYI`, (_h = method.__raw) === null || _h === void 0 ? void 0 : _h.node);
|
|
1831
1866
|
}
|
|
1832
1867
|
lroFinalResultStrategy.propertyName = method.lroMetadata.finalResultPath;
|
|
1833
1868
|
}
|
|
1834
1869
|
rustMethod = new rust.LroMethod(methodName, languageIndependentName, rustClient, pub, methodOptions, httpMethod, method.operation.path, lroFinalResultStrategy);
|
|
1870
|
+
if (this.crate.type === 'azure-arm') {
|
|
1871
|
+
rustMethod.resourceManagerFinalState = this.adaptResourceManagerFinalState(method);
|
|
1872
|
+
}
|
|
1835
1873
|
}
|
|
1836
1874
|
break;
|
|
1837
1875
|
default:
|
|
1838
|
-
throw new AdapterError('UnsupportedTsp', `method kind ${method.kind} NYI`, (
|
|
1876
|
+
throw new AdapterError('UnsupportedTsp', `method kind ${method.kind} NYI`, (_j = method.__raw) === null || _j === void 0 ? void 0 : _j.node);
|
|
1839
1877
|
}
|
|
1840
1878
|
rustMethod.docs = this.adaptDocs(method.summary, method.doc);
|
|
1841
1879
|
rustClient.methods.push(rustMethod);
|
|
@@ -1953,10 +1991,14 @@ export class Adapter {
|
|
|
1953
1991
|
// cast is safe as we only need .type, .optional, .summary, .doc from it.
|
|
1954
1992
|
const groupedParam = this.adaptMethodParameter(opParam, fieldProp, lifetime);
|
|
1955
1993
|
const fieldOptional = fieldProp ? fieldProp.optional : opParam.optional;
|
|
1956
|
-
if (!fieldOptional) {
|
|
1994
|
+
if (!fieldOptional && (groupedParam.type.kind === 'literal' || groupedParam.type.kind === 'enumValue')) {
|
|
1995
|
+
// Fixed wire values are still needed for requests, but are not caller inputs.
|
|
1996
|
+
processAdaptedParam(groupedParam, param);
|
|
1997
|
+
}
|
|
1998
|
+
else if (!fieldOptional) {
|
|
1957
1999
|
if (!paramGroup) {
|
|
1958
2000
|
if (param.type.kind !== 'model') {
|
|
1959
|
-
throw new AdapterError('InternalError', `expected model type for parameter group but got ${param.type.kind}`, (
|
|
2001
|
+
throw new AdapterError('InternalError', `expected model type for parameter group but got ${param.type.kind}`, (_k = param.__raw) === null || _k === void 0 ? void 0 : _k.node);
|
|
1960
2002
|
}
|
|
1961
2003
|
const groupName = utils.capitalize(param.type.name).replace(/\W/g, '');
|
|
1962
2004
|
const paramName = naming.getEscapedReservedName(utils.snakeCaseName(param.name), 'param', reservedParams);
|
|
@@ -1986,22 +2028,21 @@ export class Adapter {
|
|
|
1986
2028
|
for (const gp of groupedParams) {
|
|
1987
2029
|
rustMethod.params.push(gp);
|
|
1988
2030
|
}
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
}
|
|
2031
|
+
}
|
|
2032
|
+
// Group-only models are emitted in method_options.rs or disappear.
|
|
2033
|
+
// Keep models also used in payloads, including through other models.
|
|
2034
|
+
if (param.type.kind === 'model'
|
|
2035
|
+
&& (param.type.usage & (tcgc.UsageFlags.Json | tcgc.UsageFlags.Xml | tcgc.UsageFlags.Output | tcgc.UsageFlags.Spread | tcgc.UsageFlags.Exception)) === 0) {
|
|
2036
|
+
const groupModelName = utils.capitalize(param.type.name).replace(/\W/g, '');
|
|
2037
|
+
const ns = this.adaptNamespace(param.type.namespace);
|
|
2038
|
+
const idx = ns.models.findIndex(m => m.kind === 'model' && m.name === groupModelName);
|
|
2039
|
+
if (idx >= 0) {
|
|
2040
|
+
ns.models.splice(idx, 1);
|
|
2000
2041
|
}
|
|
2001
2042
|
}
|
|
2002
2043
|
}
|
|
2003
2044
|
else {
|
|
2004
|
-
throw new AdapterError('InternalError', `didn't find operation parameter for method ${method.name} parameter ${param.name}`, (
|
|
2045
|
+
throw new AdapterError('InternalError', `didn't find operation parameter for method ${method.name} parameter ${param.name}`, (_l = param.__raw) === null || _l === void 0 ? void 0 : _l.node);
|
|
2005
2046
|
}
|
|
2006
2047
|
}
|
|
2007
2048
|
// client params aren't included in method.parameters so
|
|
@@ -2084,16 +2125,16 @@ export class Adapter {
|
|
|
2084
2125
|
const responseFormat = getResponseFormat();
|
|
2085
2126
|
if (method.kind === 'paging') {
|
|
2086
2127
|
if (responseFormat !== 'JsonFormat' && responseFormat !== 'XmlFormat') {
|
|
2087
|
-
throw new AdapterError('InternalError', `paged method ${method.name} unexpected response format ${responseFormat}`, (
|
|
2128
|
+
throw new AdapterError('InternalError', `paged method ${method.name} unexpected response format ${responseFormat}`, (_m = method.__raw) === null || _m === void 0 ? void 0 : _m.node);
|
|
2088
2129
|
}
|
|
2089
2130
|
// for paged methods, tcgc models method.response.type as an Array<T>.
|
|
2090
2131
|
// however, we want the synthesized paged response envelope type instead.
|
|
2091
2132
|
const synthesizedType = method.operation.responses[0].type;
|
|
2092
2133
|
if (!synthesizedType) {
|
|
2093
|
-
throw new AdapterError('InternalError', `paged method ${method.name} has no synthesized response type`, (
|
|
2134
|
+
throw new AdapterError('InternalError', `paged method ${method.name} has no synthesized response type`, (_o = method.__raw) === null || _o === void 0 ? void 0 : _o.node);
|
|
2094
2135
|
}
|
|
2095
2136
|
else if (synthesizedType.kind !== 'model') {
|
|
2096
|
-
throw new AdapterError('UnsupportedTsp', `paged method ${method.name} synthesized response type has unexpected kind ${synthesizedType.kind}`, (
|
|
2137
|
+
throw new AdapterError('UnsupportedTsp', `paged method ${method.name} synthesized response type has unexpected kind ${synthesizedType.kind}`, (_p = method.__raw) === null || _p === void 0 ? void 0 : _p.node);
|
|
2097
2138
|
}
|
|
2098
2139
|
const synthesizedModel = this.getModel(synthesizedType, new Array());
|
|
2099
2140
|
const modelNs = this.adaptNamespace(synthesizedType.namespace);
|
|
@@ -2102,7 +2143,7 @@ export class Adapter {
|
|
|
2102
2143
|
}
|
|
2103
2144
|
// for the pager response type, remove the Option<T> around the Vec<T> for the page items
|
|
2104
2145
|
if (!method.pagingMetadata.pageItemsSegments) {
|
|
2105
|
-
throw new AdapterError('InternalError', `paged method ${method.name} has no pageItemsSegments`, (
|
|
2146
|
+
throw new AdapterError('InternalError', `paged method ${method.name} has no pageItemsSegments`, (_q = method.__raw) === null || _q === void 0 ? void 0 : _q.node);
|
|
2106
2147
|
}
|
|
2107
2148
|
// unwrap all of the segments for the paged response
|
|
2108
2149
|
let unwrappedCount = 0;
|
|
@@ -2113,13 +2154,13 @@ export class Adapter {
|
|
|
2113
2154
|
switch (responseFormat) {
|
|
2114
2155
|
case 'JsonFormat':
|
|
2115
2156
|
if (segment.kind !== 'property' || !segment.serializationOptions.json) {
|
|
2116
|
-
throw new AdapterError('InternalError', `paged method ${method.name} is missing JSON serialization data`, (
|
|
2157
|
+
throw new AdapterError('InternalError', `paged method ${method.name} is missing JSON serialization data`, (_r = method.__raw) === null || _r === void 0 ? void 0 : _r.node);
|
|
2117
2158
|
}
|
|
2118
2159
|
serde = segment.serializationOptions.json.name;
|
|
2119
2160
|
break;
|
|
2120
2161
|
case 'XmlFormat':
|
|
2121
2162
|
if (segment.kind !== 'property' || !segment.serializationOptions.xml) {
|
|
2122
|
-
throw new AdapterError('InternalError', `paged method ${method.name} is missing XML serialization data`, (
|
|
2163
|
+
throw new AdapterError('InternalError', `paged method ${method.name} is missing XML serialization data`, (_s = method.__raw) === null || _s === void 0 ? void 0 : _s.node);
|
|
2123
2164
|
}
|
|
2124
2165
|
serde = segment.serializationOptions.xml.name;
|
|
2125
2166
|
break;
|
|
@@ -2145,14 +2186,14 @@ export class Adapter {
|
|
|
2145
2186
|
}
|
|
2146
2187
|
}
|
|
2147
2188
|
if (unwrappedCount !== method.pagingMetadata.pageItemsSegments.length) {
|
|
2148
|
-
throw new AdapterError('InternalError', `failed to unwrap paged items for method ${method.name}`, (
|
|
2189
|
+
throw new AdapterError('InternalError', `failed to unwrap paged items for method ${method.name}`, (_t = method.__raw) === null || _t === void 0 ? void 0 : _t.node);
|
|
2149
2190
|
}
|
|
2150
2191
|
const pagedResponseType = new rust.Response(this.crate, synthesizedModel, responseFormat);
|
|
2151
2192
|
// default to nextLink. will update it as required when we have that info
|
|
2152
2193
|
const continuationKind = 'nextLink';
|
|
2153
2194
|
// if the method has the forcePageIterator client option set to true,
|
|
2154
2195
|
// expose this as a PageIterator so all items are accessible.
|
|
2155
|
-
const forcePageIterator = (
|
|
2196
|
+
const forcePageIterator = (_u = method.decorators.find(d => d.name === 'Azure.ClientGenerator.Core.@clientOption' && d.arguments['name'] === 'forcePageIterator')) === null || _u === void 0 ? void 0 : _u.arguments['value'];
|
|
2156
2197
|
let resultType;
|
|
2157
2198
|
if (forcePageIterator) {
|
|
2158
2199
|
resultType = new rust.PageIterator(this.crate, pagedResponseType, continuationKind);
|
|
@@ -2190,7 +2231,7 @@ export class Adapter {
|
|
|
2190
2231
|
const statusModel = this.getModel(method.lroMetadata.pollingInfo.responseModel, undefined, `${rustClient.name}${utils.pascalCase(rustMethod.name, false)}OperationStatus`);
|
|
2191
2232
|
const statusType = this.typeToWireType(statusModel);
|
|
2192
2233
|
if (statusType.kind !== 'model') {
|
|
2193
|
-
throw new AdapterError('InternalError', `status type for an LRO method '${method.name}' is not a model`, (
|
|
2234
|
+
throw new AdapterError('InternalError', `status type for an LRO method '${method.name}' is not a model`, (_v = method.__raw) === null || _v === void 0 ? void 0 : _v.node);
|
|
2194
2235
|
}
|
|
2195
2236
|
// the adapted type likely comes from core which means
|
|
2196
2237
|
// it will be in the root namespace. since we emit these
|
|
@@ -2247,10 +2288,10 @@ export class Adapter {
|
|
|
2247
2288
|
// can't do this until the method has been completely adapted
|
|
2248
2289
|
const pageableMethod = rustMethod;
|
|
2249
2290
|
pageableMethod.strategy = this.adaptPageableMethodStrategy(method, paramsMap, responseHeadersMap);
|
|
2250
|
-
if (((
|
|
2291
|
+
if (((_w = pageableMethod.strategy) === null || _w === void 0 ? void 0 : _w.kind) === 'nextLink') {
|
|
2251
2292
|
pageableMethod.strategy.reinjectedParams = this.adaptPageableMethodReinjectionParams(method, paramsMap);
|
|
2252
2293
|
}
|
|
2253
|
-
else if (((
|
|
2294
|
+
else if (((_x = pageableMethod.strategy) === null || _x === void 0 ? void 0 : _x.kind) === 'continuationToken') {
|
|
2254
2295
|
// set the continuation type to token on the Pager and the PagerOptions field in the method options
|
|
2255
2296
|
pageableMethod.returns.type.continuation = 'token';
|
|
2256
2297
|
for (const field of pageableMethod.options.type.type.fields) {
|
|
@@ -2261,6 +2302,46 @@ export class Adapter {
|
|
|
2261
2302
|
}
|
|
2262
2303
|
}
|
|
2263
2304
|
}
|
|
2305
|
+
/**
|
|
2306
|
+
* Adapts an explicit final-response selector or inline result extraction for an ARM LRO.
|
|
2307
|
+
* Without either, the Resource Manager runtime selects the final response.
|
|
2308
|
+
*
|
|
2309
|
+
* @param method the LRO method to adapt
|
|
2310
|
+
* @returns the selector and serialized result path, or undefined for runtime defaults
|
|
2311
|
+
*/
|
|
2312
|
+
adaptResourceManagerFinalState(method) {
|
|
2313
|
+
var _a, _b, _c;
|
|
2314
|
+
var _d;
|
|
2315
|
+
const metadata = method.lroMetadata;
|
|
2316
|
+
const selectors = new Map([
|
|
2317
|
+
[FinalStateValue.azureAsyncOperation, 'AzureAsyncOperation'],
|
|
2318
|
+
[FinalStateValue.location, 'Location'],
|
|
2319
|
+
[FinalStateValue.originalUri, 'OriginalUrl'],
|
|
2320
|
+
[FinalStateValue.operationLocation, 'OperationLocation'],
|
|
2321
|
+
]);
|
|
2322
|
+
if (!selectors.has(metadata.finalStateVia)) {
|
|
2323
|
+
throw new AdapterError('UnsupportedTsp', `unsupported Resource Manager final-state selector ${metadata.finalStateVia}`);
|
|
2324
|
+
}
|
|
2325
|
+
const explicit = method.decorators.find(decorator => decorator.name === 'Azure.Core.@useFinalStateVia');
|
|
2326
|
+
const explicitFinalState = explicit === null || explicit === void 0 ? void 0 : explicit.arguments.finalState;
|
|
2327
|
+
if (explicitFinalState !== undefined && typeof explicitFinalState !== 'string') {
|
|
2328
|
+
throw new AdapterError('UnsupportedTsp', 'Resource Manager final-state selector must be a string');
|
|
2329
|
+
}
|
|
2330
|
+
// Inline results need an extraction callback even without an explicit selector.
|
|
2331
|
+
const finalState = explicitFinalState !== null && explicitFinalState !== void 0 ? explicitFinalState : (((_a = metadata.finalStep) === null || _a === void 0 ? void 0 : _a.kind) === 'pollingSuccessProperty' ? metadata.finalStateVia : undefined);
|
|
2332
|
+
if (finalState === undefined) {
|
|
2333
|
+
return undefined;
|
|
2334
|
+
}
|
|
2335
|
+
const selector = selectors.get(finalState);
|
|
2336
|
+
if (!selector) {
|
|
2337
|
+
throw new AdapterError('UnsupportedTsp', `unsupported Resource Manager final-state selector ${finalState}`);
|
|
2338
|
+
}
|
|
2339
|
+
return {
|
|
2340
|
+
selector,
|
|
2341
|
+
resultPath: selector === 'OperationLocation'
|
|
2342
|
+
? (_d = (_c = (_b = metadata.finalResponse) === null || _b === void 0 ? void 0 : _b.resultSegments) === null || _c === void 0 ? void 0 : _c.map(segment => { var _a; return (_a = this.getSerializedPropertyName(segment)) !== null && _a !== void 0 ? _a : segment.name; })) !== null && _d !== void 0 ? _d : [] : [],
|
|
2343
|
+
};
|
|
2344
|
+
}
|
|
2264
2345
|
/**
|
|
2265
2346
|
* adapts response headers into Rust response headers and provides
|
|
2266
2347
|
* a mapping from the tcgc response header to the Rust equivalent.
|
|
@@ -2842,6 +2923,9 @@ export class Adapter {
|
|
|
2842
2923
|
}
|
|
2843
2924
|
}
|
|
2844
2925
|
}
|
|
2926
|
+
function isRequiredFixedInput(param) {
|
|
2927
|
+
return !param.optional && !param.isApiVersionParam && (param.type.kind === 'constant' || param.type.kind === 'enumvalue');
|
|
2928
|
+
}
|
|
2845
2929
|
/** type guard to determine if type is a Ref<HashMap> */
|
|
2846
2930
|
function isRefHashMap(type) {
|
|
2847
2931
|
return utils.asTypeOf(type, 'hashmap', 'ref') !== undefined;
|