fix(schema example): xml gen should follow json gen behavior (#6555)
* ref: #6470 * fixes: #6540 * fixes: #4943 * add example override option to json * add example override option to xml * added basic oneOf and anyOf support * fix anyof|oneof * only lift xml to items Co-authored-by: Tim Lai <timothy.lai@gmail.com>
This commit is contained in:
@@ -4,7 +4,7 @@ import ImPropTypes from "react-immutable-proptypes"
|
|||||||
import cx from "classnames"
|
import cx from "classnames"
|
||||||
import { fromJS, Seq, Iterable, List, Map } from "immutable"
|
import { fromJS, Seq, Iterable, List, Map } from "immutable"
|
||||||
import { getExtensions, getSampleSchema, fromJSOrdered, stringify } from "core/utils"
|
import { getExtensions, getSampleSchema, fromJSOrdered, stringify } from "core/utils"
|
||||||
import { isFunc } from "../utils"
|
|
||||||
|
|
||||||
const getExampleComponent = ( sampleResponse, HighlightCode, getConfigs ) => {
|
const getExampleComponent = ( sampleResponse, HighlightCode, getConfigs ) => {
|
||||||
if (
|
if (
|
||||||
@@ -121,21 +121,6 @@ export default class Response extends React.Component {
|
|||||||
specPathWithPossibleSchema = response.has("schema") ? specPath.push("schema") : specPath
|
specPathWithPossibleSchema = response.has("schema") ? specPath.push("schema") : specPath
|
||||||
}
|
}
|
||||||
|
|
||||||
const overrideSchemaExample = (oldSchema, newExample) => {
|
|
||||||
if(newExample === undefined)
|
|
||||||
return oldSchema
|
|
||||||
|
|
||||||
if(!oldSchema)
|
|
||||||
oldSchema = { }
|
|
||||||
|
|
||||||
if(isFunc(oldSchema.toJS))
|
|
||||||
oldSchema = oldSchema.toJS()
|
|
||||||
|
|
||||||
oldSchema.example = newExample && isFunc(newExample.toJS)
|
|
||||||
? newExample.toJS()
|
|
||||||
: newExample
|
|
||||||
return oldSchema
|
|
||||||
}
|
|
||||||
let mediaTypeExample
|
let mediaTypeExample
|
||||||
let shouldOverrideSchemaExample = false
|
let shouldOverrideSchemaExample = false
|
||||||
let sampleSchema
|
let sampleSchema
|
||||||
@@ -170,13 +155,12 @@ export default class Response extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const schemaForSampleGeneration = shouldOverrideSchemaExample
|
const sampleResponse = getSampleSchema(
|
||||||
? overrideSchemaExample(sampleSchema, mediaTypeExample)
|
sampleSchema,
|
||||||
: sampleSchema
|
activeContentType,
|
||||||
|
sampleGenConfig,
|
||||||
const sampleResponse = schemaForSampleGeneration
|
shouldOverrideSchemaExample ? mediaTypeExample : undefined
|
||||||
? getSampleSchema(schemaForSampleGeneration, activeContentType, sampleGenConfig)
|
)
|
||||||
: null
|
|
||||||
|
|
||||||
let example = getExampleComponent( sampleResponse, HighlightCode, getConfigs )
|
let example = getExampleComponent( sampleResponse, HighlightCode, getConfigs )
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { objectify, isFunc, normalizeArray, deeplyStripKey } from "core/utils"
|
import { objectify, isFunc, normalizeArray, deeplyStripKey } from "core/utils"
|
||||||
import XML from "@kyleshockey/xml"
|
import XML from "@kyleshockey/xml"
|
||||||
import memoizee from "memoizee"
|
import memoizee from "memoizee"
|
||||||
import deepAssign from "@kyleshockey/object-assign-deep"
|
import isEmpty from "lodash/isEmpty"
|
||||||
|
|
||||||
const primitives = {
|
const primitives = {
|
||||||
"string": () => "string",
|
"string": () => "string",
|
||||||
@@ -30,82 +30,291 @@ const primitive = (schema) => {
|
|||||||
return "Unknown Type: " + schema.type
|
return "Unknown Type: " + schema.type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// do a couple of quick sanity tests to ensure the value
|
||||||
|
// looks like a $$ref that swagger-client generates.
|
||||||
|
const sanitizeRef = (value) => deeplyStripKey(value, "$$ref", (val) =>
|
||||||
|
typeof val === "string" && val.indexOf("#") > -1)
|
||||||
|
|
||||||
export const sampleFromSchema = (schema, config={}) => {
|
const liftSampleHelper = (oldSchema, target) => {
|
||||||
let { type, example, properties, additionalProperties, items } = objectify(schema)
|
if(target.example === undefined && oldSchema.example !== undefined) {
|
||||||
|
target.example = oldSchema.example
|
||||||
|
}
|
||||||
|
if(target.default === undefined && oldSchema.default !== undefined) {
|
||||||
|
target.default = oldSchema.default
|
||||||
|
}
|
||||||
|
if(target.enum === undefined && oldSchema.enum !== undefined) {
|
||||||
|
target.enum = oldSchema.enum
|
||||||
|
}
|
||||||
|
if(target.xml === undefined && oldSchema.xml !== undefined) {
|
||||||
|
target.xml = oldSchema.xml
|
||||||
|
}
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sampleFromSchemaGeneric = (schema, config={}, exampleOverride = undefined, respectXML = false) => {
|
||||||
|
const _attr = {}
|
||||||
|
let { xml, type, example, properties, additionalProperties, items } = objectify(schema)
|
||||||
let { includeReadOnly, includeWriteOnly } = config
|
let { includeReadOnly, includeWriteOnly } = config
|
||||||
|
xml = xml || {}
|
||||||
|
let { name, prefix, namespace } = xml
|
||||||
|
let displayName
|
||||||
|
let res = {}
|
||||||
|
|
||||||
|
// set xml naming and attributes
|
||||||
if(example !== undefined) {
|
if(respectXML) {
|
||||||
return deeplyStripKey(example, "$$ref", (val) => {
|
name = name || "notagname"
|
||||||
// do a couple of quick sanity tests to ensure the value
|
// add prefix to name if exists
|
||||||
// looks like a $$ref that swagger-client generates.
|
displayName = (prefix ? prefix + ":" : "") + name
|
||||||
return typeof val === "string" && val.indexOf("#") > -1
|
if ( namespace ) {
|
||||||
})
|
//add prefix to namespace if exists
|
||||||
|
let namespacePrefix = prefix ? ( "xmlns:" + prefix ) : "xmlns"
|
||||||
|
_attr[namespacePrefix] = namespace
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!type) {
|
// init xml default response sample obj
|
||||||
if(properties) {
|
if(respectXML) {
|
||||||
|
res[displayName] = []
|
||||||
|
}
|
||||||
|
|
||||||
|
const usePlainValue = exampleOverride !== undefined || example !== undefined || schema && schema.default !== undefined
|
||||||
|
|
||||||
|
const hasOneOf = !usePlainValue && schema && schema.oneOf && schema.oneOf.length > 0
|
||||||
|
const hasAnyOf = !usePlainValue && schema && schema.anyOf && schema.anyOf.length > 0
|
||||||
|
if(!usePlainValue && (hasOneOf || hasAnyOf)) {
|
||||||
|
const someSchema = hasOneOf
|
||||||
|
? schema.oneOf[0]
|
||||||
|
: schema.anyOf[0]
|
||||||
|
liftSampleHelper(schema, someSchema)
|
||||||
|
return sampleFromSchemaGeneric(someSchema, config, undefined, respectXML)
|
||||||
|
}
|
||||||
|
|
||||||
|
// try recover missing type
|
||||||
|
if(schema && !type) {
|
||||||
|
if(properties || additionalProperties) {
|
||||||
type = "object"
|
type = "object"
|
||||||
} else if(items) {
|
} else if(items) {
|
||||||
type = "array"
|
type = "array"
|
||||||
} else {
|
} else if(!usePlainValue){
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add to result helper init for xml or json
|
||||||
|
const props = objectify(properties)
|
||||||
|
let addPropertyToResult
|
||||||
|
if(respectXML) {
|
||||||
|
addPropertyToResult = (propName, overrideE = undefined) => {
|
||||||
|
if(schema) {
|
||||||
|
// case it is an xml attribute
|
||||||
|
props[propName].xml = props[propName].xml || {}
|
||||||
|
|
||||||
|
if (props[propName].xml.attribute) {
|
||||||
|
const enumAttrVal = Array.isArray(props[propName].enum)
|
||||||
|
? props[propName].enum[0]
|
||||||
|
: undefined
|
||||||
|
const attrExample = props[propName].example
|
||||||
|
const attrDefault = props[propName].default
|
||||||
|
|
||||||
|
if(attrExample !== undefined) {
|
||||||
|
_attr[props[propName].xml.name || propName] = attrExample
|
||||||
|
} else if(attrDefault !== undefined) {
|
||||||
|
_attr[props[propName].xml.name || propName] = attrDefault
|
||||||
|
} else if(enumAttrVal !== undefined) {
|
||||||
|
_attr[props[propName].xml.name || propName] = enumAttrVal
|
||||||
|
} else {
|
||||||
|
_attr[props[propName].xml.name || propName] = primitive(props[propName])
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
props[propName].xml.name = props[propName].xml.name || propName
|
||||||
|
}
|
||||||
|
|
||||||
|
let t = sampleFromSchemaGeneric(schema && props[propName] || undefined, config, overrideE, respectXML)
|
||||||
|
if (Array.isArray(t)) {
|
||||||
|
res[displayName] = res[displayName].concat(t)
|
||||||
|
} else {
|
||||||
|
res[displayName].push(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addPropertyToResult = (propName, overrideE) =>
|
||||||
|
res[propName] = sampleFromSchemaGeneric(props[propName], config, overrideE, respectXML)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for plain value and if found use it to generate sample from it
|
||||||
|
if(usePlainValue) {
|
||||||
|
let sample
|
||||||
|
if(exampleOverride !== undefined) {
|
||||||
|
sample = sanitizeRef(exampleOverride)
|
||||||
|
} else if(example !== undefined) {
|
||||||
|
sample = sanitizeRef(example)
|
||||||
|
} else {
|
||||||
|
sample = sanitizeRef(schema.default)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if json just return
|
||||||
|
if(!respectXML) {
|
||||||
|
return sample
|
||||||
|
}
|
||||||
|
|
||||||
|
// recover missing type
|
||||||
|
if(!schema) {
|
||||||
|
type = Array.isArray(sample) ? "array" : typeof sample
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate xml sample recursively for array case
|
||||||
|
if(type === "array") {
|
||||||
|
if (!Array.isArray(sample)) {
|
||||||
|
sample = [sample]
|
||||||
|
}
|
||||||
|
const itemSchema = schema
|
||||||
|
? schema.items
|
||||||
|
: undefined
|
||||||
|
if(itemSchema) {
|
||||||
|
itemSchema.xml = itemSchema.xml || xml || {}
|
||||||
|
itemSchema.xml.name = itemSchema.xml.name || xml.name
|
||||||
|
}
|
||||||
|
const itemSamples = sample
|
||||||
|
.map(s => sampleFromSchemaGeneric(itemSchema, config, s, respectXML))
|
||||||
|
if(xml.wrapped) {
|
||||||
|
res[displayName] = itemSamples
|
||||||
|
if (!isEmpty(_attr)) {
|
||||||
|
res[displayName].push({_attr: _attr})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res = itemSamples
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate xml sample recursively for object case
|
||||||
|
if(type === "object") {
|
||||||
|
for (let propName in sample) {
|
||||||
|
if (!sample.hasOwnProperty(propName)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (schema && props[propName] && props[propName].readOnly && !includeReadOnly) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (schema && props[propName] && props[propName].writeOnly && !includeWriteOnly) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (schema && props[propName] && props[propName].xml && props[propName].xml.attribute) {
|
||||||
|
_attr[props[propName].xml.name || propName] = example[propName]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addPropertyToResult(propName, sample[propName])
|
||||||
|
}
|
||||||
|
if (!isEmpty(_attr)) {
|
||||||
|
res[displayName].push({_attr: _attr})
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
res[displayName] = !isEmpty(_attr) ? [{_attr: _attr}, sample] : sample
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// use schema to generate sample
|
||||||
|
|
||||||
if(type === "object") {
|
if(type === "object") {
|
||||||
let props = objectify(properties)
|
for (let propName in props) {
|
||||||
let obj = {}
|
if (!props.hasOwnProperty(propName)) {
|
||||||
for (var name in props) {
|
|
||||||
if ( props[name] && props[name].deprecated ) {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if ( props[name] && props[name].readOnly && !includeReadOnly ) {
|
if ( props[propName] && props[propName].deprecated ) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if ( props[name] && props[name].writeOnly && !includeWriteOnly ) {
|
if ( props[propName] && props[propName].readOnly && !includeReadOnly ) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
obj[name] = sampleFromSchema(props[name], config)
|
if ( props[propName] && props[propName].writeOnly && !includeWriteOnly ) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addPropertyToResult(propName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( additionalProperties === true ) {
|
if ( additionalProperties === true ) {
|
||||||
obj.additionalProp1 = {}
|
if(respectXML) {
|
||||||
|
res[displayName].push({additionalProp: "Anything can be here"})
|
||||||
|
} else {
|
||||||
|
res.additionalProp1 = {}
|
||||||
|
}
|
||||||
} else if ( additionalProperties ) {
|
} else if ( additionalProperties ) {
|
||||||
let additionalProps = objectify(additionalProperties)
|
const additionalProps = objectify(additionalProperties)
|
||||||
let additionalPropVal = sampleFromSchema(additionalProps, config)
|
const additionalPropSample = sampleFromSchemaGeneric(additionalProps, config, undefined, respectXML)
|
||||||
|
|
||||||
for (let i = 1; i < 4; i++) {
|
if(respectXML && additionalProps.xml && additionalProps.xml.name && additionalProps.xml.name !== "notagname")
|
||||||
obj["additionalProp" + i] = additionalPropVal
|
{
|
||||||
|
res[displayName].push(additionalPropSample)
|
||||||
|
} else {
|
||||||
|
for (let i = 1; i < 4; i++) {
|
||||||
|
if(respectXML) {
|
||||||
|
const temp = {}
|
||||||
|
temp["additionalProp" + i] = additionalPropSample["notagname"]
|
||||||
|
res[displayName].push(temp)
|
||||||
|
} else {
|
||||||
|
res["additionalProp" + i] = additionalPropSample
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return obj
|
if (respectXML && _attr) {
|
||||||
|
res[displayName].push({_attr: _attr})
|
||||||
|
}
|
||||||
|
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
if(type === "array") {
|
if(type === "array") {
|
||||||
|
let sampleArray
|
||||||
|
if(respectXML) {
|
||||||
|
items.xml = items.xml || schema.xml || {}
|
||||||
|
items.xml.name = items.xml.name || xml.name
|
||||||
|
}
|
||||||
if(Array.isArray(items.anyOf)) {
|
if(Array.isArray(items.anyOf)) {
|
||||||
return items.anyOf.map(i => sampleFromSchema(i, config))
|
sampleArray = items.anyOf.map(i => sampleFromSchemaGeneric(liftSampleHelper(items, i), config, undefined, respectXML))
|
||||||
|
} else if(Array.isArray(items.oneOf)) {
|
||||||
|
sampleArray = items.oneOf.map(i => sampleFromSchemaGeneric(liftSampleHelper(items, i), config, undefined, respectXML))
|
||||||
|
} else if(!respectXML || respectXML && xml.wrapped) {
|
||||||
|
sampleArray = [sampleFromSchemaGeneric(items, config, undefined, respectXML)]
|
||||||
|
} else {
|
||||||
|
return sampleFromSchemaGeneric(items, config, undefined, respectXML)
|
||||||
}
|
}
|
||||||
|
if(respectXML && xml.wrapped) {
|
||||||
if(Array.isArray(items.oneOf)) {
|
res[displayName] = sampleArray
|
||||||
return items.oneOf.map(i => sampleFromSchema(i, config))
|
if (!isEmpty(_attr)) {
|
||||||
|
res[displayName].push({_attr: _attr})
|
||||||
|
}
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
return sampleArray
|
||||||
return [ sampleFromSchema(items, config) ]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(schema["enum"]) {
|
let value
|
||||||
if(schema["default"])
|
if (schema && Array.isArray(schema.enum)) {
|
||||||
return schema["default"]
|
//display enum first value
|
||||||
return normalizeArray(schema["enum"])[0]
|
value = normalizeArray(schema.enum)[0]
|
||||||
|
} else if(schema) {
|
||||||
|
// display schema default
|
||||||
|
value = primitive(schema)
|
||||||
|
} else {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === "file") {
|
if (type === "file") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return primitive(schema)
|
if(respectXML) {
|
||||||
|
res[displayName] = !isEmpty(_attr) ? [{_attr: _attr}, value] : value
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
export const inferSchema = (thing) => {
|
export const inferSchema = (thing) => {
|
||||||
@@ -119,162 +328,16 @@ export const inferSchema = (thing) => {
|
|||||||
return thing // Hopefully this will have something schema like in it... `type` for example
|
return thing // Hopefully this will have something schema like in it... `type` for example
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const createXMLExample = (schema, config={}, o) => {
|
||||||
export const sampleXmlFromSchema = (schema, config={}) => {
|
const json = sampleFromSchemaGeneric(schema, config, o, true)
|
||||||
let objectifySchema = deepAssign({}, objectify(schema))
|
|
||||||
let { type, properties, additionalProperties, items, example } = objectifySchema
|
|
||||||
let { includeReadOnly, includeWriteOnly } = config
|
|
||||||
let defaultValue = objectifySchema.default
|
|
||||||
let res = {}
|
|
||||||
let _attr = {}
|
|
||||||
let { xml } = schema
|
|
||||||
let { name, prefix, namespace } = xml
|
|
||||||
let enumValue = objectifySchema.enum
|
|
||||||
let displayName, value
|
|
||||||
|
|
||||||
if(!type) {
|
|
||||||
if(properties || additionalProperties) {
|
|
||||||
type = "object"
|
|
||||||
} else if(items) {
|
|
||||||
type = "array"
|
|
||||||
} else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
name = name || "notagname"
|
|
||||||
// add prefix to name if exists
|
|
||||||
displayName = (prefix ? prefix + ":" : "") + name
|
|
||||||
if ( namespace ) {
|
|
||||||
//add prefix to namespace if exists
|
|
||||||
let namespacePrefix = prefix ? ( "xmlns:" + prefix ) : "xmlns"
|
|
||||||
_attr[namespacePrefix] = namespace
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type === "array") {
|
|
||||||
if (items) {
|
|
||||||
items.xml = items.xml || xml || {}
|
|
||||||
items.xml.name = items.xml.name || xml.name
|
|
||||||
|
|
||||||
if (xml.wrapped) {
|
|
||||||
res[displayName] = []
|
|
||||||
if (Array.isArray(example)) {
|
|
||||||
example.forEach((v)=>{
|
|
||||||
items.example = v
|
|
||||||
res[displayName].push(sampleXmlFromSchema(items, config))
|
|
||||||
})
|
|
||||||
} else if (Array.isArray(defaultValue)) {
|
|
||||||
defaultValue.forEach((v)=>{
|
|
||||||
items.default = v
|
|
||||||
res[displayName].push(sampleXmlFromSchema(items, config))
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
res[displayName] = [sampleXmlFromSchema(items, config)]
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_attr) {
|
|
||||||
res[displayName].push({_attr: _attr})
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
let _res = []
|
|
||||||
|
|
||||||
if (Array.isArray(example)) {
|
|
||||||
example.forEach((v)=>{
|
|
||||||
items.example = v
|
|
||||||
_res.push(sampleXmlFromSchema(items, config))
|
|
||||||
})
|
|
||||||
return _res
|
|
||||||
} else if (Array.isArray(defaultValue)) {
|
|
||||||
defaultValue.forEach((v)=>{
|
|
||||||
items.default = v
|
|
||||||
_res.push(sampleXmlFromSchema(items, config))
|
|
||||||
})
|
|
||||||
return _res
|
|
||||||
}
|
|
||||||
|
|
||||||
return sampleXmlFromSchema(items, config)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type === "object") {
|
|
||||||
let props = objectify(properties)
|
|
||||||
res[displayName] = []
|
|
||||||
example = example || {}
|
|
||||||
|
|
||||||
for (let propName in props) {
|
|
||||||
if (!props.hasOwnProperty(propName)) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if ( props[propName].readOnly && !includeReadOnly ) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if ( props[propName].writeOnly && !includeWriteOnly ) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
props[propName].xml = props[propName].xml || {}
|
|
||||||
|
|
||||||
if (props[propName].xml.attribute) {
|
|
||||||
let enumAttrVal = Array.isArray(props[propName].enum) && props[propName].enum[0]
|
|
||||||
let attrExample = props[propName].example
|
|
||||||
let attrDefault = props[propName].default
|
|
||||||
_attr[props[propName].xml.name || propName] = attrExample!== undefined && attrExample
|
|
||||||
|| example[propName] !== undefined && example[propName] || attrDefault !== undefined && attrDefault
|
|
||||||
|| enumAttrVal || primitive(props[propName])
|
|
||||||
} else {
|
|
||||||
props[propName].xml.name = props[propName].xml.name || propName
|
|
||||||
if(props[propName].example === undefined && example[propName] !== undefined) {
|
|
||||||
props[propName].example = example[propName]
|
|
||||||
}
|
|
||||||
let t = sampleXmlFromSchema(props[propName])
|
|
||||||
if (Array.isArray(t)) {
|
|
||||||
res[displayName] = res[displayName].concat(t)
|
|
||||||
} else {
|
|
||||||
res[displayName].push(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (additionalProperties === true) {
|
|
||||||
res[displayName].push({additionalProp: "Anything can be here"})
|
|
||||||
} else if (additionalProperties) {
|
|
||||||
res[displayName].push({additionalProp: primitive(additionalProperties)})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_attr) {
|
|
||||||
res[displayName].push({_attr: _attr})
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
if (example !== undefined) {
|
|
||||||
value = example
|
|
||||||
} else if (defaultValue !== undefined) {
|
|
||||||
//display example if exists
|
|
||||||
value = defaultValue
|
|
||||||
} else if (Array.isArray(enumValue)) {
|
|
||||||
//display enum first value
|
|
||||||
value = enumValue[0]
|
|
||||||
} else {
|
|
||||||
//set default value
|
|
||||||
value = primitive(schema)
|
|
||||||
}
|
|
||||||
|
|
||||||
res[displayName] = _attr ? [{_attr: _attr}, value] : value
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createXMLExample(schema, config) {
|
|
||||||
let json = sampleXmlFromSchema(schema, config)
|
|
||||||
if (!json) { return }
|
if (!json) { return }
|
||||||
|
|
||||||
return XML(json, { declaration: true, indent: "\t" })
|
return XML(json, { declaration: true, indent: "\t" })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const sampleFromSchema = (schema, config={}, o) =>
|
||||||
|
sampleFromSchemaGeneric(schema, config, o, false)
|
||||||
|
|
||||||
export const memoizedCreateXMLExample = memoizee(createXMLExample)
|
export const memoizedCreateXMLExample = memoizee(createXMLExample)
|
||||||
|
|
||||||
export const memoizedSampleFromSchema = memoizee(sampleFromSchema)
|
export const memoizedSampleFromSchema = memoizee(sampleFromSchema)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/*
|
/*
|
||||||
ATTENTION! This file (but not the functions within) is deprecated.
|
ATTENTION! This file (but not the functions within) is deprecated.
|
||||||
|
|
||||||
You should probably add a new file to `./helpers/` instead of adding a new
|
You should probably add a new file to `./helpers/` instead of adding a new
|
||||||
@@ -133,7 +133,7 @@ export function createObjWithHashedKeys (fdObj) {
|
|||||||
trackKeys[pair[0]].length += 1
|
trackKeys[pair[0]].length += 1
|
||||||
let hashedKeyCurrent = `${pair[0]}${hashIdx}${trackKeys[pair[0]].length}`
|
let hashedKeyCurrent = `${pair[0]}${hashIdx}${trackKeys[pair[0]].length}`
|
||||||
newObj[hashedKeyCurrent] = pair[1]
|
newObj[hashedKeyCurrent] = pair[1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return newObj
|
return newObj
|
||||||
}
|
}
|
||||||
@@ -263,13 +263,13 @@ export function extractFileNameFromContentDispositionHeader(value){
|
|||||||
/filename="([^;]*);?"/i,
|
/filename="([^;]*);?"/i,
|
||||||
/filename=([^;]*);?/i
|
/filename=([^;]*);?/i
|
||||||
]
|
]
|
||||||
|
|
||||||
let responseFilename
|
let responseFilename
|
||||||
patterns.some(regex => {
|
patterns.some(regex => {
|
||||||
responseFilename = regex.exec(value)
|
responseFilename = regex.exec(value)
|
||||||
return responseFilename !== null
|
return responseFilename !== null
|
||||||
})
|
})
|
||||||
|
|
||||||
if (responseFilename !== null && responseFilename.length > 1) {
|
if (responseFilename !== null && responseFilename.length > 1) {
|
||||||
try {
|
try {
|
||||||
return decodeURIComponent(responseFilename[1])
|
return decodeURIComponent(responseFilename[1])
|
||||||
@@ -541,8 +541,8 @@ export const validateParam = (param, value, { isOAS3 = false, bypassRequiredChec
|
|||||||
return errors
|
return errors
|
||||||
}
|
}
|
||||||
|
|
||||||
const getXmlSampleSchema = (schema, config) => {
|
const getXmlSampleSchema = (schema, config, exampleOverride) => {
|
||||||
if (!schema.xml || !schema.xml.name) {
|
if (schema && (!schema.xml || !schema.xml.name)) {
|
||||||
schema.xml = schema.xml || {}
|
schema.xml = schema.xml || {}
|
||||||
|
|
||||||
if (schema.$$ref) {
|
if (schema.$$ref) {
|
||||||
@@ -554,7 +554,7 @@ const getXmlSampleSchema = (schema, config) => {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return memoizedCreateXMLExample(schema, config)
|
return memoizedCreateXMLExample(schema, config, exampleOverride)
|
||||||
}
|
}
|
||||||
|
|
||||||
const shouldStringifyTypesConfig = [
|
const shouldStringifyTypesConfig = [
|
||||||
@@ -566,8 +566,8 @@ const shouldStringifyTypesConfig = [
|
|||||||
|
|
||||||
const defaultStringifyTypes = ["object"]
|
const defaultStringifyTypes = ["object"]
|
||||||
|
|
||||||
const getStringifiedSampleForSchema = (schema, config, contentType) => {
|
const getStringifiedSampleForSchema = (schema, config, contentType, exampleOverride) => {
|
||||||
const res = memoizedSampleFromSchema(schema, config)
|
const res = memoizedSampleFromSchema(schema, config, exampleOverride)
|
||||||
const resType = typeof res
|
const resType = typeof res
|
||||||
|
|
||||||
const typesToStringify = shouldStringifyTypesConfig.reduce(
|
const typesToStringify = shouldStringifyTypesConfig.reduce(
|
||||||
@@ -581,12 +581,17 @@ const getStringifiedSampleForSchema = (schema, config, contentType) => {
|
|||||||
: res
|
: res
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getSampleSchema = (schema, contentType="", config={}) => {
|
export const getSampleSchema = (schema, contentType="", config={}, exampleOverride = undefined) => {
|
||||||
|
if(schema && isFunc(schema.toJS))
|
||||||
|
schema = schema.toJS()
|
||||||
|
if(exampleOverride && isFunc(exampleOverride.toJS))
|
||||||
|
exampleOverride = exampleOverride.toJS()
|
||||||
|
|
||||||
if (/xml/.test(contentType)) {
|
if (/xml/.test(contentType)) {
|
||||||
return getXmlSampleSchema(schema, config)
|
return getXmlSampleSchema(schema, config, exampleOverride)
|
||||||
}
|
}
|
||||||
|
|
||||||
return getStringifiedSampleForSchema(schema, config, contentType)
|
return getStringifiedSampleForSchema(schema, config, contentType, exampleOverride)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const parseSearch = () => {
|
export const parseSearch = () => {
|
||||||
@@ -766,7 +771,7 @@ export function paramToIdentifier(param, { returnAll = false, allowHashes = true
|
|||||||
}
|
}
|
||||||
const paramName = param.get("name")
|
const paramName = param.get("name")
|
||||||
const paramIn = param.get("in")
|
const paramIn = param.get("in")
|
||||||
|
|
||||||
let generatedIdentifiers = []
|
let generatedIdentifiers = []
|
||||||
|
|
||||||
// Generate identifiers in order of most to least specificity
|
// Generate identifiers in order of most to least specificity
|
||||||
@@ -774,7 +779,7 @@ export function paramToIdentifier(param, { returnAll = false, allowHashes = true
|
|||||||
if (param && param.hashCode && paramIn && paramName && allowHashes) {
|
if (param && param.hashCode && paramIn && paramName && allowHashes) {
|
||||||
generatedIdentifiers.push(`${paramIn}.${paramName}.hash-${param.hashCode()}`)
|
generatedIdentifiers.push(`${paramIn}.${paramName}.hash-${param.hashCode()}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(paramIn && paramName) {
|
if(paramIn && paramName) {
|
||||||
generatedIdentifiers.push(`${paramIn}.${paramName}`)
|
generatedIdentifiers.push(`${paramIn}.${paramName}`)
|
||||||
}
|
}
|
||||||
|
|||||||
43
test/e2e-cypress/static/documents/bugs/4943.yaml
Normal file
43
test/e2e-cypress/static/documents/bugs/4943.yaml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
openapi: 3.0.0
|
||||||
|
info:
|
||||||
|
description: Test API
|
||||||
|
version: v1
|
||||||
|
title: Test API
|
||||||
|
tags:
|
||||||
|
- name: Test
|
||||||
|
description: Test API
|
||||||
|
servers:
|
||||||
|
- url: /v1
|
||||||
|
paths:
|
||||||
|
/test:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Test
|
||||||
|
summary: Test endpoint
|
||||||
|
description: Test
|
||||||
|
operationId: postTest
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Returns response
|
||||||
|
content:
|
||||||
|
application/xml:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/test'
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
test:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
a:
|
||||||
|
type: string
|
||||||
|
b:
|
||||||
|
type: integer
|
||||||
|
c:
|
||||||
|
oneOf:
|
||||||
|
- type: object
|
||||||
|
- type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
- type: boolean
|
||||||
|
- type: integer
|
||||||
|
- type: number
|
||||||
85
test/e2e-cypress/static/documents/bugs/6540.yaml
Normal file
85
test/e2e-cypress/static/documents/bugs/6540.yaml
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
openapi: 3.0.0
|
||||||
|
info:
|
||||||
|
description: Test API
|
||||||
|
version: v1
|
||||||
|
title: Test API
|
||||||
|
tags:
|
||||||
|
- name: Test
|
||||||
|
description: Test API
|
||||||
|
servers:
|
||||||
|
- url: /v1
|
||||||
|
paths:
|
||||||
|
/test:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Test
|
||||||
|
summary: Test endpoint
|
||||||
|
description: Test
|
||||||
|
operationId: postTest
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Returns response
|
||||||
|
content:
|
||||||
|
application/xml:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/test'
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
test:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
a:
|
||||||
|
type: string
|
||||||
|
b:
|
||||||
|
type: integer
|
||||||
|
c:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Things'
|
||||||
|
d:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
anyOf:
|
||||||
|
- $ref: '#/components/schemas/TextObject'
|
||||||
|
- $ref: '#/components/schemas/ImageObject'
|
||||||
|
|
||||||
|
|
||||||
|
Things:
|
||||||
|
type: object
|
||||||
|
oneOf:
|
||||||
|
- $ref: '#/components/schemas/TextObject'
|
||||||
|
- $ref: '#/components/schemas/ImageObject'
|
||||||
|
|
||||||
|
TextObject:
|
||||||
|
required:
|
||||||
|
- data
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
objectType:
|
||||||
|
type: string
|
||||||
|
example: Text
|
||||||
|
xml:
|
||||||
|
name: ObjectType
|
||||||
|
data:
|
||||||
|
type: string
|
||||||
|
example: This is a text
|
||||||
|
xml:
|
||||||
|
name: Data
|
||||||
|
description: Contains a text
|
||||||
|
|
||||||
|
ImageObject:
|
||||||
|
required:
|
||||||
|
- data
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
objectType:
|
||||||
|
type: string
|
||||||
|
example: image
|
||||||
|
xml:
|
||||||
|
name: ObjectType
|
||||||
|
data:
|
||||||
|
type: string
|
||||||
|
example: This is a image
|
||||||
|
xml:
|
||||||
|
name: Data
|
||||||
|
description: Contains a image
|
||||||
20
test/e2e-cypress/tests/bugs/4943.js
Normal file
20
test/e2e-cypress/tests/bugs/4943.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
describe("#4943: XML example not rendered correctly with oneOf", () => {
|
||||||
|
it("should render integer property correctly", () => {
|
||||||
|
cy
|
||||||
|
.visit("/?url=/documents/bugs/4943.yaml")
|
||||||
|
.get("#operations-Test-postTest")
|
||||||
|
.click()
|
||||||
|
.get(".microlight")
|
||||||
|
.contains("<b>0</b>")
|
||||||
|
})
|
||||||
|
it("should render oneOf property correctly", () => {
|
||||||
|
cy
|
||||||
|
.visit("/?url=/documents/bugs/4943.yaml")
|
||||||
|
.get("#operations-Test-postTest")
|
||||||
|
.click()
|
||||||
|
.get(".try-out__btn")
|
||||||
|
.click()
|
||||||
|
.get(".microlight")
|
||||||
|
.contains("<c>\n\t</c>")
|
||||||
|
})
|
||||||
|
})
|
||||||
11
test/e2e-cypress/tests/bugs/6540.js
Normal file
11
test/e2e-cypress/tests/bugs/6540.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
describe("#6540: XML example not rendered correctly with oneOf", () => {
|
||||||
|
it("should render xml like json", () => {
|
||||||
|
const expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<test>\n\t<a>string</a>\n\t<b>0</b>\n\t<c>\n\t\t<ObjectType>Text</ObjectType>\n\t\t<Data>This is a text</Data>\n\t</c>\n\t<c>\n\t\t<ObjectType>image</ObjectType>\n\t\t<Data>This is a image</Data>\n\t</c>\n\t<d>\n\t\t<ObjectType>Text</ObjectType>\n\t\t<Data>This is a text</Data>\n\t</d>\n\t<d>\n\t\t<ObjectType>image</ObjectType>\n\t\t<Data>This is a image</Data>\n\t</d>\n</test>"
|
||||||
|
cy
|
||||||
|
.visit("/?url=/documents/bugs/6540.yaml")
|
||||||
|
.get("#operations-Test-postTest")
|
||||||
|
.click()
|
||||||
|
.get(".microlight")
|
||||||
|
.contains(expected)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -512,6 +512,26 @@ describe("sampleFromSchema", () => {
|
|||||||
expect(sampleFromSchema(definition)).toEqual(expected)
|
expect(sampleFromSchema(definition)).toEqual(expected)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should use overrideExample when defined", () => {
|
||||||
|
const definition = {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
foo: {
|
||||||
|
type: "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
example: {
|
||||||
|
foo: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const expected = {
|
||||||
|
foo: "override"
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(sampleFromSchema(definition, {}, expected)).toEqual(expected)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("createXMLExample", function () {
|
describe("createXMLExample", function () {
|
||||||
@@ -1337,7 +1357,7 @@ describe("createXMLExample", function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("returns object with additional props", function () {
|
it("returns object with additional props", function () {
|
||||||
let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<animals>\n\t<dog>string</dog>\n\t<additionalProp>string</additionalProp>\n</animals>"
|
let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<animals>\n\t<dog>string</dog>\n\t<additionalProp1>string</additionalProp1>\n\t<additionalProp2>string</additionalProp2>\n\t<additionalProp3>string</additionalProp3>\n</animals>"
|
||||||
let definition = {
|
let definition = {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: {
|
properties: {
|
||||||
@@ -1394,7 +1414,7 @@ describe("createXMLExample", function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("returns object with additional props with no type passed", function () {
|
it("returns object with additional props with no type passed", function () {
|
||||||
let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<animals>\n\t<additionalProp>string</additionalProp>\n</animals>"
|
let expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<animals>\n\t<additionalProp1>string</additionalProp1>\n\t<additionalProp2>string</additionalProp2>\n\t<additionalProp3>string</additionalProp3>\n</animals>"
|
||||||
let definition = {
|
let definition = {
|
||||||
additionalProperties: {
|
additionalProperties: {
|
||||||
type: "string"
|
type: "string"
|
||||||
@@ -1406,5 +1426,34 @@ describe("createXMLExample", function () {
|
|||||||
|
|
||||||
expect(sut(definition)).toEqual(expected)
|
expect(sut(definition)).toEqual(expected)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
it("should use overrideExample when defined", () => {
|
||||||
|
const expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<bar>\n\t<foo>override</foo>\n</bar>"
|
||||||
|
|
||||||
|
const definition = {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
foo: {
|
||||||
|
type: "string",
|
||||||
|
xml: {
|
||||||
|
name: "foo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
example: {
|
||||||
|
foo: null
|
||||||
|
},
|
||||||
|
xml: {
|
||||||
|
name: "bar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const overrideExample = {
|
||||||
|
foo: "override"
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(sut(definition, {}, overrideExample)).toEqual(expected)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user