jswagger-generator
Version:
This is jswagger's generator package.
188 lines (169 loc) • 6.27 kB
text/typescript
import {
findApisByTag,
OpenAPI2,
OpenAPI2Path,
OpenAPI2Reference,
OpenAPI2SchemaObject,
OpenAPI2Tag,
OpenAPI3
} from 'jswagger-common';
import {
IOptions
} from '../types';
import {
generateTypesOnly, GenerateTypesOnlyFlag
} from '../definition-interface-generator/v2';
const templateIn = `
/*INTERFACES_S*/
export interface _GenITagName {
/*METHODS_S*/
/**
* _GenMethodName
*
* @throws {ApiError}
* @return {Promise<ApiResponse<?>>}
*/
_GenMethodName(options_GenApiOptionOptional: ApiRequestOptions_GenApiRequestOptionsSuffix<_GenRequestBodyType, _GenParamsType>): Promise<ApiResponse<_GenResponseBodyType, _GenResponseHeaderType>>;
/*METHODS_E*/
}
/*INTERFACES_E*/
`;
function makeInterfaceTypeFromSchema(node: OpenAPI2SchemaObject | OpenAPI2Reference, flags?: GenerateTypesOnlyFlag): string {
return generateTypesOnly(
node,
(typeof flags === 'undefined') ? GenerateTypesOnlyFlag.INTERFACE | GenerateTypesOnlyFlag.CLASS : flags
);
}
function makeInterfaceName(tagName: string): string {
return tagName.replace(
/([-_].)/g,
(group) => group.toUpperCase()
.replace('-', '')
.replace('_', '')
);
}
export function makeApiInterfaces(
spec: OpenAPI2 | OpenAPI3,
options?: IOptions
): string {
const outputs: string[] = [];
const interfacesMatcher = /(\/\*INTERFACES_S\*\/)((?:.|\r|\n)*)(\/\*INTERFACES_E\*\/)/gm.exec(templateIn);
if (!interfacesMatcher) {
throw new Error('Unknown Error #1');
}
outputs.push(templateIn.slice(0, interfacesMatcher.index));
const interfaceTemplate = interfacesMatcher[2];
const methodsMatcher = /(\/\*METHODS_S\*\/)((?:.|\r|\n)*)(\/\*METHODS_E\*\/)/gm.exec(interfaceTemplate);
if (!methodsMatcher) {
throw new Error('Unknown Error #2');
}
const methodTemplate = methodsMatcher[2];
const tags = spec.tags && spec.tags.length > 0 ? spec.tags : (() => {
const tagNames = new Set<string>();
Object.entries(spec.paths)
.forEach((a) => {
const pathItem = a[1] as OpenAPI2Path;
Object.entries(pathItem)
.forEach(([, methodItem]) => {
methodItem.tags.forEach(tagName => {
tagNames.add(tagName);
});
});
});
return Array.from(tagNames.keys())
.reduce((result, current) => {
result.push({
name: current,
description: ''
});
return result;
}, [] as OpenAPI2Tag[]);
})();
tags.forEach((tagItem: OpenAPI2Tag) => {
const tagOutputs: string[] = [];
tagOutputs.push(interfaceTemplate.slice(0, methodsMatcher.index));
const apis = findApisByTag(spec, tagItem.name);
apis.forEach(apiItem => {
const reqBodyParameter = apiItem.api.parameters && apiItem.api.parameters.find(v => v.in === 'body');
const reqAllParameters = apiItem.api.parameters && apiItem.api.parameters.filter(v => v.in !== 'body') || [];
const reqBodyOptionalType =
reqBodyParameter ? (reqBodyParameter.required ? 'R' : 'O') :
'X';
const reqParametersOptionalType =
(reqAllParameters.length === 0) ? 'X' :
reqAllParameters.find(v => v.required) ? 'R' : 'O';
const reqBodyType = (reqBodyParameter && reqBodyParameter.schema) ?
makeInterfaceTypeFromSchema(reqBodyParameter.schema) :
'never';
const reqParamsType =
(() => {
const types: string[] = [];
reqAllParameters
.map(v => {
if (options && options.paramFilter) {
return options.paramFilter({
tag: tagItem.name,
path: apiItem.path,
method: apiItem.method
}, v);
}
return v;
})
.forEach((item) => {
if (item) {
types.push(`'${item.name}': ` + (item.schema ? makeInterfaceTypeFromSchema(item.schema) : 'any'));
}
});
return `{${types.join(', ')}}`;
})();
const resParameters = apiItem.api.responses && apiItem.api.responses['200'];
const responseBodyType = (resParameters && resParameters.schema) ?
makeInterfaceTypeFromSchema(resParameters.schema, GenerateTypesOnlyFlag.CLASS) :
'never';
const responseHeaderType =
(() => {
const types: string[] = [];
if (resParameters && resParameters.headers) {
Object.entries(resParameters.headers)
.forEach(([name, item]) => {
types.push(`'${name}': ` + makeInterfaceTypeFromSchema(item));
});
}
types.push('[key: string]: any');
return `{${types.join(', ')}}`;
})();
tagOutputs.push(
methodTemplate
.replace(/_GenMethodName/g, apiItem.api.operationId)
.replace('_GenApiRequestOptionsSuffix', reqBodyOptionalType + reqParametersOptionalType)
.replace('_GenApiOptionOptional',
(
((reqBodyOptionalType === 'X') || (reqBodyOptionalType === 'O')) &&
((reqParametersOptionalType === 'X') || (reqParametersOptionalType === 'O'))
) ? '?' : ''
)
.replace('_GenRequestBodyType', reqBodyType)
.replace('_GenResponseBodyType', responseBodyType)
.replace('_GenParamsType', reqParamsType)
.replace('_GenResponseHeaderType', responseHeaderType)
);
});
tagOutputs.push(interfaceTemplate.slice(methodsMatcher.index + methodsMatcher[0].length));
outputs.push(
tagOutputs.join('')
.replace('_GenITagName', makeInterfaceName(tagItem.name))
);
});
outputs.push(templateIn.slice(interfacesMatcher.index + interfacesMatcher[0].length));
outputs.push('export const APIS = Object.freeze({\n');
outputs.push(
tags.map((tagItem: OpenAPI2Tag) => {
return `${makeInterfaceName(tagItem.name)}: {
tag: '${tagItem.name}',
specMetadata: metadata
}`;
})
);
outputs.push('});');
return outputs.join('');
}