@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.
Files changed (50) hide show
  1. package/dist/src/codegen/clients.d.ts.map +1 -1
  2. package/dist/src/codegen/clients.js +155 -85
  3. package/dist/src/codegen/clients.js.map +1 -1
  4. package/dist/src/codegen/context.d.ts.map +1 -1
  5. package/dist/src/codegen/context.js +3 -2
  6. package/dist/src/codegen/context.js.map +1 -1
  7. package/dist/src/codegen/errors.d.ts +13 -0
  8. package/dist/src/codegen/errors.d.ts.map +1 -0
  9. package/dist/src/codegen/errors.js +15 -0
  10. package/dist/src/codegen/errors.js.map +1 -0
  11. package/dist/src/codegen/headerTraits.d.ts.map +1 -1
  12. package/dist/src/codegen/headerTraits.js +3 -2
  13. package/dist/src/codegen/headerTraits.js.map +1 -1
  14. package/dist/src/codegen/helpers.d.ts.map +1 -1
  15. package/dist/src/codegen/helpers.js +13 -3
  16. package/dist/src/codegen/helpers.js.map +1 -1
  17. package/dist/src/codegen/models.d.ts.map +1 -1
  18. package/dist/src/codegen/models.js +133 -71
  19. package/dist/src/codegen/models.js.map +1 -1
  20. package/dist/src/codegen/use.d.ts.map +1 -1
  21. package/dist/src/codegen/use.js +4 -2
  22. package/dist/src/codegen/use.js.map +1 -1
  23. package/dist/src/codemodel/client.d.ts +17 -31
  24. package/dist/src/codemodel/client.d.ts.map +1 -1
  25. package/dist/src/codemodel/client.js +1 -35
  26. package/dist/src/codemodel/client.js.map +1 -1
  27. package/dist/src/codemodel/method.d.ts +0 -2
  28. package/dist/src/codemodel/method.d.ts.map +1 -1
  29. package/dist/src/codemodel/method.js +0 -1
  30. package/dist/src/codemodel/method.js.map +1 -1
  31. package/dist/src/codemodel/types.d.ts +52 -5
  32. package/dist/src/codemodel/types.d.ts.map +1 -1
  33. package/dist/src/codemodel/types.js +26 -7
  34. package/dist/src/codemodel/types.js.map +1 -1
  35. package/dist/src/emitter.d.ts.map +1 -1
  36. package/dist/src/emitter.js +84 -34
  37. package/dist/src/emitter.js.map +1 -1
  38. package/dist/src/lib.d.ts +37 -4
  39. package/dist/src/lib.d.ts.map +1 -1
  40. package/dist/src/lib.js +27 -2
  41. package/dist/src/lib.js.map +1 -1
  42. package/dist/src/tcgcadapter/adapter.d.ts +58 -10
  43. package/dist/src/tcgcadapter/adapter.d.ts.map +1 -1
  44. package/dist/src/tcgcadapter/adapter.js +390 -176
  45. package/dist/src/tcgcadapter/adapter.js.map +1 -1
  46. package/dist/src/tcgcadapter/helpers.d.ts +8 -0
  47. package/dist/src/tcgcadapter/helpers.d.ts.map +1 -1
  48. package/dist/src/tcgcadapter/helpers.js +13 -0
  49. package/dist/src/tcgcadapter/helpers.js.map +1 -1
  50. package/package.json +22 -24
