docs-util: add warning on request body change (#10881)

This commit is contained in:
Shahed Nasser authored and GitHub committed 2025-01-08 21:40:46 +02:00
1 parent 46f987e351
commit bd73716bb6
3 files changed
+137 -36

No files matched your search

@@ -19,6 +19,7 @@
"dependencies": { "dependencies": {
"@faker-js/faker": "^8.4.0", "@faker-js/faker": "^8.4.0",
"@octokit/core": "^5.0.2", "@octokit/core": "^5.0.2",
"chalk": "^5.4.1",
"commander": "^11.1.0", "commander": "^11.1.0",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"eslint": "8.56.0", "eslint": "8.56.0",
@@ -1,3 +1,4 @@
import chalk from "chalk"
import { readFileSync, writeFileSync } from "fs" import { readFileSync, writeFileSync } from "fs"
import { OpenAPIV3 } from "openapi-types" import { OpenAPIV3 } from "openapi-types"
import { basename, join } from "path" import { basename, join } from "path"
@@ -473,6 +474,8 @@ class OasKindGenerator extends FunctionKindGenerator {
oas["x-authenticated"] = isAuthenticated oas["x-authenticated"] = isAuthenticated
oas.security = this.getSecurity({ isAdminAuthenticated, isAuthenticated }) oas.security = this.getSecurity({ isAdminAuthenticated, isAuthenticated })
let parametersUpdated = false
// update path parameters // update path parameters
const newPathParameters = this.getPathParameters({ oasPath, tagName }) const newPathParameters = this.getPathParameters({ oasPath, tagName })
@@ -480,12 +483,15 @@ class OasKindGenerator extends FunctionKindGenerator {
const headerParams = this.getHeaderParameters(oasPath) const headerParams = this.getHeaderParameters(oasPath)
newPathParameters.push(...headerParams) newPathParameters.push(...headerParams)
oas.parameters = this.updateParameters({ let updateParameterResult = this.updateParameters({
oldParameters: oas.parameters as OpenAPIV3.ParameterObject[], oldParameters: oas.parameters as OpenAPIV3.ParameterObject[],
newParameters: newPathParameters, newParameters: newPathParameters,
types: ["path", "header"], types: ["path", "header"],
}) })
oas.parameters = updateParameterResult.parameters
parametersUpdated = updateParameterResult.wasUpdated
// retrieve updated query and request schemas // retrieve updated query and request schemas
const { queryParameters, requestSchema } = this.getRequestParameters({ const { queryParameters, requestSchema } = this.getRequestParameters({
node, node,
@@ -495,12 +501,15 @@ class OasKindGenerator extends FunctionKindGenerator {
}) })
// update query parameters // update query parameters
oas.parameters = this.updateParameters({ updateParameterResult = this.updateParameters({
oldParameters: oas.parameters as OpenAPIV3.ParameterObject[], oldParameters: oas.parameters as OpenAPIV3.ParameterObject[],
newParameters: queryParameters, newParameters: queryParameters,
types: ["query"], types: ["query"],
}) })
oas.parameters = updateParameterResult.parameters
parametersUpdated = updateParameterResult.wasUpdated || parametersUpdated
if (!oas.parameters.length) { if (!oas.parameters.length) {
oas.parameters = undefined oas.parameters = undefined
} }
@@ -514,9 +523,11 @@ class OasKindGenerator extends FunctionKindGenerator {
newSchema: requestSchema, newSchema: requestSchema,
}) })
parametersUpdated = updatedRequestSchema?.wasUpdated || parametersUpdated
if ( if (
!updatedRequestSchema || !updatedRequestSchema?.schema ||
Object.keys(updatedRequestSchema).length === 0 Object.keys(updatedRequestSchema.schema).length === 0
) { ) {
// if there's no request schema, remove it from the OAS // if there's no request schema, remove it from the OAS
delete oas.requestBody delete oas.requestBody
@@ -527,9 +538,11 @@ class OasKindGenerator extends FunctionKindGenerator {
"application/json": { "application/json": {
schema: schema:
this.oasSchemaHelper.namedSchemaToReference( this.oasSchemaHelper.namedSchemaToReference(
updatedRequestSchema updatedRequestSchema.schema
) || ) ||
this.oasSchemaHelper.schemaChildrenToRefs(updatedRequestSchema), this.oasSchemaHelper.schemaChildrenToRefs(
updatedRequestSchema.schema
),
}, },
}, },
} }
@@ -581,7 +594,7 @@ class OasKindGenerator extends FunctionKindGenerator {
updatedResponseSchema = this.updateSchema({ updatedResponseSchema = this.updateSchema({
oldSchema: oldResponseSchema, oldSchema: oldResponseSchema,
newSchema: newResponseSchema, newSchema: newResponseSchema,
}) })?.schema
if (oldResponseStatus && oldResponseSchema !== newStatus) { if (oldResponseStatus && oldResponseSchema !== newStatus) {
// delete the old response schema if its status is different // delete the old response schema if its status is different
@@ -633,7 +646,7 @@ class OasKindGenerator extends FunctionKindGenerator {
parameters: (oas.parameters as OpenAPIV3.ParameterObject[])?.filter( parameters: (oas.parameters as OpenAPIV3.ParameterObject[])?.filter(
(parameter) => parameter.in === "path" (parameter) => parameter.in === "path"
), ),
requestBody: updatedRequestSchema, requestBody: updatedRequestSchema?.schema,
responseBody: updatedResponseSchema, responseBody: updatedResponseSchema,
}) })
@@ -673,6 +686,13 @@ class OasKindGenerator extends FunctionKindGenerator {
source: newCurlExample, source: newCurlExample,
}, },
] ]
} else if (parametersUpdated) {
// show a warning if the request parameters have changed
console.warn(
chalk.yellow(
`[WARNING] The request parameters of ${methodName} ${oasPath} have changed. Please update the cURL example.`
)
)
} }
// push new tags to the tags property // push new tags to the tags property
@@ -1927,9 +1947,16 @@ class OasKindGenerator extends FunctionKindGenerator {
* The type of parameters. * The type of parameters.
*/ */
types: ParameterType[] types: ParameterType[]
}): OpenAPIV3.ParameterObject[] { }): {
parameters: OpenAPIV3.ParameterObject[]
wasUpdated: boolean
} {
let wasUpdated = false
if (!oldParameters) { if (!oldParameters) {
return newParameters || [] return {
parameters: newParameters || [],
wasUpdated: !!newParameters?.length,
}
} }
const oppositeParamType = ["path", "query", "header"].filter( const oppositeParamType = ["path", "query", "header"].filter(
(item) => !types.includes(item as ParameterType) (item) => !types.includes(item as ParameterType)
@@ -1952,6 +1979,7 @@ class OasKindGenerator extends FunctionKindGenerator {
if (!updatedParameter) { if (!updatedParameter) {
// remove the parameter // remove the parameter
paramsToRemove.add(parameter.name) paramsToRemove.add(parameter.name)
wasUpdated = true
return return
} }
@@ -1964,6 +1992,7 @@ class OasKindGenerator extends FunctionKindGenerator {
if (updatedParameter.required !== parameter.required) { if (updatedParameter.required !== parameter.required) {
parameter.required = updatedParameter.required parameter.required = updatedParameter.required
wasUpdated = true
} }
if ( if (
@@ -1972,19 +2001,24 @@ class OasKindGenerator extends FunctionKindGenerator {
) { ) {
// the entire schema should be updated if the type changes. // the entire schema should be updated if the type changes.
parameter.schema = updatedParameter.schema parameter.schema = updatedParameter.schema
wasUpdated = true
} else if ((updatedParameter.schema as OpenApiSchema).type === "array") { } else if ((updatedParameter.schema as OpenApiSchema).type === "array") {
;(parameter.schema as OpenAPIV3.ArraySchemaObject).items = const updateResult = this.updateSchema({
this.updateSchema({
oldSchema: (parameter.schema as OpenAPIV3.ArraySchemaObject).items, oldSchema: (parameter.schema as OpenAPIV3.ArraySchemaObject).items,
newSchema: (updatedParameter.schema as OpenAPIV3.ArraySchemaObject) newSchema: (updatedParameter.schema as OpenAPIV3.ArraySchemaObject)
.items, .items,
}) || (updatedParameter.schema as OpenAPIV3.ArraySchemaObject).items })
;(parameter.schema as OpenAPIV3.ArraySchemaObject).items =
updateResult?.schema ||
(updatedParameter.schema as OpenAPIV3.ArraySchemaObject).items
wasUpdated = updateResult?.wasUpdated || wasUpdated
} else if ((updatedParameter.schema as OpenApiSchema).type === "object") { } else if ((updatedParameter.schema as OpenApiSchema).type === "object") {
parameter.schema = const updateResult = this.updateSchema({
this.updateSchema({
oldSchema: parameter.schema, oldSchema: parameter.schema,
newSchema: updatedParameter.schema, newSchema: updatedParameter.schema,
}) || updatedParameter.schema })
parameter.schema = updateResult?.schema || updatedParameter.schema
wasUpdated = updateResult?.wasUpdated || wasUpdated
} }
if ( if (
@@ -1994,6 +2028,7 @@ class OasKindGenerator extends FunctionKindGenerator {
;(parameter.schema as OpenApiSchema).title = ( ;(parameter.schema as OpenApiSchema).title = (
updatedParameter.schema as OpenApiSchema updatedParameter.schema as OpenApiSchema
).title ).title
wasUpdated = true
} }
if ( if (
@@ -2014,10 +2049,12 @@ class OasKindGenerator extends FunctionKindGenerator {
} }
existingParams?.push(parameter) existingParams?.push(parameter)
wasUpdated = true
}) })
// remove parameters no longer existing // remove parameters no longer existing
return [ return {
parameters: [
...oppositeParams, ...oppositeParams,
...(existingParams?.filter( ...(existingParams?.filter(
(parameter) => (parameter) =>
@@ -2026,7 +2063,9 @@ class OasKindGenerator extends FunctionKindGenerator {
) || ) ||
!paramsToRemove.has((parameter as OpenAPIV3.ParameterObject).name) !paramsToRemove.has((parameter as OpenAPIV3.ParameterObject).name)
) || []), ) || []),
] ],
wasUpdated,
}
} }
/** /**
@@ -2053,7 +2092,13 @@ class OasKindGenerator extends FunctionKindGenerator {
* maximum call stack size exceeded error * maximum call stack size exceeded error
*/ */
level?: number level?: number
}): OpenApiSchema | undefined { }):
| {
schema: OpenApiSchema | undefined
wasUpdated: boolean
}
| undefined {
let wasUpdated = false
if (isLevelExceeded(level, this.MAX_LEVEL)) { if (isLevelExceeded(level, this.MAX_LEVEL)) {
return return
} }
@@ -2070,10 +2115,28 @@ class OasKindGenerator extends FunctionKindGenerator {
: newSchema : newSchema
) as OpenApiSchema | undefined ) as OpenApiSchema | undefined
if (!oldSchemaObj && newSchemaObj) { const oldSchemaKeys = oldSchemaObj ? Object.keys(oldSchemaObj) : []
return newSchemaObj const hasOldSchemaObj =
} else if (!newSchemaObj || !Object.keys(newSchemaObj).length) { oldSchemaObj !== undefined && oldSchemaKeys.length > 0
return undefined const hasNewSchemaObj =
newSchemaObj !== undefined && Object.keys(newSchemaObj).length > 0
if (!hasOldSchemaObj || !hasNewSchemaObj) {
// if old schema is just made up of description, return it.
const useOldSchema =
oldSchemaKeys.length === 1 &&
newSchemaObj !== undefined &&
oldSchemaKeys[0] === "description"
return {
schema: hasNewSchemaObj
? newSchemaObj
: useOldSchema
? oldSchemaObj
: undefined,
wasUpdated: !hasNewSchemaObj
? !useOldSchema && hasOldSchemaObj
: hasOldSchemaObj !== hasNewSchemaObj,
}
} }
const oldSchemaType = this.inferOasSchemaType(oldSchemaObj) const oldSchemaType = this.inferOasSchemaType(oldSchemaObj)
@@ -2085,28 +2148,36 @@ class OasKindGenerator extends FunctionKindGenerator {
description: oldSchemaObj?.description, description: oldSchemaObj?.description,
example: oldSchemaObj?.example || newSchemaObj.example, example: oldSchemaObj?.example || newSchemaObj.example,
} }
wasUpdated = true
} else if ( } else if (
oldSchemaObj?.allOf && oldSchemaObj?.allOf &&
newSchemaObj.allOf && newSchemaObj.allOf &&
oldSchemaObj.allOf.length !== newSchemaObj.allOf.length oldSchemaObj.allOf.length !== newSchemaObj.allOf.length
) { ) {
oldSchemaObj.allOf = newSchemaObj.allOf oldSchemaObj.allOf = newSchemaObj.allOf
wasUpdated = true
} else if ( } else if (
oldSchemaObj?.oneOf && oldSchemaObj?.oneOf &&
newSchemaObj.oneOf && newSchemaObj.oneOf &&
oldSchemaObj.oneOf.length !== newSchemaObj.oneOf.length oldSchemaObj.oneOf.length !== newSchemaObj.oneOf.length
) { ) {
oldSchemaObj.oneOf = newSchemaObj.oneOf oldSchemaObj.oneOf = newSchemaObj.oneOf
wasUpdated = true
} else if ( } else if (
oldSchemaObj?.anyOf && oldSchemaObj?.anyOf &&
newSchemaObj.anyOf && newSchemaObj.anyOf &&
oldSchemaObj.anyOf.length !== newSchemaObj.anyOf.length oldSchemaObj.anyOf.length !== newSchemaObj.anyOf.length
) { ) {
oldSchemaObj.anyOf = newSchemaObj.anyOf oldSchemaObj.anyOf = newSchemaObj.anyOf
wasUpdated = true
} else if (oldSchemaType === "object") { } else if (oldSchemaType === "object") {
if (!oldSchemaObj?.properties && newSchemaObj?.properties) { if (!oldSchemaObj?.properties && newSchemaObj?.properties) {
oldSchemaObj!.properties = newSchemaObj.properties oldSchemaObj!.properties = newSchemaObj.properties
wasUpdated = true
} else if (!newSchemaObj?.properties) { } else if (!newSchemaObj?.properties) {
if (oldSchemaObj!.properties) {
wasUpdated = true
}
delete oldSchemaObj!.properties delete oldSchemaObj!.properties
// check if additionalProperties should be updated // check if additionalProperties should be updated
@@ -2121,12 +2192,13 @@ class OasKindGenerator extends FunctionKindGenerator {
typeof oldSchemaObj!.additionalProperties !== "boolean" && typeof oldSchemaObj!.additionalProperties !== "boolean" &&
typeof newSchemaObj!.additionalProperties !== "boolean" typeof newSchemaObj!.additionalProperties !== "boolean"
) { ) {
oldSchemaObj!.additionalProperties = const updateResult = this.updateSchema({
this.updateSchema({
oldSchema: oldSchemaObj!.additionalProperties, oldSchema: oldSchemaObj!.additionalProperties,
newSchema: newSchemaObj.additionalProperties, newSchema: newSchemaObj.additionalProperties,
level: maybeIncrementLevel(level, "object"), level: maybeIncrementLevel(level, "object"),
}) || oldSchemaObj!.additionalProperties })
oldSchemaObj!.additionalProperties =
updateResult?.schema || oldSchemaObj!.additionalProperties
} }
} else { } else {
// update existing properties // update existing properties
@@ -2138,17 +2210,20 @@ class OasKindGenerator extends FunctionKindGenerator {
if (!newPropertySchemaKey) { if (!newPropertySchemaKey) {
// remove property // remove property
delete oldSchemaObj!.properties![propertyName] delete oldSchemaObj!.properties![propertyName]
wasUpdated = true
return return
} }
oldSchemaObj!.properties![propertyName] = const updateResult = this.updateSchema({
this.updateSchema({
oldSchema: propertySchema as OpenApiSchema, oldSchema: propertySchema as OpenApiSchema,
newSchema: newSchemaObj!.properties![ newSchema: newSchemaObj!.properties![
propertyName propertyName
] as OpenApiSchema, ] as OpenApiSchema,
level: maybeIncrementLevel(level, "object"), level: maybeIncrementLevel(level, "object"),
}) || propertySchema })
oldSchemaObj!.properties![propertyName] =
updateResult?.schema || propertySchema
wasUpdated = updateResult?.wasUpdated || wasUpdated
} }
) )
// add new properties // add new properties
@@ -2177,12 +2252,13 @@ class OasKindGenerator extends FunctionKindGenerator {
) )
if (schemaToUpdate) { if (schemaToUpdate) {
updatedSchema = const updateResult = this.updateSchema({
this.updateSchema({
oldSchema: schemaToUpdate.schema, oldSchema: schemaToUpdate.schema,
newSchema: schema, newSchema: schema,
level: maybeIncrementLevel(level, "object"), level: maybeIncrementLevel(level, "object"),
}) || newProperty })
updatedSchema = updateResult?.schema || newProperty
wasUpdated = updateResult?.wasUpdated || wasUpdated
} }
} }
@@ -2207,12 +2283,13 @@ class OasKindGenerator extends FunctionKindGenerator {
oldSchemaObj?.type === "array" && oldSchemaObj?.type === "array" &&
newSchemaObj?.type === "array" newSchemaObj?.type === "array"
) { ) {
oldSchemaObj.items = const updateResult = this.updateSchema({
this.updateSchema({
oldSchema: oldSchemaObj.items as OpenApiSchema, oldSchema: oldSchemaObj.items as OpenApiSchema,
newSchema: newSchemaObj!.items as OpenApiSchema, newSchema: newSchemaObj!.items as OpenApiSchema,
level: maybeIncrementLevel(level, "array"), level: maybeIncrementLevel(level, "array"),
}) || oldSchemaObj.items })
oldSchemaObj.items = updateResult?.schema || oldSchemaObj.items
wasUpdated = updateResult?.wasUpdated || wasUpdated
} }
if ( if (
@@ -2223,10 +2300,25 @@ class OasKindGenerator extends FunctionKindGenerator {
newSchemaObj?.description || SUMMARY_PLACEHOLDER newSchemaObj?.description || SUMMARY_PLACEHOLDER
} }
if (!wasUpdated) {
const requiredChanged =
oldSchemaObj!.required?.length !== newSchemaObj?.required?.length ||
oldSchemaObj!.required?.some(
(item, index) => item !== newSchemaObj!.required![index]
) ||
false
const schemaNameChanged =
oldSchemaObj!["x-schemaName"] !== newSchemaObj?.["x-schemaName"]
wasUpdated = requiredChanged || schemaNameChanged
}
oldSchemaObj!.required = newSchemaObj?.required oldSchemaObj!.required = newSchemaObj?.required
oldSchemaObj!["x-schemaName"] = newSchemaObj?.["x-schemaName"] oldSchemaObj!["x-schemaName"] = newSchemaObj?.["x-schemaName"]
return oldSchemaObj return {
schema: oldSchemaObj,
wasUpdated,
}
} }
/** /**
+8
View File
@@ -2242,6 +2242,13 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"chalk@npm:^5.4.1":
version: 5.4.1
resolution: "chalk@npm:5.4.1"
checksum: b23e88132c702f4855ca6d25cb5538b1114343e41472d5263ee8a37cccfccd9c4216d111e1097c6a27830407a1dc81fecdf2a56f2c63033d4dbbd88c10b0dcef
languageName: node
linkType: hard
"charenc@npm:0.0.2": "charenc@npm:0.0.2":
version: 0.0.2 version: 0.0.2
resolution: "charenc@npm:0.0.2" resolution: "charenc@npm:0.0.2"
@@ -2605,6 +2612,7 @@ __metadata:
"@types/eslint": 8.56.6 "@types/eslint": 8.56.6
"@types/node": ^20.12.10 "@types/node": ^20.12.10
"@types/pluralize": ^0.0.33 "@types/pluralize": ^0.0.33
chalk: ^5.4.1
commander: ^11.1.0 commander: ^11.1.0
dotenv: ^16.3.1 dotenv: ^16.3.1
eslint: 8.56.0 eslint: 8.56.0