openapi-format
Version: 
Format an OpenAPI document by ordering, formatting and filtering fields.
129 lines (107 loc) • 3.99 kB
JavaScript
;
const {changeCase} = require('./casing');
/**
 * Method to parse a template string
 * @param {Object} dto - Parse template DTO
 * @param {string} [dto.template] - Template string to parse
 * @param {Object} [dto.oaOperation] - OpenAPI operation object
 * @param {Object} [dto.dynamicValues] - Dynamic values to replace in the template
 * @param {Object} [dto.options] - Options for parsing
 * @param {string} [dto.options.casing] - Casing style to apply
 * @param {string} [dto.options.prefix] - Prefix to add to the generated string
 * @param {string} [dto.options.suffix] - Suffix to add to the generated string
 * @param {boolean} [dto.options.caseOnlyExpressions] - Whether to apply casing only to template expressions
 * @returns {string} - The parsed template string
 */
function parseTpl(dto) {
  const {template = '<opsRef>.<varProp>', oaOperation, dynamicValues, options} = dto;
  if (!template || typeof template !== 'string') return template;
  let varName = template;
  let partsCounter = 0;
  const pathParts = oaOperation?.path?.split('/') ?? [];
  const pathPartsObj = pathParts.reduce((acc, pathPart) => {
    if (pathPart.trim() !== '') {
      partsCounter++;
      acc[`pathPart${partsCounter}`] = pathPart;
    }
    return acc;
  }, {});
  const tags = oaOperation?.tags ?? [];
  const tagsObj = tags.reduce((acc, tag, index) => {
    acc[`tag${index + 1}`] = tag;
    return acc;
  }, {});
  const openApiInfo =
    {
      operationId: oaOperation?.id,
      path: oaOperation?.path,
      pathRef: oaOperation?.pathRef,
      method: oaOperation?.method,
      opsRef: oaOperation?.id ?? oaOperation?.pathRef,
      tag: oaOperation?.tags?.[0]
    } || {};
  const tplValues = {...pathPartsObj, ...tagsObj, ...openApiInfo, ...dynamicValues};
  const startSymbol = '<';
  const endSymbol = '>';
  const placeholderRegex = new RegExp(`${startSymbol}(.*?)${endSymbol}`, 'g');
  varName = varName.replace(placeholderRegex, (_, placeholder) => {
    placeholder = placeholder.trim();
    const tplValue = tplValues[placeholder];
    const casedTplValue =
      options?.caseOnlyExpressions === true && options?.casing ? changeCase(tplValue, options?.casing) : tplValue;
    return casedTplValue ? casedTplValue : '';
  });
  if (options?.prefix) {
    varName = options.prefix.trim() + varName;
  }
  if (options?.suffix) {
    varName = varName + options.suffix.trim();
  }
  if (options?.casing && varName && options?.caseOnlyExpressions !== true) {
    const placeholderRegex = new RegExp(`({{{?|{{)(.*?)(}}}?|}})`, 'g');
    varName = varName.replace(placeholderRegex, (_, openingBraces, placeholder, closingBraces) => {
      if (options.casing) {
        return `${openingBraces}${changeCase(placeholder.trim(), options.casing)}${closingBraces}`;
      }
      return `${openingBraces}${placeholder}${closingBraces}`;
    });
    if (!varName.includes('{{') && !varName.includes('}}')) {
      varName = changeCase(varName, options.casing);
    }
  }
  return varName;
}
function hasTpl(template) {
  if (!template) return false;
  const symbolsRegex = /<|>/;
  return symbolsRegex.test(template);
}
function getOperation(path, method, oa) {
  let operation;
  // Normalize the method to lowercase to ensure case insensitivity
  const normalizedMethod = method.toLowerCase();
  const upperMethod = method.toUpperCase();
  // Check if the path exists in the OpenAPI object
  if (oa.paths && oa.paths[path]) {
    // Check if the method exists for the specified path
    if (oa.paths[path][normalizedMethod]) {
      operation = oa.paths[path][normalizedMethod]; // Return the operation object
    } else {
      return undefined;
    }
  }
  return {
    operation: operation,
    id: operation?.operationId,
    operationId: operation?.operationId,
    method: normalizedMethod,
    path: path,
    pathRef: `${upperMethod}::${path}`,
    tags: operation?.tags
  };
}
module.exports = {
  parseTpl,
  hasTpl,
  getOperation
};