Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

openapi-gen-typescript

Package Overview
Dependencies
Maintainers
1
Versions
40
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

openapi-gen-typescript - npm Package Compare versions

Comparing version 0.3.3 to 0.3.4

dist/utils/fileStream.d.ts

3

dist/constants.d.ts

@@ -1,2 +0,3 @@

export declare const AllMethods: string[];
import { methods } from './utils/type';
export declare const AllMethods: methods[];
export declare const SortList: string[];

@@ -3,0 +4,0 @@ export declare const NotModifyCode = "/* tslint:disable */\n/**\n* This file was automatically generated by openapi-gen-typescript.\n* DO NOT MODIFY IT BY HAND.\n*/\n";

@@ -1,19 +0,4 @@

import { OpenAPI, OpenAPIV3 } from 'openapi-types';
import { ETemplateCode } from './constants';
import OperationObject = OpenAPIV3.OperationObject;
declare type PostScriptReturnType = {
[key in ETemplateCode]: string;
} | {
[key: string]: string;
};
export declare function gen(options: {
url?: string;
path?: string;
version: string;
object?: OpenAPI.Document;
outputDir: string;
fetchModuleFile?: string;
pascalCase?: boolean;
handlePostScript?: (obj: OperationObject, method?: string) => PostScriptReturnType;
}): Promise<void>;
export {};
import { IGenParmas } from './utils/type';
export declare function gen(options: IGenParmas): Promise<void>;
export declare const genDirWithPaths: (props: import("./utils/type").IPathsGenProp) => import("./utils/type").IHandelGenPathResult;
export declare const genDirWithTags: (props: import("./utils/type").ITagsGenProp) => import("./utils/type").IHandelGenPathResult;