@@ -1 +1 @@
1
- {"version":3,"file":"clients.d.ts","sourceRoot":"","sources":["../../../src/codegen/clients.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AAGxC,OAAO,KAAK,IAAI,MAAM,uBAAuB,CAAC;AAE9C,yBAAyB;AACzB,MAAM,WAAW,aAAa;IAC5B,iCAAiC;IACjC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAE/B,uCAAuC;IACvC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,aAAa,GAAG,SAAS,CAoPxE"}
1
+ {"version":3,"file":"clients.d.ts","sourceRoot":"","sources":["../../../src/codegen/clients.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AAGxC,OAAO,KAAK,IAAI,MAAM,uBAAuB,CAAC;AAE9C,yBAAyB;AACzB,MAAM,WAAW,aAAa;IAC5B,iCAAiC;IACjC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAE/B,uCAAuC;IACvC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,aAAa,GAAG,SAAS,CAoPxE"}
@@ -4,6 +4,7 @@
4
4
  *--------------------------------------------------------------------------------------------*/
5
5
  import * as codegen from '@azure-tools/codegen';
6
6
  import { values } from '@azure-tools/linq';
7
+ import { CodegenError } from './errors.js';
7
8
  import * as helpers from './helpers.js';
8
9
  import queryString from 'query-string';
9
10
  import { Use } from './use.js';
@@ -112,7 +113,7 @@ export function emitClients(crate) {
112
113
  continue;
113
114
  }
114
115
  if (!client.fields.find((v) => { return v.name === param.name; })) {
115
- throw new Error(`didn't find field in client ${client.name} for param ${param.name}`);
116
+ throw new CodegenError('InternalError', `didn't find field in client ${client.name} for param ${param.name}`);
116
117
  }
117
118
  // by convention, the param field and param name are the
118
119
  // same so we can use shorthand initialization syntax
@@ -124,10 +125,10 @@ export function emitClients(crate) {
124
125
  continue;
125
126
  }
126
127
  if (!client.fields.find((v) => { return v.name === param.name; })) {
127
- throw new Error(`didn't find field in client ${client.name} for param ${param.name}`);
128
+ throw new CodegenError('InternalError', `didn't find field in client ${client.name} for param ${param.name}`);
128
129
  }
129
130
  if (!client.constructable.options.type.fields.find((v) => { return v.name === param.name; })) {
130
- throw new Error(`didn't find field in client options ${client.constructable.options.type.name} for optional param ${param.name}`);
131
+ throw new CodegenError('InternalError', `didn't find field in client options ${client.constructable.options.type.name} for optional param ${param.name}`);
131
132
  }
132
133
  body += `${indent.get()}${param.name}: options.${param.name},\n`;
133
134
  }
@@ -349,11 +350,7 @@ function getConstructorParamsSig(params, options, use) {
349
350
  continue;
350
351
  }
351
352
  use.addForType(param.type);
352
- let ref = '';
353
- if (param.kind === 'clientMethod' && param.ref) {
354
- ref = '&';
355
- }
356
- paramsSig.push(`${param.name}: ${ref}${helpers.getTypeDeclaration(param.type)}`);
353
+ paramsSig.push(`${param.name}: ${helpers.getTypeDeclaration(param.type)}`);
357
354
  }
358
355
  paramsSig.push(`options: ${helpers.getTypeDeclaration(options)}`);
359
356
  return paramsSig.join(', ');
@@ -379,13 +376,14 @@ function getMethodParamsSig(method, use) {
379
376
  }
