<commit_before>import { getLogger, Logger } from 'debuggo';
import { Eredita } from 'eredita';
import * as express from 'express';
import { NextFunction, Request, Response, Router, RouterOptions } from 'express';
import * as http from 'http';
import * as https from 'https';
import * as refs from 'jsonref'; // TODO include everything from openapi-police
import * as _ from 'lodash';
import { OpenAPIV3, ValidationError } from 'openapi-police';
import * as semver from 'semver';
import { DEFAULT_DOCUMENT } from './defaults';
import { RESTError } from './error';
import { Resource } from './resource';
import { Scopes } from './scopes';
import { APIRequest, APIResponse } from './types';
import request = require('request');

let reqId: number = 0;

export class API {
  public document: OpenAPIV3.Document;

  protected logger: Logger;
  protected resources: Resource[];
  protected internalRouter: Promise<Router>;
  protected parseOptions: refs.ParseOptions;

  constructor(info?:OpenAPIV3.InfoObject) {
    this.document = Eredita.deepExtend(_.cloneDeep(DEFAULT_DOCUMENT), { info: info || {} });
    if (!semver.valid(this.document.info.version)) {
      throw new Error('Invalid version');
    }
    this.logger = getLogger(this.getDebugLabel());
    this.resources = [ ];
    this.parseOptions = {
      scope: 'http://vivocha.com/api/v3',
      retriever: this.defaultSchemaRetriever.bind(this)
    };
  }

  protected getDebugLabel(): string {
    return 'arrest';
  }
  protected getDebugContext(): string {
    return `#${++reqId}`;
  }
  protected async defaultSchemaRetriever(url: string): Promise<any> {
    return new Promise(function(resolve, reject) {
      request({
        url: url,
        method: 'GET',
        json: true
      }, function(err, response, data) {
        if (err) {
          reject(err);
        } else if (response.statusCode !== 200) {
          reject(new RESTError(response.statusCode as number));
        } else {
          resolve(data);
        }
      });
    });
  }

  addResource(resource:Resource): this {
    this.resources.push(resource);
    resource.attach(this);
    return this;
  }

  registerSchema(name: string, schema: OpenAPIV3.SchemaObject) {
    if (!this.document.components) {
      this.document.components = {};
    }
    if (!this.document.components.schemas) {
      this.document.components.schemas = {};
    }
    this.document.components.schemas[name] = schema;
  }
  registerOperation(path:string, method:string, operation: OpenAPIV3.OperationObject) {
    if (!this.document.paths) {<commit_msg>fix: deep clone schemas when registering them<commit_after>import { getLogger, Logger } from 'debuggo';
import { Eredita } from 'eredita';
import * as express from 'express';
import { NextFunction, Request, Response, Router, RouterOptions } from 'express';
import * as http from 'http';
import * as https from 'https';
import * as refs from 'jsonref'; // TODO include everything from openapi-police
import * as _ from 'lodash';
import { OpenAPIV3, ValidationError } from 'openapi-police';
import * as semver from 'semver';
import { DEFAULT_DOCUMENT } from './defaults';
import { RESTError } from './error';
import { Resource } from './resource';
import { Scopes } from './scopes';
import { APIRequest, APIResponse } from './types';
import request = require('request');

let reqId: number = 0;

export class API {
  public document: OpenAPIV3.Document;

  protected logger: Logger;
  protected resources: Resource[];
  protected internalRouter: Promise<Router>;
  protected parseOptions: refs.ParseOptions;

  constructor(info?:OpenAPIV3.InfoObject) {
    this.document = Eredita.deepExtend(_.cloneDeep(DEFAULT_DOCUMENT), { info: info || {} });
    if (!semver.valid(this.document.info.version)) {
      throw new Error('Invalid version');
    }
    this.logger = getLogger(this.getDebugLabel());
    this.resources = [ ];
    this.parseOptions = {
      scope: 'http://vivocha.com/api/v3',
      retriever: this.defaultSchemaRetriever.bind(this)
    };
  }

  protected getDebugLabel(): string {
    return 'arrest';
  }
  protected getDebugContext(): string {
    return `#${++reqId}`;
  }
  protected async defaultSchemaRetriever(url: string): Promise<any> {
    return new Promise(function(resolve, reject) {
      request({
        url: url,
        method: 'GET',
        json: true
      }, function(err, response, data) {
        if (err) {
          reject(err);
        } else if (response.statusCode !== 200) {
          reject(new RESTError(response.statusCode as number));
        } else {
          resolve(data);
        }
      });
    });
  }

  addResource(resource:Resource): this {
    this.resources.push(resource);
    resource.attach(this);
    return this;
  }

  registerSchema(name: string, schema: OpenAPIV3.SchemaObject) {
    if (!this.document.components) {
      this.document.components = {};
    }
    if (!this.document.components.schemas) {
      this.document.components.schemas = {};
    }
    this.document.components.schemas[name] = _.cloneDeep(schema);
  }
  registerOperation(path:string, method:string, operation: OpenAPIV3.OperationObject) {
    if (!this.document.paths) {
{'fraction_non_alphanumeric': 0.13539054966248795, 'fraction_numerical': 0.003857280617164899, 'mean_word_length': 3.4553264604811, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2579528', 'n_tokens_mistral': 1548, 'n_tokens_neox': 1506, 'n_words': 380}