/************************************************************************* * * Troven CONFIDENTIAL * __________________ * * (c) 2017-2020 Troven Ventures Pty Ltd * All Rights Reserved. * * NOTICE: All information contained herein is, and remains * the property of Troven Pty Ltd and its licensors, * if any. The intellectual and technical concepts contained * herein are proprietary to Troven Pty Ltd * and its suppliers and may be covered by International and Regional Patents, * patents in process, and are protected by trade secret or copyright law. * Dissemination of this information or reproduction of this material * is strictly forbidden unless prior written permission is obtained * from Troven Pty Ltd. */ import * as assert from "assert"; import * as _ from "lodash"; import {IChassisContext, IOpenAPIv3} from "../interfaces"; import { Paths, Security } from "./OpenAPI"; // import { Validator } from "./s"; import { Schemas } from "./Schemas"; import { Operation } from "./Operation"; import { Vars } from "../helpers"; export { Paths } from "./Paths"; export { Security } from "./Security"; export class OpenAPI { // validator: Validator; schemas: Schemas; paths: Paths; security: Security; spec: any; ix_tags: any = {}; /** * openapi_spec is merged from static settings. * * The default title and version are inferred from the chassis pkg. * The "openapi" key within config is used as the service default * Finally, the '_openapi_spec' are considered the authoriative source. * */ constructor( protected context: IChassisContext ) { // this.load(spec); // , spec: IOpenAPIv3 } public load(orginal_spec: IOpenAPIv3) { let default_spec = { openapi: '3.0.0', paths: {}, info: { title: this.context.config.name, version: this.context.pkg.version || "0.0.0" }, security: {}, tags: [], components: { securitySchemes: {}, schemas: {} } }; // merge specifications let spec = this.safely_merge_specs( default_spec, orginal_spec ); assert(spec.openapi == "3.0.0", "Only OpenAPI v3 is supported"); this.ix_tags = this.index_tags(spec.tags); this.schemas = new Schemas(spec); // process security this.security = new Security(spec); // process paths this.paths = new Paths(this.context, this.security); this.paths.resources(spec); // ingest all schemas from OpenAPI spec (global, parameters, request and response) // this.validator = new Validator(this.schemas) ; // this.validator.addOpenAPI( this.spec ); this.spec = spec; return spec; } public add(oper: Operation): Operation { this.schemas.operation(oper); this.paths.add(oper); this.index_tags(oper.spec.tags); return oper; } /** * merge each of our OAS fragments into a single OAS specification * * @param args * @returns {any} */ private safely_merge_specs = function (...args: any[]): any { assert(args, "missing merge objects"); let spec = {}; for(let args in arguments) { let _spec = arguments[args]; // merge OAS root objects for(let s in _spec) { // objects get merged if (_spec.hasOwnProperty(s)) { if (Array.isArray(_spec[s])) { spec[s] = _spec[s] || spec[s]; } else if (_.isObject(_spec[s])) { spec[s] = _.extend({}, spec[s], _spec[s]); } else { // otherwise - set key to most recent truthy value spec[s] = spec[s]?spec[s]:_spec[s]; } } } } // return the merged specification return spec; }; index_tags(tags: any) { _.each(tags, (tag: any)=> { if (_.isString(tag)) { this.ix_tags[tag] = { name: tag, description: Vars.capitalize(tag) }; } else if (tag) { assert(tag.name, "missing `tag.name`"); this.ix_tags[tag.name] = tag; } }); return this.ix_tags; } getTags() { let tags = []; _.each(this.ix_tags, (tag) => { tags.push(tag); }); return tags; } }