import { CodeModel , Operation , Parameter , StringSchema , Protocol , ParameterLocation , ImplementationLocation } from "@autorest/codemodel" ; import { cloneOperation } from "../utils/cloneOperation" ; import { extractPaginationDetails } from "../utils/extractPaginationDetails" ; import { getLanguageMetadata } from "../utils/languageHelpers" ; import { cloneDeep } from "lodash" ; param codeModel export function normalizeModelWithExtensions ( codeModel ) { normalizeObjectPropertySerializedNames ( codeModel ) ; addPageableMethods ( codeModel ) ; normalizeMultipleContentTypes ( codeModel ) ; } param codeModel function normalizeObjectPropertySerializedNames ( codeModel ) { const schemas = codeModel . schemas ; const objectSchemas = schemas . objects ?? [ ] ; for ( const objectSchema of objectSchemas ) { for ( const property of objectSchema . properties ?? [ ] ) { if ( property . serializedName ) { property . serializedName = property . serializedName . replace ( "." , "\\." ) ; } } } } param codeModel function normalizeMultipleContentTypes ( codeModel ) { const operationGroups = codeModel . operationGroups ; for ( const operationGroup of operationGroups ) { const operations = operationGroup . operations . slice ( ) ; for ( const operation of operations ) { const requests = operation . requests ; if ( ! requests || ( requests && requests . length > 1 ) ) { continue ; } for ( const request of requests ) { const parameters = request . parameters ; if ( ! parameters ) { continue ; } for ( const parameter of parameters ) { const parameterMetadata = getLanguageMetadata ( parameter . language ) ; if ( parameterMetadata . name . toLowerCase ( ) === "contenttype" ) { parameter . required = false ; } } } } } } param codeModel function addPageableMethods ( codeModel ) { const operationGroups = codeModel . operationGroups ; for ( const operationGroup of operationGroups ) { const operationGroupMetadata = getLanguageMetadata ( operationGroup . language ) ; const operations = operationGroup . operations . slice ( ) ; for ( const operation of operations ) { const paginationDetails = extractPaginationDetails ( operation ) ; const operationMetadata = getLanguageMetadata ( operation . language ) ; const operationName = operationMetadata . name ; const operationDescription = operationMetadata . description ; if ( ! paginationDetails || ! paginationDetails . nextLinkName ) { continue ; } const nextLinkOperationName = paginationDetails . nextLinkOperationName ; if ( ! nextLinkOperationName ) { throw new Error ( `Unable to determine the x-ms-pageable operationName for "${ operationName }".` ) ; } let nextLinkMethod = findOperation ( codeModel , paginationDetails . group ?? operationGroupMetadata . name , nextLinkOperationName ) ; if ( nextLinkMethod ) { const nextMetadata = getLanguageMetadata ( nextLinkMethod . language ) ; nextMetadata . paging = { ... nextMetadata . paging , isNextLinkMethod : true } ; operationMetadata . paging = { ... operationMetadata . paging , nextLinkOperation : nextLinkMethod , isNextLinkMethod : false } ; continue ; } nextLinkMethod = cloneOperation ( operation , nextLinkOperationName , operationDescription ) ; const nextLinkMethodMetadata = getLanguageMetadata ( nextLinkMethod . language ) ; nextLinkMethodMetadata . paging = { ... nextLinkMethodMetadata . paging , isNextLinkMethod : true } ; operationMetadata . paging = { ... operationMetadata . paging , nextLinkOperation : nextLinkMethod , isNextLinkMethod : false } ; const nextLinkRequestProtocol = nextLinkMethod . requests ?. [ 0 ] . protocol . http ?? new Protocol ( ) ; nextLinkRequestProtocol . path = "{nextLink}" ; nextLinkRequestProtocol . method = "GET" ; let isLro = false ; if ( nextLinkMethod . extensions && "x-ms-long-running-operation" in nextLinkMethod . extensions ) { delete nextLinkMethod . extensions [ "x-ms-long-running-operation" ] ; isLro = true ; } inject200Response ( nextLinkMethod , isLro ) ; const httpProtocol = new Protocol ( ) ; httpProtocol . in = ParameterLocation . Path ; const nextLinkParameter = new Parameter ( "nextLink" , `The nextLink from the previous successful call to the ${ operationName } method.` , new StringSchema ( "string" , "" ) , { required : true , language : { default : { serializedName : "nextLink" } } , extensions : { "x-ms-skip-url-encoding" : true } , protocol : { http : httpProtocol } , implementation : ImplementationLocation . Method } ) ; for ( const request of nextLinkMethod . requests ?? [ ] ) { const parameters = request . parameters ?? [ ] ; parameters . push ( nextLinkParameter ) ; request . parameters = parameters ; } operationGroup . addOperation ( nextLinkMethod ) ; } } } param nextLinkMethod param isLro function inject200Response ( nextLinkMethod , isLro ) { if ( ! isLro ) { return ; } if ( nextLinkMethod . responses && ! nextLinkMethod . responses . find ( r => { return ! ! r . protocol . http ?. statusCodes . includes ( "200" ) ; } ) ) { const successResponse = nextLinkMethod . responses . find ( r => { const statusCodes = r . protocol . http ?. statusCodes || [ ] ; return statusCodes . find ( s => { const status = Number . parseInt ( s ) ; return status >= 200 && status < 300 ; } ) ; } ) ; if ( ! successResponse ) { throw new Error ( "Expected nextLink of Lro operation to have a success response defined" ) ; } const success200 = cloneDeep ( successResponse ) ; success200 . protocol . http ! . statusCodes = [ "200" ] ; nextLinkMethod . responses = [ ... nextLinkMethod . responses , success200 ] ; } } function findOperation ( codeModel , operationGroupName , operationName ) { const operationGroup = codeModel . operationGroups . find ( og => getLanguageMetadata ( og . language ) . name === operationGroupName ) ; return ( operationGroup ?. operations || [ ] ) . find ( operation => { const languageMetadata = getLanguageMetadata ( operation . language ) ; return languageMetadata . name === operationName ; } ) ; }