private adaptResponseEnvelope()

in packages/typespec-go/src/tcgcadapter/clients.ts [580:692]


  private adaptResponseEnvelope(sdkMethod: tcgc.SdkServiceMethod<tcgc.SdkHttpOperation>, method: go.Method): go.ResponseEnvelope {
    // TODO: add Envelope suffix if name collides with existing type
    let prefix = method.client.name;
    if (this.opts['single-client']) {
      prefix = '';
    }
    let respEnvName = `${prefix}${method.name}Response`;
    if (sdkMethod.access === 'internal') {
      respEnvName = uncapitalize(respEnvName);
    }
    const respEnv = new go.ResponseEnvelope(respEnvName, {summary: createResponseEnvelopeDescription(respEnvName, this.getMethodNameForDocComment(method))}, method);
    this.ta.codeModel.responseEnvelopes.push(respEnv);

    // add any headers
    const addedHeaders = new Set<string>();
    for (const httpResp of sdkMethod.operation.responses) {
      for (const httpHeader of httpResp.headers) {
        if (addedHeaders.has(httpHeader.serializedName)) {
          continue;
        } else if (go.isLROMethod(method) && httpHeader.serializedName.match(/Azure-AsyncOperation|Location|Operation-Location|Retry-After/i)) {
          // we omit the LRO polling headers as they aren't useful on the response envelope
          continue;
        }

        // TODO: x-ms-header-collection-prefix
        const headerResp = new go.HeaderResponse(ensureNameCase(httpHeader.serializedName), this.adaptHeaderType(httpHeader.type, false), httpHeader.serializedName, isTypePassedByValue(httpHeader.type));
        headerResp.docs.summary = httpHeader.summary;
        headerResp.docs.description = httpHeader.doc;
        respEnv.headers.push(headerResp);
        addedHeaders.add(httpHeader.serializedName);
      }
    }

    let sdkResponseType = sdkMethod.response.type;

    // since HEAD requests don't return a type, we must check this before checking sdkResponseType
    if (method.httpMethod === 'head' && this.opts['head-as-boolean'] === true) {
      respEnv.result = new go.HeadAsBooleanResult('Success');
      respEnv.result.docs.summary = 'Success indicates if the operation succeeded or failed.';
    }

    if (!sdkResponseType) {
      // method doesn't return a type, so we're done
      return respEnv;
    }

    // for paged methods, tcgc models the method response type as an Array<T>.
    // however, we want the synthesized paged response envelope as that's what Go returns.
    if (sdkMethod.kind === 'paging') {
      // grab the paged response envelope type from the first response
      sdkResponseType = values(sdkMethod.operation.responses).first()!.type!;
    }

    // we have a response type, determine the content type
    let contentType: go.BodyFormat = 'binary';
    if (sdkMethod.kind === 'lro') {
      // we can't grovel through the operation responses for LROs as some of them
      // return only headers, thus have no content type. while it's highly likely
      // to only ever be JSON, this will be broken for LROs that return text/plain
      // or a binary response. the former seems unlikely, the latter though...??
      // TODO: https://github.com/Azure/typespec-azure/issues/535
      contentType = 'JSON';
    } else {
      let foundResp = false;
      for (const httpResp of sdkMethod.operation.responses) {
        if (!httpResp.type || !httpResp.defaultContentType || httpResp.type.kind !== sdkResponseType.kind) {
          continue;
        }
        contentType = this.adaptContentType(httpResp.defaultContentType);
        foundResp = true;
        break;
      }
      if (!foundResp) {
        throw new AdapterError('InternalError', `didn't find HTTP response for kind ${sdkResponseType.kind} in method ${method.name}`, sdkResponseType.__raw?.node ?? NoTarget);
      }
    }

    if (contentType === 'binary') {
      respEnv.result = new go.BinaryResult('Body', 'binary');
      respEnv.result.docs.summary = 'Body contains the streaming response.';
      return respEnv;
    } else if (sdkResponseType.kind === 'model') {
      let modelType: go.ModelType | undefined;
      const modelName = ensureNameCase(sdkResponseType.name).toUpperCase();
      for (const model of this.ta.codeModel.models) {
        if (model.name.toUpperCase() === modelName) {
          modelType = model;
          break;
        }
      }
      if (!modelType) {
        throw new AdapterError('InternalError', `didn't find model type name ${sdkResponseType.name} for response envelope ${respEnv.name}`, sdkResponseType.__raw?.node ?? NoTarget);
      }
      if (go.isPolymorphicType(modelType)) {
        respEnv.result = new go.PolymorphicResult(modelType.interface);
      } else {
        if (contentType !== 'JSON' && contentType !== 'XML') {
          throw new AdapterError('InternalError', `unexpected content type ${contentType} for model ${modelType.name}`, NoTarget);
        }
        respEnv.result = new go.ModelResult(modelType, contentType);
      }
      respEnv.result.docs.summary = sdkResponseType.summary;
      respEnv.result.docs.description = sdkResponseType.doc;
    } else {
      const resultType = this.ta.getPossibleType(sdkResponseType, false, false);
      if (go.isInterfaceType(resultType) || go.isLiteralValue(resultType) || go.isModelType(resultType) || go.isPolymorphicType(resultType) || go.isQualifiedType(resultType)) {
        throw new AdapterError('InternalError', `invalid monomorphic result type ${go.getTypeDeclaration(resultType)}`, sdkResponseType.__raw?.node ?? NoTarget);
      }
      respEnv.result = new go.MonomorphicResult(this.recursiveTypeName(sdkResponseType, false), contentType, resultType, isTypePassedByValue(sdkResponseType));
    }

    return respEnv;
  }