<commit_before>import { writeFileSync } from 'fs';
import { edk } from '@ditsmod/core';
import { Injectable, Injector, ReflectiveInjector } from '@ts-stack/di';
import { XOasObject, XOperationObject, XParameterObject, XPathsObject } from '@ts-stack/openapi-spec';

import { OAS_OBJECT } from '../di-tokens';
import { OasRouteMeta } from '../types/oas-route-meta';
import { DEFAULT_OAS_OBJECT } from '../constants';

@Injectable()
export class OpenapiCompilerExtension implements edk.Extension<XOasObject> {
  #oasObject: XOasObject;

  constructor(private extensionManager: edk.ExtensionsManager, private injectorPerApp: Injector) {}

  async init() {
    if (this.#oasObject) {
      return this.#oasObject;
    }

    const paths: XPathsObject = {};

    const rawRouteMeta = await this.extensionManager.init(edk.ROUTES_EXTENSIONS);
    rawRouteMeta.forEach((rawMeta) => {
      const injectorPerRou = ReflectiveInjector.resolveAndCreate(rawMeta.providersPerRou);
      const oasRouteMeta = injectorPerRou.get(OasRouteMeta) as OasRouteMeta;
      if (oasRouteMeta.pathItem) {
        paths[`/${oasRouteMeta.oasPath}`] = oasRouteMeta.pathItem;
      } else {
        this.applyNonOasRoute(paths, oasRouteMeta);
      }
    });

    this.#oasObject = Object.assign({}, DEFAULT_OAS_OBJECT, this.injectorPerApp.get(OAS_OBJECT));
    this.#oasObject.paths = paths;

    writeFileSync('./packages/openapi/src/openapi.json', JSON.stringify(this.#oasObject, null, '  '));

    return this.#oasObject;
  }

  protected applyNonOasRoute(paths: XPathsObject, routeMeta: edk.RouteMeta) {
    const httpMethod = routeMeta.httpMethod.toLowerCase();
    const parameters: XParameterObject[] = [];
    let path = routeMeta.path;
    path = `/${path}`.replace(/:([^\/]+)/g, (_, name) => {
      parameters.push({ in: 'path', name, required: true });
      return `{${name}}`;
    });
    const operationObject: XOperationObject = { parameters, responses: {} };
    if (paths[path]) {
      paths[path][httpMethod] = operationObject;
    } else {
      paths[path] = { [httpMethod]: operationObject };
    }
  }
}
<commit_msg>refactor(openapi): added compileOasObject()<commit_after>import { writeFileSync } from 'fs';
import { edk } from '@ditsmod/core';
import { Injectable, Injector, ReflectiveInjector } from '@ts-stack/di';
import { XOasObject, XOperationObject, XParameterObject, XPathsObject } from '@ts-stack/openapi-spec';

import { OAS_OBJECT } from '../di-tokens';
import { OasRouteMeta } from '../types/oas-route-meta';
import { DEFAULT_OAS_OBJECT } from '../constants';

@Injectable()
export class OpenapiCompilerExtension implements edk.Extension<XOasObject> {
  #oasObject: XOasObject;

  constructor(private extensionManager: edk.ExtensionsManager, private injectorPerApp: Injector) {}

  async init() {
    if (this.#oasObject) {
      return this.#oasObject;
    }

    await this.compileOasObject();
    writeFileSync('./packages/openapi/src/openapi.json', JSON.stringify(this.#oasObject, null, '  '));

    return this.#oasObject;
  }

  protected async compileOasObject() {
    const paths: XPathsObject = {};

    const rawRouteMeta = await this.extensionManager.init(edk.ROUTES_EXTENSIONS);
    rawRouteMeta.forEach((rawMeta) => {
      const injectorPerRou = ReflectiveInjector.resolveAndCreate(rawMeta.providersPerRou);
      const oasRouteMeta = injectorPerRou.get(OasRouteMeta) as OasRouteMeta;
      if (oasRouteMeta.pathItem) {
        paths[`/${oasRouteMeta.oasPath}`] = oasRouteMeta.pathItem;
      } else {
        this.applyNonOasRoute(paths, oasRouteMeta);
      }
    });

    this.#oasObject = Object.assign({}, DEFAULT_OAS_OBJECT, this.injectorPerApp.get(OAS_OBJECT));
    this.#oasObject.paths = paths;

    return this.#oasObject;
  }

  protected applyNonOasRoute(paths: XPathsObject, routeMeta: edk.RouteMeta) {
    const httpMethod = routeMeta.httpMethod.toLowerCase();
    const parameters: XParameterObject[] = [];
    let path = routeMeta.path;
    path = `/${path}`.replace(/:([^\/]+)/g, (_, name) => {
      parameters.push({ in: 'path', name, required: true });
      return `{${name}}`;
    });
    const operationObject: XOperationObject = { parameters, responses: {} };
    if (paths[path]) {
      paths[path][httpMethod] = operationObject;
    } else {
      paths[path] = { [httpMethod]: operationObject };
    }
  }
}

{'fraction_non_alphanumeric': 0.14321781042001377, 'fraction_numerical': 0.0, 'mean_word_length': 3.9919816723940436, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, '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': '5904723', 'n_tokens_mistral': 1420, 'n_tokens_neox': 1417, 'n_words': 259}