import { ParameterDetails } from "../../models/parameterDetails" ; import { OperationDetails , OperationRequestDetails } from "../../models/operationDetails" ; import { ImplementationLocation , SchemaType , ParameterLocation , Parameter } from "@autorest/codemodel" ; import { wrapString , IndentationType } from "./stringUtils" ; import { ClassDeclaration , InterfaceDeclaration } from "ts-morph" ; import { ParameterWithDescription } from "./docsUtils" ; import { NameType , normalizeName , normalizeTypeName } from "../../utils/nameUtils" ; import { getParameterDescription } from "../../utils/getParameterDescription" ; import { getLanguageMetadata } from "../../utils/languageHelpers" ; import { getAutorestOptions } from "../../autorestSession" ; interface ParameterFilterOptions { includeOptional ? : boolean ; includeClientParams ? : boolean ; includeUriParameters ? : boolean ; includeGlobalParameters ? : boolean ; includeConstantParameters ? : boolean ; includeGroupedParameters ? : boolean ; includeContentType ? : boolean ; } param parameters param operation param param2 export function filterOperationParameters ( parameters , operation , { includeOptional , includeClientParams , includeGlobalParameters , includeConstantParameters , includeGroupedParameters , includeContentType } = { } ) { const isContentType = ( param ) => param . name === "contentType" && param . location === ParameterLocation . Header ; const optionalFilter = ( param ) => ! ! ( includeOptional || param . required ) ; const constantFilter = ( param ) => ( includeContentType && isContentType ( param ) ) || ! ! ( includeConstantParameters || param . schemaType !== SchemaType . Constant ) ; const clientParamFilter = ( param ) => ! ! ( includeClientParams || param . implementationLocation !== ImplementationLocation . Client ) ; const globalFilter = ( param ) => ! ! ( includeGlobalParameters || ! param . isGlobal ) ; const isInOperation = ( param ) => ! ! ( param . operationsIn && param . operationsIn [ operation . fullName ] ) ; const groupedFilter = ( param ) => ! ! ( includeGroupedParameters || ! param . parameter . groupedBy ) ; return parameters . filter ( param => groupedFilter ( param ) && globalFilter ( param ) && isInOperation ( param ) && optionalFilter ( param ) && constantFilter ( param ) && clientParamFilter ( param ) ) ; } export function formatJsDocParam ( parameters ) { return parameters . map ( p => wrapString ( `@param ${ p . name } ${ p . description }` , { indentationType : IndentationType . JSDocParam , paramNameLength : p . name ?. length } ) ) ; } /**
 * Gets a list of parameter declarations for each overload the operation supports,
 * and the list of parameter declarations for the base operation.
 */ export function getOperationParameterSignatures ( operation , parameters , importedModels , operationGroupClass ) { const operationParameters = filterOperationParameters ( parameters , operation , { includeContentType : true } ) . filter ( p => ! p . isFlattened ) ; const operationRequests = operation . requests ; const overloadParameterDeclarations = [ ] ; const hasMultipleOverloads = operationRequests . length > 1 ; for ( const request of operationRequests ) { const requestMediaType = request . mediaType ; const requestParameters = operationParameters . filter ( ( { targetMediaType } ) => ! targetMediaType || requestMediaType === targetMediaType ) ; const parameterDeclarations = requestParameters . reduce < ParameterWithDescription [ ] > ( ( acc , param ) => { const { usedModels } = param . typeDetails ; let type = normalizeTypeName ( param . typeDetails ) ; if ( param . typeDetails . isConstant && param . typeDetails . typeName === "string" && param . typeDetails . defaultValue ) { type = `"${ param . typeDetails . defaultValue }"` ; } const uniqueTypeName = operationGroupClass . getName ( ) === type ? `${ type }Model` : type ; const typeName = param . nullable ? uniqueTypeName + " | null" : uniqueTypeName ; if ( usedModels . length ) { usedModels . forEach ( model => importedModels . add ( model ) ) ; } const newParameter = { name : param . name , description : getParameterDescription ( param , operation . fullName ) , type : typeName , hasQuestionToken : ! param . required , isContentType : Boolean ( param . serializedName === "Content-Type" && param . location === "header" ) } ; const newParameterPosition = param . required ? findLastRequiredParamIndex ( acc ) + 1 : acc . length ; acc . splice ( newParameterPosition , 0 , newParameter ) ; return acc ; } , [ ] ) ; trackParameterGroups ( operation , parameters , importedModels , parameterDeclarations ) ; const orderedParameterDeclarations = sortOperationParameters ( operation , request , parameterDeclarations ) ; const optionalParameter = getOptionsParameter ( operation , parameters , importedModels , { mediaType : hasMultipleOverloads ? requestMediaType : undefined } ) ; orderedParameterDeclarations . push ( optionalParameter ) ; overloadParameterDeclarations . push ( orderedParameterDeclarations ) ; } const baseMethodParameters = getBaseMethodParameterDeclarations ( overloadParameterDeclarations ) ; return { overloadParameterDeclarations , baseMethodParameters } ; } function findLastRequiredParamIndex ( params ) { for ( let i = params . length ; i -- ; ) { if ( ! params [ i ] . hasQuestionToken ) { return i ; } } return - 1 ; } function trackParameterGroups ( operation , parameters , importedModels , parameterDeclarations ) { const groupedParameters = getGroupedParameters ( operation , parameters , importedModels ) . filter ( gp => ! gp . hasQuestionToken ) ; const lastRequiredIndex = findLastRequiredParamIndex ( parameterDeclarations ) + 1 ; if ( groupedParameters . length ) { parameterDeclarations . splice ( lastRequiredIndex , 0 , ... groupedParameters ) ; } } /**
 * This function gets the parameter groups specified in the swagger
 * by the parameter grouping extension x-ms-parameter-grouping
 */ function getGroupedParameters ( operation , parameters , importedModels ) { const parameterGroups = [ ] ; filterOperationParameters ( parameters , operation , { includeGroupedParameters : true } ) . filter ( ( { parameter } ) => parameter . groupedBy ) . forEach ( ( { parameter : { groupedBy } } ) => { if ( ! groupedBy || ! groupedBy . required ) { return ; } const groupNAme = getLanguageMetadata ( groupedBy . language ) . name ; if ( parameterGroups . some ( p => getLanguageMetadata ( p . language ) . name === groupNAme ) ) { return ; } parameterGroups . push ( groupedBy ) ; } ) ; return parameterGroups . filter ( ( { required } ) => required ) . map ( ( { language } ) => { const { name , description } = getLanguageMetadata ( language ) ; const type = normalizeName ( name , NameType . Interface ) ; importedModels . add ( type ) ; return { name , type , description } ; } ) ; } param operation param request param parameterDeclarations function sortOperationParameters ( operation , request , parameterDeclarations ) { const expectedParameterOrdering = [ ... operation . parameters , ... ( request . parameters ?? [ ] ) ] . filter ( param => param . implementation === ImplementationLocation . Method ) . map ( param => getLanguageMetadata ( param . language ) . name ) ; const orderedParameterDeclarations = [ ] ; for ( const parameterName of expectedParameterOrdering ) { const index = parameterDeclarations . findIndex ( p => p . name === parameterName ) ; if ( index === - 1 ) { continue ; } orderedParameterDeclarations . push ( ... parameterDeclarations . splice ( index , 1 ) ) ; } orderedParameterDeclarations . push ( ... parameterDeclarations ) ; return orderedParameterDeclarations ; } /**
 * This function takes care of Typescript generator specific Optional parameters grouping.
 *
 * In the Typescript generator we always group optional parameters to provide a simpler interface.
 * This function is responsible for the default optional parameter grouping, which groups into an
 * options bag any optional parameter, including optional grouped parameters.
 */ function getOptionsParameter ( operation , parameters , importedModels , { isOptional = true , mediaType } = { } ) { const { useCoreV2 } = getAutorestOptions ( ) ; let type = ! useCoreV2 ? "coreHttp.OperationOptions" : "coreClient.OperationOptions" ; const operationParameters = filterOperationParameters ( parameters , operation , { includeOptional : true , includeGroupedParameters : true } ) ; const mediaPrefix = mediaType ? `$${ mediaType }` : "" ; type = `${ operation . typeDetails . typeName }${ mediaPrefix }OptionalParams` ; importedModels . add ( type ) ; return { name : "options" , type , hasQuestionToken : isOptional , description : "The options parameters." } ; } param overloadParameterDeclarations function getBaseMethodParameterDeclarations ( overloadParameterDeclarations ) { if ( ! overloadParameterDeclarations . length ) { return [ ] ; } if ( overloadParameterDeclarations . length === 1 ) { return [ ... overloadParameterDeclarations [ 0 ] ] ; } const baseMethodArg = { name : "args" , isRestParameter : true , description : "Includes all the parameters for this operation." , type : overloadParameterDeclarations . map ( overloadParams => { return `[ ${ overloadParams . map ( p => ( p . hasQuestionToken ? `${ p . type }?` : p . type ) ) . join ( ", " ) } ]` ; } ) . join ( " | " ) } ; return [ baseMethodArg ] ; }