@azure-tools/typespec-rust 0.25.0 → 0.27.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/dist/src/codegen/clients.js +127 -45
- package/dist/src/codegen/clients.js.map +1 -1
- package/dist/src/codegen/context.d.ts +2 -1
- package/dist/src/codegen/context.d.ts.map +1 -1
- package/dist/src/codegen/context.js +14 -5
- package/dist/src/codegen/context.js.map +1 -1
- package/dist/src/codegen/enums.js +117 -5
- package/dist/src/codegen/enums.js.map +1 -1
- package/dist/src/codegen/helpers.js +1 -1
- package/dist/src/codegen/helpers.js.map +1 -1
- package/dist/src/codegen/models.js +22 -18
- package/dist/src/codegen/models.js.map +1 -1
- package/dist/src/codemodel/client.d.ts +26 -1
- package/dist/src/codemodel/client.d.ts.map +1 -1
- package/dist/src/codemodel/client.js +13 -1
- package/dist/src/codemodel/client.js.map +1 -1
- package/dist/src/codemodel/types.d.ts +13 -5
- package/dist/src/codemodel/types.d.ts.map +1 -1
- package/dist/src/codemodel/types.js +6 -3
- package/dist/src/codemodel/types.js.map +1 -1
- package/dist/src/tcgcadapter/adapter.d.ts +1 -0
- package/dist/src/tcgcadapter/adapter.d.ts.map +1 -1
- package/dist/src/tcgcadapter/adapter.js +95 -28
- package/dist/src/tcgcadapter/adapter.js.map +1 -1
- package/package.json +1 -1
|
@@ -11,6 +11,7 @@ import * as naming from './naming.js';
|
|
|
11
11
|
import * as shared from '../shared/shared.js';
|
|
12
12
|
import * as tcgc from '@azure-tools/typespec-client-generator-core';
|
|
13
13
|
import * as rust from '../codemodel/index.js';
|
|
14
|
+
import { FinalStateValue } from "@azure-tools/typespec-azure-core";
|
|
14
15
|
/**
|
|
15
16
|
* AdapterError is thrown when the emitter fails to convert part of the tcgc code
|
|
16
17
|
* model to the emitter code model. this could be due to the emitter not supporting
|
|
@@ -42,7 +43,7 @@ export class Adapter {
|
|
|
42
43
|
// same as TypeSpec.Xml.@name. however, it's filtered out by default
|
|
43
44
|
// so we need to add it to the allow list of decorators
|
|
44
45
|
const ctx = await tcgc.createSdkContext(context, '@azure-tools/typespec-rust', {
|
|
45
|
-
additionalDecorators: ['TypeSpec\\.@encodedName', '@clientName'],
|
|
46
|
+
additionalDecorators: ['TypeSpec\\.@encodedName', '@clientName', 'Azure.ClientGenerator.Core.@deserializeEmptyStringAsNull'],
|
|
46
47
|
disableUsageAccessPropagationToBase: true,
|
|
47
48
|
});
|
|
48
49
|
context.program.reportDiagnostics(ctx.diagnostics);
|
|
@@ -78,7 +79,7 @@ export class Adapter {
|
|
|
78
79
|
this.crate.addDependency(new rust.CrateDependency('serde'));
|
|
79
80
|
}
|
|
80
81
|
if (this.crate.clients.length > 0 || this.crate.enums.length > 0 || this.crate.models.length > 0 || this.crate.unions.length > 0) {
|
|
81
|
-
this.crate.addDependency(new rust.CrateDependency('
|
|
82
|
+
this.crate.addDependency(new rust.CrateDependency('azure_core'));
|
|
82
83
|
}
|
|
83
84
|
this.crate.sortContent();
|
|
84
85
|
return this.crate;
|
|
@@ -120,8 +121,6 @@ export class Adapter {
|
|
|
120
121
|
}
|
|
121
122
|
const rustModel = this.getModel(model);
|
|
122
123
|
this.crate.models.push(rustModel);
|
|
123
|
-
// presence of models requires the derive feature
|
|
124
|
-
this.crate.addDependency(new rust.CrateDependency('typespec_client_core', ['derive']));
|
|
125
124
|
}
|
|
126
125
|
}
|
|
127
126
|
/**
|
|
@@ -131,13 +130,36 @@ export class Adapter {
|
|
|
131
130
|
* @returns a Rust enum
|
|
132
131
|
*/
|
|
133
132
|
getEnum(sdkEnum) {
|
|
134
|
-
var _a;
|
|
133
|
+
var _a, _b;
|
|
135
134
|
const enumName = codegen.deconstruct(sdkEnum.name).map((each) => codegen.capitalize(each)).join('');
|
|
136
135
|
let rustEnum = this.types.get(enumName);
|
|
137
136
|
if (rustEnum) {
|
|
138
137
|
return rustEnum;
|
|
139
138
|
}
|
|
140
|
-
|
|
139
|
+
let enumType;
|
|
140
|
+
switch (sdkEnum.valueType.kind) {
|
|
141
|
+
case 'float':
|
|
142
|
+
case 'float32':
|
|
143
|
+
enumType = 'f32';
|
|
144
|
+
break;
|
|
145
|
+
case 'float64':
|
|
146
|
+
enumType = 'f64';
|
|
147
|
+
break;
|
|
148
|
+
case 'int8':
|
|
149
|
+
case 'int16':
|
|
150
|
+
case 'int32':
|
|
151
|
+
enumType = 'i32';
|
|
152
|
+
break;
|
|
153
|
+
case 'int64':
|
|
154
|
+
enumType = 'i64';
|
|
155
|
+
break;
|
|
156
|
+
case 'string':
|
|
157
|
+
enumType = 'String';
|
|
158
|
+
break;
|
|
159
|
+
default:
|
|
160
|
+
throw new AdapterError('UnsupportedTsp', `unsupported enum underlying type ${sdkEnum.valueType.kind}`, (_a = sdkEnum.__raw) === null || _a === void 0 ? void 0 : _a.node);
|
|
161
|
+
}
|
|
162
|
+
rustEnum = new rust.Enum(enumName, sdkEnum.access === 'public', !sdkEnum.isFixed, enumType);
|
|
141
163
|
rustEnum.docs = this.adaptDocs(sdkEnum.summary, sdkEnum.doc);
|
|
142
164
|
this.types.set(enumName, rustEnum);
|
|
143
165
|
const rustEnumNameToSdkEnumName = new Map();
|
|
@@ -145,7 +167,7 @@ export class Adapter {
|
|
|
145
167
|
const enumValueName = naming.fixUpEnumValueName(value);
|
|
146
168
|
const existingMapping = rustEnumNameToSdkEnumName.get(enumValueName);
|
|
147
169
|
if (existingMapping) {
|
|
148
|
-
throw new AdapterError('NameCollision', `enum values ${value.name} and ${existingMapping} coalesce into the same name ${enumValueName}`, (
|
|
170
|
+
throw new AdapterError('NameCollision', `enum values ${value.name} and ${existingMapping} coalesce into the same name ${enumValueName}`, (_b = sdkEnum.__raw) === null || _b === void 0 ? void 0 : _b.node);
|
|
149
171
|
}
|
|
150
172
|
rustEnumNameToSdkEnumName.set(enumValueName, value.name);
|
|
151
173
|
const rustEnumValue = new rust.EnumValue(enumValueName, rustEnum, value.value);
|
|
@@ -177,14 +199,16 @@ export class Adapter {
|
|
|
177
199
|
*
|
|
178
200
|
* @param model the tcgc model to convert
|
|
179
201
|
* @param stack is a stack of model type names used to detect recursive type definitions
|
|
202
|
+
* @param modelName optional parameter to override model name
|
|
180
203
|
* @returns a Rust model
|
|
181
204
|
*/
|
|
182
|
-
getModel(model, stack) {
|
|
205
|
+
getModel(model, stack, modelName) {
|
|
183
206
|
var _a, _b, _c, _d;
|
|
184
|
-
|
|
207
|
+
modelName = modelName !== null && modelName !== void 0 ? modelName : model.name;
|
|
208
|
+
if (modelName.length === 0) {
|
|
185
209
|
throw new AdapterError('InternalError', 'unnamed model', (_a = model.__raw) === null || _a === void 0 ? void 0 : _a.node); // TODO: this might no longer be an issue
|
|
186
210
|
}
|
|
187
|
-
|
|
211
|
+
modelName = codegen.capitalize(modelName);
|
|
188
212
|
let rustModel = this.types.get(modelName);
|
|
189
213
|
if (rustModel) {
|
|
190
214
|
return rustModel;
|
|
@@ -409,6 +433,9 @@ export class Adapter {
|
|
|
409
433
|
if (!this.fieldsMap.get(property)) {
|
|
410
434
|
this.fieldsMap.set(property, modelField);
|
|
411
435
|
}
|
|
436
|
+
if (property.decorators.find((decorator) => decorator.name === 'Azure.ClientGenerator.Core.@deserializeEmptyStringAsNull') !== undefined) {
|
|
437
|
+
modelField.flags |= rust.ModelFieldFlags.DeserializeEmptyStringAsNone;
|
|
438
|
+
}
|
|
412
439
|
return modelField;
|
|
413
440
|
}
|
|
414
441
|
/**
|
|
@@ -1106,7 +1133,7 @@ export class Adapter {
|
|
|
1106
1133
|
* @param rustClient the client to which the method belongs
|
|
1107
1134
|
*/
|
|
1108
1135
|
adaptMethod(method, rustClient) {
|
|
1109
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
1136
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
|
1110
1137
|
let srcMethodName = method.name;
|
|
1111
1138
|
if (method.kind === 'paging' && !srcMethodName.match(/^list/i)) {
|
|
1112
1139
|
const chunks = codegen.deconstruct(srcMethodName);
|
|
@@ -1138,7 +1165,14 @@ export class Adapter {
|
|
|
1138
1165
|
const methodOptionsStruct = new rust.Struct(`${rustClient.name}${codegen.pascalCase(srcMethodName, false)}Options`, 'pub');
|
|
1139
1166
|
methodOptionsStruct.lifetime = optionsLifetime;
|
|
1140
1167
|
methodOptionsStruct.docs.summary = `Options to be passed to ${this.asDocLink(`${rustClient.name}::${methodName}()`, `crate::generated::clients::${rustClient.name}::${methodName}()`)}`;
|
|
1141
|
-
|
|
1168
|
+
let clientMethodOptions;
|
|
1169
|
+
switch (method.kind) {
|
|
1170
|
+
case 'paging':
|
|
1171
|
+
clientMethodOptions = new rust.ExternalType(this.crate, 'PagerOptions', 'azure_core::http::pager');
|
|
1172
|
+
break;
|
|
1173
|
+
default:
|
|
1174
|
+
clientMethodOptions = new rust.ExternalType(this.crate, 'ClientMethodOptions', 'azure_core::http');
|
|
1175
|
+
}
|
|
1142
1176
|
clientMethodOptions.lifetime = optionsLifetime;
|
|
1143
1177
|
const methodOptionsField = new rust.StructField('method_options', 'pub', clientMethodOptions);
|
|
1144
1178
|
methodOptionsField.docs.summary = 'Allows customization of the method call.';
|
|
@@ -1161,10 +1195,29 @@ export class Adapter {
|
|
|
1161
1195
|
rustMethod = new rust.PageableMethod(methodName, languageIndependentName, rustClient, pub, methodOptions, httpMethod, method.operation.path);
|
|
1162
1196
|
break;
|
|
1163
1197
|
case 'lro':
|
|
1164
|
-
|
|
1198
|
+
{
|
|
1199
|
+
let lroFinalResultStrategy = new rust.LroFinalResultStrategyOriginalUri();
|
|
1200
|
+
if (method.lroMetadata.finalStateVia !== FinalStateValue.originalUri) {
|
|
1201
|
+
switch (method.lroMetadata.finalStateVia) {
|
|
1202
|
+
case FinalStateValue.operationLocation:
|
|
1203
|
+
lroFinalResultStrategy = new rust.LroFinalResultStrategyHeader('operation-location');
|
|
1204
|
+
break;
|
|
1205
|
+
case FinalStateValue.location:
|
|
1206
|
+
lroFinalResultStrategy = new rust.LroFinalResultStrategyHeader('location');
|
|
1207
|
+
break;
|
|
1208
|
+
case FinalStateValue.azureAsyncOperation:
|
|
1209
|
+
lroFinalResultStrategy = new rust.LroFinalResultStrategyHeader('azure-asyncoperation');
|
|
1210
|
+
break;
|
|
1211
|
+
default:
|
|
1212
|
+
throw new AdapterError('UnsupportedTsp', `lroMetadata.finalStateVia ${method.lroMetadata.finalStateVia} NYI`, (_d = method.__raw) === null || _d === void 0 ? void 0 : _d.node);
|
|
1213
|
+
}
|
|
1214
|
+
lroFinalResultStrategy.propertyName = method.lroMetadata.finalResultPath;
|
|
1215
|
+
}
|
|
1216
|
+
rustMethod = new rust.LroMethod(methodName, languageIndependentName, rustClient, pub, methodOptions, httpMethod, method.operation.path, lroFinalResultStrategy);
|
|
1217
|
+
}
|
|
1165
1218
|
break;
|
|
1166
1219
|
default:
|
|
1167
|
-
throw new AdapterError('UnsupportedTsp', `method kind ${method.kind} NYI`, (
|
|
1220
|
+
throw new AdapterError('UnsupportedTsp', `method kind ${method.kind} NYI`, (_e = method.__raw) === null || _e === void 0 ? void 0 : _e.node);
|
|
1168
1221
|
}
|
|
1169
1222
|
rustMethod.docs = this.adaptDocs(method.summary, method.doc);
|
|
1170
1223
|
rustClient.methods.push(rustMethod);
|
|
@@ -1187,7 +1240,12 @@ export class Adapter {
|
|
|
1187
1240
|
}).any();
|
|
1188
1241
|
}).first();
|
|
1189
1242
|
if (!opParam) {
|
|
1190
|
-
throw new AdapterError('InternalError', `didn't find operation parameter for method ${method.name} parameter ${param.name}`, (
|
|
1243
|
+
throw new AdapterError('InternalError', `didn't find operation parameter for method ${method.name} parameter ${param.name}`, (_f = param.__raw) === null || _f === void 0 ? void 0 : _f.node);
|
|
1244
|
+
}
|
|
1245
|
+
if (opParam.kind === 'header' && opParam.serializedName.toLowerCase() === 'x-ms-client-request-id') {
|
|
1246
|
+
// x-ms-client-request-id is automatically inserted into requests via
|
|
1247
|
+
// a pipeline policy. so we don't want to expose this as an actual param.
|
|
1248
|
+
continue;
|
|
1191
1249
|
}
|
|
1192
1250
|
let adaptedParam;
|
|
1193
1251
|
// for spread params there are two cases we need to consider.
|
|
@@ -1311,16 +1369,16 @@ export class Adapter {
|
|
|
1311
1369
|
const responseFormat = getResponseFormat();
|
|
1312
1370
|
if (method.kind === 'paging') {
|
|
1313
1371
|
if (responseFormat === 'NoFormat') {
|
|
1314
|
-
throw new AdapterError('InternalError', `paged method ${method.name} unexpected response format ${responseFormat}`, (
|
|
1372
|
+
throw new AdapterError('InternalError', `paged method ${method.name} unexpected response format ${responseFormat}`, (_g = method.__raw) === null || _g === void 0 ? void 0 : _g.node);
|
|
1315
1373
|
}
|
|
1316
1374
|
// for paged methods, tcgc models method.response.type as an Array<T>.
|
|
1317
1375
|
// however, we want the synthesized paged response envelope type instead.
|
|
1318
1376
|
const synthesizedType = method.operation.responses[0].type;
|
|
1319
1377
|
if (!synthesizedType) {
|
|
1320
|
-
throw new AdapterError('InternalError', `paged method ${method.name} has no synthesized response type`, (
|
|
1378
|
+
throw new AdapterError('InternalError', `paged method ${method.name} has no synthesized response type`, (_h = method.__raw) === null || _h === void 0 ? void 0 : _h.node);
|
|
1321
1379
|
}
|
|
1322
1380
|
else if (synthesizedType.kind !== 'model') {
|
|
1323
|
-
throw new AdapterError('UnsupportedTsp', `paged method ${method.name} synthesized response type has unexpected kind ${synthesizedType.kind}`, (
|
|
1381
|
+
throw new AdapterError('UnsupportedTsp', `paged method ${method.name} synthesized response type has unexpected kind ${synthesizedType.kind}`, (_j = method.__raw) === null || _j === void 0 ? void 0 : _j.node);
|
|
1324
1382
|
}
|
|
1325
1383
|
const synthesizedModel = this.getModel(synthesizedType, new Array());
|
|
1326
1384
|
if (!this.crate.models.includes(synthesizedModel)) {
|
|
@@ -1328,7 +1386,7 @@ export class Adapter {
|
|
|
1328
1386
|
}
|
|
1329
1387
|
// for the pager response type, remove the Option<T> around the Vec<T> for the page items
|
|
1330
1388
|
if (!method.pagingMetadata.pageItemsSegments) {
|
|
1331
|
-
throw new AdapterError('InternalError', `paged method ${method.name} has no pageItemsSegments`, (
|
|
1389
|
+
throw new AdapterError('InternalError', `paged method ${method.name} has no pageItemsSegments`, (_k = method.__raw) === null || _k === void 0 ? void 0 : _k.node);
|
|
1332
1390
|
}
|
|
1333
1391
|
// unwrap all of the segments for the paged response
|
|
1334
1392
|
let unwrappedCount = 0;
|
|
@@ -1339,13 +1397,13 @@ export class Adapter {
|
|
|
1339
1397
|
switch (responseFormat) {
|
|
1340
1398
|
case 'JsonFormat':
|
|
1341
1399
|
if (segment.kind !== 'property' || !segment.serializationOptions.json) {
|
|
1342
|
-
throw new AdapterError('InternalError', `paged method ${method.name} is missing JSON serialization data`, (
|
|
1400
|
+
throw new AdapterError('InternalError', `paged method ${method.name} is missing JSON serialization data`, (_l = method.__raw) === null || _l === void 0 ? void 0 : _l.node);
|
|
1343
1401
|
}
|
|
1344
1402
|
serde = segment.serializationOptions.json.name;
|
|
1345
1403
|
break;
|
|
1346
1404
|
case 'XmlFormat':
|
|
1347
1405
|
if (segment.kind !== 'property' || !segment.serializationOptions.xml) {
|
|
1348
|
-
throw new AdapterError('InternalError', `paged method ${method.name} is missing XML serialization data`, (
|
|
1406
|
+
throw new AdapterError('InternalError', `paged method ${method.name} is missing XML serialization data`, (_m = method.__raw) === null || _m === void 0 ? void 0 : _m.node);
|
|
1349
1407
|
}
|
|
1350
1408
|
serde = segment.serializationOptions.xml.name;
|
|
1351
1409
|
break;
|
|
@@ -1371,16 +1429,16 @@ export class Adapter {
|
|
|
1371
1429
|
}
|
|
1372
1430
|
}
|
|
1373
1431
|
if (unwrappedCount !== method.pagingMetadata.pageItemsSegments.length) {
|
|
1374
|
-
throw new AdapterError('InternalError', `failed to unwrap paged items for method ${method.name}`, (
|
|
1432
|
+
throw new AdapterError('InternalError', `failed to unwrap paged items for method ${method.name}`, (_o = method.__raw) === null || _o === void 0 ? void 0 : _o.node);
|
|
1375
1433
|
}
|
|
1376
1434
|
this.crate.addDependency(new rust.CrateDependency('async-trait'));
|
|
1377
1435
|
rustMethod.returns = new rust.Result(this.crate, new rust.Pager(this.crate, new rust.Response(this.crate, synthesizedModel, responseFormat)));
|
|
1378
1436
|
}
|
|
1379
1437
|
else if (method.kind === 'lro') {
|
|
1380
1438
|
const format = responseFormat === 'NoFormat' ? 'JsonFormat' : responseFormat;
|
|
1381
|
-
const
|
|
1382
|
-
if (
|
|
1383
|
-
throw new AdapterError('InternalError', `
|
|
1439
|
+
const statusType = this.typeToWireType(this.getModel(method.lroMetadata.pollingInfo.responseModel, undefined, `${rustClient.name}${codegen.pascalCase(rustMethod.name, false)}OperationStatus`));
|
|
1440
|
+
if (statusType.kind !== 'model') {
|
|
1441
|
+
throw new AdapterError('InternalError', `status type for an LRO method '${method.name}' is not a model`, (_p = method.__raw) === null || _p === void 0 ? void 0 : _p.node);
|
|
1384
1442
|
}
|
|
1385
1443
|
const pushModels = (model, crate) => {
|
|
1386
1444
|
if (crate.models.some(m => m === model)) {
|
|
@@ -1396,8 +1454,17 @@ export class Adapter {
|
|
|
1396
1454
|
}
|
|
1397
1455
|
}
|
|
1398
1456
|
};
|
|
1399
|
-
pushModels(
|
|
1400
|
-
|
|
1457
|
+
pushModels(statusType, this.crate);
|
|
1458
|
+
const poller = new rust.Poller(this.crate, new rust.Response(this.crate, statusType, format));
|
|
1459
|
+
if (((_q = method.response.type) === null || _q === void 0 ? void 0 : _q.kind) === "model") {
|
|
1460
|
+
const responseType = this.typeToWireType(this.getModel(method.response.type));
|
|
1461
|
+
if (responseType.kind !== 'model') {
|
|
1462
|
+
throw new AdapterError('InternalError', `response type for an LRO method '${method.name}' is not a model`, (_r = method.__raw) === null || _r === void 0 ? void 0 : _r.node);
|
|
1463
|
+
}
|
|
1464
|
+
pushModels(responseType, this.crate);
|
|
1465
|
+
poller.resultType = new rust.Response(this.crate, responseType, format);
|
|
1466
|
+
}
|
|
1467
|
+
rustMethod.returns = new rust.Result(this.crate, poller);
|
|
1401
1468
|
}
|
|
1402
1469
|
else if (method.response.type && !(method.response.type.kind === 'bytes' && method.response.type.encode === 'bytes')) {
|
|
1403
1470
|
const response = new rust.Response(this.crate, this.typeToWireType(this.getType(method.response.type)), responseFormat);
|
|
@@ -1441,7 +1508,7 @@ export class Adapter {
|
|
|
1441
1508
|
// can't do this until the method has been completely adapted
|
|
1442
1509
|
const pageableMethod = rustMethod;
|
|
1443
1510
|
pageableMethod.strategy = this.adaptPageableMethodStrategy(method, paramsMap, responseHeadersMap);
|
|
1444
|
-
if (((
|
|
1511
|
+
if (((_s = pageableMethod.strategy) === null || _s === void 0 ? void 0 : _s.kind) === 'nextLink') {
|
|
1445
1512
|
pageableMethod.strategy.reinjectedParams = this.adaptPageableMethodReinjectionParams(method, paramsMap);
|
|
1446
1513
|
}
|
|
1447
1514
|
}
|