Private/Document/ConvertFrom-OpenApiSwagger2Operation.ps1
|
function ConvertFrom-OpenApiSwagger2Operation { <# .SYNOPSIS Converts a Swagger 2.0 operation (with its path-level parameters) to an OpenAPI 3 operation. .DESCRIPTION - '#/parameters/...' and '#/responses/...' refs are inlined (unresolvable ones are left for the normaliser to report). - Path-level parameters are merged in; operation-level ones win on (name, in). - The body parameter becomes requestBody with one media type per consumes type. - formData parameters become a requestBody object schema (properties + required) with multipart/form-data when any parameter is a file (or consumes lists only multipart/form-data), otherwise application/x-www-form-urlencoded. - consumes/produces default to the document's, then to application/json. - x- extensions are kept. #> [CmdletBinding()] [OutputType([System.Collections.Specialized.OrderedDictionary])] param( [Parameter(Mandatory)] [System.Collections.IDictionary]$Root, [Parameter(Mandatory)] [System.Collections.IDictionary]$Operation, [AllowNull()] [object]$PathParameters, [AllowEmptyCollection()] [string[]]$Consumes = @(), [AllowEmptyCollection()] [string[]]$Produces = @() ) $result = [System.Collections.Specialized.OrderedDictionary]::new([System.StringComparer]::Ordinal) foreach ($key in @($Operation.Keys)) { if ($key -cin @('tags', 'summary', 'description', 'externalDocs', 'operationId', 'deprecated', 'security') -or $key.StartsWith('x-')) { $result[$key] = $Operation[$key] } } if ($Operation.Contains('consumes')) { $Consumes = @($Operation['consumes'] | Where-Object { $null -ne $_ } | ForEach-Object { [string]$_ }) } if ($Consumes.Count -eq 0) { $Consumes = @('application/json') } if ($Operation.Contains('produces')) { $Produces = @($Operation['produces'] | Where-Object { $null -ne $_ } | ForEach-Object { [string]$_ }) } if ($Produces.Count -eq 0) { $Produces = @('application/json') } # Merge path-level and operation-level parameters, resolving '#/parameters/...' refs $merged = [System.Collections.Specialized.OrderedDictionary]::new([System.StringComparer]::Ordinal) foreach ($source in @($PathParameters, $Operation['parameters'])) { if ($source -isnot [System.Collections.IList]) { continue } foreach ($raw in $source) { $parameter = $raw if ($parameter -is [System.Collections.IDictionary] -and $parameter.Contains('$ref')) { $target = Resolve-OpenApiPointer -Root $Root -Reference ([string]$parameter['$ref']) if ($target.Found -and $target.Value -is [System.Collections.IDictionary]) { $parameter = $target.Value } } if ($parameter -isnot [System.Collections.IDictionary]) { continue } if ($parameter.Contains('$ref')) { $key = 'ref|' + [string]$parameter['$ref'] } else { $key = '{0}|{1}' -f $parameter['in'], $parameter['name'] } $merged[$key] = $parameter } } $parameters = [System.Collections.Generic.List[object]]::new() $body = $null $formData = [System.Collections.Generic.List[object]]::new() foreach ($parameter in $merged.Values) { if ($parameter.Contains('$ref')) { $parameters.Add($parameter) continue } switch ([string]$parameter['in']) { 'body' { $body = $parameter } 'formData' { $formData.Add($parameter) } default { $parameters.Add((ConvertFrom-OpenApiSwagger2Parameter -Node $parameter)) } } } if ($parameters.Count -gt 0) { $result['parameters'] = $parameters.ToArray() } if ($null -ne $body) { $requestBody = [System.Collections.Specialized.OrderedDictionary]::new([System.StringComparer]::Ordinal) if ($body.Contains('description')) { $requestBody['description'] = $body['description'] } $requestBody['required'] = $body['required'] -eq $true $content = [System.Collections.Specialized.OrderedDictionary]::new([System.StringComparer]::Ordinal) foreach ($contentType in $Consumes) { $media = [System.Collections.Specialized.OrderedDictionary]::new([System.StringComparer]::Ordinal) $media['schema'] = $body['schema'] $content[$contentType] = $media } $requestBody['content'] = $content foreach ($key in @($body.Keys)) { if ($key.StartsWith('x-')) { $requestBody[$key] = $body[$key] } } $result['requestBody'] = $requestBody } elseif ($formData.Count -gt 0) { $hasFile = @($formData | Where-Object { [string]$_['type'] -ceq 'file' }).Count -gt 0 $multipartOnly = ($Consumes -contains 'multipart/form-data') -and -not ($Consumes -contains 'application/x-www-form-urlencoded') $contentType = 'application/x-www-form-urlencoded' if ($hasFile -or $multipartOnly) { $contentType = 'multipart/form-data' } $properties = [System.Collections.Specialized.OrderedDictionary]::new([System.StringComparer]::Ordinal) $required = [System.Collections.Generic.List[string]]::new() foreach ($parameter in $formData) { $property = ConvertFrom-OpenApiSwagger2SimpleSchema -Node $parameter if ($parameter.Contains('description')) { $property['description'] = $parameter['description'] } $properties[[string]$parameter['name']] = $property if ($parameter['required'] -eq $true) { $required.Add([string]$parameter['name']) } } $schema = [System.Collections.Specialized.OrderedDictionary]::new([System.StringComparer]::Ordinal) $schema['type'] = 'object' $schema['properties'] = $properties if ($required.Count -gt 0) { $schema['required'] = [object[]]$required.ToArray() } $media = [System.Collections.Specialized.OrderedDictionary]::new([System.StringComparer]::Ordinal) $media['schema'] = $schema $content = [System.Collections.Specialized.OrderedDictionary]::new([System.StringComparer]::Ordinal) $content[$contentType] = $media $requestBody = [System.Collections.Specialized.OrderedDictionary]::new([System.StringComparer]::Ordinal) $requestBody['required'] = $required.Count -gt 0 $requestBody['content'] = $content $result['requestBody'] = $requestBody } if ($Operation['responses'] -is [System.Collections.IDictionary]) { $responses = [System.Collections.Specialized.OrderedDictionary]::new([System.StringComparer]::Ordinal) foreach ($code in @($Operation['responses'].Keys)) { $response = $Operation['responses'][$code] if ($response -is [System.Collections.IDictionary] -and $response.Contains('$ref')) { $target = Resolve-OpenApiPointer -Root $Root -Reference ([string]$response['$ref']) if ($target.Found -and $target.Value -is [System.Collections.IDictionary]) { $response = $target.Value } else { $responses[$code] = $response continue } } if ($response -is [System.Collections.IDictionary]) { $responses[$code] = ConvertFrom-OpenApiSwagger2Response -Node $response -Produces $Produces } } $result['responses'] = $responses } return $result } |