UNPKG

openapi-explorer

Version:

OpenAPI Explorer - API viewer with dynamically generated components, documentation, and interaction console

718 lines (710 loc) 31.5 kB
"use strict"; exports.__esModule = true; exports.generateExample = generateExample; exports.getExampleValuesFromSchema = getExampleValuesFromSchema; exports.getSampleValueByType = getSampleValueByType; exports.getTypeInfo = getTypeInfo; exports.isPatternProperty = isPatternProperty; exports.schemaInObjectNotation = schemaInObjectNotation; var _lodash = _interopRequireDefault(require("lodash.clonedeep")); var _lodash2 = _interopRequireDefault(require("lodash.merge")); var _randexp = _interopRequireDefault(require("randexp")); var _xml = _interopRequireDefault(require("./xml/xml.js")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } // When the type is not known for a property set the displayed type to be this: const IS_MISSING_TYPE_INFO_TYPE = ''; const EXAMPLE_VALUE_FOR_MISSING_TYPE = ''; /* Generates an schema object containing type and constraint info */ function getTypeInfo(parameter, options = { includeNulls: false, enableExampleGeneration: false }) { var _schema$items, _schema$default; if (!parameter) { return undefined; } const schema = Object.assign({}, parameter, parameter.schema); let dataType = IS_MISSING_TYPE_INFO_TYPE; let format = schema.format || ((_schema$items = schema.items) === null || _schema$items === void 0 ? void 0 : _schema$items.format) || ''; if (schema.type || schema.const) { if (!schema.type && schema.const) { schema.type = 'const'; } const arraySchema = Array.isArray(schema.type) ? schema.type : typeof schema.type === 'string' ? schema.type.split('┃') : schema.type; dataType = Array.isArray(arraySchema) ? arraySchema.filter(s => s !== 'null' || options.includeNulls).join('┃') : schema.type; ['string', 'number'].forEach(type => { dataType = dataType.replace(type, typeof schema.const !== 'undefined' && 'const' || schema.enum && `${type} enum` || schema.format || type); }); if (schema.nullable && options.includeNulls) { dataType += '┃null'; } if (dataType.includes('┃null') && schema.format) { format += '┃null'; } } const examples = schema.examples || schema.example || (options === null || options === void 0 ? void 0 : options.enableExampleGeneration) && getSampleValueByType(schema, null) || ''; const info = { type: dataType, format, cssType: dataType.replace(/┃.*/g, '').replace(/[^a-zA-Z0-9+\s]/g, '').toLowerCase(), pattern: schema.pattern && !schema.enum ? schema.pattern.replace(/(^\^)|(\$$)/g, '') : '', readOrWriteOnly: schema.readOnly && '🆁' || schema.writeOnly && '🆆' || '', deprecated: !!schema.deprecated, example: examples || '', default: (_schema$default = schema.default) !== null && _schema$default !== void 0 ? _schema$default : '', title: schema.title || '', description: schema.description || '', constraints: [], allowedValues: typeof schema.const !== 'undefined' && [schema.const] || schema.enum && [].concat(schema.nullable || !schema.required ? null : []).concat(schema.enum) || null, arrayType: '' }; if (dataType === 'array' && schema.items) { var _ref, _schema$items$default; const arrayItemType = schema.items.type; const arrayItemDefault = (_ref = (_schema$items$default = schema.items.default) !== null && _schema$items$default !== void 0 ? _schema$items$default : schema.default) !== null && _ref !== void 0 ? _ref : ''; info.arrayType = `${schema.type} of ${Array.isArray(arrayItemType) ? arrayItemType.join('') : arrayItemType}`; info.default = arrayItemDefault; info.allowedValues = typeof schema.const !== 'undefined' && [schema.const] || schema.items.enum || null; } if (schema.uniqueItems) { info.constraints.push('Requires unique items'); } if (dataType.match(/integer|number/g)) { var _schema$minimum, _schema$maximum; const minimum = (_schema$minimum = schema.minimum) !== null && _schema$minimum !== void 0 ? _schema$minimum : schema.exclusiveMinimum; const maximum = (_schema$maximum = schema.maximum) !== null && _schema$maximum !== void 0 ? _schema$maximum : schema.exclusiveMaximum; const leftBound = schema.minimum !== undefined ? '[' : '('; const rightBound = schema.maximum !== undefined ? ']' : ')'; if (typeof minimum === 'number' || typeof maximum === 'number') { info.constraints.push(`Range: ${leftBound}${minimum !== null && minimum !== void 0 ? minimum : ''},${maximum !== null && maximum !== void 0 ? maximum : ''}${rightBound}`); } if (schema.multipleOf !== undefined) { info.constraints.push(`Multiples: ${schema.multipleOf}`); } } if (dataType.match(/string/g)) { if (schema.minLength !== undefined && schema.maxLength !== undefined) { info.constraints.push(`Min length: ${schema.minLength}, Max length: ${schema.maxLength}`); } else if (schema.minLength !== undefined) { info.constraints.push(`Min length: ${schema.minLength}`); } else if (schema.maxLength !== undefined) { info.constraints.push(`Max length: ${schema.maxLength}`); } } info.html = JSON.stringify({ type: info.type, format: info.format, cssType: info.cssType, readOrWriteOnly: info.readOrWriteOnly, constraints: info.constraints, defaultValue: info.default, example: info.example, allowedValues: info.allowedValues, pattern: info.pattern, schemaDescription: info.description, schemaTitle: info.title, deprecated: info.deprecated }); return info; } function getSampleValueByType(schemaObj, fallbackPropertyName, skipExampleIds) { var _schemaObj$type; const propertyName = fallbackPropertyName || 'string'; if (schemaObj.default) { return schemaObj.default; } if (Object.keys(schemaObj).length === 0) { return EXAMPLE_VALUE_FOR_MISSING_TYPE; } if (schemaObj.circularReference) { return schemaObj.$ref; } const typeValue = Array.isArray(schemaObj.type) ? schemaObj.type.filter(t => t !== 'null')[0] : (_schemaObj$type = schemaObj.type) !== null && _schemaObj$type !== void 0 ? _schemaObj$type : ''; if (typeof schemaObj.const !== 'undefined') { return schemaObj.const; } if (schemaObj.enum) { return schemaObj.enum[0]; } if (typeValue.match(/^integer|^number/g)) { const multipleOf = Number.isNaN(Number(schemaObj.multipleOf)) ? undefined : Number(schemaObj.multipleOf); const maximum = Number.isNaN(Number(schemaObj.maximum)) ? undefined : Number(schemaObj.maximum); const minimumPossibleVal = Number.isNaN(Number(schemaObj.minimum)) ? Number.isNaN(Number(schemaObj.exclusiveMinimum)) ? maximum || 0 : Number(schemaObj.exclusiveMinimum) + (typeValue.startsWith('integer') ? 1 : 0.001) : Number(schemaObj.minimum); const finalVal = multipleOf ? multipleOf >= minimumPossibleVal ? multipleOf : minimumPossibleVal % multipleOf === 0 ? minimumPossibleVal : Math.ceil(minimumPossibleVal / multipleOf) * multipleOf : minimumPossibleVal; return finalVal; } if (typeValue.match(/^boolean/g)) { return false; } if (typeValue.match(/^null/g)) { return null; } if (skipExampleIds && typeValue.match(/^string/g) && propertyName.match(/id$/i)) { return ''; } if (typeValue.match(/^string/g)) { if (schemaObj.pattern) { const examplePattern = schemaObj.pattern.replace(/[+*](?![^\][]*[\]])/g, '{8}').replace(/\{\d*,(\d+)?\}/g, '{8}'); try { return new _randexp.default(examplePattern).gen() || propertyName; } catch (error) { return propertyName; } } if (schemaObj.format) { switch (schemaObj.format.toLowerCase()) { case 'url': return 'https://example.com'; case 'uri': return 'urn:namespace:type:example/resource'; case 'date': return new Date().toISOString().split('T')[0]; case 'time': return new Date().toISOString().split('T')[1]; case 'date-time': return new Date().toISOString(); case 'duration': return 'P3Y6M4DT12H30M5S'; // P=Period 3-Years 6-Months 4-Days 12-Hours 30-Minutes 5-Seconds case 'email': case 'idn-email': return 'user@example.com'; case 'hostname': case 'idn-hostname': return 'www.example.com'; case 'ipv4': return '192.168.0.1'; case 'ipv6': return '2001:0db8:5b96:0000:0000:426f:8e17:642a'; case 'uuid': return '4e0ba220-9575-11eb-a8b3-0242ac130003'; case 'byte': // Byte type is actually a base64 encoded string: https://spec.openapis.org/oas/v3.0.0#data-types return Buffer.from('example').toString('base64'); default: return schemaObj.format; } } else { return propertyName; } } // If type cannot be determined return EXAMPLE_VALUE_FOR_MISSING_TYPE; } function duplicateExampleWithNewPropertyValues(objectExamples, propertyName, propertyValues) { // Limit max number of property examples to 2 and limit the max number of examples to 10 return objectExamples.reduce((exampleList, example) => { const examplesFromPropertyValues = propertyValues.slice(0, 2).map(value => ({ ...(0, _lodash.default)(example), [propertyName]: value })); return exampleList.concat(...examplesFromPropertyValues); }, []).slice(0, 10); } function getExampleValuesFromSchema(schema, config = {}) { // Wrap the top level so that the recursive object can treat it as a normal property and we'll hit the 'object' below, otherwise we'll never create the top level. if (config.xml) { const xmlResult = getExampleValuesFromSchemaRecursive((schema === null || schema === void 0 ? void 0 : schema.type) === 'object' ? { properties: { _root: schema } } : schema, config); return xmlResult.map(example => example[0]); } return getExampleValuesFromSchemaRecursive(schema, config); } // TODO: Support getting the `summary` from the examples object or the `title` from the schema object function getExampleValuesFromSchemaRecursive(rawSchema, config = {}) { var _rawSchema$items, _rawSchema$items$xml, _rawSchema$xml; if (!rawSchema) { return []; } // XML Support const xmlAttributes = {}; const xmlTagProperties = []; const { prefix, namespace } = rawSchema.xml || {}; if (namespace) { xmlAttributes[prefix ? `xmlns:${prefix}` : 'xmlns'] = namespace; } const nodeName = (rawSchema === null || rawSchema === void 0 ? void 0 : (_rawSchema$items = rawSchema.items) === null || _rawSchema$items === void 0 ? void 0 : (_rawSchema$items$xml = _rawSchema$items.xml) === null || _rawSchema$items$xml === void 0 ? void 0 : _rawSchema$items$xml.name) || (rawSchema === null || rawSchema === void 0 ? void 0 : (_rawSchema$xml = rawSchema.xml) === null || _rawSchema$xml === void 0 ? void 0 : _rawSchema$xml.name) || config.propertyName || 'root'; const overridePropertyName = prefix ? `${prefix}:${nodeName}` : nodeName; const { allOf, oneOf, anyOf, ...schema } = rawSchema; if (allOf) { const mergedAllOf = (0, _lodash2.default)({}, ...allOf, schema); return getExampleValuesFromSchemaRecursive(mergedAllOf, config); } if (oneOf || anyOf) { const examples = (oneOf || anyOf).map(s => getExampleValuesFromSchemaRecursive((0, _lodash2.default)({}, schema, s), config)).flat(1); const hash = value => { if (typeof value === 'object') { return JSON.stringify(value); } return value; }; const uniqueExamples = examples.reduce((acc, e) => { acc[hash(e)] = e; return acc; }, {}); return Object.values(uniqueExamples); } return getSimpleValueResult(schema, config, namespace, prefix, xmlAttributes, xmlTagProperties, overridePropertyName); } function getSimpleValueResult(schema, config, namespace, prefix, xmlAttributes, xmlTagProperties, overridePropertyName) { const examples = Array.isArray(schema.examples) && schema.examples || schema.examples && typeof schema.examples === 'object' && Object.values(schema.examples).map(e => e.value).filter(v => v) || schema.example && [schema.example] || []; if (config.skipExampleIds && config.propertyName && config.propertyName.match(/id$/i)) { return ['']; } if (examples.length) { return examples; } if (schema.type === 'array' || schema.items) { if (!config.xml) { return [getExampleValuesFromSchemaRecursive(schema.items || {}, config)]; } if (!schema.xml || !schema.xml.wrapped) { const arrayExamples = getExampleValuesFromSchemaRecursive(schema.items || {}, config); xmlTagProperties.push({ [overridePropertyName]: arrayExamples[0] }, { _attr: xmlAttributes }); return [xmlTagProperties]; } const arrayExamples = getExampleValuesFromSchemaRecursive(schema.items || {}, { ...config, propertyName: overridePropertyName }); xmlTagProperties.push({ [overridePropertyName]: arrayExamples[0] }, { _attr: xmlAttributes }); return [xmlTagProperties]; } if (schema.type === 'object' || schema.properties) { let objectExamples = [{}]; Object.keys(schema.properties || {}).forEach(propertyName => { const innerSchema = schema.properties[propertyName] || {}; if (innerSchema.deprecated) { return; } if (innerSchema.readOnly && !config.includeReadOnly) { return; } if (innerSchema.writeOnly && !config.includeWriteOnly) { return; } const propertyExamples = getExampleValuesFromSchemaRecursive(innerSchema, { ...config, propertyName }); objectExamples = duplicateExampleWithNewPropertyValues(objectExamples, propertyName, propertyExamples); if (innerSchema.xml && innerSchema.xml.namespace) { xmlAttributes[innerSchema.xml.prefix ? `xmlns:${innerSchema.xml.prefix}` : 'xmlns'] = namespace; } const innerNodeName = innerSchema.xml && innerSchema.xml.name || propertyName || config.propertyName; const innerOverridePropertyName = prefix ? `${prefix}:${innerNodeName}` : innerNodeName; if (innerSchema.xml && innerSchema.xml.attribute) { xmlAttributes[innerOverridePropertyName] = propertyExamples[0]; } else { xmlTagProperties.push({ [innerOverridePropertyName]: propertyExamples[0] }); } }); if (Object.keys(xmlAttributes).length) { xmlTagProperties.push({ _attr: xmlAttributes }); } return config.xml ? [xmlTagProperties] : objectExamples; } const value = getSampleValueByType(schema, config.propertyName, config.skipExampleIds); return [value]; } function isPatternProperty(label) { return label.match(/^<any-key>|<pattern:/); } /** * For changing OpenAPI-Schema to an Object Notation, * This Object would further be an input to UI Components to generate an Object-Tree * @param {object} schema - Schema object from OpenAPI spec * @param {object} options - recursively pass this object to generate object notation * @param {number} level - recursion level * @param {string} suffix - used for suffixing property names to avoid duplicate props during object composition */ function schemaInObjectNotation(rawSchema, options, level = 0, suffix = '') { const { allOf, oneOf, anyOf, items: arrayItemsSchema, properties: schemaProperties, patternProperties: schemaPatternProperties, ...schema } = rawSchema || {}; const propertyType = schema.type; const metadata = { constraints: [] }; if (schema.uniqueItems) { metadata.constraints.push('Requires unique items'); } if (typeof schema.minItems === 'number' || typeof schema.maxItems === 'number') { metadata.constraints.push(`Length: [${schema.minItems || 0}${schema.maxItems ? ', ' : '+'}${schema.maxItems || ''}]`); } if (allOf) { // If allOf is an array of multiple elements, then all the keys makes a single object const objWithAllProps = {}; allOf.map((v, i) => { if (v.type === 'object' || v.properties || v.allOf || v.anyOf || v.oneOf) { const propSuffix = (v.anyOf || v.oneOf) && i > 0 ? i : ''; const partialObj = schemaInObjectNotation(v, options, level + 1, propSuffix); Object.assign(objWithAllProps, partialObj); } else if (v.type === 'array' || v.items) { const partialObj = schemaInObjectNotation(v, options, level + 1); Object.assign(objWithAllProps, partialObj); } else if (v.type) { const prop = `prop${Object.keys(objWithAllProps).length}`; const typeObj = getTypeInfo(v, options); objWithAllProps[prop] = `${typeObj.html}`; } }); const obj = schemaInObjectNotation(schema, options, 0); const resultObj = typeof obj === 'object' && !Array.isArray(obj) ? obj : {}; // These are the only valuable properties from allOf, everything else isn't going to be available, otherwise fallback to whatever was there from the children objects resultObj['::title'] = schema.title || resultObj['::title']; resultObj['::description'] = schema.description || resultObj['::description']; return Object.assign({}, objWithAllProps, resultObj); } if (anyOf || oneOf) { const objWithAnyOfProps = {}; objWithAnyOfProps['::type'] = 'xxx-of-option'; let writeOnly = true; let readOnly = true; (anyOf || oneOf || []).forEach((v, index) => { if (v.type === 'object' || v.properties || v.allOf || v.anyOf || v.oneOf || v.type === 'array' || v.items) { const partialObj = schemaInObjectNotation(v, options); if (partialObj) { var _partialObj$Flags, _partialObj$Flags2; objWithAnyOfProps[`::OPTION~${index + 1}${v.title ? `~${v.title}` : ''}`] = partialObj; readOnly = readOnly && ((_partialObj$Flags = partialObj['::flags']) === null || _partialObj$Flags === void 0 ? void 0 : _partialObj$Flags['🆁']); writeOnly = writeOnly && ((_partialObj$Flags2 = partialObj['::flags']) === null || _partialObj$Flags2 === void 0 ? void 0 : _partialObj$Flags2['🆆']); } } else { const typeInfo = getTypeInfo(v, options); if (typeInfo !== null && typeInfo !== void 0 && typeInfo.type) { var _objWithAnyOfProps$, _objWithAnyOfProps$2; const prop = `::OPTION~${index + 1}${v.title ? `~${v.title}` : ''}`; objWithAnyOfProps[prop] = `${typeInfo.html}`; readOnly = readOnly && ((_objWithAnyOfProps$ = objWithAnyOfProps['::flags']) === null || _objWithAnyOfProps$ === void 0 ? void 0 : _objWithAnyOfProps$['🆁']); writeOnly = writeOnly && ((_objWithAnyOfProps$2 = objWithAnyOfProps['::flags']) === null || _objWithAnyOfProps$2 === void 0 ? void 0 : _objWithAnyOfProps$2['🆆']); } } }); const obj = schemaInObjectNotation(schema, options, 0); const resultObj = typeof obj === 'object' && !Array.isArray(obj) ? obj : {}; if (Object.keys(objWithAnyOfProps).length) { resultObj[anyOf ? `::ANY~OF ${suffix}` : `::ONE~OF ${suffix}`] = objWithAnyOfProps; } resultObj['::link'] = schema.title || ''; resultObj['::circular'] = !!schema.circularReference; resultObj['::type'] = 'object'; resultObj['::flags'] = { '🆁': readOnly && '🆁', '🆆': writeOnly && '🆆' }; resultObj['::title'] = schema.title || ''; resultObj['::description'] = schema.description || ''; resultObj['::metadata'] = metadata; return resultObj; } if (Array.isArray(propertyType)) { const obj = { '::type': '' }; // When a property has multiple types, then check further if any of the types are array or object, if yes then modify the schema using one-of // Clone the schema - as it will be modified to replace multi-data-types with one-of; const subSchema = JSON.parse(JSON.stringify(schema)); const primitiveType = []; const complexTypes = []; subSchema.type.forEach(v => { if (v.match(/integer|number|string|null|boolean/g)) { primitiveType.push(v); } else if (v === 'array' && typeof (subSchema.items && subSchema.items.type) === 'string' && arrayItemsSchema && subSchema.items.type.match(/integer|number|string|null|boolean/g)) { // Array with primitive types should also be treated as primitive type if (subSchema.items.type === 'string' && subSchema.items.format) { primitiveType.push(`${subSchema.items.format}[]`); } else { primitiveType.push(`${subSchema.items.type}[]`); } } else { complexTypes.push(v); } }); let multiPrimitiveTypes; if (primitiveType.length > 0) { subSchema.type = primitiveType.join('┃'); multiPrimitiveTypes = getTypeInfo(subSchema, options); if (complexTypes.length === 0) { var _multiPrimitiveTypes; return `${((_multiPrimitiveTypes = multiPrimitiveTypes) === null || _multiPrimitiveTypes === void 0 ? void 0 : _multiPrimitiveTypes.html) || ''}`; } } if (complexTypes.length > 0) { obj['::link'] = schema.title || ''; obj['::circular'] = !!schema.circularReference; obj['::type'] = 'object'; const multiTypeOptions = { '::type': 'xxx-of-option' }; // Generate ONE-OF options for complexTypes complexTypes.forEach((v, i) => { if (v === 'null') { multiTypeOptions[`::OPTION~${i + 1}`] = 'NULL~|~~|~~|~~|~~|~~|~~|~~|~'; } else if ('integer, number, string, boolean,'.includes(`${v},`)) { subSchema.type = Array.isArray(v) ? v.join('┃') : v; const primitiveTypeInfo = getTypeInfo(subSchema, options); multiTypeOptions[`::OPTION~${i + 1}`] = primitiveTypeInfo.html; } else if (v === 'object') { // If object type iterate all the properties and create an object-type-option const objTypeOption = { '::title': schema.title || '', '::description': schema.description || '', '::flags': { '🆁': schema.readOnly && '🆁', '🆆': schema.writeOnly && '🆆' }, '::link': schema.title || '', '::circular': !!schema.circularReference, '::type': 'object', '::deprecated': schema.deprecated || false, '::metadata': metadata }; for (const key in schemaProperties) { var _schema$required; if (!schema.deprecated && !schemaProperties[key].deprecated && (_schema$required = schema.required) !== null && _schema$required !== void 0 && _schema$required.includes(key)) { objTypeOption[`${key}*`] = schemaInObjectNotation(schemaProperties[key], options, level + 1); } else { objTypeOption[key] = schemaInObjectNotation(schemaProperties[key], options, level + 1); } } multiTypeOptions[`::OPTION~${i + 1}`] = objTypeOption; } else if (v === 'array') { multiTypeOptions[`::OPTION~${i + 1}`] = { '::title': schema.title || '', '::description': schema.description || (arrayItemsSchema === null || arrayItemsSchema === void 0 ? void 0 : arrayItemsSchema.description) || '', '::flags': { '🆁': schema.readOnly && '🆁', '🆆': schema.writeOnly && '🆆' }, '::link': arrayItemsSchema.title || schema.title || '', '::circular': !!schema.circularReference, '::type': 'array', // Array properties are read from the ::props object instead of reading from the keys of this object '::props': schemaInObjectNotation(Object.assign({}, schema, arrayItemsSchema, { description: schema.description || (arrayItemsSchema === null || arrayItemsSchema === void 0 ? void 0 : arrayItemsSchema.description) }), options, level + 1), '::deprecated': schema.deprecated || false, '::metadata': metadata }; } }); multiTypeOptions[`::OPTION~${complexTypes.length + 1}`] = multiPrimitiveTypes && multiPrimitiveTypes.html || ''; obj['::ONE~OF'] = multiTypeOptions; } return obj; } if (propertyType === 'object' || schemaProperties || schema.circularReference) { const obj = { '::type': '' }; obj['::title'] = schema.title || ''; obj['::description'] = schema.description || ''; obj['::flags'] = { '🆁': schema.readOnly && '🆁', '🆆': schema.writeOnly && '🆆' }; obj['::link'] = schema.title || ''; obj['::circular'] = !!schema.circularReference; obj['::type'] = 'object'; obj['::deprecated'] = schema.deprecated || false; obj['::metadata'] = metadata; for (const key in schemaProperties) { var _schemaProperties$key, _schema$required2; if (!schema.deprecated && !((_schemaProperties$key = schemaProperties[key]) !== null && _schemaProperties$key !== void 0 && _schemaProperties$key.deprecated) && (_schema$required2 = schema.required) !== null && _schema$required2 !== void 0 && _schema$required2.includes(key)) { obj[`${key}*`] = schemaInObjectNotation(schemaProperties[key], options, level + 1); } else { obj[key] = schemaInObjectNotation(schemaProperties[key], options, level + 1); } } for (const key in schemaPatternProperties) { obj[`<pattern: ${key}>`] = schemaInObjectNotation(schemaPatternProperties[key], options, level + 1); } if (schema.additionalProperties) { obj['<any-key>'] = schemaInObjectNotation(schema.additionalProperties, options); } return obj; } if (propertyType === 'array' || arrayItemsSchema) { // If Array const obj = { '::type': '' }; obj['::title'] = schema.title || ''; obj['::description'] = schema.description || (arrayItemsSchema === null || arrayItemsSchema === void 0 ? void 0 : arrayItemsSchema.description) || ''; obj['::flags'] = { '🆁': schema.readOnly && '🆁', '🆆': schema.writeOnly && '🆆' }; obj['::link'] = (arrayItemsSchema === null || arrayItemsSchema === void 0 ? void 0 : arrayItemsSchema.title) || schema.title || ''; obj['::circular'] = !!schema.circularReference; obj['::type'] = 'array'; obj['::deprecated'] = schema.deprecated || false; obj['::metadata'] = metadata; // Array properties are read from the ::props object instead of reading from the keys of this object // Use type: undefined to prevent schema recursion by passing array from the parent to the next loop. arrayItemsSchema should have had type defined but it doesn't. obj['::props'] = schemaInObjectNotation(Object.assign({}, schema, { type: undefined }, arrayItemsSchema, { description: obj['::description'] }), options, level + 1); if (arrayItemsSchema !== null && arrayItemsSchema !== void 0 && arrayItemsSchema.items) { obj['::array-type'] = arrayItemsSchema.items.type; } return obj; } const typeObj = getTypeInfo(schema, options); return `${(typeObj === null || typeObj === void 0 ? void 0 : typeObj.html) || ''}`; } /* Create Example object */ function generateExample(examples, example, schema, rawMimeType, includeReadOnly = true, includeWriteOnly = true, outputType, skipExampleIds = false) { const mimeType = rawMimeType || 'application/json'; const finalExamples = []; // First check if examples is provided if (examples) { for (const eg in examples) { let egContent = ''; let egFormat = 'json'; if (mimeType.toLowerCase().includes('json')) { if (outputType === 'text') { egContent = typeof examples[eg].value === 'string' ? examples[eg].value : JSON.stringify(examples[eg].value, undefined, 2); egFormat = 'text'; } else { egContent = examples[eg].value; if (typeof examples[eg].value === 'string') { try { const fixedJsonString = examples[eg].value.replace(/([\w]+)(:)/g, '"$1"$2').replace(/'/g, '"'); egContent = JSON.parse(fixedJsonString); egFormat = 'json'; } catch (err) { egFormat = 'text'; egContent = examples[eg].value; } } } } else { egContent = examples[eg].value; egFormat = 'text'; } finalExamples.push({ exampleId: eg, exampleSummary: examples[eg].summary || '', exampleDescription: examples[eg].description || '', exampleType: mimeType, exampleValue: egContent, exampleFormat: egFormat }); } } else if (example) { let egContent = ''; let egFormat = 'json'; if (mimeType.toLowerCase().includes('json')) { if (outputType === 'text') { egContent = typeof example === 'string' ? example : JSON.stringify(example, undefined, 2); egFormat = 'text'; } else if (typeof example === 'object') { egContent = example; egFormat = 'json'; } else if (typeof example === 'string') { try { egContent = JSON.parse(example); egFormat = 'json'; } catch (err) { egFormat = 'text'; egContent = example; } } } else { egContent = example; egFormat = 'text'; } finalExamples.push({ exampleId: 'Example', exampleSummary: '', exampleDescription: '', exampleType: mimeType, exampleValue: egContent, exampleFormat: egFormat }); } // If schema-level examples are not provided then generate one based on the schema field types if (finalExamples.length) { return finalExamples; } if (schema !== null && schema !== void 0 && schema.example) { // Note: schema.examples (plurals) is not allowed as per spec return [{ exampleId: 'Example', exampleSummary: '', exampleDescription: '', exampleType: mimeType, exampleValue: schema.example, exampleFormat: mimeType.toLowerCase().includes('json') && typeof schema.example === 'object' ? 'json' : 'text' }]; } const config = { includeReadOnly, includeWriteOnly, skipExampleIds, xml: mimeType.toLowerCase().includes('xml') }; const samples = getExampleValuesFromSchema(schema, config); if (!samples || !mimeType.toLowerCase().includes('json') && !mimeType.toLowerCase().includes('text') && !mimeType.toLowerCase().includes('*/*') && !mimeType.toLowerCase().includes('xml')) { return [{ exampleId: 'Example', exampleSummary: '', exampleDescription: '', exampleType: mimeType, exampleValue: '', exampleFormat: 'text' }]; } return samples.map((sample, sampleCounter) => { let exampleValue = ''; if (mimeType.toLowerCase().includes('xml')) { exampleValue = (0, _xml.default)(sample, { declaration: true, indent: ' ' }); } else { exampleValue = outputType === 'text' ? JSON.stringify(sample, null, 8) : sample; } return { exampleId: `Example-${sampleCounter}`, exampleSummary: '', exampleDescription: '', exampleType: mimeType, exampleFormat: mimeType.toLowerCase().includes('xml') ? 'text' : outputType, exampleValue }; }).filter(s => s); }