зеркало из https://github.com/github/docs.git
Revert "Refactor openapi table func" (#30040)
This commit is contained in:
Родитель
5024b0dc07
Коммит
961f985cfe
|
@ -1,57 +1,58 @@
|
|||
import { useTranslation } from 'components/hooks/useTranslation'
|
||||
import { ParameterRow } from './ParameterRow'
|
||||
import type { ChildParameter } from './types'
|
||||
import type { ChildParamsGroup } from './types'
|
||||
|
||||
type Props = {
|
||||
slug: string
|
||||
childParamsGroups: ChildParameter[]
|
||||
parentName: string
|
||||
parentType: string
|
||||
childParamsGroups?: ChildParamsGroup[]
|
||||
}
|
||||
|
||||
export function ChildBodyParametersRows({
|
||||
slug,
|
||||
parentName,
|
||||
parentType,
|
||||
childParamsGroups,
|
||||
}: Props) {
|
||||
export function ChildBodyParametersRows({ slug, childParamsGroups }: Props) {
|
||||
const { t } = useTranslation('products')
|
||||
|
||||
return (
|
||||
<tr className="border-top-0">
|
||||
<tr className="border-none">
|
||||
<td colSpan={4} className="has-nested-table">
|
||||
<details className="ml-1">
|
||||
<summary role="button" aria-expanded="false" className="keyboard-focus color-fg-muted">
|
||||
<span className="d-inline-block mb-3" id={`${slug}-${parentName}-${parentType}`}>
|
||||
Properties of the
|
||||
<code>{parentName}</code>
|
||||
{parentType}
|
||||
</span>
|
||||
</summary>
|
||||
<table id={`${parentName}-object`} className="mb-4 mt-2 color-bg-subtle">
|
||||
<thead className="visually-hidden">
|
||||
<tr>
|
||||
<th>
|
||||
{`${t('rest.reference.name')}, ${t('rest.reference.type')}, ${t(
|
||||
'rest.reference.description'
|
||||
)}`}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{childParamsGroups.map((childParam) => {
|
||||
return (
|
||||
{childParamsGroups?.map((childParamGroup) => (
|
||||
<details key={childParamGroup.id}>
|
||||
<summary role="button" aria-expanded="false" className="keyboard-focus color-fg-muted">
|
||||
<span className="d-inline-block mb-3" id={`${slug}-${childParamGroup.id}`}>
|
||||
Properties of the
|
||||
<code>{childParamGroup.parentName}</code>
|
||||
{childParamGroup.parentType}
|
||||
</span>
|
||||
</summary>
|
||||
<table
|
||||
id={`${childParamGroup.parentName}-object`}
|
||||
className="ml-4 mb-4 mt-2 color-bg-subtle"
|
||||
>
|
||||
<thead className="visually-hidden">
|
||||
<tr>
|
||||
<th>
|
||||
{`${t('rest.reference.name')}, ${t('rest.reference.type')}, ${t(
|
||||
'rest.reference.description'
|
||||
)}`}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{childParamGroup.params.map((childParam, index) => (
|
||||
<ParameterRow
|
||||
rowParams={childParam}
|
||||
name={childParam.name}
|
||||
description={childParam.description}
|
||||
type={childParam.type}
|
||||
isRequired={childParam.isRequired}
|
||||
defaultValue={childParam.default}
|
||||
enumValues={childParam.enum}
|
||||
slug={slug}
|
||||
isChild={true}
|
||||
key={childParam.name}
|
||||
key={`${index}-${childParam}`}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</details>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</details>
|
||||
))}
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
|
|
|
@ -1,24 +1,44 @@
|
|||
import { useTranslation } from 'components/hooks/useTranslation'
|
||||
import { ChildBodyParametersRows } from './ChildBodyParametersRows'
|
||||
import type { ChildParameter } from './types'
|
||||
import type { ChildParamsGroup } from './types'
|
||||
|
||||
type Props = {
|
||||
rowParams: ChildParameter
|
||||
name: string
|
||||
type: string | string[]
|
||||
description: string
|
||||
isRequired?: boolean
|
||||
defaultValue?: string
|
||||
enumValues?: string[]
|
||||
slug: string
|
||||
childParamsGroups?: ChildParamsGroup[] | null
|
||||
numPreviews?: number
|
||||
isChild?: boolean
|
||||
}
|
||||
|
||||
export function ParameterRow({ rowParams, slug, numPreviews = 0, isChild = false }: Props) {
|
||||
export function ParameterRow({
|
||||
name,
|
||||
type,
|
||||
description,
|
||||
isRequired,
|
||||
defaultValue,
|
||||
enumValues,
|
||||
slug,
|
||||
childParamsGroups = null,
|
||||
numPreviews = 0,
|
||||
isChild = false,
|
||||
}: Props) {
|
||||
const { t } = useTranslation('products')
|
||||
|
||||
return (
|
||||
<>
|
||||
<tr className={`${isChild ? 'color-bg-subtle' : ''}`}>
|
||||
<td className={`${isChild ? 'px-3' : ''}`}>
|
||||
<td className={`${isChild ? 'pl-2' : ''}`}>
|
||||
<div>
|
||||
<code className={`text-bold ${isChild ? 'f6' : 'f5'}`}>{rowParams.name}</code>
|
||||
<span className="color-fg-muted pl-2 f5">{rowParams.type}</span>
|
||||
{rowParams.isRequired ? (
|
||||
<code className={`text-bold ${isChild ? 'f6' : 'f5'}`}>{name}</code>
|
||||
<span className="color-fg-muted pl-2 f5">
|
||||
{Array.isArray(type) ? type.join(' or ') : type}
|
||||
</span>
|
||||
{isRequired ? (
|
||||
<span className={`color-fg-attention f5 ${isChild ? 'pl-3' : 'float-right'}`}>
|
||||
{t('rest.reference.required')}
|
||||
</span>
|
||||
|
@ -26,7 +46,7 @@ export function ParameterRow({ rowParams, slug, numPreviews = 0, isChild = false
|
|||
</div>
|
||||
|
||||
<div className="pl-1 pt-2 color-fg-muted f5">
|
||||
<div dangerouslySetInnerHTML={{ __html: rowParams.description }} />
|
||||
<div dangerouslySetInnerHTML={{ __html: description }} />
|
||||
{numPreviews > 0 && (
|
||||
<a href={`#${slug}-preview-notices`} className="d-inline">
|
||||
{numPreviews > 1
|
||||
|
@ -35,18 +55,18 @@ export function ParameterRow({ rowParams, slug, numPreviews = 0, isChild = false
|
|||
</a>
|
||||
)}
|
||||
<div className="pt-2">
|
||||
{rowParams.default && (
|
||||
{defaultValue !== undefined && (
|
||||
<p>
|
||||
<span>{t('rest.reference.default')}: </span>
|
||||
<code>{rowParams.default}</code>
|
||||
<code>{defaultValue.toString()}</code>
|
||||
</p>
|
||||
)}
|
||||
{rowParams.enum && rowParams.enum.length && (
|
||||
{enumValues && (
|
||||
<p>
|
||||
<span>{t('rest.reference.enum_description_title')}: </span>
|
||||
|
||||
{rowParams.enum.map((item, index, array) => {
|
||||
return index !== array.length - 1 ? (
|
||||
{enumValues.map((item, index) => {
|
||||
return index !== enumValues.length - 1 ? (
|
||||
<span key={item + index}>
|
||||
<code>{item}</code>,{' '}
|
||||
</span>
|
||||
|
@ -62,13 +82,8 @@ export function ParameterRow({ rowParams, slug, numPreviews = 0, isChild = false
|
|||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{rowParams.childParamsGroups && rowParams.childParamsGroups.length > 0 && (
|
||||
<ChildBodyParametersRows
|
||||
slug={slug}
|
||||
parentName={rowParams.name}
|
||||
parentType={rowParams.type}
|
||||
childParamsGroups={rowParams.childParamsGroups}
|
||||
/>
|
||||
{childParamsGroups && childParamsGroups.length > 0 && (
|
||||
<ChildBodyParametersRows slug={slug} childParamsGroups={childParamsGroups} />
|
||||
)}
|
||||
</>
|
||||
)
|
||||
|
|
|
@ -42,12 +42,10 @@ export function RestParameterTable({ slug, numPreviews, parameters, bodyParamete
|
|||
|
||||
<tbody>
|
||||
<ParameterRow
|
||||
rowParams={{
|
||||
name: 'accept',
|
||||
type: 'string',
|
||||
description: `<p>Setting to <code>application/vnd.github+json</code> is recommended.</p>`,
|
||||
isRequired: false,
|
||||
}}
|
||||
name={'accept'}
|
||||
type={'string'}
|
||||
description={`<p>Setting to <code>application/vnd.github+json</code> is recommended.</p>`}
|
||||
isRequired={false}
|
||||
slug={slug}
|
||||
numPreviews={numPreviews}
|
||||
/>
|
||||
|
@ -67,14 +65,12 @@ export function RestParameterTable({ slug, numPreviews, parameters, bodyParamete
|
|||
</tr>
|
||||
{pathParams.map((param, index) => (
|
||||
<ParameterRow
|
||||
rowParams={{
|
||||
name: param.name,
|
||||
type: param.schema.type,
|
||||
description: param.description,
|
||||
isRequired: param.required,
|
||||
default: param.schema.default,
|
||||
enum: param.schema.enum,
|
||||
}}
|
||||
name={param.name}
|
||||
type={param.schema.type}
|
||||
description={param.description}
|
||||
isRequired={param.required}
|
||||
defaultValue={param.schema.default}
|
||||
enumValues={param.schema.enum}
|
||||
slug={slug}
|
||||
key={`${index}-${param}`}
|
||||
/>
|
||||
|
@ -99,14 +95,12 @@ export function RestParameterTable({ slug, numPreviews, parameters, bodyParamete
|
|||
|
||||
{queryParams.map((param, index) => (
|
||||
<ParameterRow
|
||||
rowParams={{
|
||||
name: param.name,
|
||||
type: param.schema.type,
|
||||
description: param.description,
|
||||
isRequired: param.required,
|
||||
default: param.schema.default,
|
||||
enum: param.schema.enum,
|
||||
}}
|
||||
name={param.name}
|
||||
type={param.schema.type}
|
||||
description={param.description}
|
||||
isRequired={param.required}
|
||||
defaultValue={param.schema.default}
|
||||
enumValues={param.schema.enum}
|
||||
slug={slug}
|
||||
key={`${index}-${param}`}
|
||||
/>
|
||||
|
@ -130,7 +124,17 @@ export function RestParameterTable({ slug, numPreviews, parameters, bodyParamete
|
|||
</tr>
|
||||
|
||||
{bodyParameters.map((param, index) => (
|
||||
<ParameterRow rowParams={param} slug={slug} key={`${index}-${param}`} />
|
||||
<ParameterRow
|
||||
name={param.name}
|
||||
type={param.type}
|
||||
description={param.description}
|
||||
isRequired={param.isRequired}
|
||||
defaultValue={param.default}
|
||||
enumValues={param.enum}
|
||||
slug={slug}
|
||||
childParamsGroups={param.childParamsGroups}
|
||||
key={`${index}-${param}`}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
|
|
|
@ -54,20 +54,26 @@ export interface BodyParameter {
|
|||
name: string
|
||||
description: string
|
||||
type: string
|
||||
isRequired?: boolean
|
||||
isRequired: boolean
|
||||
default?: string
|
||||
enum?: Array<string>
|
||||
childParamsGroups?: Array<ChildParameter>
|
||||
childParamsGroups?: Array<ChildParamsGroup>
|
||||
}
|
||||
|
||||
export interface ChildParamsGroup {
|
||||
id: string
|
||||
params: Array<ChildParameter>
|
||||
parentName: string
|
||||
parentType: string
|
||||
}
|
||||
|
||||
export interface ChildParameter {
|
||||
name: string
|
||||
description: string
|
||||
type: string
|
||||
isRequired?: boolean
|
||||
isRequired: boolean
|
||||
enum?: Array<string>
|
||||
default?: string
|
||||
childParamsGroups?: ChildParameter[]
|
||||
}
|
||||
|
||||
export type ExampleT = {
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,8 +1,9 @@
|
|||
#!/usr/bin/env node
|
||||
import Ajv from 'ajv'
|
||||
import GitHubSlugger from 'github-slugger'
|
||||
import httpStatusCodes from 'http-status-code'
|
||||
import { readFile } from 'fs/promises'
|
||||
import { get, isPlainObject } from 'lodash-es'
|
||||
import { get, flatten, isPlainObject } from 'lodash-es'
|
||||
import { parseTemplate } from 'url-template'
|
||||
|
||||
import renderContent from '../../../lib/render-content/index.js'
|
||||
|
@ -12,6 +13,7 @@ import operationSchema from './operation-schema.js'
|
|||
const { operationUrls } = JSON.parse(
|
||||
await readFile('script/rest/utils/rest-api-overrides.json', 'utf8')
|
||||
)
|
||||
const slugger = new GitHubSlugger()
|
||||
|
||||
export default class Operation {
|
||||
#operation
|
||||
|
@ -34,6 +36,7 @@ export default class Operation {
|
|||
}
|
||||
|
||||
this.serverUrl = this.serverUrl.replace('http:', 'http(s):')
|
||||
this.serverUrlOverride()
|
||||
|
||||
// Attach some global properties to the operation object to use
|
||||
// during processing
|
||||
|
@ -78,6 +81,17 @@ export default class Operation {
|
|||
}
|
||||
}
|
||||
|
||||
serverUrlOverride() {
|
||||
// TODO - remove this once github pull #214649
|
||||
// lands in this repo's lib/rest/static/dereferenced directory
|
||||
if (
|
||||
this.#operation['x-github'].subcategory &&
|
||||
this.#operation['x-github'].subcategory === 'management-console'
|
||||
) {
|
||||
this.serverUrl = this.serverUrl.replace('/api/v3', '')
|
||||
}
|
||||
}
|
||||
|
||||
async process() {
|
||||
await Promise.all([
|
||||
this.renderDescription(),
|
||||
|
@ -155,13 +169,54 @@ export default class Operation {
|
|||
// and the request body parameter types are the same for both.
|
||||
// Operation Id: markdown/render-raw
|
||||
const contentType = Object.keys(this.#operation.requestBody.content)[0]
|
||||
const schema = get(this.#operation, `requestBody.content.${contentType}.schema`, {})
|
||||
// TODO: Remove this check
|
||||
if (this.#operation.operationId === 'checks/create') {
|
||||
delete schema.oneOf
|
||||
}
|
||||
let bodyParamsObject = get(
|
||||
this.#operation,
|
||||
`requestBody.content.${contentType}.schema.properties`,
|
||||
{}
|
||||
)
|
||||
let requiredParams = get(
|
||||
this.#operation,
|
||||
`requestBody.content.${contentType}.schema.required`,
|
||||
[]
|
||||
)
|
||||
const oneOfObject = get(
|
||||
this.#operation,
|
||||
`requestBody.content.${contentType}.schema.oneOf`,
|
||||
undefined
|
||||
)
|
||||
|
||||
this.bodyParameters = isPlainObject(schema) ? await getBodyParams(schema, true) : []
|
||||
// oneOf is an array of input parameter options, so we need to either
|
||||
// use the first option or munge the options together.
|
||||
if (oneOfObject) {
|
||||
const firstOneOfObject = oneOfObject[0]
|
||||
const allOneOfAreObjects =
|
||||
oneOfObject.filter((elem) => elem.type === 'object').length === oneOfObject.length
|
||||
|
||||
// TODO: Remove this check
|
||||
// This operation shouldn't have a oneOf in this case, it needs to be
|
||||
// removed from the schema in the openapi schema repo.
|
||||
if (this.#operation.operationId === 'checks/create') {
|
||||
delete bodyParamsObject.oneOf
|
||||
} else if (allOneOfAreObjects) {
|
||||
// When all of the oneOf objects have the `type: object` we
|
||||
// need to display all of the parameters.
|
||||
// This merges all of the properties and required values into the
|
||||
// first requestBody object.
|
||||
for (let i = 1; i < oneOfObject.length; i++) {
|
||||
Object.assign(firstOneOfObject.properties, oneOfObject[i].properties)
|
||||
requiredParams = firstOneOfObject.required.concat(oneOfObject[i].required)
|
||||
}
|
||||
bodyParamsObject = firstOneOfObject.properties
|
||||
} else if (oneOfObject) {
|
||||
// When a oneOf exists but the `type` differs, the case has historically
|
||||
// been that the alternate option is an array, where the first option
|
||||
// is the array as a property of the object. We need to ensure that the
|
||||
// first option listed is the most comprehensive and preferred option.
|
||||
bodyParamsObject = firstOneOfObject.properties
|
||||
requiredParams = firstOneOfObject.required
|
||||
}
|
||||
}
|
||||
this.bodyParameters = await getBodyParams(bodyParamsObject, requiredParams)
|
||||
}
|
||||
|
||||
async renderPreviewNotes() {
|
||||
|
@ -185,123 +240,215 @@ export default class Operation {
|
|||
}
|
||||
}
|
||||
|
||||
// If there is a oneOf at the top level, then we have to present one
|
||||
// in the docs. We don't currently have a convention for showing more than one
|
||||
// set of input parameters in the docs. Having a top-level oneOf is also very
|
||||
// uncommon.
|
||||
// Currently there are only two operations that require this treatment:
|
||||
// Create a project card
|
||||
// Create a codespace for the authenticated user
|
||||
async function getTopLevelOneOfProperty(schema) {
|
||||
const firstOneOfObject = schema.oneOf[0]
|
||||
const allOneOfAreObjects = schema.oneOf.every((elem) => elem.type === 'object')
|
||||
let requiredParams
|
||||
let propertiesObject
|
||||
// This operation shouldn't have a oneOf in this case, it needs to be
|
||||
// removed from the schema in the openapi schema repo.
|
||||
if (allOneOfAreObjects) {
|
||||
// When all of the oneOf objects have the `type: object` we
|
||||
// need to display all of the parameters.
|
||||
// This merges all of the properties and required values into the
|
||||
// first requestBody object.
|
||||
for (let i = 1; i < schema.oneOf.length; i++) {
|
||||
Object.assign(firstOneOfObject.properties, schema.oneOf[i].properties)
|
||||
requiredParams = firstOneOfObject.required.concat(schema.oneOf[i].required)
|
||||
}
|
||||
propertiesObject = firstOneOfObject.properties
|
||||
} else if (schema.oneOf) {
|
||||
// When a oneOf exists but the `type` differs, the case has historically
|
||||
// been that the alternate option is an array, where the first option
|
||||
// is the array as a property of the object. We need to ensure that the
|
||||
// first option listed is the most comprehensive and preferred option.
|
||||
propertiesObject = firstOneOfObject.properties
|
||||
requiredParams = firstOneOfObject.required
|
||||
}
|
||||
return { propertiesObject, requiredParams }
|
||||
}
|
||||
|
||||
// need to use this function recursively to get child and grandchild params
|
||||
async function getBodyParams(schema, topLevel = false) {
|
||||
const bodyParametersParsed = []
|
||||
const oneOf = get(schema.oneOf, undefined)
|
||||
const propertiesObject =
|
||||
oneOf && topLevel ? getTopLevelOneOfProperty(schema) : get(schema, 'properties', {})
|
||||
async function getBodyParams(paramsObject, requiredParams) {
|
||||
if (!isPlainObject(paramsObject)) return []
|
||||
|
||||
for (const paramKey of Object.keys(propertiesObject)) {
|
||||
const param = propertiesObject[paramKey]
|
||||
const paramDecorated = {}
|
||||
return Promise.all(
|
||||
Object.keys(paramsObject).map(async (paramKey) => {
|
||||
const param = paramsObject[paramKey]
|
||||
param.name = paramKey
|
||||
param.in = 'body'
|
||||
param.rawType = param.type
|
||||
// OpenAPI 3.0 only had a single value for `type`. OpenAPI 3.1
|
||||
// will either be a single value or an array of values.
|
||||
// This makes type an array regardless of how many values the array
|
||||
// includes. This allows us to support 3.1 while remaining backwards
|
||||
// compatible with 3.0.
|
||||
if (!Array.isArray(param.type)) param.type = [param.type]
|
||||
param.rawDescription = param.description
|
||||
|
||||
// OpenAPI 3.0 only had a single value for `type`. OpenAPI 3.1
|
||||
// will either be a single value or an array of values.
|
||||
// This makes type an array regardless of how many values the array
|
||||
// includes. This allows us to support 3.1 while remaining backwards
|
||||
// compatible with 3.0.
|
||||
const paramType = Array.isArray(param.type) ? param.type : [param.type]
|
||||
const childParamsGroups = []
|
||||
// Stores the types listed under the `Type` column in the `Parameters`
|
||||
// table in the REST API docs. When the parameter contains oneOf
|
||||
// there are multiple acceptable parameters that we should list.
|
||||
let paramArray = []
|
||||
|
||||
// If the parameter is an array, object, or oneOf,
|
||||
// then we need to get the child parameters
|
||||
if (paramType && paramType.includes('array')) {
|
||||
const arrayType = param.items.type
|
||||
if (arrayType) {
|
||||
paramType.splice(paramType.indexOf('array'), 1, `array of ${arrayType}s`)
|
||||
const oneOfArray = param.oneOf
|
||||
const isOneOfObjectOrArray = oneOfArray
|
||||
? oneOfArray.filter((elem) => elem.type !== 'object' || elem.type !== 'array')
|
||||
: false
|
||||
|
||||
// When oneOf has the type array or object, the type is defined
|
||||
// in a child object
|
||||
if (oneOfArray && isOneOfObjectOrArray.length > 0) {
|
||||
// Store the defined types
|
||||
paramArray.push(oneOfArray.filter((elem) => elem.type).map((elem) => elem.type))
|
||||
|
||||
// If an object doesn't have a description, it is invalid
|
||||
const oneOfArrayWithDescription = oneOfArray.filter((elem) => elem.description)
|
||||
|
||||
// Use the parent description when set, otherwise enumerate each
|
||||
// description in the `Description` column of the `Parameters` table.
|
||||
if (!param.description && oneOfArrayWithDescription.length > 1) {
|
||||
param.description = oneOfArray
|
||||
.filter((elem) => elem.description)
|
||||
.map((elem) => `**Type ${elem.type}** - ${elem.description}`)
|
||||
.join('\n\n')
|
||||
} else if (!param.description && oneOfArrayWithDescription.length === 1) {
|
||||
// When there is only on valid description, use that one.
|
||||
param.description = oneOfArrayWithDescription[0].description
|
||||
}
|
||||
}
|
||||
if (arrayType === 'object') {
|
||||
childParamsGroups.push(...(await getBodyParams(param.items)))
|
||||
}
|
||||
} else if (paramType && paramType.includes('object')) {
|
||||
childParamsGroups.push(...(await getBodyParams(param)))
|
||||
} else if (param && param.oneOf) {
|
||||
// get concatenated description and type
|
||||
const descriptions = []
|
||||
for (const childParam of param.oneOf) {
|
||||
paramType.push(childParam.type)
|
||||
// If there is no parent description, create a description from
|
||||
// each type
|
||||
if (!param.description) {
|
||||
if (childParam.type === 'array') {
|
||||
if (childParam.items.description) {
|
||||
descriptions.push({
|
||||
type: childParam.type,
|
||||
description: childParam.items.description,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if (childParam.description) {
|
||||
descriptions.push({ type: childParam.type, description: childParam.description })
|
||||
}
|
||||
|
||||
// Arrays require modifying the displayed type (e.g., array of strings)
|
||||
if (param.type.includes('array')) {
|
||||
if (param.items.type) paramArray.push(`array of ${param.items.type}s`)
|
||||
if (param.items.oneOf) {
|
||||
paramArray.push(param.items.oneOf.map((elem) => `array of ${elem.type}s`))
|
||||
}
|
||||
// push the remaining types in the param.type array
|
||||
// that aren't type array
|
||||
const remainingItems = [...param.type]
|
||||
const indexOfArrayType = remainingItems.indexOf('array')
|
||||
remainingItems.splice(indexOfArrayType, 1)
|
||||
paramArray.push(...remainingItems)
|
||||
} else if (param.type) {
|
||||
paramArray = paramArray.flat()
|
||||
for (const type of param.type) {
|
||||
if (type && paramArray.indexOf(type) === -1) {
|
||||
paramArray.push(type)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Occasionally, there is no parent description and the description
|
||||
// is in the first child parameter.
|
||||
const oneOfDescriptions = descriptions.length ? descriptions[0].description : ''
|
||||
if (!param.description) param.description = oneOfDescriptions
|
||||
}
|
||||
// Supports backwards compatibility for OpenAPI 3.0
|
||||
// In 3.1 a nullable type is part of the param.type array and
|
||||
// the property param.nullable does not exist.
|
||||
if (param.nullable) paramArray.push('null')
|
||||
|
||||
paramDecorated.type = paramType.filter(Boolean).join(' or ')
|
||||
paramDecorated.name = paramKey
|
||||
if (topLevel) {
|
||||
paramDecorated.in = 'body'
|
||||
}
|
||||
paramDecorated.description = await renderContent(param.description)
|
||||
if (schema.required && schema.required.includes(paramKey)) {
|
||||
paramDecorated.isRequired = true
|
||||
}
|
||||
if (childParamsGroups.length > 0) {
|
||||
paramDecorated.childParamsGroups = childParamsGroups
|
||||
}
|
||||
if (param.enum) {
|
||||
paramDecorated.enum = param.enum
|
||||
}
|
||||
if (param.default) {
|
||||
paramDecorated.default = param.default
|
||||
}
|
||||
// Supports backwards compatibility for OpenAPI 3.0
|
||||
// In 3.1 a nullable type is part of the param.type array and
|
||||
// the property param.nullable does not exist.
|
||||
if (param.nullable) paramDecorated.type('null')
|
||||
bodyParametersParsed.push(paramDecorated)
|
||||
}
|
||||
return bodyParametersParsed
|
||||
param.type = paramArray.flat().join(' or ')
|
||||
param.description = param.description || ''
|
||||
const isRequired = requiredParams && requiredParams.includes(param.name)
|
||||
param.isRequired = isRequired
|
||||
param.description = await renderContent(param.description)
|
||||
// there may be zero, one, or multiple object parameters that have children parameters
|
||||
param.childParamsGroups = []
|
||||
let childParamsGroup
|
||||
|
||||
// When additionalProperties is defined with a type of `object`
|
||||
// the input parameter is a dictionary. This handles cases for
|
||||
// a dictionary. We don't have any list cases yet, and when
|
||||
// the type is `string` we don't need to render additional rows of
|
||||
// parameters.
|
||||
// https://swagger.io/docs/specification/data-models/dictionaries/
|
||||
|
||||
// This conditional accounts for additionalProperties of type object
|
||||
// and [null, 'object']
|
||||
if (
|
||||
param.additionalProperties &&
|
||||
(param.additionalProperties.type === 'object' ||
|
||||
(Array.isArray(param.additionalProperties.type) &&
|
||||
param.additionalProperties.type.includes('object')))
|
||||
) {
|
||||
// Add the first element which will always be the user-defined key
|
||||
slugger.reset()
|
||||
const id = slugger.slug(`${param.name}-${param.type}`)
|
||||
param.childParamsGroups.push({
|
||||
parentName: param.name,
|
||||
parentType: param.type,
|
||||
id,
|
||||
params: [
|
||||
{
|
||||
description: `<p>A user-defined key to represent an item in <code>${param.name}</code>.</p>`,
|
||||
type: 'string',
|
||||
name: 'key',
|
||||
in: 'body',
|
||||
rawType: 'string',
|
||||
rawDescription: `A key to represent an item in ${param.name}.`,
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
// Construct a new parameter using the child properties set in
|
||||
// additionalProperties.
|
||||
const newParam = param.additionalProperties
|
||||
newParam.rawType = 'object'
|
||||
newParam.name = 'key'
|
||||
childParamsGroup = await getChildParamsGroup(newParam)
|
||||
} else {
|
||||
childParamsGroup = await getChildParamsGroup(param)
|
||||
}
|
||||
|
||||
if (childParamsGroup && childParamsGroup.params.length) {
|
||||
param.childParamsGroups.push(childParamsGroup)
|
||||
}
|
||||
|
||||
// If the param is an object, it may have child object params that have child params :/
|
||||
// Objects can potentially be null where the rawType is [ 'object', 'null' ].
|
||||
if (
|
||||
param.rawType === 'object' ||
|
||||
(Array.isArray(param.rawType) && param.rawType.includes('object'))
|
||||
) {
|
||||
param.childParamsGroups.push(
|
||||
...flatten(
|
||||
childParamsGroup.params
|
||||
.filter((param) => param.childParamsGroups?.length)
|
||||
.map((param) => param.childParamsGroups)
|
||||
)
|
||||
)
|
||||
}
|
||||
const paramDecorated = { ...param }
|
||||
delete paramDecorated.items
|
||||
delete paramDecorated.rawDescription
|
||||
delete paramDecorated.rawType
|
||||
if (paramDecorated.childParamsGroups.length === 0) delete paramDecorated.childParamsGroups
|
||||
return paramDecorated
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
async function getChildParamsGroup(param) {
|
||||
// Only objects, arrays of objects, anyOf, allOf, and oneOf have child params.
|
||||
// Objects can potentially be null where the rawType is [ 'object', 'null' ].
|
||||
if (
|
||||
!(
|
||||
param.rawType === 'array' ||
|
||||
(Array.isArray(param.rawType) && param.rawType.includes('array')) ||
|
||||
param.rawType === 'object' ||
|
||||
(Array.isArray(param.rawType) && param.rawType.includes('object')) ||
|
||||
param.oneOf
|
||||
)
|
||||
)
|
||||
return
|
||||
if (
|
||||
param.oneOf &&
|
||||
!param.oneOf.filter((param) => param.type === 'object' || param.type === 'array')
|
||||
)
|
||||
return
|
||||
if (param.items && param.items.type !== 'object') return
|
||||
|
||||
const childParamsObject =
|
||||
param.rawType === 'array' || (Array.isArray(param.rawType) && param.rawType.includes('array'))
|
||||
? param.items.properties
|
||||
: param.properties
|
||||
const requiredParams =
|
||||
param.rawType === 'array' || (Array.isArray(param.rawType) && param.rawType.includes('array'))
|
||||
? param.items.required
|
||||
: param.required
|
||||
const childParams = await getBodyParams(childParamsObject, requiredParams)
|
||||
|
||||
// adjust the type for easier readability in the child table
|
||||
let parentType
|
||||
|
||||
if (param.rawType === 'array') {
|
||||
parentType = 'items'
|
||||
} else if (Array.isArray(param.rawType) && param.rawType.includes('array')) {
|
||||
// handle the case where rawType is [ 'array', 'null' ]
|
||||
parentType = 'items'
|
||||
} else if (Array.isArray(param.rawType) && param.rawType.includes('object')) {
|
||||
// handle the case where rawType is [ 'object', 'null' ]
|
||||
parentType = 'object'
|
||||
} else {
|
||||
parentType = param.rawType
|
||||
}
|
||||
|
||||
// add an ID to the child table so they can be linked to
|
||||
slugger.reset()
|
||||
const id = slugger.slug(`${param.name}-${parentType}`)
|
||||
|
||||
return {
|
||||
parentName: param.name,
|
||||
parentType,
|
||||
id,
|
||||
params: childParams,
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче