/
home
/
infinitibizsol
/
.trash
/
node_modules.11
/
swagger-jsdoc
/
src
/
File Upload :
llllll
Current File: /home/infinitibizsol/.trash/node_modules.11/swagger-jsdoc/src/specification.js
const doctrine = require('doctrine'); const parser = require('swagger-parser'); const YAML = require('yaml'); const { hasEmptyProperty, convertGlobPaths, extractAnnotations, mergeDeep, extractYamlFromJsDoc, isTagPresentInTags, } = require('./utils'); /** * Prepare the swagger/openapi specification object. * @see https://github.com/OAI/OpenAPI-Specification/tree/master/versions * @param {object} definition - The `definition` or `swaggerDefinition` from options. * @returns {object} swaggerObject */ function prepare(definition) { const swaggerObject = JSON.parse(JSON.stringify(definition)); const specificationTemplate = { v2: [ 'paths', 'definitions', 'responses', 'parameters', 'securityDefinitions', ], v3: [ 'paths', 'definitions', 'responses', 'parameters', 'securityDefinitions', 'components', ], v4: ['components', 'channels'], }; const getVersion = () => { if (swaggerObject.asyncapi) { return 'v4'; } if (swaggerObject.openapi) { return 'v3'; } if (swaggerObject.swagger) { return 'v2'; } swaggerObject.swagger = '2.0'; return 'v2'; }; const version = getVersion(); specificationTemplate[version].forEach((property) => { swaggerObject[property] = swaggerObject[property] || {}; }); swaggerObject.tags = swaggerObject.tags || []; return swaggerObject; } /** * @param {object} obj * @param {string} ext */ function format(swaggerObject, ext) { if (ext === '.yml' || ext === '.yaml') { return YAML.stringify(swaggerObject); } return swaggerObject; } /** * OpenAPI specification validator does not accept empty values for a few properties. * Solves validator error: "Schema error should NOT have additional properties" * @param {object} swaggerObject * @returns {object} swaggerObject */ function clean(swaggerObject) { for (const prop of [ 'definitions', 'responses', 'parameters', 'securityDefinitions', ]) { if (hasEmptyProperty(swaggerObject[prop])) { delete swaggerObject[prop]; } } return swaggerObject; } /** * Parse the swagger object and remove useless properties if necessary. * * @param {object} swaggerObject - Swagger object from parsing the api files. * @returns {object} The specification. */ function finalize(swaggerObject, options) { let specification = swaggerObject; parser.parse(swaggerObject, (err, api) => { if (!err) { specification = api; } }); if (specification.openapi) { specification = clean(specification); } return format(specification, options.format); } /** * @param {object} swaggerObject * @param {object} annotation * @param {string} property */ function organize(swaggerObject, annotation, property) { // Root property on purpose. // @see https://github.com/OAI/OpenAPI-Specification/blob/master/proposals/002_Webhooks.md#proposed-solution if (property === 'x-webhooks') { swaggerObject[property] = mergeDeep( swaggerObject[property], annotation[property] ); } // Other extensions can be in varying places depending on different vendors and opinions. // The following return makes it so that they are not put in `paths` in the last case. // New specific extensions will need to be handled on case-by-case if to be included in `paths`. if (property.startsWith('x-')) return; const commonProperties = [ 'components', 'consumes', 'produces', 'paths', 'schemas', 'securityDefinitions', 'responses', 'parameters', 'definitions', 'channels', ]; if (commonProperties.includes(property)) { for (const definition of Object.keys(annotation[property])) { swaggerObject[property][definition] = mergeDeep( swaggerObject[property][definition], annotation[property][definition] ); } } else if (property === 'tags') { const { tags } = annotation; if (Array.isArray(tags)) { for (const tag of tags) { if (!isTagPresentInTags(tag, swaggerObject.tags)) { swaggerObject.tags.push(tag); } } } else if (!isTagPresentInTags(tags, swaggerObject.tags)) { swaggerObject.tags.push(tags); } } else { // Paths which are not defined as "paths" property, starting with a slash "/" swaggerObject.paths[property] = mergeDeep( swaggerObject.paths[property], annotation[property] ); } } /** * @param {object} options * @returns {object} swaggerObject */ function build(options) { YAML.defaultOptions.keepCstNodes = true; // Get input definition and prepare the specification's skeleton const definition = options.swaggerDefinition || options.definition; const specification = prepare(definition); const yamlDocsAnchors = new Map(); const yamlDocsErrors = []; const yamlDocsReady = []; for (const filePath of convertGlobPaths(options.apis)) { const { yaml: yamlAnnotations, jsdoc: jsdocAnnotations, } = extractAnnotations(filePath, options.encoding); if (yamlAnnotations.length) { for (const annotation of yamlAnnotations) { const parsed = Object.assign(YAML.parseDocument(annotation), { filePath, }); const anchors = parsed.anchors.getNames(); if (anchors.length) { for (const anchor of anchors) { yamlDocsAnchors.set(anchor, parsed); } } else if (parsed.errors && parsed.errors.length) { // Attach the relevent yaml section to the error for verbose logging parsed.errors.forEach((err) => { err.annotation = annotation; }); yamlDocsErrors.push(parsed); } else { yamlDocsReady.push(parsed); } } } if (jsdocAnnotations.length) { for (const annotation of jsdocAnnotations) { const jsDocComment = doctrine.parse(annotation, { unwrap: true }); for (const doc of extractYamlFromJsDoc(jsDocComment)) { const parsed = Object.assign(YAML.parseDocument(doc), { filePath }); const anchors = parsed.anchors.getNames(); if (anchors.length) { for (const anchor of anchors) { yamlDocsAnchors.set(anchor, parsed); } } else if (parsed.errors && parsed.errors.length) { // Attach the relevent yaml section to the error for verbose logging parsed.errors.forEach((err) => { err.annotation = doc; }); yamlDocsErrors.push(parsed); } else { yamlDocsReady.push(parsed); } } } } } if (yamlDocsErrors.length) { for (const docWithErr of yamlDocsErrors) { const errsToDelete = []; docWithErr.errors.forEach((error, index) => { if (error.name === 'YAMLReferenceError') { // This should either be a smart regex or ideally a YAML library method using the error.range. // The following works with both pretty and not pretty errors. const refErr = error.message .split('Aliased anchor not found: ') .filter((a) => a) .join('') .split(' at line')[0]; const anchor = yamlDocsAnchors.get(refErr); const anchorString = anchor.cstNode.toString(); const originalString = docWithErr.cstNode.toString(); const readyDocument = YAML.parseDocument( `${anchorString}\n${originalString}` ); yamlDocsReady.push(readyDocument); errsToDelete.push(index); } }); // reverse sort the deletion array so we always delete from the end errsToDelete.sort((a, b) => b - a); // Cleanup solved errors in order to allow for parser to pass through. for (const errIndex of errsToDelete) { docWithErr.errors.splice(errIndex, 1); } } // Format errors into a printable/throwable string const errReport = yamlDocsErrors .filter((doc) => doc.errors.length) .map(({ errors, filePath }) => { let str = `Error in ${filePath} :\n`; if (options.verbose) { str += errors .map( (e) => `${e.toString()}\nImbedded within:\n\`\`\`\n ${e.annotation.replace( /\n/g, '\n ' )}\n\`\`\`` ) .join('\n'); } else { str += errors.map((e) => e.toString()).join('\n'); } return str; }) .filter((error) => !!error); if (errReport.length) { if (options.failOnErrors) { throw new Error(errReport); } // Place to provide feedback for errors. Previously throwing, now reporting only. console.info( 'Not all input has been taken into account at your final specification.' ); console.error(`Here's the report: \n\n\n ${errReport}`); } } for (const document of yamlDocsReady) { const parsedDoc = document.toJSON(); for (const property in parsedDoc) { organize(specification, parsedDoc, property); } } return finalize(specification, options); } module.exports = { prepare, build, organize, finalize, format };
Copyright ©2k19 -
Hexid
|
Tex7ure