@@ -11,371 +11,23 @@ "use strict";

};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.gen = void 0;
// @ts-ignore
const swagger2openapi = require("swagger2openapi");
const swaggerParser = require("@apidevtools/swagger-parser");
// @ts-ignore
const mkdirp = require("mkdirp");
const camelcase = require("camelcase");
const fs = require("fs");
const path = require("path");
const transform_1 = require("./schemaToTypes/transform");
const util_1 = require("./util");
const constants_1 = require("./constants");
const axios_1 = require("axios");
const _ = require("lodash");
function getCamelcase(urlPath, options) {
return camelcase(urlPath.split('/').join('_'), options);
}
function getCodeFromParameter(parameter, name) {
const { description, required } = parameter;
let code = '';
if (description) {
code += `/* ${description} */\n`;
}
code += `${name}${!!required ? '' : '?'}: string;`;
return code;
}
function getCodeFromParameters(parameters, name, exportKey = false) {
exports.genDirWithTags = exports.genDirWithPaths = exports.gen = void 0;
const genCodes_1 = require("./utils/genCodes");
const fileStream_1 = require("./utils/fileStream");
const getFilePath_1 = require("./utils/getFilePath");
const getInterfaceInfo_1 = require("./utils/getInterfaceInfo");
function gen(options) {
return __awaiter(this, void 0, void 0, function* () {
if (!parameters) {
return '';
}
const bodyCode = yield Promise.all(Object.keys(parameters).map(parameterName => {
return getCodeFromParameter(parameters[parameterName], parameterName);
}));
return `${exportKey ? 'export' : ''} interface ${name} {\n${bodyCode.join('\n')}\n}`;
});
}
function getCodeFromContent(content, typeNamePrefix, comment = '', responseTypeNames = []) {
return __awaiter(this, void 0, void 0, function* () {
if (!content) {
return '';
}
const contentCode = yield Promise.all(Object.keys(content).map((mediaType, index) => __awaiter(this, void 0, void 0, function* () {
const responseTypeName = `${typeNamePrefix}${index > 0 ? getCamelcase(mediaType, { pascalCase: true }) : ''}`;
let jsonSchema = transform_1.transform(content[mediaType].schema);
if (jsonSchema.lastIndexOf('[]') === jsonSchema.length - 2) {
jsonSchema = jsonSchema.replace(/\(|\)|(\[\])+/g, '');
responseTypeNames.push(`${responseTypeName}[]`);
}
else if (/^\(([\s\S]+)\)$/.test(jsonSchema)) {
jsonSchema = jsonSchema.replace(/^\(([\s\S]+)\)$/, '$1');
responseTypeNames.push(responseTypeName);
}
else {
responseTypeNames.push(responseTypeName);
}
return `export type ${responseTypeName} = ${jsonSchema}`;
})));
return contentCode.join('\n');
});
}
function getTagWithPaths(allTags, pathsMap) {
const commonTag = {
name: 'common',
description: 'common tag',
};
const customTags = allTags ? allTags.concat([commonTag]) : [commonTag];
const commonfilterPaths = Object.keys(pathsMap).filter(namespaceName => {
let filter = true;
customTags.forEach(currTag => {
if (pathsMap[namespaceName].tags.includes(currTag.name)) {
filter = false;
}
const { fetchModuleFile = `${__dirname}/defaultFetch.ts`, outputDir, pascalCase = true, } = options;
const openApiData = yield getInterfaceInfo_1.getOpenApiDoc(options);
const { fileCodeList, pathsCode } = yield genCodes_1.genCodes({ openApiData, options });
const { schemasClassCode, schemasTypesCode } = getInterfaceInfo_1.handleSchema({ pascalCase, openApiData });
yield fileStream_1.deleteFolderRecursive(outputDir);
yield fileStream_1.writeFileFromIFileCode({
outputDir,
fileCodeList,
fetchModuleFile,
schemasClassCode,
schemasTypesCode,
pathsCode,
});
return filter;
});
return customTags.map(currTag => {
const pathsInCurrTag = {};
let filterPaths = Object.keys(pathsMap).filter(namespaceName => pathsMap[namespaceName].tags.includes(currTag.name));
if (currTag.name === 'common') {
filterPaths = filterPaths.concat(commonfilterPaths);
}
filterPaths.map(namespaceName => {
pathsInCurrTag[namespaceName] = pathsMap[namespaceName];
});
return Object.assign(Object.assign({}, currTag), { pathsInCurrTag });
});
}
function getContentFromComponents(openApiData, ref, typename, arr) {
return __awaiter(this, void 0, void 0, function* () {
const splitRef = ref.replace(/^[^/]+\/components\//, '').split('/');
const result = _.get(openApiData.components, splitRef.join('.'));
const { content, description } = result;
const requestBodyCode = yield getCodeFromContent(content, typename, description, arr);
return requestBodyCode;
});
}
function gen(options) {
return __awaiter(this, void 0, void 0, function* () {
const { url, path: filePath, version, object, fetchModuleFile = `${__dirname}/defaultFetch.ts`, outputDir, pascalCase = true, } = options;
let openApiData;
if (url || filePath || object) {
const { dereference, parse } = swaggerParser;
// convertUrl响应速度很慢,改为使用convertObj
const { convertObj, convertFile } = swagger2openapi;
let params;
let openapi;
if (version === '2') {
if (url) {
try {
const result = yield axios_1.default.get(url);
if (result.status !== 200) {
throw Error(`未返回正确的status code ${result.status}: ${url}`);
}
params = result.data;
}
catch (e) {
console.error('e :>> ', e.message);
}
openapi = yield convertObj(params, {
patch: true,
});
}
if (filePath) {
params = filePath;
openapi = yield convertFile(params, {
patch: true,
});
}
if (object) {
params = object;
openapi = yield convertObj(params, {
patch: true,
});
}
openApiData = openapi.openapi || (yield dereference(openapi.openapi));
}
else {
openApiData = (yield parse(params));
}
}
else {
throw 'option: url or filePath or object must be specified one';
}
let baseUrl = '';
if (openApiData.servers) {
baseUrl = openApiData.servers[0].url;
}
const schemasTypesCode = [];
const schemasClassCode = [];
const { schemas } = openApiData.components || {};
if (schemas) {
Object.keys(schemas).forEach(schemaKey => {
const schemaObject = schemas[schemaKey];
if (pascalCase) {
schemaKey = camelcase(schemaKey, { pascalCase: true });
}
const transformObject = transform_1.transform(schemaObject);
schemasTypesCode.push(`export type ${schemaKey} = ${transformObject}`);
const classObject = transformObject.replace(/[()]/g, '').replace(/components.schemas./g, '');
schemasClassCode.push(`export class ${schemaKey} ${classObject}\n`);
});
}
const { paths, tags: allTags } = openApiData;
const pathsCode = [];
const pathsMap = {};
yield Promise.all(Object.keys(paths).map((urlPath) => __awaiter(this, void 0, void 0, function* () {
const pathsObject = paths[urlPath];
const filterMethods = constants_1.AllMethods.filter(method => !!pathsObject[method]);
const pathsTypesCode = [];
yield Promise.all(filterMethods.map((method) => __awaiter(this, void 0, void 0, function* () {
const objectElement = pathsObject[method];
const { operationId, parameters = [], requestBody = {}, responses, summary, tags, } = objectElement;
let namespaceName = operationId ||
`${method.toLowerCase()}${getCamelcase(urlPath, {
pascalCase: true,
})}`;
namespaceName = camelcase(namespaceName.replace(/[^a-zA-Z0-9_]/g, ''), {
pascalCase: true,
});
// request parameter
const requestPath = {};
const requestHeaders = {};
const requestCookies = {};
const requestQuery = {};
parameters.forEach(parameter => {
const _a = parameter, { in: keyIn, name } = _a, otherParams = __rest(_a, ["in", "name"]);
switch (keyIn) {
case 'path':
requestPath[name] = otherParams;
break;
case 'query':
requestQuery[name] = otherParams;
break;
case 'cookie':
requestCookies[name] = otherParams;
break;
case 'header':
if (['CONTENT-TYPE', 'COOKIE'].indexOf(name.toUpperCase()) === -1) {
requestHeaders[name] = otherParams;
}
break;
}
});
const requestPathCode = yield getCodeFromParameters(requestPath, 'Path', true);
const requestQueryCode = yield getCodeFromParameters(requestQuery, 'Query', true);
const requestCookieCode = yield getCodeFromParameters(requestCookies, 'Cookie', true);
const requestHeaderCode = yield getCodeFromParameters(requestHeaders, 'RequestHeader', true);
// request body
const { $ref: requestRef, content, required: requestBodyRequired, description: requestBodyDescription, } = requestBody;
let requestBodyCode = '';
const requestBodyTypeNames = [];
if (requestRef) {
requestBodyCode = yield getContentFromComponents(openApiData, requestRef, `Body`, requestBodyTypeNames);
}
else {
requestBodyCode = yield getCodeFromContent(content, `Body`, requestBodyDescription, requestBodyTypeNames);
}
// response
const responseTypeNames = [];
const responsesArr = Object.keys(responses);
const responsesCode = (yield Promise.all(responsesArr.map((statusCode) => __awaiter(this, void 0, void 0, function* () {
const responsesObjectElement = responses[statusCode];
const { $ref, content, description } = responsesObjectElement;
const typeNamePrefix = `Response${camelcase(statusCode, {
pascalCase: true,
})}`;
if ($ref) {
const responseCode = yield getContentFromComponents(openApiData, requestRef, typeNamePrefix, requestBodyTypeNames);
return responseCode;
}
else {
// response
const responseCode = yield getCodeFromContent(content, typeNamePrefix, description, responseTypeNames);
return responseCode;
}
})))).join('\n');
const requestFuncTypeCode = `
export const request = async (options: {
path?: Path;
query?: Query;
body${requestBodyRequired ? '' : '?'}: ${requestBodyTypeNames.length > 0 ? requestBodyTypeNames.join('|') : 'any'};
headers?: RequestHeader;
cookie?: Cookie;
}, otherOptions?: any): Promise<{ body: ${responseTypeNames.length > 0 ? responseTypeNames.join('|') : 'any'} }> => {
let resolvedUrl = '${(baseUrl + urlPath).replace('//', '/')}';
${_.isEmpty(requestPath)
? ''
: `if (!!options.path) {
Object.keys(options.path).map(key => {
const regex = new RegExp(\`({(\${key})})|(:(\${key}))\`, 'g');
resolvedUrl = url.replace(regex, options.path[key]);
});
}`}
return fetchImpl({
url: resolvedUrl,
method: '${method.toLowerCase()}',
...options,
...otherOptions
});
};
`;
const requestUrl = `export const url = \`${(baseUrl + urlPath).replace('//', '/')}\``;
let exportObj = {
requestUrl,
requestPathCode,
requestQueryCode,
requestHeaderCode,
requestCookieCode,
requestBodyCode,
responsesCode,
requestFuncTypeCode,
};
if (options.handlePostScript) {
const result = yield options.handlePostScript(objectElement, method);
exportObj = Object.assign({}, exportObj, result);
}
const exportArr = [];
constants_1.SortList.forEach(item => {
exportArr.push(exportObj[item]);
});
Object.keys(exportObj).forEach(item => {
if (!constants_1.SortList.includes(item)) {
exportArr.unshift(exportObj[item]);
}
});
const pathsTypesArr = exportArr.map(exp => {
return exp
.replace(/export const request = async/, 'export type request =')
.replace(/: Promise<([^>]+)>((\s|\S)+)/g, '=> Promise<$1>;');
});
pathsTypesCode.push(`export namespace ${namespaceName} {\n${pathsTypesArr.join('\n')}\n}`);
const generateClassArr = exportArr.map(exp => {
const exp1 = exp.replace(/ interface | type = /g, ' class ');
const exp2 = exp1.replace(/ type ([^=]+) = components.([a-zA-Z0-9._]+)[;{}]?/g, ' class $1 extends $2 {}');
const exp3 = exp2.replace(/ type ([^=]+) = {/g, ' class $1 {');
const exp4 = exp3.replace(/components.schemas/g, 'schemas');
return exp4;
});
pathsMap[namespaceName] = {
summary,
tags: tags || [],
code: generateClassArr.join('\n'),
};
})));
pathsCode.push(pathsTypesCode.join('\n'));
})));
yield util_1.deleteFolderRecursive(outputDir);
// generate code
yield mkdirp(outputDir);
const tagWithPaths = getTagWithPaths(allTags, pathsMap);
yield Promise.all(tagWithPaths.map((currTag) => __awaiter(this, void 0, void 0, function* () {
const currMap = currTag.pathsInCurrTag;
if (Object.keys(currMap).length > 0) {
const currTagNameDir = `${outputDir}/${currTag.name}`;
yield mkdirp(currTagNameDir);
const namespaceNameArr = [];
Object.keys(currMap).map((namespaceName) => {
const { summary, code } = currMap[namespaceName];
const pathCode = [
`/**
* @namespace ${namespaceName}
* @summary ${summary}
*/\n`,
`import fetchImpl from '${path
.relative(currTagNameDir, fetchModuleFile)
.replace(/\.ts$/, '')}';`
.split(path.sep)
.join('/'),
schemasClassCode.length > 0 ? `import * as schemas from '../schemas';\n` : '\n',
code,
].join('\n');
namespaceNameArr.push(namespaceName);
fs.writeFileSync(`${currTagNameDir}/${namespaceName}.ts`, util_1.format(pathCode));
});
const tagCode = [
`/**
* @description ${currTag.description}
*/\n`,
...namespaceNameArr.map(key => `import * as ${key} from './${key}';`),
`\nexport {
${namespaceNameArr.join(',\n')}
}`,
].join('\n');
fs.writeFileSync(`${currTagNameDir}/index.ts`, util_1.format(tagCode));
}
})));
const typesCode = [
constants_1.NotModifyCode,
`export namespace components { export namespace schemas { ${schemasTypesCode.join('\n')} } } `,
`export namespace Api { ${pathsCode.join('\n')} } `,
].join('\n');
fs.writeFileSync(`${outputDir}/index.ts`, util_1.format(typesCode));
if (schemasClassCode.length > 0) {
const schemasCode = [constants_1.NotModifyCode, schemasClassCode.join('\n')].join('\n');
fs.writeFileSync(`${outputDir}/schemas.ts`, util_1.format(schemasCode));
}
console.info(`Generate code successful in directory: ${outputDir}`);

@@ -385,1 +37,3 @@ });

exports.gen = gen;
exports.genDirWithPaths = getFilePath_1.genPaths;
exports.genDirWithTags = getFilePath_1.genTags;
{
"name": "openapi-gen-typescript",
"version": "0.3.3",
"version": "0.3.4",
"main": "dist/index.js",

@@ -5,0 +5,0 @@ "types": "dist/index.d.ts",

@@ -22,5 +22,5 @@ # openapi-gen-typescript

| object | The docs of fetch openapi or swagger data |
| version | The version of Swagger or OpenApi, example: `2`, `3` |
| outputDir | Dir of output files |
| fetchModuleFile | Fetch impl file path |
| handleGenPath | Processing generated paths |
| handlePostScript | post script to customize the result |

@@ -1,3 +0,5 @@

export const AllMethods: string[] = ['get', 'post', 'options', 'put', 'delete', 'patch', 'head'];
import { methods } from './utils/type';
export const AllMethods: methods[] = ['get', 'post', 'options', 'put', 'delete', 'patch', 'head'];
export const SortList = [

@@ -4,0 +6,0 @@ 'requestUrl',

// @ts-ignore
import * as swagger2openapi from 'swagger2openapi';
import * as swaggerParser from '@apidevtools/swagger-parser';
// @ts-ignore
import * as mkdirp from 'mkdirp';
import * as camelcase from 'camelcase';
import { Options } from 'camelcase';
import * as fs from 'fs';
import * as path from 'path';
import { transform } from './schemaToTypes/transform';
import { format, deleteFolderRecursive } from './util';
import { IJsonSchema, OpenAPI, OpenAPIV3 } from 'openapi-types';
import { AllMethods, SortList, NotModifyCode, ETemplateCode } from './constants';
import ParameterBaseObject = OpenAPIV3.ParameterBaseObject;
import MediaTypeObject = OpenAPIV3.MediaTypeObject;
import OperationObject = OpenAPIV3.OperationObject;
import PathItemObject = OpenAPIV3.PathItemObject;
import ResponseObject = OpenAPIV3.ResponseObject;
import ReferenceObject = OpenAPIV3.ReferenceObject;
import ParameterObject = OpenAPIV3.ParameterObject;
import RequestBodyObject = OpenAPIV3.RequestBodyObject;
import Axios from 'axios';
import { OpenAPIV3 } from 'openapi-types';
import * as _ from 'lodash';
import { IGenParmas } from './utils/type';
import { genCodes } from './utils/genCodes';
import { deleteFolderRecursive, writeFileFromIFileCode } from './utils/fileStream';
import { genPaths, genTags } from './utils/getFilePath';
import { getOpenApiDoc, handleSchema } from './utils/getInterfaceInfo';
type ContentObject = {
[media: string]: MediaTypeObject;
};
type PostScriptReturnType =
| {
[key in ETemplateCode]: string;
}
| {
[key: string]: string;
};
function getCamelcase(urlPath: string, options?: Options): string {
return camelcase(urlPath.split('/').join('_'), options);
}
function getCodeFromParameter(parameter: ParameterBaseObject, name: string): string {
const { description, required } = parameter;
let code = '';
if (description) {
code += `/* ${description} */\n`;
}
code += `${name}${!!required ? '' : '?'}: string;`;
return code;
}
interface IParameterMap {
[name: string]: ParameterBaseObject;
}
interface IPathMapContent {
summary: string | undefined;
tags: string[];
code: string;
}
interface IPathMap {
[key: string]: IPathMapContent;
}
async function getCodeFromParameters(
parameters: IParameterMap | undefined,
name: string,
exportKey: boolean = false,
): Promise<string> {
if (!parameters) {
return '';
}
const bodyCode = await Promise.all(
Object.keys(parameters).map(parameterName => {
return getCodeFromParameter(parameters[parameterName], parameterName);
}),
);
return `${exportKey ? 'export' : ''} interface ${name} {\n${bodyCode.join('\n')}\n}`;
}
async function getCodeFromContent(
content: ContentObject,
typeNamePrefix: string,
comment: string = '',
responseTypeNames: string[] = [],
): Promise<string> {
if (!content) {
return '';
}
const contentCode = await Promise.all(
Object.keys(content).map(async (mediaType, index) => {
const responseTypeName = `${typeNamePrefix}${
index > 0 ? getCamelcase(mediaType, { pascalCase: true }) : ''
}`;
let jsonSchema = transform((content[mediaType] as MediaTypeObject).schema as IJsonSchema);
if (jsonSchema.lastIndexOf('[]') === jsonSchema.length - 2) {
jsonSchema = jsonSchema.replace(/\(|\)|(\[\])+/g, '');
responseTypeNames.push(`${responseTypeName}[]`);
} else if (/^\(([\s\S]+)\)$/.test(jsonSchema)) {
jsonSchema = jsonSchema.replace(/^\(([\s\S]+)\)$/, '$1');
responseTypeNames.push(responseTypeName);
} else {
responseTypeNames.push(responseTypeName);
}
return `export type ${responseTypeName} = ${jsonSchema}`;
}),
);
return contentCode.join('\n');
}
function getTagWithPaths(allTags: OpenAPIV3.TagObject[] | undefined, pathsMap: IPathMap) {
const commonTag: OpenAPIV3.TagObject = {
name: 'common',
description: 'common tag',
};
const customTags = allTags ? allTags.concat([commonTag]) : [commonTag];
const commonfilterPaths = Object.keys(pathsMap).filter(namespaceName => {
let filter = true;
customTags.forEach(currTag => {
if (pathsMap[namespaceName].tags.includes(currTag.name)) {
filter = false;
}
});
return filter;
});
return customTags.map(currTag => {
const pathsInCurrTag: { [key: string]: any } = {};
let filterPaths = Object.keys(pathsMap).filter(namespaceName =>
pathsMap[namespaceName].tags.includes(currTag.name),
);
if (currTag.name === 'common') {
filterPaths = filterPaths.concat(commonfilterPaths);
}
filterPaths.map(namespaceName => {
pathsInCurrTag[namespaceName] = pathsMap[namespaceName];
});
return {
...currTag,
pathsInCurrTag,
};
});
}
async function getContentFromComponents(
openApiData: OpenAPIV3.Document,
ref: string,
typename: string,
arr: string[],
): Promise<string> {
const splitRef = ref.replace(/^[^/]+\/components\//, '').split('/');
const result = _.get(openApiData.components, splitRef.join('.'));
const { content, description }: ReferenceObject & RequestBodyObject = result as any;
const requestBodyCode = await getCodeFromContent(content, typename, description, arr);
return requestBodyCode;
}
export async function gen(options: {
url?: string;
path?: string;
version: string;
object?: OpenAPI.Document;
// dir of output files
outputDir: string;
// fetch impl file path
fetchModuleFile?: string;
pascalCase?: boolean;
handlePostScript?: (obj: OperationObject, method?: string) => PostScriptReturnType;
}) {
export async function gen(options: IGenParmas) {
const {
url,
path: filePath,
version,
object,
fetchModuleFile = `${__dirname}/defaultFetch.ts`,

@@ -185,347 +20,24 @@ outputDir,

let openApiData: OpenAPIV3.Document;
if (url || filePath || object) {
const { dereference, parse } = swaggerParser;
// convertUrl响应速度很慢,改为使用convertObj
const { convertObj, convertFile } = swagger2openapi;
let params: any;
let openapi: any;
if (version === '2') {
if (url) {
try {
const result = await Axios.get(url);
if (result.status !== 200) {
throw Error(`未返回正确的status code ${result.status}: ${url}`);
}
params = result.data;
} catch (e) {
console.error('e :>> ', e.message);
}
openapi = await convertObj(params, {
patch: true,
});
}
if (filePath) {
params = filePath;
openapi = await convertFile(params, {
patch: true,
});
}
if (object) {
params = object;
openapi = await convertObj(params, {
patch: true,
});
}
openApiData = openapi.openapi || (await dereference(openapi.openapi));
} else {
openApiData = (await parse(params)) as OpenAPIV3.Document;
}
} else {
throw 'option: url or filePath or object must be specified one';
}
const openApiData: OpenAPIV3.Document = await getOpenApiDoc(options);
let baseUrl = '';
if (openApiData.servers) {
baseUrl = openApiData.servers[0].url;
}
const { fileCodeList, pathsCode } = await genCodes({ openApiData, options });
const schemasTypesCode: string[] = [];
const schemasClassCode: string[] = [];
const { schemas } = openApiData.components || {};
if (schemas) {
Object.keys(schemas).forEach(schemaKey => {
const schemaObject = schemas[schemaKey] as IJsonSchema;
if (pascalCase) {
schemaKey = camelcase(schemaKey, { pascalCase: true });
}
const transformObject = transform(schemaObject);
schemasTypesCode.push(`export type ${schemaKey} = ${transformObject}`);
const classObject = transformObject.replace(/[()]/g, '').replace(/components.schemas./g, '');
schemasClassCode.push(`export class ${schemaKey} ${classObject}\n`);
});
}
const { schemasClassCode, schemasTypesCode } = handleSchema({ pascalCase, openApiData });
const { paths, tags: allTags } = openApiData;
const pathsCode: string[] = [];
const pathsMap: IPathMap = {};
await Promise.all(
Object.keys(paths).map(async urlPath => {
const pathsObject: PathItemObject = paths[urlPath] as any;
const filterMethods = AllMethods.filter(method => !!(pathsObject as any)[method]);
const pathsTypesCode: string[] = [];
await Promise.all(
filterMethods.map(async method => {
const objectElement: OperationObject = (pathsObject as any)[method] as OperationObject;
const {
operationId,
parameters = [],
requestBody = {},
responses,
summary,
tags,
} = objectElement;
let namespaceName =
operationId ||
`${method.toLowerCase()}${getCamelcase(urlPath, {
pascalCase: true,
})}`;
namespaceName = camelcase(namespaceName.replace(/[^a-zA-Z0-9_]/g, ''), {
pascalCase: true,
});
// request parameter
const requestPath: IParameterMap = {};
const requestHeaders: IParameterMap = {};
const requestCookies: IParameterMap = {};
const requestQuery: IParameterMap = {};
parameters.forEach(parameter => {
const { in: keyIn, name, ...otherParams } = parameter as ParameterObject;
switch (keyIn) {
case 'path':
requestPath[name] = otherParams;
break;
case 'query':
requestQuery[name] = otherParams;
break;
case 'cookie':
requestCookies[name] = otherParams;
break;
case 'header':
if (['CONTENT-TYPE', 'COOKIE'].indexOf(name.toUpperCase()) === -1) {
requestHeaders[name] = otherParams;
}
break;
}
});
const requestPathCode = await getCodeFromParameters(requestPath, 'Path', true);
const requestQueryCode = await getCodeFromParameters(requestQuery, 'Query', true);
const requestCookieCode = await getCodeFromParameters(requestCookies, 'Cookie', true);
const requestHeaderCode = await getCodeFromParameters(
requestHeaders,
'RequestHeader',
true,
);
// request body
const {
$ref: requestRef,
content,
required: requestBodyRequired,
description: requestBodyDescription,
}: ReferenceObject & RequestBodyObject = requestBody as any;
let requestBodyCode = '';
const requestBodyTypeNames: string[] = [];
if (requestRef) {
requestBodyCode = await getContentFromComponents(
openApiData,
requestRef,
`Body`,
requestBodyTypeNames,
);
} else {
requestBodyCode = await getCodeFromContent(
content,
`Body`,
requestBodyDescription,
requestBodyTypeNames,
);
}
// response
const responseTypeNames: string[] = [];
const responsesArr = Object.keys(responses as Object);
const responsesCode = (
await Promise.all(
responsesArr.map(async statusCode => {
const responsesObjectElement: ResponseObject & ReferenceObject = (responses as any)[
statusCode
];
const { $ref, content, description } = responsesObjectElement;
const typeNamePrefix = `Response${camelcase(statusCode, {
pascalCase: true,
})}`;
if ($ref) {
const responseCode = await getContentFromComponents(
openApiData,
requestRef,
typeNamePrefix,
requestBodyTypeNames,
);
return responseCode;
} else {
// response
const responseCode = await getCodeFromContent(
content as ContentObject,
typeNamePrefix,
description,
responseTypeNames,
);
return responseCode;
}
}),
)
).join('\n');
const requestFuncTypeCode = `
export const request = async (options: {
path?: Path;
query?: Query;
body${requestBodyRequired ? '' : '?'}: ${
requestBodyTypeNames.length > 0 ? requestBodyTypeNames.join('|') : 'any'
};
headers?: RequestHeader;
cookie?: Cookie;
}, otherOptions?: any): Promise<{ body: ${
responseTypeNames.length > 0 ? responseTypeNames.join('|') : 'any'
} }> => {
let resolvedUrl = '${(baseUrl + urlPath).replace('//', '/')}';
${
_.isEmpty(requestPath)
? ''
: `if (!!options.path) {
Object.keys(options.path).map(key => {
const regex = new RegExp(\`({(\${key})})|(:(\${key}))\`, 'g');
resolvedUrl = url.replace(regex, options.path[key]);
});
}`
}
return fetchImpl({
url: resolvedUrl,
method: '${method.toLowerCase()}',
...options,
...otherOptions
});
};
`;
const requestUrl = `export const url = \`${(baseUrl + urlPath).replace('//', '/')}\``;
let exportObj: { [key: string]: string } = {
requestUrl,
requestPathCode,
requestQueryCode,
requestHeaderCode,
requestCookieCode,
requestBodyCode,
responsesCode,
requestFuncTypeCode,
};
if (options.handlePostScript) {
const result = await options.handlePostScript(objectElement, method);
exportObj = Object.assign({}, exportObj, result);
}
const exportArr: string[] = [];
SortList.forEach(item => {
exportArr.push(exportObj[item]);
});
Object.keys(exportObj).forEach(item => {
if (!SortList.includes(item)) {
exportArr.unshift(exportObj[item]);
}
});
const pathsTypesArr = exportArr.map(exp => {
return exp
.replace(/export const request = async/, 'export type request =')
.replace(/: Promise<([^>]+)>((\s|\S)+)/g, '=> Promise<$1>;');
});
pathsTypesCode.push(
`export namespace ${namespaceName} {\n${pathsTypesArr.join('\n')}\n}`,
);
const generateClassArr = exportArr.map(exp => {
const exp1 = exp.replace(/ interface | type = /g, ' class ');
const exp2 = exp1.replace(
/ type ([^=]+) = components.([a-zA-Z0-9._]+)[;{}]?/g,
' class $1 extends $2 {}',
);
const exp3 = exp2.replace(/ type ([^=]+) = {/g, ' class $1 {');
const exp4 = exp3.replace(/components.schemas/g, 'schemas');
return exp4;
});
pathsMap[namespaceName] = {
summary,
tags: tags || [],
code: generateClassArr.join('\n'),
};
}),
);
pathsCode.push(pathsTypesCode.join('\n'));
}),
);
await deleteFolderRecursive(outputDir);
// generate code
await mkdirp(outputDir);
await writeFileFromIFileCode({
outputDir,
fileCodeList,
fetchModuleFile,
schemasClassCode,
schemasTypesCode,
pathsCode,
});
const tagWithPaths = getTagWithPaths(allTags, pathsMap);
console.info(`Generate code successful in directory: ${outputDir}`);
}
await Promise.all(
tagWithPaths.map(async currTag => {
const currMap = currTag.pathsInCurrTag;
if (Object.keys(currMap).length > 0) {
const currTagNameDir = `${outputDir}/${currTag.name}`;
await mkdirp(currTagNameDir);
const namespaceNameArr: string[] = [];
Object.keys(currMap).map((namespaceName: string) => {
const { summary, code } = currMap[namespaceName];
const pathCode = [
`/**
* @namespace ${namespaceName}
* @summary ${summary}
*/\n`,
`import fetchImpl from '${path
.relative(currTagNameDir, fetchModuleFile)
.replace(/\.ts$/, '')}';`
.split(path.sep)
.join('/'),
schemasClassCode.length > 0 ? `import * as schemas from '../schemas';\n` : '\n',
code,
].join('\n');
namespaceNameArr.push(namespaceName);
fs.writeFileSync(`${currTagNameDir}/${namespaceName}.ts`, format(pathCode));
});
const tagCode = [
`/**
* @description ${currTag.description}
*/\n`,
...namespaceNameArr.map(key => `import * as ${key} from './${key}';`),
`\nexport {
${namespaceNameArr.join(',\n')}
}`,
].join('\n');
export const genDirWithPaths = genPaths;
fs.writeFileSync(`${currTagNameDir}/index.ts`, format(tagCode));
}
}),
);
const typesCode = [
NotModifyCode,
`export namespace components { export namespace schemas { ${schemasTypesCode.join('\n')} } } `,
`export namespace Api { ${pathsCode.join('\n')} } `,
].join('\n');
fs.writeFileSync(`${outputDir}/index.ts`, format(typesCode));
if (schemasClassCode.length > 0) {
const schemasCode = [NotModifyCode, schemasClassCode.join('\n')].join('\n');
fs.writeFileSync(`${outputDir}/schemas.ts`, format(schemasCode));
}
console.info(`Generate code successful in directory: ${outputDir}`);
}
export const genDirWithTags = genTags;

@@ -14,3 +14,4 @@ {

"sourceMap": false,
"outDir": "dist"
"outDir": "dist",
"baseUrl": "src"
},

@@ -17,0 +18,0 @@ "include": [

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc