UNPKG

mares-swagger-spec-maker

Version:

mares framework ���조에 맞춰서openapi spec을 combine 해주는 모듈입니다.

134 lines (102 loc) 4.35 kB
const utils = require('./utils') const coreUtils = require('mares-welder-utils') const path = require('path') const fs = require('fs') const API_SPEC_NAME = '.spec.js' const BOUNDED_CONTEXT_API_SPEC_NAME = '.context-api-spec.js' const VERSION_API_SPEC_NAME = '.version-api-spec.js' const DOMAIN_NAME = 'domain/aggregates' module.exports = () => { return { /** * paths spec 안에 있는 모든 리소스명 앞이 prefix를 추가해준다. * @param {Object} paths - root spec 안에 있는 paths spec 객체 * @param {string} prefix - prefix 문자열 * @return {Object} 리소스에 prefix가 추가된 root spec 객체 */ addPrefix: (paths, prefix) => { return utils.addResourcePrefixInPaths(paths, prefix) }, /** * root spec에 bounded-context spec, api spec, api version spec, components.schemas(도메인을 읽어서 추가)를 머지한다. * @param {Object} rootSpec - root spec, root project 폴더에 위치함. 현재 이름은 .root-api-spec.js로 고정 * @param {string} boundedContextPath - boundedContext의 root 경로 문자열 * @return {Object} bounded-context에 있는 모든 스펙(version spec, api spec, bounded-context spec)이 merge된 root spec 객체 */ merge: (rootSpec, boundedContextPath) => { // version 스펙 let versionPaths = coreUtils.findFile(boundedContextPath, VERSION_API_SPEC_NAME, ['node_modules']) // api 스펙 let specPaths = coreUtils.findFile(boundedContextPath, API_SPEC_NAME, ['node_modules']) // bounded-context 폴더 경로 let bcPath = path.resolve(boundedContextPath, './', BOUNDED_CONTEXT_API_SPEC_NAME) // domain 폴더 경로 let domainPath = path.resolve(boundedContextPath, './', DOMAIN_NAME) // components.schemas에 추가될 객체 let schemas = {} let bcSpec = null let Aggregates = null if (fs.existsSync(bcPath)) { bcSpec = require(bcPath) } if (fs.existsSync(domainPath)) { Aggregates = require(domainPath) } for (let k in Aggregates) { let domain = Aggregates[k] let schemaName = domain.meta.name let schema = utils.convertDomainToSchema(domain) schema = utils.updateRequiredType(schema) schemas[schemaName] = schema } if (!rootSpec.components) rootSpec.components = {} rootSpec.components = utils.addSchemasToComponents(rootSpec.components, schemas) // 루트 보안스키마가 없으면 빈객체 생성 if (!rootSpec.components.securitySchemes) rootSpec.components.securitySchemes = {} specPaths.forEach((specPath) => { let securitySchemes = bcSpec.components.securitySchemes securitySchemes = {...securitySchemes, ...rootSpec.components.securitySchemes} let spec = require(specPath) if (bcSpec) { spec = utils.addSecurityToPath(spec, securitySchemes) } versionPaths.forEach((versionPath) => { let versionDirname = path.dirname(versionPath) let pathDirname = path.dirname(specPath) if (pathDirname.indexOf(versionDirname) > -1) { let version = require(versionPath) spec = utils.addVersionToPath(spec, version) } }) rootSpec = utils.mergeRootAndPath(rootSpec, spec) }) rootSpec = utils.mergeRootAndBoundedContext(rootSpec, bcSpec) return rootSpec }, /** * swagger3.0 spec에서 components의 값을 실제 스펙안으로 대치시킨다. * @param {Object} rootSpec - swagger 3.0 spec, * @returns {Object} replacedRootSpec - {'$ref':'#/components/*'}가 components의 value로 대치된 스펙 */ replaceAllComponents: (rootSpec) => { // ref 참조 단계 (ex: ref->ref->ref 면 3depth) let refDepth = 0 // 최대 ref 참조 단계는 우선 10으로 설정 const MAX_REF_DEPTH = 10 let stringSpecPaths = JSON.stringify(rootSpec.paths) let loopSpec = rootSpec while (stringSpecPaths.indexOf('$ref') !== -1) { refDepth++ if (refDepth > MAX_REF_DEPTH) { let idx = stringSpecPaths.indexOf('$ref') let sub = stringSpecPaths.substr(idx, 1000) console.warn('스웨거 파싱중에 문제가 발견되었습니다. 선언은 했으나 쓰지 않는 컴포넌트가 있을 수 있으니 확인바랍니다.', sub) break } loopSpec = utils.replaceAllComponents(loopSpec) stringSpecPaths = JSON.stringify(loopSpec.paths) } return loopSpec } } }