380
377
  else {
381
378
  for (const param of method.params) {
382
- if (param.type.kind === 'literal') {
379
+ const paramType = helpers.unwrapType(param.type);
380
+ if (paramType.kind === 'literal') {
383
381
  // literal params are embedded directly in the code (e.g. accept header param)
384
382
  continue;
385
383
  }
386
- else if (param.type.kind === 'enumValue') {
384
+ else if (paramType.kind === 'enumValue') {
387
385
  // enum values are treated like literals, we just need to use their type
388
- use.addForType(param.type.type);
386
+ use.addForType(paramType.type);
389
387
  continue;
390
388
  }
391
389
  // don't add client or optional params to the method param sig
@@ -428,7 +426,7 @@ function getAuthPolicy(ctor, use) {
428
426
  */
429
427
  function formatParamTypeName(param) {
430
428
  let format = '';
431
- if (param.ref) {
429
+ if (param.ref === true) {
432
430
  format = '&';
433
431
  }
434
432
  if (param.mut) {
@@ -462,13 +460,13 @@ function getEndpointFieldName(client) {
462
460
  for (const field of client.fields) {
463
461
  if (field.type.kind === 'Url') {
464
462
  if (endpointFieldName) {
465
- throw new Error(`found multiple URL fields in client ${client.name} which is unexpected`);
463
+ throw new CodegenError('InternalError', `found multiple URL fields in client ${client.name} which is unexpected`);
466
464
  }
467
465
  endpointFieldName = field.name;
468
466
  }
469
467
  }
470
468
  if (!endpointFieldName) {
471
- throw new Error(`didn't find URI field for client ${client.name}`);
469
+ throw new CodegenError('InternalError', `didn't find URI field for client ${client.name}`);
472
470
  }
473
471
  return endpointFieldName;
474
472
  }
@@ -533,7 +531,7 @@ function getMethodParamGroup(method) {
533
531
  queryParams.push(param);
534
532
  break;
535
533
  }
536
- if (param.kind === 'query' && param.isApiVersion) {
534
+ if ((param.kind === 'header' || param.kind === 'query') && param.isApiVersion) {
537
535
  apiVersionParam = param;
538
536
  }
539
537
  }
@@ -544,7 +542,7 @@ function getMethodParamGroup(method) {
544
542
  for (const param of method.params) {
545
543
  if (param.kind === 'body') {
546
544
  if (bodyParam) {
547
- throw new Error(`method ${method.name} has multiple body parameters`);
545
+ throw new CodegenError('InternalError', `method ${method.name} has multiple body parameters`);
548
546
  }
549
547
  bodyParam = param;
550
548
  }
@@ -568,13 +566,14 @@ function getMethodParamGroup(method) {
568
566
  * @param indent the indentation helper currently in scope
569
567
  * @param param the parameter to which the contents of setter apply
570
568
  * @param setter the callback that emits the code to read from a param var
569
+ * @param inClosure indicates if the value is being read from within a closure (e.g. pageable methods)
571
570
  * @returns
572
571
  */
573
- function getParamValueHelper(indent, param, setter) {
572
+ function getParamValueHelper(indent, param, inClosure, setter) {
574
573
  if (param.optional) {
575
574
  // optional params are in the unwrapped options local var
576
575
  const op = indent.get() + helpers.buildIfBlock(indent, {
577
- condition: `let Some(${param.name}) = options.${param.name}`,
576
+ condition: `let Some(${param.name}) = ${inClosure ? '&' : ''}options.${param.name}`,
578
577
  body: setter,
579
578
  });
580
579
  return op + '\n';
@@ -596,11 +595,14 @@ function constructUrl(indent, use, method, paramGroups, urlVarName = 'url') {
596
595
  // including them in the call to set_path() causes the chars to be path-escaped.
597
596
  const pathChunks = method.httpPath.split('?');
598
597
  if (pathChunks.length > 2) {
599
- throw new Error('too many HTTP path chunks');
598
+ throw new CodegenError('InternalError', 'too many HTTP path chunks');
600
599
  }
601
600
  /** returns & if the param needs to be borrowed (which is the majority of cases), else the empty string */
602
601
  const borrowOrNot = function (param) {
603
- return param.ref ? '' : '&';
602
+ if (param.type.kind !== 'ref' || param.type.type.kind === 'encodedBytes' || param.type.type.kind === 'slice') {
603
+ return '&';
604
+ }
605
+ return '';
604
606
  };
605
607
  let body = '';
606
608
  // if path is just "/" no need to set it again, we're already there
@@ -649,7 +651,7 @@ function constructUrl(indent, use, method, paramGroups, urlVarName = 'url') {
649
651
  }
650
652
  for (const queryParam of paramGroups.query) {
651
653
  if (queryParam.kind === 'queryCollection' && queryParam.format === 'multi') {
652
- body += getParamValueHelper(indent, queryParam, () => {
654
+ body += getParamValueHelper(indent, queryParam, false, () => {
653
655
  const valueVar = queryParam.name[0];
654
656
  let text = `${indent.get()}for ${valueVar} in ${queryParam.name}.iter() {\n`;
655
657
  text += `${indent.push().get()}${urlVarName}.query_pairs_mut().append_pair("${queryParam.key}", ${valueVar});\n`;
@@ -658,7 +660,7 @@ function constructUrl(indent, use, method, paramGroups, urlVarName = 'url') {
658
660
  });
659
661
  }
660
662
  else {
661
- body += getParamValueHelper(indent, queryParam, () => {
663
+ body += getParamValueHelper(indent, queryParam, false, () => {
662
664
  // for enums we call .as_ref() which elides the need to borrow
663
665
  const borrow = queryParam.type.kind === 'enum' ? '' : borrowOrNot(queryParam);
664
666
  return `${indent.get()}${urlVarName}.query_pairs_mut().append_pair("${queryParam.key}", ${borrow}${getHeaderPathQueryParamValue(use, queryParam, !queryParam.optional)});\n`;
@@ -676,13 +678,24 @@ function constructUrl(indent, use, method, paramGroups, urlVarName = 'url') {
676
678
  * @param use the use statement builder currently in scope
677
679
  * @param method the method for which we're building the body
678
680
  * @param paramGroups the param groups for the provided method
679
- * @param fromSelf applicable for client params. when true, the prefix "self." is included
681
+ * @param inClosure indicates if the request is being constructed within a closure (e.g. pageable methods)
680
682
  * @returns the request construction code
681
683
  */
682
- function constructRequest(indent, use, method, paramGroups, fromSelf = true) {
684
+ function constructRequest(indent, use, method, paramGroups, inClosure) {
685
+ var _a, _b, _c;
683
686
  let body = `${indent.get()}let mut request = Request::new(url, Method::${codegen.capitalize(method.httpMethod)});\n`;
684
687
  for (const headerParam of paramGroups.header) {
685
- body += getParamValueHelper(indent, headerParam, () => {
688
+ if (method.kind === 'pageable' && ((_a = method.strategy) === null || _a === void 0 ? void 0 : _a.kind) === 'continuationToken' && ((_b = method.strategy) === null || _b === void 0 ? void 0 : _b.requestToken.kind) === 'header' && ((_c = method.strategy) === null || _c === void 0 ? void 0 : _c.requestToken) === headerParam) {
689
+ // we have some special handling for the header continuation token.
690
+ // if we have a token value, i.e. from the next page, then use that value.
691
+ // if not, then check if an optional token value was provided.
692
+ body += indent.get() + helpers.buildIfBlock(indent, {
693
+ condition: `let Some(${headerParam.name}) = ${headerParam.name}.or_else(|| options.${headerParam.name}.clone())`,
694
+ body: (indent) => `${indent.get()}request.insert_header("${headerParam.header}", ${headerParam.name});\n`,
695
+ });
696
+ continue;
697
+ }
698
+ body += getParamValueHelper(indent, headerParam, inClosure, () => {
686
699
  if (headerParam.kind === 'headerHashMap') {
687
700
  let setter = `for (k, v) in &${headerParam.name} {\n`;
688
701
  setter += `${indent.push().get()}request.insert_header(format!("${headerParam.header}-{}", k), v);\n`;
@@ -690,14 +703,13 @@ function constructRequest(indent, use, method, paramGroups, fromSelf = true) {
690
703
  return setter;
691
704
  }
692
705
  const borrow = headerParam.location === 'client' && nonCopyableType(headerParam.type) ? '&' : '';
693
- const toOwned = headerParam.ref ? '.to_owned()' : '';
694
- return `${indent.get()}request.insert_header("${headerParam.header.toLowerCase()}", ${borrow}${getHeaderPathQueryParamValue(use, headerParam, fromSelf)}${toOwned});\n`;
706
+ return `${indent.get()}request.insert_header("${headerParam.header.toLowerCase()}", ${borrow}${getHeaderPathQueryParamValue(use, headerParam, !inClosure)});\n`;
695
707
  });
696
708
  }
697
709
  const bodyParam = paramGroups.body;
698
710
  if (bodyParam) {
699
- body += getParamValueHelper(indent, bodyParam, () => {
700
- return `${indent.get()}request.set_body(${bodyParam.name});\n`;
711
+ body += getParamValueHelper(indent, bodyParam, inClosure, () => {
712
+ return `${indent.get()}request.set_body(${bodyParam.name}${inClosure ? '.clone()' : ''});\n`;
701
713
  });
702
714
  }
703
715
  else if (paramGroups.partialBody.length > 0) {
@@ -708,16 +720,13 @@ function constructRequest(indent, use, method, paramGroups, fromSelf = true) {
708
720
  indent.push();
709
721
  for (const partialBodyParam of paramGroups.partialBody) {
710
722
  if (partialBodyParam.type.content.type !== requestContentType.content.type) {
711
- throw new Error(`spread param ${partialBodyParam.name} has conflicting model type ${partialBodyParam.type.content.type.name}, expected model type ${requestContentType.content.type.name}`);
723
+ throw new CodegenError('InternalError', `spread param ${partialBodyParam.name} has conflicting model type ${partialBodyParam.type.content.type.name}, expected model type ${requestContentType.content.type.name}`);
712
724
  }
713
725
  if (partialBodyParam.optional) {
714
726
  body += `${indent.get()}${partialBodyParam.name}: options.${partialBodyParam.name},\n`;
715
727
  continue;
716
728
  }
717
729
  let initializer = partialBodyParam.name;
718
- if (partialBodyParam.ref) {
719
- initializer = `${initializer}.to_owned()`;
720
- }
721
730
  if (requestContentType.content.type.visibility === 'pub') {
722
731
  // spread param maps to a non-internal model, so it must be wrapped in Some()
723
732
  initializer = `Some(${initializer})`;
@@ -761,7 +770,7 @@ function getAsyncMethodBody(indent, use, client, method) {
761
770
  body += `${indent.get()}let ctx = Context::with_context(&options.method_options.context);\n`;
762
771
  body += `${indent.get()}let ${urlVarNeedsMut(paramGroups, method)}url = self.${getEndpointFieldName(client)}.clone();\n`;
763
772
  body += constructUrl(indent, use, method, paramGroups);
764
- body += constructRequest(indent, use, method, paramGroups);
773
+ body += constructRequest(indent, use, method, paramGroups, false);
765
774
  body += `${indent.get()}self.pipeline.send(&ctx, &mut request).await\n`;
766
775
  return body;
767
776
  }
@@ -776,14 +785,10 @@ function getAsyncMethodBody(indent, use, client, method) {
776
785
  */
777
786
  function getPageableMethodBody(indent, use, client, method) {
778
787
  if (!method.strategy) {
779
- throw new Error('paged method with no strategy NYI');
780
- }
781
- else if (method.strategy.kind !== 'nextLink') {
782
- throw new Error('paged methods other than nextLink NYI');
788
+ throw new CodegenError('InternalError', 'paged method with no strategy NYI');
783
789
  }
784
- const nextLinkName = method.strategy.nextLink.name;
785
790
  use.add('azure_core::http', 'Method', 'Pager', 'PagerResult', 'Request', 'Response', 'Url');
786
- use.add('azure_core', 'json', 'Result');
791
+ use.add('azure_core', method.returns.type.type.format, 'Result');
787
792
  use.addForType(method.returns.type.type.type);
788
793
  const paramGroups = getMethodParamGroup(method);
789
794
  const urlVar = 'first_url';
@@ -794,44 +799,108 @@ function getPageableMethodBody(indent, use, client, method) {
794
799
  if (paramGroups.apiVersion) {
795
800
  body += `${indent.get()}let ${paramGroups.apiVersion.name} = ${getHeaderPathQueryParamValue(use, paramGroups.apiVersion, true)}.clone();\n`;
796
801
  }
797
- body += `${indent.get()}Ok(Pager::from_callback(move |${nextLinkName}: Option<Url>| {\n`;
798
- body += `${indent.push().get()}let url = ` + helpers.buildMatch(indent, nextLinkName, [{
799
- pattern: `Some(${nextLinkName})`,
800
- body: (indent) => {
801
- if (paramGroups.apiVersion) {
802
- const apiVersionKey = `"${paramGroups.apiVersion.key}"`;
803
- // there are no APIs to set/update an existing query parameter.
804
- // so, we filter the existing query params to remove the api-version
805
- // query param. we then add back the filtered set and then add the
806
- // api-version as specified on the client.
807
- let setApiVerBody = `${indent.get()}let qp = ${nextLinkName}.query_pairs().filter(|(name, _)| name.ne(${apiVersionKey}));\n`;
808
- setApiVerBody += `${indent.get()}let mut ${nextLinkName} = ${nextLinkName}.clone();\n`;
809
- setApiVerBody += `${indent.get()}${nextLinkName}.query_pairs_mut().clear().extend_pairs(qp).append_pair(${apiVersionKey}, &${paramGroups.apiVersion.name});\n`;
810
- setApiVerBody += `${indent.get()}${nextLinkName}\n`;
811
- return setApiVerBody;
812
- }
813
- return `${indent.get()} ${nextLinkName}\n`;
802
+ switch (method.strategy.kind) {
803
+ case 'continuationToken': {
804
+ const reqTokenParam = method.strategy.requestToken.name;
805
+ body += `${indent.get()}Ok(Pager::from_callback(move |${reqTokenParam}: Option<String>| {\n`;
806
+ body += `${indent.push().get()}let ${method.strategy.requestToken.kind === 'query' ? 'mut ' : ''}url = first_url.clone();\n`;
807
+ if (method.strategy.requestToken.kind === 'query') {
808
+ // if the url already contains the token query param,
809
+ // e.g. we started on some page, then we need to remove
810
+ // it before appending the token for the next page.
811
+ const reqTokenValue = method.strategy.requestToken.key;
812
+ body += `${indent.get()}${helpers.buildIfBlock(indent, {
813
+ condition: `let Some(${reqTokenParam}) = ${reqTokenParam}`,
814
+ body: (indent) => {
815
+ let body = indent.get() + helpers.buildIfBlock(indent, {
816
+ condition: `url.query_pairs().any(|(name, _)| name.eq("${reqTokenValue}"))`,
817
+ body: (indent) => {
818
+ let body = `${indent.get()}let mut new_url = url.clone();\n`;
819
+ body += `${indent.get()}new_url.query_pairs_mut().clear().extend_pairs(url.query_pairs().filter(|(name, _)| name.ne("${reqTokenValue}")));\n`;
820
+ body += `${indent.get()}url = new_url;\n`;
821
+ return body;
822
+ },
823
+ });
824
+ body += `${indent.get()}url.query_pairs_mut().append_pair("${reqTokenValue}", &${reqTokenParam});\n`;
825
+ return body;
826
+ }
827
+ })}`;
814
828
  }
815
- }, {
816
- pattern: 'None',
817
- body: (indent) => `${indent.get()}${urlVar}.clone()\n`
818
- }]);
819
- body += ';\n';
829
+ break;
830
+ }
831
+ case 'nextLink': {
832
+ const nextLinkName = method.strategy.nextLink.name;
833
+ body += `${indent.get()}Ok(Pager::from_callback(move |${nextLinkName}: Option<Url>| {\n`;
834
+ body += `${indent.push().get()}let url = ` + helpers.buildMatch(indent, nextLinkName, [{
835
+ pattern: `Some(${nextLinkName})`,
836
+ body: (indent) => {
837
+ if (paramGroups.apiVersion && paramGroups.apiVersion.kind === 'query') {
838
+ const apiVersionKey = `"${paramGroups.apiVersion.key}"`;
839
+ // there are no APIs to set/update an existing query parameter.
840
+ // so, we filter the existing query params to remove the api-version
841
+ // query param. we then add back the filtered set and then add the
842
+ // api-version as specified on the client.
843
+ let setApiVerBody = `${indent.get()}let qp = ${nextLinkName}.query_pairs().filter(|(name, _)| name.ne(${apiVersionKey}));\n`;
844
+ setApiVerBody += `${indent.get()}let mut ${nextLinkName} = ${nextLinkName}.clone();\n`;
845
+ setApiVerBody += `${indent.get()}${nextLinkName}.query_pairs_mut().clear().extend_pairs(qp).append_pair(${apiVersionKey}, &${paramGroups.apiVersion.name});\n`;
846
+ setApiVerBody += `${indent.get()}${nextLinkName}\n`;
847
+ return setApiVerBody;
848
+ }
849
+ return `${indent.get()} ${nextLinkName}\n`;
850
+ }
851
+ }, {
852
+ pattern: 'None',
853
+ body: (indent) => `${indent.get()}${urlVar}.clone()\n`
854
+ }]);
855
+ body += ';\n';
856
+ break;
857
+ }
858
+ }
820
859
  // here we want the T in Pager<T>
821
860
  const returnType = helpers.getTypeDeclaration(method.returns.type.type.type);
822
- body += constructRequest(indent, use, method, paramGroups, false);
861
+ body += constructRequest(indent, use, method, paramGroups, true);
823
862
  body += `${indent.get()}let ctx = options.method_options.context.clone();\n`;
824
863
  body += `${indent.get()}let pipeline = pipeline.clone();\n`;
825
864
  body += `${indent.get()}async move {\n`;
826
865
  body += `${indent.push().get()}let rsp: Response<${returnType}> = pipeline.send(&ctx, &mut request).await?;\n`;
827
- body += `${indent.get()}let (status, headers, body) = rsp.deconstruct();\n`;
828
- body += `${indent.get()}let bytes = body.collect().await?;\n`;
829
- body += `${indent.get()}let res: ${returnType} = json::from_json(bytes.clone())?;\n`;
830
- body += `${indent.get()}let rsp = Response::from_bytes(status, headers, bytes);\n`;
831
- body += `${indent.get()}Ok(${helpers.buildMatch(indent, `res.${nextLinkName}`, [{
832
- pattern: `Some(${nextLinkName})`,
866
+ // check if we need to extract the next link field from the response model
867
+ if (method.strategy.kind === 'nextLink' || method.strategy.responseToken.kind === 'modelField') {
868
+ body += `${indent.get()}let (status, headers, body) = rsp.deconstruct();\n`;
869
+ body += `${indent.get()}let bytes = body.collect().await?;\n`;
870
+ const deserialize = method.returns.type.type.format === 'json' ? 'json::from_json' : 'xml::read_xml';
871
+ body += `${indent.get()}let res: ${returnType} = ${deserialize}(&bytes)?;\n`;
872
+ body += `${indent.get()}let rsp = Response::from_bytes(status, headers, bytes);\n`;
873
+ }
874
+ let matchCondition;
875
+ let nextPageValue;
876
+ let continuation;
877
+ switch (method.strategy.kind) {
878
+ case 'continuationToken':
879
+ nextPageValue = method.strategy.responseToken.name;
880
+ continuation = nextPageValue;
881
+ switch (method.strategy.responseToken.kind) {
882
+ case 'modelField':
883
+ matchCondition = `res.${nextPageValue}`;
884
+ break;
885
+ case 'responseHeaderScalar':
886
+ if (!method.responseHeaders) {
887
+ throw new CodegenError('InternalError', `missing response headers trait for method ${method.name}`);
888
+ }
889
+ use.addForType(method.responseHeaders);
890
+ matchCondition = `rsp.${method.strategy.responseToken.name}()?`;
891
+ break;
892
+ }
893
+ break;
894
+ case 'nextLink':
895
+ nextPageValue = method.strategy.nextLink.name;
896
+ matchCondition = `res.${nextPageValue}`;
897
+ continuation = `${nextPageValue}.parse()?`;
898
+ break;
899
+ }
900
+ body += `${indent.get()}Ok(${helpers.buildMatch(indent, matchCondition, [{
901
+ pattern: `Some(${nextPageValue})`,
833
902
  returns: 'PagerResult::Continue',
834
- body: (indent) => `${indent.get()}response: rsp,\n${indent.get()}continuation: ${nextLinkName}.parse()?,\n`
903
+ body: (indent) => `${indent.get()}response: rsp,\n${indent.get()}continuation: ${continuation},\n`
835
904
  }, {
836
905
  pattern: 'None',
837
906
  returns: 'PagerResult::Complete',
@@ -862,7 +931,7 @@ function getClientEndpointParamValue(param) {
862
931
  case 'scalar':
863
932
  return `&${paramName}.to_string()`;
864
933
  default:
865
- throw new Error(`unhandled ${param.kind} param type kind ${param.type.kind}`);
934
+ throw new CodegenError('InternalError', `unhandled ${param.kind} param type kind ${param.type.kind}`);
866
935
  }
867
936
  }
868
937
  /**
@@ -913,51 +982,52 @@ function getHeaderPathQueryParamValue(use, param, fromSelf) {
913
982
  return `${param}.unix_timestamp().to_string()`;
914
983
  }
915
984
  };
985
+ const paramType = helpers.unwrapType(param.type);
916
986
  if (param.kind === 'headerCollection' || param.kind === 'queryCollection') {
917
987
  if (param.format === 'multi') {
918
- throw new Error('multi should have been handled outside getHeaderPathQueryParamValue');
988
+ throw new CodegenError('InternalError', 'multi should have been handled outside getHeaderPathQueryParamValue');
919
989
  }
920
- else if (param.type.type.kind === 'String') {
990
+ else if (paramType.kind === 'String' || paramType.kind === 'str') {
921
991
  return `${paramName}.join("${getCollectionDelimiter(param.format)}")`;
922
992
  }
923
993
  // convert the items to strings
924
994
  let strConv;
925
- switch (param.type.type.kind) {
995
+ switch (paramType.kind) {
926
996
  case 'encodedBytes':
927
- strConv = encodeBytes(param.type.type);
997
+ strConv = encodeBytes(paramType);
928
998
  break;
929
999
  case 'offsetDateTime':
930
- strConv = `|i| ${encodeDateTime(param.type.type, 'i')}`;
1000
+ strConv = `|i| ${encodeDateTime(paramType, 'i')}`;
931
1001
  break;
932
1002
  default:
933
1003
  strConv = '|i| i.to_string()';
934
1004
  }
935
1005
  return `${param.name}.iter().map(${strConv}).collect::<Vec<String>>().join("${getCollectionDelimiter(param.format)}")`;
936
1006
  }
937
- switch (param.type.kind) {
1007
+ switch (paramType.kind) {
938
1008
  case 'String':
939
1009
  case 'str':
940
1010
  return paramName;
1011
+ case 'decimal':
1012
+ return `${param.name}.to_string()`;
941
1013
  case 'encodedBytes':
942
- return encodeBytes(param.type, paramName);
1014
+ return encodeBytes(paramType, paramName);
943
1015
  case 'enum':
944
1016
  case 'scalar':
945
- if (param.type.kind === 'enum' && param.kind === 'query') {
1017
+ if (paramType.kind === 'enum' && param.kind === 'query') {
946
1018
  // append_pair wants a reference to the string
947
1019
  // TODO: https://github.com/Azure/typespec-rust/issues/25
948
1020
  return `${paramName}.as_ref()`;
949
1021
  }
950
1022
  return `${paramName}.to_string()`;
951
1023
  case 'enumValue':
952
- return `${param.type.type.name}::${param.type.name}.to_string()`;
953
- case 'implTrait':
954
- return `${paramName}.into()`;
1024
+ return `${paramType.type.name}::${paramType.name}.to_string()`;
955
1025
  case 'literal':
956
- return `"${param.type.value}"`;
1026
+ return `"${paramType.value}"`;
957
1027
  case 'offsetDateTime':
958
- return encodeDateTime(param.type, param.name);
1028
+ return encodeDateTime(paramType, param.name);
959
1029
  default:
960
- throw new Error(`unhandled ${param.kind} param type kind ${param.type.kind}`);
1030
+ throw new CodegenError('InternalError', `unhandled ${param.kind} param type kind ${paramType.kind}`);
961
1031
  }
962
1032
  }
963
1033
  /**