@azure-tools/typespec-rust 0.13.3 → 0.14.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.d.ts.map +1 -1
- package/dist/src/codegen/clients.js +155 -85
- package/dist/src/codegen/clients.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 +13 -0
- package/dist/src/codegen/errors.d.ts.map +1 -0
- package/dist/src/codegen/errors.js +15 -0
- package/dist/src/codegen/errors.js.map +1 -0
- package/dist/src/codegen/headerTraits.d.ts.map +1 -1
- package/dist/src/codegen/headerTraits.js +3 -2
- package/dist/src/codegen/headerTraits.js.map +1 -1
- package/dist/src/codegen/helpers.d.ts.map +1 -1
- package/dist/src/codegen/helpers.js +13 -3
- package/dist/src/codegen/helpers.js.map +1 -1
- package/dist/src/codegen/models.d.ts.map +1 -1
- package/dist/src/codegen/models.js +133 -71
- package/dist/src/codegen/models.js.map +1 -1
- package/dist/src/codegen/use.d.ts.map +1 -1
- package/dist/src/codegen/use.js +4 -2
- package/dist/src/codegen/use.js.map +1 -1
- package/dist/src/codemodel/client.d.ts +17 -31
- package/dist/src/codemodel/client.d.ts.map +1 -1
- package/dist/src/codemodel/client.js +1 -35
- package/dist/src/codemodel/client.js.map +1 -1
- package/dist/src/codemodel/method.d.ts +0 -2
- package/dist/src/codemodel/method.d.ts.map +1 -1
- package/dist/src/codemodel/method.js +0 -1
- package/dist/src/codemodel/method.js.map +1 -1
- package/dist/src/codemodel/types.d.ts +52 -5
- package/dist/src/codemodel/types.d.ts.map +1 -1
- package/dist/src/codemodel/types.js +26 -7
- package/dist/src/codemodel/types.js.map +1 -1
- package/dist/src/emitter.d.ts.map +1 -1
- package/dist/src/emitter.js +84 -34
- package/dist/src/emitter.js.map +1 -1
- package/dist/src/lib.d.ts +37 -4
- package/dist/src/lib.d.ts.map +1 -1
- package/dist/src/lib.js +27 -2
- package/dist/src/lib.js.map +1 -1
- package/dist/src/tcgcadapter/adapter.d.ts +58 -10
- package/dist/src/tcgcadapter/adapter.d.ts.map +1 -1
- package/dist/src/tcgcadapter/adapter.js +390 -176
- package/dist/src/tcgcadapter/adapter.js.map +1 -1
- package/dist/src/tcgcadapter/helpers.d.ts +8 -0
- package/dist/src/tcgcadapter/helpers.d.ts.map +1 -1
- package/dist/src/tcgcadapter/helpers.js +13 -0
- package/dist/src/tcgcadapter/helpers.js.map +1 -1
- package/package.json +22 -24
|
@@ -9,6 +9,18 @@ import * as helpers from './helpers.js';
|
|
|
9
9
|
import * as naming from './naming.js';
|
|
10
10
|
import * as tcgc from '@azure-tools/typespec-client-generator-core';
|
|
11
11
|
import * as rust from '../codemodel/index.js';
|
|
12
|
+
/**
|
|
13
|
+
* AdapterError is thrown when the emitter fails to convert part of the tcgc code
|
|
14
|
+
* model to the emitter code model. this could be due to the emitter not supporting
|
|
15
|
+
* some tsp construct.
|
|
16
|
+
*/
|
|
17
|
+
export class AdapterError extends Error {
|
|
18
|
+
constructor(code, message, target) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.code = code;
|
|
21
|
+
this.target = target !== null && target !== void 0 ? target : NoTarget;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
12
24
|
/** Adapter converts the tcgc code model to a Rust Crate */
|
|
13
25
|
export class Adapter {
|
|
14
26
|
/**
|
|
@@ -135,6 +147,7 @@ export class Adapter {
|
|
|
135
147
|
* @returns a Rust enum value
|
|
136
148
|
*/
|
|
137
149
|
getEnumValue(sdkEnumValue) {
|
|
150
|
+
var _a;
|
|
138
151
|
const enumType = this.getEnum(sdkEnumValue.enumType);
|
|
139
152
|
// find the specified enum value
|
|
140
153
|
for (const value of enumType.values) {
|
|
@@ -142,23 +155,31 @@ export class Adapter {
|
|
|
142
155
|
return value;
|
|
143
156
|
}
|
|
144
157
|
}
|
|
145
|
-
throw new
|
|
158
|
+
throw new AdapterError('InternalError', `didn't find enum value for name ${sdkEnumValue.name} in enum ${enumType.name}`, (_a = sdkEnumValue.__raw) === null || _a === void 0 ? void 0 : _a.node);
|
|
146
159
|
}
|
|
147
160
|
/**
|
|
148
161
|
* converts a tcgc model to a Rust model
|
|
149
162
|
*
|
|
150
163
|
* @param model the tcgc model to convert
|
|
164
|
+
* @param stack is a stack of model type names used to detect recursive type definitions
|
|
151
165
|
* @returns a Rust model
|
|
152
166
|
*/
|
|
153
|
-
getModel(model) {
|
|
167
|
+
getModel(model, stack) {
|
|
168
|
+
var _a, _b;
|
|
154
169
|
if (model.name.length === 0) {
|
|
155
|
-
throw new
|
|
170
|
+
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
|
|
156
171
|
}
|
|
157
172
|
const modelName = codegen.capitalize(model.name);
|
|
158
173
|
let rustModel = this.types.get(modelName);
|
|
159
174
|
if (rustModel) {
|
|
160
175
|
return rustModel;
|
|
161
176
|
}
|
|
177
|
+
// no stack means this is the first model in
|
|
178
|
+
// the chain of potentially recursive calls
|
|
179
|
+
if (!stack) {
|
|
180
|
+
stack = new Array();
|
|
181
|
+
}
|
|
182
|
+
stack.push(modelName);
|
|
162
183
|
let modelFlags = rust.ModelFlags.Unspecified;
|
|
163
184
|
if ((model.usage & tcgc.UsageFlags.Input) === tcgc.UsageFlags.Input) {
|
|
164
185
|
modelFlags |= rust.ModelFlags.Input;
|
|
@@ -202,12 +223,13 @@ export class Adapter {
|
|
|
202
223
|
// we just adapt it here as a regular model field.
|
|
203
224
|
}
|
|
204
225
|
else {
|
|
205
|
-
throw new
|
|
226
|
+
throw new AdapterError('UnsupportedTsp', `model property kind ${property.kind} NYI`, (_b = property.__raw) === null || _b === void 0 ? void 0 : _b.node);
|
|
206
227
|
}
|
|
207
228
|
}
|
|
208
|
-
const structField = this.getModelField(property, rustModel.visibility);
|
|
229
|
+
const structField = this.getModelField(property, rustModel.visibility, stack);
|
|
209
230
|
rustModel.fields.push(structField);
|
|
210
231
|
}
|
|
232
|
+
stack.pop();
|
|
211
233
|
return rustModel;
|
|
212
234
|
}
|
|
213
235
|
/**
|
|
@@ -215,15 +237,19 @@ export class Adapter {
|
|
|
215
237
|
*
|
|
216
238
|
* @param property the tcgc model property to convert
|
|
217
239
|
* @param modelVisibility the visibility of the model that contains the property
|
|
240
|
+
* @param stack is a stack of model type names used to detect recursive type definitions
|
|
218
241
|
* @returns a Rust model field
|
|
219
242
|
*/
|
|
220
|
-
getModelField(property, modelVisibility) {
|
|
221
|
-
let fieldType = this.getType(property.type);
|
|
243
|
+
getModelField(property, modelVisibility, stack) {
|
|
244
|
+
let fieldType = this.getType(property.type, stack);
|
|
245
|
+
// if the field's type is a model and it's in the type stack then
|
|
246
|
+
// box it. this is to avoid infinitely recursive type definitions.
|
|
247
|
+
if (fieldType.kind === 'model' && stack.includes(fieldType.name)) {
|
|
248
|
+
fieldType = new rust.Box(fieldType);
|
|
249
|
+
}
|
|
222
250
|
// for public models each field is always an Option<T>.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
if ((modelVisibility === 'pub' || property.optional) && fieldType.kind !== 'hashmap' && fieldType.kind !== 'Vec') {
|
|
226
|
-
fieldType = new rust.Option(this.typeToWireType(fieldType));
|
|
251
|
+
if (modelVisibility === 'pub' || property.optional) {
|
|
252
|
+
fieldType = new rust.Option(fieldType.kind === 'box' ? fieldType : this.typeToWireType(fieldType));
|
|
227
253
|
}
|
|
228
254
|
const modelField = new rust.ModelField(naming.getEscapedReservedName(snakeCaseName(property.name), 'prop'), property.serializedName, modelVisibility, fieldType);
|
|
229
255
|
modelField.docs = this.adaptDocs(property.summary, property.doc);
|
|
@@ -239,8 +265,15 @@ export class Adapter {
|
|
|
239
265
|
}
|
|
240
266
|
return modelField;
|
|
241
267
|
}
|
|
242
|
-
/**
|
|
243
|
-
|
|
268
|
+
/**
|
|
269
|
+
* converts a tcgc type to a Rust type
|
|
270
|
+
*
|
|
271
|
+
* @param type the tcgc type to convert
|
|
272
|
+
* @param stack is a stack of model type names used to detect recursive type definitions
|
|
273
|
+
* @returns the adapted Rust type
|
|
274
|
+
*/
|
|
275
|
+
getType(type, stack) {
|
|
276
|
+
var _a, _b;
|
|
244
277
|
const getDateTimeEncoding = (encoding) => {
|
|
245
278
|
switch (encoding) {
|
|
246
279
|
case 'rfc3339':
|
|
@@ -251,10 +284,6 @@ export class Adapter {
|
|
|
251
284
|
}
|
|
252
285
|
};
|
|
253
286
|
const getScalar = (kind) => {
|
|
254
|
-
let scalar = this.types.get(kind);
|
|
255
|
-
if (scalar) {
|
|
256
|
-
return scalar;
|
|
257
|
-
}
|
|
258
287
|
let scalarType;
|
|
259
288
|
switch (kind) {
|
|
260
289
|
case 'boolean':
|
|
@@ -292,47 +321,32 @@ export class Adapter {
|
|
|
292
321
|
scalarType = 'u8';
|
|
293
322
|
break;
|
|
294
323
|
}
|
|
295
|
-
|
|
296
|
-
this.types.set(kind, scalar);
|
|
297
|
-
return scalar;
|
|
324
|
+
return this.getScalar(scalarType);
|
|
298
325
|
};
|
|
299
326
|
switch (type.kind) {
|
|
300
|
-
case 'array':
|
|
301
|
-
|
|
302
|
-
let vectorType = this.types.get(keyName);
|
|
303
|
-
if (vectorType) {
|
|
304
|
-
return vectorType;
|
|
305
|
-
}
|
|
306
|
-
vectorType = new rust.Vector(this.typeToWireType(this.getType(type.valueType)));
|
|
307
|
-
this.types.set(keyName, vectorType);
|
|
308
|
-
return vectorType;
|
|
309
|
-
}
|
|
327
|
+
case 'array':
|
|
328
|
+
return this.getVec(this.typeToWireType(this.getType(type.valueType, stack)));
|
|
310
329
|
case 'bytes': {
|
|
311
330
|
let encoding = 'std';
|
|
312
331
|
if (type.encode === 'base64url') {
|
|
313
332
|
encoding = 'url';
|
|
314
333
|
}
|
|
315
|
-
|
|
316
|
-
let encodedBytesType = this.types.get(keyName);
|
|
317
|
-
if (encodedBytesType) {
|
|
318
|
-
return encodedBytesType;
|
|
319
|
-
}
|
|
320
|
-
encodedBytesType = new rust.EncodedBytes(encoding);
|
|
321
|
-
this.types.set(keyName, encodedBytesType);
|
|
322
|
-
return encodedBytesType;
|
|
334
|
+
return this.getEncodedBytes(encoding, false);
|
|
323
335
|
}
|
|
324
336
|
case 'constant':
|
|
325
337
|
return this.getLiteral(type);
|
|
326
|
-
case '
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
338
|
+
case 'decimal':
|
|
339
|
+
case 'decimal128': {
|
|
340
|
+
const keyName = 'decimal';
|
|
341
|
+
let decimalType = this.types.get(keyName);
|
|
342
|
+
if (!decimalType) {
|
|
343
|
+
decimalType = new rust.Decimal(this.crate);
|
|
344
|
+
this.types.set(keyName, decimalType);
|
|
331
345
|
}
|
|
332
|
-
|
|
333
|
-
this.types.set(keyName, hashmapType);
|
|
334
|
-
return hashmapType;
|
|
346
|
+
return decimalType;
|
|
335
347
|
}
|
|
348
|
+
case 'dict':
|
|
349
|
+
return this.getHashMap(this.typeToWireType(this.getType(type.valueType, stack)));
|
|
336
350
|
case 'duration':
|
|
337
351
|
switch (type.wireType.kind) {
|
|
338
352
|
case 'float':
|
|
@@ -344,7 +358,7 @@ export class Adapter {
|
|
|
344
358
|
case 'string':
|
|
345
359
|
return this.getStringType();
|
|
346
360
|
default:
|
|
347
|
-
throw new
|
|
361
|
+
throw new AdapterError('UnsupportedTsp', `unhandled duration wireType.kind ${type.wireType.kind}`, (_a = type.__raw) === null || _a === void 0 ? void 0 : _a.node);
|
|
348
362
|
}
|
|
349
363
|
case 'boolean':
|
|
350
364
|
case 'float32':
|
|
@@ -363,12 +377,12 @@ export class Adapter {
|
|
|
363
377
|
case 'enumvalue':
|
|
364
378
|
return this.getEnumValue(type);
|
|
365
379
|
case 'model':
|
|
366
|
-
return this.getModel(type);
|
|
380
|
+
return this.getModel(type, stack);
|
|
367
381
|
case 'endpoint':
|
|
368
382
|
case 'string':
|
|
369
383
|
case 'url': {
|
|
370
384
|
if (type.kind === 'string' && type.crossLanguageDefinitionId === 'Azure.Core.eTag') {
|
|
371
|
-
const etagKey = '
|
|
385
|
+
const etagKey = 'Etag';
|
|
372
386
|
let etagType = this.types.get(etagKey);
|
|
373
387
|
if (etagType) {
|
|
374
388
|
return etagType;
|
|
@@ -381,40 +395,94 @@ export class Adapter {
|
|
|
381
395
|
}
|
|
382
396
|
case 'nullable':
|
|
383
397
|
// TODO: workaround until https://github.com/Azure/typespec-rust/issues/42 is fixed
|
|
384
|
-
return this.getType(type.type);
|
|
398
|
+
return this.getType(type.type, stack);
|
|
385
399
|
case 'offsetDateTime': {
|
|
386
|
-
const
|
|
400
|
+
const encoding = getDateTimeEncoding(type.encode);
|
|
401
|
+
const keyName = `offsetDateTime-${encoding}`;
|
|
387
402
|
let timeType = this.types.get(keyName);
|
|
388
403
|
if (timeType) {
|
|
389
404
|
return timeType;
|
|
390
405
|
}
|
|
391
|
-
timeType = new rust.OffsetDateTime(this.crate,
|
|
406
|
+
timeType = new rust.OffsetDateTime(this.crate, encoding, false);
|
|
392
407
|
this.types.set(keyName, timeType);
|
|
393
408
|
return timeType;
|
|
394
409
|
}
|
|
395
410
|
case 'unknown': {
|
|
396
|
-
|
|
411
|
+
const keyName = 'jsonValue';
|
|
412
|
+
let anyType = this.types.get(keyName);
|
|
397
413
|
if (anyType) {
|
|
398
414
|
return anyType;
|
|
399
415
|
}
|
|
400
416
|
anyType = new rust.JsonValue(this.crate);
|
|
401
|
-
this.types.set(
|
|
417
|
+
this.types.set(keyName, anyType);
|
|
402
418
|
return anyType;
|
|
403
419
|
}
|
|
404
420
|
case 'utcDateTime': {
|
|
405
|
-
const
|
|
421
|
+
const encoding = getDateTimeEncoding(type.encode);
|
|
422
|
+
const keyName = `offsetDateTime-${encoding}-utc`;
|
|
406
423
|
let timeType = this.types.get(keyName);
|
|
407
424
|
if (timeType) {
|
|
408
425
|
return timeType;
|
|
409
426
|
}
|
|
410
|
-
timeType = new rust.OffsetDateTime(this.crate,
|
|
427
|
+
timeType = new rust.OffsetDateTime(this.crate, encoding, true);
|
|
411
428
|
this.types.set(keyName, timeType);
|
|
412
429
|
return timeType;
|
|
413
430
|
}
|
|
414
431
|
default:
|
|
415
|
-
throw new
|
|
432
|
+
throw new AdapterError('UnsupportedTsp', `unhandled tcgc type ${type.kind}`, (_b = type.__raw) === null || _b === void 0 ? void 0 : _b.node);
|
|
416
433
|
}
|
|
417
434
|
}
|
|
435
|
+
/** returns an EncodedBytes type with the specified encoding */
|
|
436
|
+
getEncodedBytes(encoding, asSlice) {
|
|
437
|
+
const keyName = `encodedBytes-${encoding}${asSlice ? '-slice' : ''}`;
|
|
438
|
+
let encodedBytesType = this.types.get(keyName);
|
|
439
|
+
if (encodedBytesType) {
|
|
440
|
+
return encodedBytesType;
|
|
441
|
+
}
|
|
442
|
+
encodedBytesType = new rust.EncodedBytes(encoding, asSlice);
|
|
443
|
+
this.types.set(keyName, encodedBytesType);
|
|
444
|
+
return encodedBytesType;
|
|
445
|
+
}
|
|
446
|
+
/** returns a HashMap<String, type> */
|
|
447
|
+
getHashMap(type) {
|
|
448
|
+
const keyName = recursiveKeyName('hashmap', type);
|
|
449
|
+
let hashmapType = this.types.get(keyName);
|
|
450
|
+
if (hashmapType) {
|
|
451
|
+
return hashmapType;
|
|
452
|
+
}
|
|
453
|
+
hashmapType = new rust.HashMap(type);
|
|
454
|
+
this.types.set(keyName, hashmapType);
|
|
455
|
+
return hashmapType;
|
|
456
|
+
}
|
|
457
|
+
/** returns the specified type wrapped in a Ref */
|
|
458
|
+
getRefType(type) {
|
|
459
|
+
const typeKey = recursiveKeyName('ref', type);
|
|
460
|
+
let refType = this.types.get(typeKey);
|
|
461
|
+
if (!refType) {
|
|
462
|
+
refType = new rust.Ref(type);
|
|
463
|
+
this.types.set(typeKey, refType);
|
|
464
|
+
}
|
|
465
|
+
return refType;
|
|
466
|
+
}
|
|
467
|
+
/** returns a scalar for the specified scalar type */
|
|
468
|
+
getScalar(type) {
|
|
469
|
+
let scalar = this.types.get(type);
|
|
470
|
+
if (!scalar) {
|
|
471
|
+
scalar = new rust.Scalar(type);
|
|
472
|
+
this.types.set(type, scalar);
|
|
473
|
+
}
|
|
474
|
+
return scalar;
|
|
475
|
+
}
|
|
476
|
+
/** returns a slice of the specified type */
|
|
477
|
+
getSlice(type) {
|
|
478
|
+
const typeKey = recursiveKeyName('slice', type);
|
|
479
|
+
let slice = this.types.get(typeKey);
|
|
480
|
+
if (!slice) {
|
|
481
|
+
slice = new rust.Slice(type);
|
|
482
|
+
this.types.set(typeKey, slice);
|
|
483
|
+
}
|
|
484
|
+
return slice;
|
|
485
|
+
}
|
|
418
486
|
/** returns the Rust string slice type */
|
|
419
487
|
getStringSlice() {
|
|
420
488
|
const typeKey = 'str';
|
|
@@ -448,6 +516,17 @@ export class Adapter {
|
|
|
448
516
|
this.types.set(typeKey, unitType);
|
|
449
517
|
return unitType;
|
|
450
518
|
}
|
|
519
|
+
/** returns a Vec<type> */
|
|
520
|
+
getVec(type) {
|
|
521
|
+
const keyName = recursiveKeyName('Vec', type);
|
|
522
|
+
let vectorType = this.types.get(keyName);
|
|
523
|
+
if (vectorType) {
|
|
524
|
+
return vectorType;
|
|
525
|
+
}
|
|
526
|
+
vectorType = new rust.Vector(type);
|
|
527
|
+
this.types.set(keyName, vectorType);
|
|
528
|
+
return vectorType;
|
|
529
|
+
}
|
|
451
530
|
/**
|
|
452
531
|
* converts a tcgc constant to a Rust literal
|
|
453
532
|
*
|
|
@@ -497,7 +576,7 @@ export class Adapter {
|
|
|
497
576
|
* @returns a Rust client
|
|
498
577
|
*/
|
|
499
578
|
recursiveAdaptClient(client, parent) {
|
|
500
|
-
var _a;
|
|
579
|
+
var _a, _b, _c, _d, _e;
|
|
501
580
|
let clientName = client.name;
|
|
502
581
|
// NOTE: if the client has the @clientName decorator applied then use that verbatim
|
|
503
582
|
if (parent && !client.decorators.find((decorator) => decorator.name === 'Azure.ClientGenerator.Core.@clientName')) {
|
|
@@ -564,7 +643,7 @@ export class Adapter {
|
|
|
564
643
|
}
|
|
565
644
|
default:
|
|
566
645
|
if (throwOnDefault) {
|
|
567
|
-
throw new
|
|
646
|
+
throw new AdapterError('UnsupportedTsp', `credential scheme type ${cred.type} NYI`);
|
|
568
647
|
}
|
|
569
648
|
return AuthTypes.Default;
|
|
570
649
|
}
|
|
@@ -588,7 +667,7 @@ export class Adapter {
|
|
|
588
667
|
}
|
|
589
668
|
// no supported credential types were specified
|
|
590
669
|
if (authType === AuthTypes.Default) {
|
|
591
|
-
throw new
|
|
670
|
+
throw new AdapterError('UnsupportedTsp', `credential scheme types ${variantKinds.join()} NYI`, (_a = param.__raw) === null || _a === void 0 ? void 0 : _a.node);
|
|
592
671
|
}
|
|
593
672
|
continue;
|
|
594
673
|
}
|
|
@@ -616,7 +695,7 @@ export class Adapter {
|
|
|
616
695
|
// note that the types of the param and the field are different.
|
|
617
696
|
// NOTE: we use param.name here instead of templateArg.name as
|
|
618
697
|
// the former has the fixed name "endpoint" which is what we want.
|
|
619
|
-
const adaptedParam = new rust.ClientMethodParameter(param.name, this.getStringSlice(), false
|
|
698
|
+
const adaptedParam = new rust.ClientMethodParameter(param.name, this.getRefType(this.getStringSlice()), false);
|
|
620
699
|
adaptedParam.docs = this.adaptDocs(param.summary, param.doc);
|
|
621
700
|
ctorParams.push(adaptedParam);
|
|
622
701
|
rustClient.fields.push(new rust.StructField(param.name, 'pubCrate', new rust.Url(this.crate)));
|
|
@@ -645,9 +724,9 @@ export class Adapter {
|
|
|
645
724
|
}
|
|
646
725
|
const clientParam = this.adaptClientParameter(templateArg, rustClient.constructable);
|
|
647
726
|
if (clientParam.kind !== 'clientEndpoint') {
|
|
648
|
-
throw new
|
|
727
|
+
throw new AdapterError('InternalError', `unexpected client parameter kind ${clientParam.kind}`, (_b = templateArg.__raw) === null || _b === void 0 ? void 0 : _b.node);
|
|
649
728
|
}
|
|
650
|
-
(
|
|
729
|
+
(_c = rustClient.constructable.endpoint) === null || _c === void 0 ? void 0 : _c.parameters.push(clientParam);
|
|
651
730
|
ctorParams.push(clientParam);
|
|
652
731
|
}
|
|
653
732
|
break;
|
|
@@ -694,7 +773,7 @@ export class Adapter {
|
|
|
694
773
|
}
|
|
695
774
|
}
|
|
696
775
|
else {
|
|
697
|
-
throw new
|
|
776
|
+
throw new AdapterError('InternalError', `uninstantiable client ${client.name} has no parent`);
|
|
698
777
|
}
|
|
699
778
|
for (const child of values(client.children)) {
|
|
700
779
|
const subClient = this.recursiveAdaptClient(child, rustClient);
|
|
@@ -708,7 +787,7 @@ export class Adapter {
|
|
|
708
787
|
code: 'LroNotSupported',
|
|
709
788
|
severity: 'warning',
|
|
710
789
|
message: `skip emitting LRO ${method.name}`,
|
|
711
|
-
target: method.__raw ?
|
|
790
|
+
target: (_e = (_d = method.__raw) === null || _d === void 0 ? void 0 : _d.node) !== null && _e !== void 0 ? _e : NoTarget,
|
|
712
791
|
});
|
|
713
792
|
continue;
|
|
714
793
|
}
|
|
@@ -726,12 +805,15 @@ export class Adapter {
|
|
|
726
805
|
*/
|
|
727
806
|
createTokenCredentialCtor(rustClient, cred) {
|
|
728
807
|
if (cred.flows.length === 0) {
|
|
729
|
-
throw new
|
|
808
|
+
throw new AdapterError('InternalError', `no flows defined for credential type ${cred.type}`, cred.model);
|
|
730
809
|
}
|
|
731
810
|
const scopes = new Array();
|
|
732
811
|
for (const scope of cred.flows[0].scopes) {
|
|
733
812
|
scopes.push(scope.value);
|
|
734
813
|
}
|
|
814
|
+
if (scopes.length === 0) {
|
|
815
|
+
throw new AdapterError('InternalError', 'scopes must contain at least one entry', cred.model);
|
|
816
|
+
}
|
|
735
817
|
const ctorTokenCredential = new rust.Constructor('new');
|
|
736
818
|
const tokenCredParam = new rust.ClientMethodParameter('credential', new rust.Arc(new rust.TokenCredential(this.crate, scopes)), false);
|
|
737
819
|
tokenCredParam.docs.summary = `An implementation of [\`TokenCredential\`](azure_core::credentials::TokenCredential) that can provide an Entra ID token to use when authenticating.`;
|
|
@@ -747,10 +829,11 @@ export class Adapter {
|
|
|
747
829
|
* @returns the Rust client parameter
|
|
748
830
|
*/
|
|
749
831
|
adaptClientParameter(param, constructable) {
|
|
832
|
+
var _a;
|
|
750
833
|
let paramType;
|
|
751
834
|
if (param.isApiVersionParam) {
|
|
752
835
|
if (!param.clientDefaultValue) {
|
|
753
|
-
throw new
|
|
836
|
+
throw new AdapterError('InternalError', `API version parameter ${param.name} has no clientDefaultValue`, (_a = param.__raw) === null || _a === void 0 ? void 0 : _a.node);
|
|
754
837
|
}
|
|
755
838
|
paramType = this.getStringType();
|
|
756
839
|
}
|
|
@@ -819,6 +902,7 @@ export class Adapter {
|
|
|
819
902
|
* @param rustClient the client to which the method belongs
|
|
820
903
|
*/
|
|
821
904
|
adaptMethod(method, rustClient) {
|
|
905
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
822
906
|
let srcMethodName = method.name;
|
|
823
907
|
if (method.kind === 'paging' && !srcMethodName.match(/^list/i)) {
|
|
824
908
|
const chunks = codegen.deconstruct(srcMethodName);
|
|
@@ -829,11 +913,11 @@ export class Adapter {
|
|
|
829
913
|
code: 'PagingMethodRename',
|
|
830
914
|
severity: 'warning',
|
|
831
915
|
message: `renamed paging method from ${method.name} to ${srcMethodName}`,
|
|
832
|
-
target: method.__raw ?
|
|
916
|
+
target: (_b = (_a = method.__raw) === null || _a === void 0 ? void 0 : _a.node) !== null && _b !== void 0 ? _b : NoTarget,
|
|
833
917
|
});
|
|
834
918
|
}
|
|
835
919
|
else if (this.renamedMethods.has(srcMethodName)) {
|
|
836
|
-
throw new
|
|
920
|
+
throw new AdapterError('NameCollision', `method name ${srcMethodName} collides with a renamed method`, (_c = method.__raw) === null || _c === void 0 ? void 0 : _c.node);
|
|
837
921
|
}
|
|
838
922
|
const methodName = naming.getEscapedReservedName(snakeCaseName(srcMethodName), 'fn');
|
|
839
923
|
const optionsLifetime = new rust.Lifetime('a');
|
|
@@ -868,7 +952,7 @@ export class Adapter {
|
|
|
868
952
|
rustMethod = new rust.PageableMethod(methodName, rustClient, pub, methodOptions, httpMethod, httpPath);
|
|
869
953
|
break;
|
|
870
954
|
default:
|
|
871
|
-
throw new
|
|
955
|
+
throw new AdapterError('UnsupportedTsp', `method kind ${method.kind} NYI`, (_d = method.__raw) === null || _d === void 0 ? void 0 : _d.node);
|
|
872
956
|
}
|
|
873
957
|
rustMethod.docs = this.adaptDocs(method.summary, method.doc);
|
|
874
958
|
rustClient.methods.push(rustMethod);
|
|
@@ -878,6 +962,8 @@ export class Adapter {
|
|
|
878
962
|
if (method.operation.bodyParam) {
|
|
879
963
|
allOpParams.push(method.operation.bodyParam);
|
|
880
964
|
}
|
|
965
|
+
// maps tcgc method header/query params to their Rust method params
|
|
966
|
+
const paramsMap = new Map();
|
|
881
967
|
for (const param of method.parameters) {
|
|
882
968
|
// we need to translate from the method param to its underlying operation param.
|
|
883
969
|
// most params have a one-to-one mapping. however, for spread params, there will
|
|
@@ -889,7 +975,7 @@ export class Adapter {
|
|
|
889
975
|
}).any();
|
|
890
976
|
}).first();
|
|
891
977
|
if (!opParam) {
|
|
892
|
-
throw new
|
|
978
|
+
throw new AdapterError('InternalError', `didn't find operation parameter for method ${method.name} parameter ${param.name}`, (_e = param.__raw) === null || _e === void 0 ? void 0 : _e.node);
|
|
893
979
|
}
|
|
894
980
|
let adaptedParam;
|
|
895
981
|
// for spread params there are two cases we need to consider.
|
|
@@ -903,6 +989,9 @@ export class Adapter {
|
|
|
903
989
|
else {
|
|
904
990
|
adaptedParam = this.adaptMethodParameter(opParam);
|
|
905
991
|
}
|
|
992
|
+
if (adaptedParam.kind === 'header' || adaptedParam.kind === 'query') {
|
|
993
|
+
paramsMap.set(param, adaptedParam);
|
|
994
|
+
}
|
|
906
995
|
adaptedParam.docs = this.adaptDocs(param.summary, param.doc);
|
|
907
996
|
rustMethod.params.push(adaptedParam);
|
|
908
997
|
if (adaptedParam.optional) {
|
|
@@ -914,18 +1003,11 @@ export class Adapter {
|
|
|
914
1003
|
// already wrapped in an Option<T> type.
|
|
915
1004
|
const field = adaptedParam.type.content.type.fields.find(f => { return f.name === adaptedParam.name; });
|
|
916
1005
|
if (!field) {
|
|
917
|
-
throw new
|
|
1006
|
+
throw new AdapterError('InternalError', `didn't find spread param field ${adaptedParam.name} in type ${adaptedParam.type.content.type.name}`);
|
|
918
1007
|
}
|
|
919
1008
|
fieldType = field.type;
|
|
920
1009
|
}
|
|
921
1010
|
else {
|
|
922
|
-
switch (adaptedParam.type.kind) {
|
|
923
|
-
case 'requestContent':
|
|
924
|
-
case 'struct':
|
|
925
|
-
break;
|
|
926
|
-
default:
|
|
927
|
-
adaptedParam.type = this.typeToWireType(adaptedParam.type);
|
|
928
|
-
}
|
|
929
1011
|
fieldType = new rust.Option(adaptedParam.type);
|
|
930
1012
|
}
|
|
931
1013
|
const optionsField = new rust.StructField(adaptedParam.name, 'pub', fieldType);
|
|
@@ -943,17 +1025,18 @@ export class Adapter {
|
|
|
943
1025
|
}
|
|
944
1026
|
}
|
|
945
1027
|
const getBodyFormat = () => {
|
|
1028
|
+
var _a, _b;
|
|
946
1029
|
// fetch the body format from the HTTP responses.
|
|
947
1030
|
// they should all have the same type so no need to match responses to type.
|
|
948
1031
|
let defaultContentType;
|
|
949
1032
|
for (const httpResp of method.operation.responses) {
|
|
950
1033
|
if (defaultContentType && httpResp.defaultContentType && defaultContentType !== httpResp.defaultContentType) {
|
|
951
|
-
throw new
|
|
1034
|
+
throw new AdapterError('InternalError', `method ${method.name} has conflicting content types`, (_a = method.__raw) === null || _a === void 0 ? void 0 : _a.node);
|
|
952
1035
|
}
|
|
953
1036
|
defaultContentType = httpResp.defaultContentType;
|
|
954
1037
|
}
|
|
955
1038
|
if (!defaultContentType) {
|
|
956
|
-
throw new
|
|
1039
|
+
throw new AdapterError('InternalError', `unable to determine content type for method ${method.name}`, (_b = method.__raw) === null || _b === void 0 ? void 0 : _b.node);
|
|
957
1040
|
}
|
|
958
1041
|
return this.adaptBodyFormat(defaultContentType);
|
|
959
1042
|
};
|
|
@@ -983,16 +1066,53 @@ export class Adapter {
|
|
|
983
1066
|
// however, we want the synthesized paged response envelope type instead.
|
|
984
1067
|
const synthesizedType = method.operation.responses[0].type;
|
|
985
1068
|
if (!synthesizedType) {
|
|
986
|
-
throw new
|
|
1069
|
+
throw new AdapterError('InternalError', `paged method ${method.name} has no synthesized response type`, (_f = method.__raw) === null || _f === void 0 ? void 0 : _f.node);
|
|
987
1070
|
}
|
|
988
1071
|
else if (synthesizedType.kind !== 'model') {
|
|
989
|
-
throw new
|
|
1072
|
+
throw new AdapterError('UnsupportedTsp', `paged method ${method.name} synthesized response type has unexpected kind ${synthesizedType.kind}`, (_g = method.__raw) === null || _g === void 0 ? void 0 : _g.node);
|
|
990
1073
|
}
|
|
991
1074
|
const format = getBodyFormat();
|
|
992
|
-
const synthesizedModel = this.getModel(synthesizedType);
|
|
1075
|
+
const synthesizedModel = this.getModel(synthesizedType, new Array());
|
|
993
1076
|
if (!this.crate.models.includes(synthesizedModel)) {
|
|
994
1077
|
this.crate.models.push(synthesizedModel);
|
|
995
1078
|
}
|
|
1079
|
+
// for the pager response type, remove the Option<T> around the Vec<T> for the page items
|
|
1080
|
+
if (!method.pagingMetadata.pageItemsSegments) {
|
|
1081
|
+
throw new AdapterError('InternalError', `paged method ${method.name} has no pageItemsSegments`, (_h = method.__raw) === null || _h === void 0 ? void 0 : _h.node);
|
|
1082
|
+
}
|
|
1083
|
+
// unwrap all of the segments for the paged response
|
|
1084
|
+
let unwrappedCount = 0;
|
|
1085
|
+
let typeToUnwrap = synthesizedModel;
|
|
1086
|
+
for (const pageItemsSegment of method.pagingMetadata.pageItemsSegments) {
|
|
1087
|
+
const segment = pageItemsSegment;
|
|
1088
|
+
let serde;
|
|
1089
|
+
switch (format) {
|
|
1090
|
+
case 'json':
|
|
1091
|
+
serde = segment.serializationOptions.json.name;
|
|
1092
|
+
break;
|
|
1093
|
+
case 'xml':
|
|
1094
|
+
serde = segment.serializationOptions.xml.name;
|
|
1095
|
+
break;
|
|
1096
|
+
}
|
|
1097
|
+
for (let i = 0; i < typeToUnwrap.fields.length; ++i) {
|
|
1098
|
+
const field = typeToUnwrap.fields[i];
|
|
1099
|
+
if (field.serde === serde) {
|
|
1100
|
+
// check if this has already been unwrapped (e.g. type is shared across operations)
|
|
1101
|
+
if (field.type.kind === 'option') {
|
|
1102
|
+
typeToUnwrap.fields[i].type = typeToUnwrap.fields[i].type.type;
|
|
1103
|
+
}
|
|
1104
|
+
// move to the next segment
|
|
1105
|
+
if (field.type.kind === 'model') {
|
|
1106
|
+
typeToUnwrap = field.type;
|
|
1107
|
+
}
|
|
1108
|
+
++unwrappedCount;
|
|
1109
|
+
break;
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
if (unwrappedCount !== method.pagingMetadata.pageItemsSegments.length) {
|
|
1114
|
+
throw new AdapterError('InternalError', `failed to unwrap paged items for method ${method.name}`, (_j = method.__raw) === null || _j === void 0 ? void 0 : _j.node);
|
|
1115
|
+
}
|
|
996
1116
|
returnType = new rust.Pager(this.crate, new rust.Payload(synthesizedModel, format));
|
|
997
1117
|
}
|
|
998
1118
|
else if (method.response.type && !(method.response.type.kind === 'bytes' && method.response.type.encode === 'bytes')) {
|
|
@@ -1018,7 +1138,7 @@ export class Adapter {
|
|
|
1018
1138
|
rustMethod.responseHeaders = this.adaptResponseHeadersTrait(rustClient, rustMethod, Array.from(responseHeadersMap.values()));
|
|
1019
1139
|
if (method.kind === 'paging') {
|
|
1020
1140
|
// can't do this until the method has been completely adapted
|
|
1021
|
-
rustMethod.strategy = this.adaptPageableMethodStrategy(method);
|
|
1141
|
+
rustMethod.strategy = this.adaptPageableMethodStrategy(method, paramsMap, responseHeadersMap);
|
|
1022
1142
|
}
|
|
1023
1143
|
}
|
|
1024
1144
|
/**
|
|
@@ -1036,12 +1156,12 @@ export class Adapter {
|
|
|
1036
1156
|
let responseHeader;
|
|
1037
1157
|
if (header.type.kind === 'dict') {
|
|
1038
1158
|
if (header.serializedName !== 'x-ms-meta' && header.serializedName !== 'x-ms-or') {
|
|
1039
|
-
throw new
|
|
1159
|
+
throw new AdapterError('InternalError', `unexpected response header collection ${header.serializedName}`, header.__raw.node);
|
|
1040
1160
|
}
|
|
1041
1161
|
responseHeader = new rust.ResponseHeaderHashMap(snakeCaseName(header.name), header.serializedName);
|
|
1042
1162
|
}
|
|
1043
1163
|
else {
|
|
1044
|
-
responseHeader = new rust.ResponseHeaderScalar(snakeCaseName(header.name), fixETagName(header.serializedName), this.getType(header.type));
|
|
1164
|
+
responseHeader = new rust.ResponseHeaderScalar(snakeCaseName(header.name), fixETagName(header.serializedName), this.typeToWireType(this.getType(header.type)));
|
|
1045
1165
|
}
|
|
1046
1166
|
responseHeader.docs = this.adaptDocs(header.summary, header.doc);
|
|
1047
1167
|
responseHeadersMap.set(header, responseHeader);
|
|
@@ -1061,6 +1181,32 @@ export class Adapter {
|
|
|
1061
1181
|
if (responseHeaders.length === 0) {
|
|
1062
1182
|
return undefined;
|
|
1063
1183
|
}
|
|
1184
|
+
/**
|
|
1185
|
+
* recursively builds a name from the specified type.
|
|
1186
|
+
* e.g. Vec<FooModel> would be VecFooModel etc.
|
|
1187
|
+
*
|
|
1188
|
+
* @param type the type for which to build a name
|
|
1189
|
+
* @returns the name
|
|
1190
|
+
*/
|
|
1191
|
+
const recursiveTypeName = function (type) {
|
|
1192
|
+
switch (type.kind) {
|
|
1193
|
+
case 'enum':
|
|
1194
|
+
case 'model':
|
|
1195
|
+
return type.name;
|
|
1196
|
+
case 'hashmap':
|
|
1197
|
+
return `${type.name}${recursiveTypeName(type.type)}`;
|
|
1198
|
+
case 'ref':
|
|
1199
|
+
return `Ref${recursiveTypeName(type.type)}`;
|
|
1200
|
+
case 'scalar':
|
|
1201
|
+
return codegen.capitalize(type.type);
|
|
1202
|
+
case 'slice':
|
|
1203
|
+
return `Slice${recursiveTypeName(type.type)}`;
|
|
1204
|
+
case 'Vec':
|
|
1205
|
+
return `${type.kind}${recursiveTypeName(type.type)}`;
|
|
1206
|
+
default:
|
|
1207
|
+
return codegen.capitalize(type.kind);
|
|
1208
|
+
}
|
|
1209
|
+
};
|
|
1064
1210
|
// response header traits are only ever for marker types and payloads
|
|
1065
1211
|
let implFor;
|
|
1066
1212
|
switch (method.returns.type.kind) {
|
|
@@ -1069,13 +1215,13 @@ export class Adapter {
|
|
|
1069
1215
|
break;
|
|
1070
1216
|
case 'response':
|
|
1071
1217
|
if (method.returns.type.content.kind !== 'marker' && method.returns.type.content.kind !== 'payload') {
|
|
1072
|
-
throw new
|
|
1218
|
+
throw new AdapterError('InternalError', `unexpected method content kind ${method.returns.type.content.kind}`);
|
|
1073
1219
|
}
|
|
1074
1220
|
implFor = method.returns.type.content;
|
|
1075
1221
|
break;
|
|
1076
1222
|
default:
|
|
1077
1223
|
// this is Unit which should have been previously skipped
|
|
1078
|
-
throw new
|
|
1224
|
+
throw new AdapterError('InternalError', `unexpected method return kind ${method.returns.type.kind}`);
|
|
1079
1225
|
}
|
|
1080
1226
|
let traitName;
|
|
1081
1227
|
switch (implFor.kind) {
|
|
@@ -1083,7 +1229,7 @@ export class Adapter {
|
|
|
1083
1229
|
traitName = implFor.name;
|
|
1084
1230
|
break;
|
|
1085
1231
|
case 'payload':
|
|
1086
|
-
traitName =
|
|
1232
|
+
traitName = recursiveTypeName(implFor.type);
|
|
1087
1233
|
break;
|
|
1088
1234
|
}
|
|
1089
1235
|
traitName += 'Headers';
|
|
@@ -1093,59 +1239,89 @@ export class Adapter {
|
|
|
1093
1239
|
responseHeadersTrait.headers.push(...responseHeaders);
|
|
1094
1240
|
return responseHeadersTrait;
|
|
1095
1241
|
}
|
|
1096
|
-
/**
|
|
1097
|
-
* recursively builds a name from the specified type.
|
|
1098
|
-
* e.g. Vec<FooModel> would be VecFooModel etc.
|
|
1099
|
-
*
|
|
1100
|
-
* @param type the type for which to build a name
|
|
1101
|
-
* @returns the name
|
|
1102
|
-
*/
|
|
1103
|
-
recursiveTypeName(type) {
|
|
1104
|
-
switch (type.kind) {
|
|
1105
|
-
case 'enum':
|
|
1106
|
-
case 'model':
|
|
1107
|
-
return type.name;
|
|
1108
|
-
case 'hashmap':
|
|
1109
|
-
return `${type.name}${this.recursiveTypeName(type.type)}`;
|
|
1110
|
-
case 'Vec':
|
|
1111
|
-
return `${type.kind}${this.recursiveTypeName(type.type)}`;
|
|
1112
|
-
default:
|
|
1113
|
-
return codegen.capitalize(type.kind);
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
1242
|
/**
|
|
1117
1243
|
* creates the pageable strategy based on the method definition
|
|
1118
1244
|
*
|
|
1119
1245
|
* @param method the pageable method for which to create a strategy
|
|
1246
|
+
* @param paramsMap maps tcgc method params to Rust params (needed for continuation token strategy)
|
|
1247
|
+
* @param respHeadersMap maps tcgc response headers to Rust response headers (needed for continuation token strategy)
|
|
1120
1248
|
* @returns the pageable strategy
|
|
1121
1249
|
*/
|
|
1122
|
-
adaptPageableMethodStrategy(method) {
|
|
1250
|
+
adaptPageableMethodStrategy(method, paramsMap, respHeadersMap) {
|
|
1251
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
1123
1252
|
if (method.pagingMetadata.nextLinkOperation) {
|
|
1124
1253
|
// TODO: https://github.com/Azure/autorest.rust/issues/103
|
|
1125
|
-
throw new
|
|
1254
|
+
throw new AdapterError('UnsupportedTsp', 'next page operation NYI', (_a = method.__raw) === null || _a === void 0 ? void 0 : _a.node);
|
|
1126
1255
|
}
|
|
1127
1256
|
else if (method.pagingMetadata.nextLinkSegments) {
|
|
1128
1257
|
if (method.pagingMetadata.nextLinkSegments.length > 1) {
|
|
1129
1258
|
// TODO: https://github.com/Azure/autorest.rust/issues/102
|
|
1130
|
-
throw new
|
|
1259
|
+
throw new AdapterError('UnsupportedTsp', 'nested next link path NYI', (_b = method.__raw) === null || _b === void 0 ? void 0 : _b.node);
|
|
1131
1260
|
}
|
|
1132
1261
|
// this is the field in the response type that contains the next link URL
|
|
1133
1262
|
const nextLinkSegment = method.pagingMetadata.nextLinkSegments[0];
|
|
1134
1263
|
if (nextLinkSegment.kind !== 'property') {
|
|
1135
|
-
throw new
|
|
1264
|
+
throw new AdapterError('InternalError', `unexpected kind ${nextLinkSegment.kind} for next link segment in operation ${method.name}`, (_c = method.__raw) === null || _c === void 0 ? void 0 : _c.node);
|
|
1136
1265
|
}
|
|
1137
1266
|
const nextLinkField = this.fieldsMap.get(nextLinkSegment);
|
|
1138
1267
|
if (!nextLinkField) {
|
|
1139
1268
|
// the most likely explanation for this is lack of reference equality
|
|
1140
|
-
throw new
|
|
1269
|
+
throw new AdapterError('InternalError', `missing next link field name ${nextLinkSegment.name} for operation ${method.name}`, (_d = method.__raw) === null || _d === void 0 ? void 0 : _d.node);
|
|
1141
1270
|
}
|
|
1142
1271
|
return new rust.PageableStrategyNextLink(nextLinkField);
|
|
1143
1272
|
}
|
|
1144
1273
|
else if (method.pagingMetadata.continuationTokenParameterSegments && method.pagingMetadata.continuationTokenResponseSegments) {
|
|
1145
|
-
|
|
1274
|
+
if (method.pagingMetadata.continuationTokenParameterSegments.length > 1) {
|
|
1275
|
+
throw new AdapterError('UnsupportedTsp', `nested continuationTokenParameterSegments NYI`, (_e = method.__raw) === null || _e === void 0 ? void 0 : _e.node);
|
|
1276
|
+
}
|
|
1277
|
+
if (method.pagingMetadata.continuationTokenResponseSegments.length > 1) {
|
|
1278
|
+
throw new AdapterError('UnsupportedTsp', `nested continuationTokenResponseSegments NYI`, (_f = method.__raw) === null || _f === void 0 ? void 0 : _f.node);
|
|
1279
|
+
}
|
|
1280
|
+
const tokenReq = method.pagingMetadata.continuationTokenParameterSegments[0];
|
|
1281
|
+
const tokenResp = method.pagingMetadata.continuationTokenResponseSegments[0];
|
|
1282
|
+
// find the continuation token parameter
|
|
1283
|
+
let requestToken;
|
|
1284
|
+
switch (tokenReq.kind) {
|
|
1285
|
+
case 'method': {
|
|
1286
|
+
const tokenParam = paramsMap.get(tokenReq);
|
|
1287
|
+
if (!tokenParam) {
|
|
1288
|
+
throw new AdapterError('InternalError', `missing continuation token request parameter name ${tokenResp.name} for operation ${method.name}`, (_g = method.__raw) === null || _g === void 0 ? void 0 : _g.node);
|
|
1289
|
+
}
|
|
1290
|
+
requestToken = tokenParam;
|
|
1291
|
+
break;
|
|
1292
|
+
}
|
|
1293
|
+
default:
|
|
1294
|
+
throw new AdapterError('InternalError', `unhandled continuationTokenParameterSegment kind ${tokenReq.kind}`, (_h = tokenReq.__raw) === null || _h === void 0 ? void 0 : _h.node);
|
|
1295
|
+
}
|
|
1296
|
+
// find the continuation token response
|
|
1297
|
+
let responseToken;
|
|
1298
|
+
switch (tokenResp.kind) {
|
|
1299
|
+
case 'property': {
|
|
1300
|
+
const tokenField = this.fieldsMap.get(tokenResp);
|
|
1301
|
+
if (!tokenField) {
|
|
1302
|
+
throw new AdapterError('InternalError', `missing continuation token response field name ${tokenResp.name} for operation ${method.name}`, (_j = method.__raw) === null || _j === void 0 ? void 0 : _j.node);
|
|
1303
|
+
}
|
|
1304
|
+
responseToken = tokenField;
|
|
1305
|
+
break;
|
|
1306
|
+
}
|
|
1307
|
+
case 'responseheader': {
|
|
1308
|
+
const tokenHeader = respHeadersMap.get(tokenResp);
|
|
1309
|
+
if (!tokenHeader) {
|
|
1310
|
+
throw new AdapterError('InternalError', `missing continuation token response header name ${tokenResp.name} for operation ${method.name}`, (_k = method.__raw) === null || _k === void 0 ? void 0 : _k.node);
|
|
1311
|
+
}
|
|
1312
|
+
if (tokenHeader.kind !== 'responseHeaderScalar') {
|
|
1313
|
+
throw new AdapterError('InternalError', `unexpected response header kind ${tokenHeader.kind}`);
|
|
1314
|
+
}
|
|
1315
|
+
responseToken = tokenHeader;
|
|
1316
|
+
break;
|
|
1317
|
+
}
|
|
1318
|
+
default:
|
|
1319
|
+
throw new AdapterError('InternalError', `unhandled continuationTokenResponseSegment kind ${tokenResp.kind}`);
|
|
1320
|
+
}
|
|
1321
|
+
return new rust.PageableStrategyContinuationToken(requestToken, responseToken);
|
|
1146
1322
|
}
|
|
1147
1323
|
else {
|
|
1148
|
-
throw new
|
|
1324
|
+
throw new AdapterError('InternalError', `unknown paging strategy for operation ${method.name}`, (_l = method.__raw) === null || _l === void 0 ? void 0 : _l.node);
|
|
1149
1325
|
}
|
|
1150
1326
|
}
|
|
1151
1327
|
/**
|
|
@@ -1155,6 +1331,7 @@ export class Adapter {
|
|
|
1155
1331
|
* @returns a Rust method parameter
|
|
1156
1332
|
*/
|
|
1157
1333
|
adaptMethodParameter(param) {
|
|
1334
|
+
var _a, _b, _c, _d, _e;
|
|
1158
1335
|
const paramLoc = param.onClient ? 'client' : 'method';
|
|
1159
1336
|
/**
|
|
1160
1337
|
* used to create keys for this.clientMethodParams
|
|
@@ -1175,11 +1352,12 @@ export class Adapter {
|
|
|
1175
1352
|
}
|
|
1176
1353
|
const paramName = naming.getEscapedReservedName(snakeCaseName(param.name), 'param');
|
|
1177
1354
|
let paramType = this.getType(param.type);
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1355
|
+
// for required header/path/query method string params, we might emit them as borrowed types
|
|
1356
|
+
if (!param.optional && !param.onClient && (param.kind === 'header' || param.kind === 'path' || param.kind === 'query')) {
|
|
1357
|
+
const borrowedType = this.canBorrowMethodParam(paramType, param.kind);
|
|
1358
|
+
if (borrowedType) {
|
|
1359
|
+
paramType = borrowedType;
|
|
1360
|
+
}
|
|
1183
1361
|
}
|
|
1184
1362
|
let adaptedParam;
|
|
1185
1363
|
switch (param.kind) {
|
|
@@ -1197,11 +1375,11 @@ export class Adapter {
|
|
|
1197
1375
|
}
|
|
1198
1376
|
case 'cookie':
|
|
1199
1377
|
// TODO: https://github.com/Azure/typespec-rust/issues/192
|
|
1200
|
-
throw new
|
|
1378
|
+
throw new AdapterError('UnsupportedTsp', 'cookie parameters are not supported', (_a = param.__raw) === null || _a === void 0 ? void 0 : _a.node);
|
|
1201
1379
|
case 'header':
|
|
1202
1380
|
if (param.collectionFormat) {
|
|
1203
|
-
if (paramType.kind !== 'Vec') {
|
|
1204
|
-
throw new
|
|
1381
|
+
if (paramType.kind !== 'Vec' && !isRefSlice(paramType)) {
|
|
1382
|
+
throw new AdapterError('InternalError', `unexpected kind ${paramType.kind} for HeaderCollectionParameter`, (_b = param.__raw) === null || _b === void 0 ? void 0 : _b.node);
|
|
1205
1383
|
}
|
|
1206
1384
|
let format;
|
|
1207
1385
|
switch (param.collectionFormat) {
|
|
@@ -1215,47 +1393,91 @@ export class Adapter {
|
|
|
1215
1393
|
format = param.collectionFormat;
|
|
1216
1394
|
break;
|
|
1217
1395
|
default:
|
|
1218
|
-
throw new
|
|
1396
|
+
throw new AdapterError('InternalError', `unexpected format ${param.collectionFormat} for HeaderCollectionParameter`, (_c = param.__raw) === null || _c === void 0 ? void 0 : _c.node);
|
|
1219
1397
|
}
|
|
1220
1398
|
adaptedParam = new rust.HeaderCollectionParameter(paramName, param.serializedName, paramLoc, param.optional, paramType, format);
|
|
1221
1399
|
}
|
|
1222
1400
|
else if (param.serializedName === 'x-ms-meta') {
|
|
1223
1401
|
if (paramType.kind !== 'hashmap') {
|
|
1224
|
-
throw new
|
|
1402
|
+
throw new AdapterError('InternalError', `unexpected kind ${paramType.kind} for header ${param.serializedName}`, (_d = param.__raw) === null || _d === void 0 ? void 0 : _d.node);
|
|
1225
1403
|
}
|
|
1226
1404
|
adaptedParam = new rust.HeaderHashMapParameter(paramName, param.serializedName, paramLoc, param.optional, paramType);
|
|
1227
1405
|
}
|
|
1228
1406
|
else {
|
|
1229
|
-
adaptedParam = new rust.HeaderParameter(paramName, param.serializedName, paramLoc, param.optional, paramType);
|
|
1407
|
+
adaptedParam = new rust.HeaderParameter(paramName, param.serializedName, paramLoc, param.optional, this.typeToWireType(paramType));
|
|
1230
1408
|
adaptedParam.isApiVersion = param.isApiVersionParam;
|
|
1231
1409
|
}
|
|
1232
1410
|
break;
|
|
1233
1411
|
case 'path':
|
|
1234
|
-
adaptedParam = new rust.PathParameter(paramName, param.serializedName, paramLoc, param.optional, paramType, param.allowReserved);
|
|
1412
|
+
adaptedParam = new rust.PathParameter(paramName, param.serializedName, paramLoc, param.optional, this.typeToWireType(paramType), param.allowReserved);
|
|
1235
1413
|
break;
|
|
1236
1414
|
case 'query':
|
|
1237
1415
|
if (param.collectionFormat) {
|
|
1238
1416
|
const format = param.collectionFormat === 'simple' ? 'csv' : (param.collectionFormat === 'form' ? 'multi' : param.collectionFormat);
|
|
1239
|
-
if (paramType.kind !== 'Vec') {
|
|
1240
|
-
throw new
|
|
1417
|
+
if (paramType.kind !== 'Vec' && !isRefSlice(paramType)) {
|
|
1418
|
+
throw new AdapterError('InternalError', `unexpected kind ${paramType.kind} for QueryCollectionParameter`, (_e = param.__raw) === null || _e === void 0 ? void 0 : _e.node);
|
|
1241
1419
|
}
|
|
1242
1420
|
// TODO: hard-coded encoding setting, https://github.com/Azure/typespec-azure/issues/1314
|
|
1243
1421
|
adaptedParam = new rust.QueryCollectionParameter(paramName, param.serializedName, paramLoc, param.optional, paramType, true, format);
|
|
1244
1422
|
}
|
|
1245
1423
|
else {
|
|
1246
1424
|
// TODO: hard-coded encoding setting, https://github.com/Azure/typespec-azure/issues/1314
|
|
1247
|
-
adaptedParam = new rust.QueryParameter(paramName, param.serializedName, paramLoc, param.optional, paramType, true);
|
|
1425
|
+
adaptedParam = new rust.QueryParameter(paramName, param.serializedName, paramLoc, param.optional, this.typeToWireType(paramType), true);
|
|
1248
1426
|
adaptedParam.isApiVersion = param.isApiVersionParam;
|
|
1249
1427
|
}
|
|
1250
1428
|
break;
|
|
1251
1429
|
}
|
|
1252
1430
|
adaptedParam.docs = this.adaptDocs(param.summary, param.doc);
|
|
1253
|
-
adaptedParam.ref = paramByRef;
|
|
1254
1431
|
if (paramLoc === 'client') {
|
|
1255
1432
|
this.clientMethodParams.set(getClientParamsKey(param), adaptedParam);
|
|
1256
1433
|
}
|
|
1257
1434
|
return adaptedParam;
|
|
1258
1435
|
}
|
|
1436
|
+
/**
|
|
1437
|
+
* updates the specified type to a borrowed type based on its type and kind.
|
|
1438
|
+
* if no such transformation is necessary, undefined is returned.
|
|
1439
|
+
* e.g. a String param that doesn't need to be owned will be
|
|
1440
|
+
* returned as a &str.
|
|
1441
|
+
*
|
|
1442
|
+
* @param type the param type to be updated
|
|
1443
|
+
* @param kind the kind of param
|
|
1444
|
+
* @returns the updated param type or undefined
|
|
1445
|
+
*/
|
|
1446
|
+
canBorrowMethodParam(type, kind) {
|
|
1447
|
+
const recursiveBuildVecStr = (v) => {
|
|
1448
|
+
switch (v.kind) {
|
|
1449
|
+
case 'encodedBytes':
|
|
1450
|
+
return this.getRefType(this.getEncodedBytes(v.encoding, true));
|
|
1451
|
+
case 'hashmap':
|
|
1452
|
+
return this.getHashMap(this.typeToWireType(recursiveBuildVecStr(v.type)));
|
|
1453
|
+
case 'String':
|
|
1454
|
+
return this.getRefType(this.getStringSlice());
|
|
1455
|
+
case 'Vec':
|
|
1456
|
+
return this.getVec(this.typeToWireType(recursiveBuildVecStr(v.type)));
|
|
1457
|
+
default:
|
|
1458
|
+
throw new AdapterError('InternalError', `unexpected kind ${v.kind}`);
|
|
1459
|
+
}
|
|
1460
|
+
};
|
|
1461
|
+
switch (type.kind) {
|
|
1462
|
+
case 'String':
|
|
1463
|
+
// header String params are always owned
|
|
1464
|
+
if (kind !== 'header') {
|
|
1465
|
+
return this.getRefType(this.getStringSlice());
|
|
1466
|
+
}
|
|
1467
|
+
break;
|
|
1468
|
+
case 'Vec': {
|
|
1469
|
+
// if this is an array of string, we ultimately want a slice of &str
|
|
1470
|
+
const unwrapped = helpers.unwrapVec(type);
|
|
1471
|
+
if (unwrapped.kind === 'String' || unwrapped.kind === 'encodedBytes') {
|
|
1472
|
+
return this.getRefType(this.getSlice(recursiveBuildVecStr(type.type)));
|
|
1473
|
+
}
|
|
1474
|
+
return this.getRefType(this.getSlice(type.type));
|
|
1475
|
+
}
|
|
1476
|
+
case 'encodedBytes':
|
|
1477
|
+
return this.getRefType(this.getEncodedBytes(type.encoding, true));
|
|
1478
|
+
}
|
|
1479
|
+
return undefined;
|
|
1480
|
+
}
|
|
1259
1481
|
/**
|
|
1260
1482
|
* narrows a rust.Type to a rust.WireType.
|
|
1261
1483
|
* if type isn't a rust.WireType, an error is thrown.
|
|
@@ -1266,6 +1488,7 @@ export class Adapter {
|
|
|
1266
1488
|
typeToWireType(type) {
|
|
1267
1489
|
switch (type.kind) {
|
|
1268
1490
|
case 'bytes':
|
|
1491
|
+
case 'decimal':
|
|
1269
1492
|
case 'encodedBytes':
|
|
1270
1493
|
case 'enum':
|
|
1271
1494
|
case 'enumValue':
|
|
@@ -1275,14 +1498,16 @@ export class Adapter {
|
|
|
1275
1498
|
case 'literal':
|
|
1276
1499
|
case 'model':
|
|
1277
1500
|
case 'offsetDateTime':
|
|
1501
|
+
case 'ref':
|
|
1278
1502
|
case 'scalar':
|
|
1503
|
+
case 'slice':
|
|
1279
1504
|
case 'str':
|
|
1280
1505
|
case 'String':
|
|
1281
1506
|
case 'Url':
|
|
1282
1507
|
case 'Vec':
|
|
1283
1508
|
return type;
|
|
1284
1509
|
default:
|
|
1285
|
-
throw new
|
|
1510
|
+
throw new AdapterError('InternalError', `cannot convert ${type.kind} to a wire type`);
|
|
1286
1511
|
}
|
|
1287
1512
|
}
|
|
1288
1513
|
/**
|
|
@@ -1294,6 +1519,7 @@ export class Adapter {
|
|
|
1294
1519
|
* @returns a Rust partial body parameter
|
|
1295
1520
|
*/
|
|
1296
1521
|
adaptMethodSpreadParameter(param, format, opParamType) {
|
|
1522
|
+
var _a, _b;
|
|
1297
1523
|
switch (format) {
|
|
1298
1524
|
case 'json':
|
|
1299
1525
|
case 'xml': {
|
|
@@ -1306,27 +1532,16 @@ export class Adapter {
|
|
|
1306
1532
|
}
|
|
1307
1533
|
}
|
|
1308
1534
|
if (serializedName === undefined) {
|
|
1309
|
-
throw new
|
|
1310
|
-
}
|
|
1311
|
-
// this is the param type as surfaced in the method sig.
|
|
1312
|
-
// it's usually the same type as its corresponding field type
|
|
1313
|
-
// in the underlying model. the only exception is for String
|
|
1314
|
-
// types. we want to surface those as &str in the method sig.
|
|
1315
|
-
let paramType = this.getType(param.type);
|
|
1316
|
-
let paramByRef = false;
|
|
1317
|
-
if (!param.optional && !param.onClient && paramType.kind === 'String') {
|
|
1318
|
-
paramType = this.getStringSlice();
|
|
1319
|
-
paramByRef = true;
|
|
1535
|
+
throw new AdapterError('InternalError', `didn't find body model property for spread parameter ${param.name}`, (_a = param.__raw) === null || _a === void 0 ? void 0 : _a.node);
|
|
1320
1536
|
}
|
|
1321
1537
|
// this is the internal model type that the spread params coalesce into
|
|
1322
1538
|
const payloadType = this.getType(opParamType);
|
|
1323
1539
|
if (payloadType.kind !== 'model') {
|
|
1324
|
-
throw new
|
|
1540
|
+
throw new AdapterError('InternalError', `unexpected kind ${payloadType.kind} for spread body param`, (_b = opParamType.__raw) === null || _b === void 0 ? void 0 : _b.node);
|
|
1325
1541
|
}
|
|
1326
1542
|
const paramName = naming.getEscapedReservedName(snakeCaseName(param.name), 'param');
|
|
1327
1543
|
const paramLoc = 'method';
|
|
1328
|
-
const adaptedParam = new rust.PartialBodyParameter(paramName, paramLoc, param.optional, serializedName,
|
|
1329
|
-
adaptedParam.ref = paramByRef;
|
|
1544
|
+
const adaptedParam = new rust.PartialBodyParameter(paramName, paramLoc, param.optional, serializedName, this.getType(param.type), new rust.RequestContent(this.crate, new rust.Payload(payloadType, format)));
|
|
1330
1545
|
return adaptedParam;
|
|
1331
1546
|
}
|
|
1332
1547
|
}
|
|
@@ -1349,10 +1564,14 @@ export class Adapter {
|
|
|
1349
1564
|
return 'xml';
|
|
1350
1565
|
}
|
|
1351
1566
|
else {
|
|
1352
|
-
throw new
|
|
1567
|
+
throw new AdapterError('InternalError', `unexpected contentType ${contentType}`);
|
|
1353
1568
|
}
|
|
1354
1569
|
}
|
|
1355
1570
|
}
|
|
1571
|
+
/** typeguard to determine if type is a Ref<Slice> */
|
|
1572
|
+
function isRefSlice(type) {
|
|
1573
|
+
return type.kind === 'ref' && type.type.kind === 'slice';
|
|
1574
|
+
}
|
|
1356
1575
|
/**
|
|
1357
1576
|
* transforms Etag etc to all lower case.
|
|
1358
1577
|
* this is to prevent inadvertently snake-casing
|
|
@@ -1383,41 +1602,36 @@ function snakeCaseName(name) {
|
|
|
1383
1602
|
*
|
|
1384
1603
|
* obj is recursively unwrapped, and each layer is used to construct
|
|
1385
1604
|
* the key. e.g. if obj is a HashMap<String, Vec<i32>> this would
|
|
1386
|
-
* unwrap to
|
|
1605
|
+
* unwrap to hashmap-Vec-i32.
|
|
1387
1606
|
*
|
|
1388
1607
|
* @param root the starting value for the key
|
|
1389
1608
|
* @param obj the type for which to create the key
|
|
1390
1609
|
* @returns a string containing the complete map key
|
|
1391
1610
|
*/
|
|
1392
|
-
function recursiveKeyName(root,
|
|
1393
|
-
switch (
|
|
1394
|
-
case '
|
|
1395
|
-
return recursiveKeyName(`${root}
|
|
1396
|
-
case '
|
|
1397
|
-
return `${root}
|
|
1611
|
+
function recursiveKeyName(root, type) {
|
|
1612
|
+
switch (type.kind) {
|
|
1613
|
+
case 'Vec':
|
|
1614
|
+
return recursiveKeyName(`${root}-${type.kind}`, type.type);
|
|
1615
|
+
case 'encodedBytes':
|
|
1616
|
+
return `${root}-${type.kind}-${type.encoding}${type.slice ? '-slice' : ''}`;
|
|
1398
1617
|
case 'enum':
|
|
1399
|
-
return `${root}-${
|
|
1400
|
-
case '
|
|
1401
|
-
return `${root}-${
|
|
1402
|
-
case '
|
|
1403
|
-
return recursiveKeyName(`${root}
|
|
1404
|
-
case '
|
|
1405
|
-
return `${root}-
|
|
1406
|
-
case 'utcDateTime':
|
|
1407
|
-
return `${root}-${obj.encode}`;
|
|
1408
|
-
case 'duration':
|
|
1409
|
-
// TODO: this should be: return `${root}-duration-${obj.encode}`;
|
|
1410
|
-
// as it is now, it treats the duration as a String
|
|
1411
|
-
// https://github.com/Azure/typespec-rust/issues/41
|
|
1412
|
-
return `${root}-${obj.wireType.kind}`;
|
|
1618
|
+
return `${root}-${type.kind}-${type.name}`;
|
|
1619
|
+
case 'enumValue':
|
|
1620
|
+
return `${root}-${type.type.name}-${type.name}`;
|
|
1621
|
+
case 'hashmap':
|
|
1622
|
+
return recursiveKeyName(`${root}-${type.kind}`, type.type);
|
|
1623
|
+
case 'offsetDateTime':
|
|
1624
|
+
return `${root}-${type.kind}-${type.encoding}${type.utc ? '-utc' : ''}`;
|
|
1413
1625
|
case 'model':
|
|
1414
|
-
return `${root}-${
|
|
1415
|
-
case '
|
|
1416
|
-
return recursiveKeyName(`${root}
|
|
1417
|
-
case '
|
|
1418
|
-
return `${root}
|
|
1626
|
+
return `${root}-${type.kind}-${type.name}`;
|
|
1627
|
+
case 'ref':
|
|
1628
|
+
return recursiveKeyName(`${root}-${type.kind}`, type.type);
|
|
1629
|
+
case 'scalar':
|
|
1630
|
+
return `${root}-${type.kind}-${type.type}`;
|
|
1631
|
+
case 'slice':
|
|
1632
|
+
return recursiveKeyName(`${root}-${type.kind}`, type.type);
|
|
1419
1633
|
default:
|
|
1420
|
-
return `${root}-${
|
|
1634
|
+
return `${root}-${type.kind}`;
|
|
1421
1635
|
}
|
|
1422
1636
|
}
|
|
1423
1637
|
/**
|