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.1.0 to 0.1.2

.prettierrc.json

11

dist/index.d.ts

@@ -1,11 +0,4 @@

import { OpenAPI, OpenAPIV3 } from "openapi-types";
import { OpenAPI, OpenAPIV3 } from 'openapi-types';
import { ETemplateCode } from './constants';
import OperationObject = OpenAPIV3.OperationObject;
declare enum ETemplateCode {
RequestQueryCode = "requestQueryCode",
RequestHeaderCode = "requestHeaderCode",
RequestCookieCode = "requestCookieCode",
RequestBodyCode = "requestBodyCode",
ResponsesCode = "responsesCode",
RequestFuncTypeCode = "requestFuncTypeCode"
}
declare type PostScriptReturnType = {

@@ -12,0 +5,0 @@ [key in ETemplateCode]: string;

@@ -34,11 +34,3 @@ "use strict";

const util_1 = require("./util");
var ETemplateCode;
(function (ETemplateCode) {
ETemplateCode["RequestQueryCode"] = "requestQueryCode";
ETemplateCode["RequestHeaderCode"] = "requestHeaderCode";
ETemplateCode["RequestCookieCode"] = "requestCookieCode";
ETemplateCode["RequestBodyCode"] = "requestBodyCode";
ETemplateCode["ResponsesCode"] = "responsesCode";
ETemplateCode["RequestFuncTypeCode"] = "requestFuncTypeCode";
})(ETemplateCode || (ETemplateCode = {}));
const constants_1 = require("./constants");
function getCamelcase(urlPath, options) {

@@ -61,6 +53,6 @@ return camelcase(urlPath.split('/').join('_'), options);

}
const bodyCode = (yield Promise.all(Object.keys(parameters).map((parameterName) => {
const bodyCode = yield Promise.all(Object.keys(parameters).map(parameterName => {
return getCodeFromParameter(parameters[parameterName], parameterName);
}))).join('\n');
return `${exportKey ? 'export' : ''} interface ${name} {\n${bodyCode}\n}`;
}));
return `${exportKey ? 'export' : ''} interface ${name} {\n${bodyCode.join('\n')}\n}`;
});

@@ -73,36 +65,63 @@ }

}
return (yield Promise.all(Object.keys(content).map((mediaType, index) => __awaiter(this, void 0, void 0, function* () {
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 }) : ''}`;
responseTypeNames.push(responseTypeName);
return `export type ${responseTypeName} = ${transform_1.transform(content[mediaType].schema)}`;
})))).join('\n');
let jsonSchema = transform_1.transform(content[mediaType].schema);
if (jsonSchema.includes('[]')) {
jsonSchema = jsonSchema.replace(/[\(\)\[\]]+/g, '');
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;
}
});
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 gen(options) {
return __awaiter(this, void 0, void 0, function* () {
const { url, path: filePath, version, object, fetchModuleFile = `${__dirname}/defaultFetch.ts`, outputDir, pascalCase = true, } = options;
const fetchModuleImportCode = `import fetchImpl from '${path.relative(outputDir, fetchModuleFile).replace(/\.ts$/, '')}';\n`;
let openApiData;
if (url) {
if (url || filePath) {
const { dereference, parse } = swaggerParser;
const params = url || filePath;
if (version === '2') {
const openapi = yield swagger2openapi.convertUrl(url, {
const { convertUrl, convertFile } = swagger2openapi;
const openapiConvert = url ? convertUrl : convertFile;
const openapi = yield openapiConvert(params, {
patch: true,
});
openApiData = openapi.openapi || (yield swaggerParser.dereference(openapi.openapi));
openApiData = openapi.openapi || (yield dereference(openapi.openapi));
}
else {
openApiData = (yield swaggerParser.parse(url));
openApiData = (yield parse(params));
}
}
else if (filePath) {
if (version === '2') {
const openapi = yield swagger2openapi.convertFile(filePath, {
patch: true,
});
openApiData = openapi.openapi || (yield swaggerParser.dereference(openapi.openapi));
}
else {
openApiData = (yield swaggerParser.parse(filePath));
}
}
else if (!object) {

@@ -118,6 +137,7 @@ throw 'option: url or object must be specified one';

}
let schemasCode = '';
const schemasTypesCode = [];
const schemasClassCode = [];
const { schemas } = openApiData.components || {};
if (schemas) {
schemasCode = (yield Promise.all(Object.keys(schemas).map((schemaKey) => __awaiter(this, void 0, void 0, function* () {
Object.keys(schemas).forEach(schemaKey => {
const schemaObject = schemas[schemaKey];

@@ -127,33 +147,24 @@ if (pascalCase) {

}
return `export type ${schemaKey} = ${transform_1.transform(schemaObject)}`;
})))).join('\n');
const transformObject = transform_1.transform(schemaObject);
schemasTypesCode.push(`export type ${schemaKey} = ${transformObject}`);
schemasClassCode.push(`export class ${schemaKey} ${transformObject.replace(/[()]/g, '')}\n`);
});
}
const { paths } = openApiData;
const methods = ['get', 'post', 'options', 'put', 'delete', 'patch', 'head'];
const pathsCode = (yield Promise.all(Object.keys(paths)
.map((urlPath) => __awaiter(this, void 0, void 0, function* () {
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];
return (yield Promise.all(methods.filter(method => !!pathsObject[method])
.map((method) => __awaiter(this, void 0, void 0, function* () {
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, } = objectElement;
let namespaceName = operationId || `${method.toLowerCase()}${getCamelcase(urlPath, { pascalCase: true })}`;
namespaceName = camelcase(namespaceName.replace(/[^a-zA-Z0-9_]/g, ""), { pascalCase: true });
const responseTypeNames = [];
const responsesCode = (yield Promise.all(Object.keys(responses)
.filter(key => key !== 'default')
.map((statusCode) => __awaiter(this, void 0, void 0, function* () {
const responsesObjectElement = responses[statusCode];
const { $ref, content, description } = responsesObjectElement;
if ($ref) {
// TODO
return '';
}
else {
// response
const typeNamePrefix = `Response${camelcase(statusCode, { pascalCase: true })}`;
const responseCode = yield getCodeFromContent(content, typeNamePrefix, description, responseTypeNames);
return responseCode;
}
})))).join('\n');
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

@@ -163,3 +174,3 @@ const requestHeaders = {};

const requestQuery = {};
parameters.forEach((parameter) => {
parameters.forEach(parameter => {
const _a = parameter, { in: keyIn, name } = _a, otherParams = __rest(_a, ["in", "name"]);

@@ -174,3 +185,3 @@ switch (keyIn) {

case 'header':
if (["CONTENT-TYPE", "COOKIE"].indexOf(name.toUpperCase()) === -1) {
if (['CONTENT-TYPE', 'COOKIE'].indexOf(name.toUpperCase()) === -1) {
requestHeaders[name] = otherParams;

@@ -184,15 +195,36 @@ }

const requestCookieCode = yield getCodeFromParameters(requestCookies, 'Cookie', true);
const { content, required: requestBodyRequired, description: requestBodyDescription } = requestBody;
// request body
const { content, required: requestBodyRequired, description: requestBodyDescription, } = requestBody;
const requestBodyTypeNames = [];
const 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;
if ($ref) {
// TODO
return [];
}
else {
// response
const typeNamePrefix = `Response${camelcase(statusCode, {
pascalCase: true,
})}`;
const responseCode = yield getCodeFromContent(content, typeNamePrefix, description, responseTypeNames);
return responseCode;
}
})))).join('\n');
const requestFuncTypeCode = `
export async function request(options: {
query: Query;
body${requestBodyRequired ? '' : '?'}: ${requestBodyTypeNames.length > 0 ? requestBodyTypeNames.join('|') : 'any'};
headers?: RequestHeader;
cookie?: Cookie;
}, otherOptions?: any): Promise<{ body: ${responseTypeNames.length > 0 ? responseTypeNames.join('|') : 'any'} }> {
return fetchImpl({...options, ...otherOptions, url: '${baseUrl}${urlPath}', method: '${method.toLowerCase()}'});
}
`;
export const request = async (options: {
query: Query;
body${requestBodyRequired ? '' : '?'}: ${requestBodyTypeNames.length > 0 ? requestBodyTypeNames.join('|') : 'any'};
headers?: RequestHeader;
cookie?: Cookie;
}, otherOptions?: any): Promise<{ body: ${responseTypeNames.length > 0 ? responseTypeNames.join('|') : 'any'} }> => {
return fetchImpl({...options, ...otherOptions, url: '${baseUrl}${urlPath}', method: '${method.toLowerCase()}'});
};
`;
const requestUrl = `export const url = \`${baseUrl}${urlPath}\``;
let exportObj = {

@@ -205,2 +237,3 @@ requestQueryCode,

requestFuncTypeCode,
requestUrl,
};

@@ -211,29 +244,78 @@ if (options.handlePostScript) {

}
const sortList = ['requestQueryCode', 'requestHeaderCode', 'requestCookieCode', 'requestBodyCode', 'responsesCode', 'requestFuncTypeCode'];
const exportArr = [];
sortList.forEach(item => {
constants_1.SortList.forEach(item => {
exportArr.push(exportObj[item]);
});
Object.keys(exportObj).forEach(item => {
if (!sortList.includes(item)) {
if (!constants_1.SortList.includes(item)) {
exportArr.unshift(exportObj[item]);
}
});
return `export namespace ${namespaceName} {\n${exportArr.join('\n')} \n}`;
}))))
.join('\n');
}))))
.join('\n');
const code = util_1.format([
`/* tslint:disable */
/**
* This file was automatically generated by openapi-gen-typescript.
* DO NOT MODIFY IT BY HAND.
*/`,
fetchModuleImportCode,
`export namespace components { export namespace schemas { ${schemasCode} } } `,
`export namespace Api { ${pathsCode} } `,
].join('\n'));
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 => {
return exp
.replace(/ interface | type = /g, ' class ')
.replace(/ type ([^=]+) = components.([a-zA-Z.]+)[;{}]?/g, ' class $1 extends $2 {}');
});
pathsMap[namespaceName] = {
summary,
tags: tags || [],
code: generateClassArr.join('\n'),
};
})));
pathsCode.push(pathsTypesCode.join('\n'));
})));
yield util_1.deleteFolderRecursive(outputDir);
// generate code
yield mkdirp(outputDir);
fs.writeFileSync(`${outputDir}/index.ts`, code);
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 tagIndex = [];
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$/, '')}';`,
`import * as schemas from '../schemas';\n`,
code,
].join('\n');
tagIndex.push(`export * as ${namespaceName} from './${namespaceName}';`);
fs.writeFileSync(`${currTagNameDir}/${namespaceName}.ts`, util_1.format(pathCode));
});
const tagCode = [
`/**
* @description ${currTag.description}
*/\n`,
...tagIndex,
].join('\n');
fs.writeFileSync(`${currTagNameDir}/index.ts`, util_1.format(tagCode));
}
})));
const typesCode = [
constants_1.NotModifyCode,
`import fetchImpl from '${path.relative(outputDir, fetchModuleFile).replace(/\.ts$/, '')}';`,
`export namespace components { export namespace schemas { ${schemasTypesCode.join('\n')} } } `,
`export namespace Api { ${pathsCode.join('\n')} } `,
].join('\n');
const schemasCode = [
constants_1.NotModifyCode,
`import { components } from './index';\n`,
schemasClassCode.join('\n'),
].join('\n');
fs.writeFileSync(`${outputDir}/index.ts`, util_1.format(typesCode));
fs.writeFileSync(`${outputDir}/schemas.ts`, util_1.format(schemasCode));
console.info(`Generate code successful in directory: ${outputDir}`);

@@ -240,0 +322,0 @@ });

import { Options } from 'prettier';
export declare const DEFAULT_OPTIONS: Options;
export declare function format(code: string, options?: Options): string;
/**
*
* @param {*} filePath
*/
export declare function deleteFolderRecursive(filePath: string): void;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.format = exports.DEFAULT_OPTIONS = void 0;
exports.deleteFolderRecursive = exports.format = exports.DEFAULT_OPTIONS = void 0;
const prettier_1 = require("prettier");
const fs = require("fs");
const path = require("path");
exports.DEFAULT_OPTIONS = {

@@ -12,3 +14,3 @@ bracketSpacing: false,

trailingComma: 'none',
useTabs: false
useTabs: false,
};

@@ -19,1 +21,39 @@ function format(code, options = exports.DEFAULT_OPTIONS) {

exports.format = format;
/**
*
* @param {*} filePath
*/
function deleteFolderRecursive(filePath) {
let files = [];
/**
* 判断给定的路径是否存在
*/
if (fs.existsSync(filePath)) {
/**
* 返回文件和子目录的数组
*/
files = fs.readdirSync(filePath);
files.forEach(function (file, index) {
const curPath = path.join(filePath, file);
console.log(curPath);
/**
* fs.statSync同步读取文件夹文件,如果是文件夹,在重复触发函数
*/
if (fs.statSync(curPath).isDirectory()) {
// recurse
deleteFolderRecursive(curPath);
}
else {
fs.unlinkSync(curPath);
}
});
/**
* 清除文件夹
*/
fs.rmdirSync(filePath);
}
else {
// console.log('给定的路径不存在,请给出正确的路径');
}
}
exports.deleteFolderRecursive = deleteFolderRecursive;
{
"name": "openapi-gen-typescript",
"version": "0.1.0",
"version": "0.1.2",
"main": "dist/index.js",

@@ -19,11 +19,12 @@ "types": "dist/index.d.ts",

"ts-node": "^9.0.0",
"tslint": "^6.1.3",
"typescript": "^4.0.3"
},
"dependencies": {
"openapi-types": "^7.0.1",
"@apidevtools/swagger-parser": "^10.0.2",
"camelcase": "^6.1.0",
"mkdirp": "^1.0.4",
"openapi-types": "^7.0.1",
"swagger2openapi": "^7.0.3"
}
}
}

@@ -19,2 +19,3 @@ # openapi-gen-typescript

| url | The url of fetch openapi or swagger data |
| path | The filePath of fetch openapi or swagger data |
| version | The version of Swagger or OpenApi, example: `2`, `3` |

@@ -21,0 +22,0 @@ | outputDir | Dir of output files |

@@ -7,8 +7,9 @@ // @ts-ignore

import * as camelcase from 'camelcase';
import { Options } from "camelcase";
import { Options } from 'camelcase';
import * as fs from 'fs';
import * as path from "path";
import { transform } from "./schemaToTypes/transform";
import { format } from "./util";
import { IJsonSchema, OpenAPI, OpenAPIV3 } from "openapi-types";
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;

@@ -25,19 +26,12 @@ import MediaTypeObject = OpenAPIV3.MediaTypeObject;

[media: string]: MediaTypeObject;
}
};
enum ETemplateCode {
RequestQueryCode = 'requestQueryCode',
RequestHeaderCode = 'requestHeaderCode',
RequestCookieCode = 'requestCookieCode',
RequestBodyCode = 'requestBodyCode',
ResponsesCode = 'responsesCode',
RequestFuncTypeCode = 'requestFuncTypeCode',
}
type PostScriptReturnType =
| {
[key in ETemplateCode]: string;
}
| {
[key: string]: string;
};
type PostScriptReturnType = {
[key in ETemplateCode]: string;
} | {
[key: string]: string;
}
function getCamelcase(urlPath: string, options?: Options): string {

@@ -53,3 +47,3 @@ return camelcase(urlPath.split('/').join('_'), options);

if (description) {
code += `/* ${description} */\n`
code += `/* ${description} */\n`;
}

@@ -62,8 +56,18 @@

interface ParameterMap {
interface IParameterMap {
[name: string]: ParameterBaseObject;
}
interface IPathMapContent {
summary: string | undefined;
tags: string[];
code: string;
}
interface IPathMap {
[key: string]: IPathMapContent;
}
async function getCodeFromParameters(
parameters: ParameterMap | undefined,
parameters: IParameterMap | undefined,
name: string,

@@ -76,6 +80,8 @@ exportKey: boolean = false,

const bodyCode = (await Promise.all(Object.keys(parameters).map((parameterName) => {
return getCodeFromParameter(parameters[parameterName], parameterName);
}))).join('\n');
return `${exportKey ? 'export' : ''} interface ${name} {\n${bodyCode}\n}`;
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}`;
}

@@ -93,9 +99,53 @@

return (await Promise.all(Object.keys(content).map(async (mediaType, index) => {
const responseTypeName = `${typeNamePrefix}${index > 0 ? getCamelcase(mediaType, { pascalCase: true }) : ''}`;
responseTypeNames.push(responseTypeName);
return `export type ${responseTypeName} = ${transform((content[mediaType] as MediaTypeObject).schema as IJsonSchema)}`
}))).join('\n');
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.includes('[]')) {
jsonSchema = jsonSchema.replace(/[\(\)\[\]]+/g, '');
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,
};
});
}
export async function gen(options: {

@@ -123,25 +173,18 @@ url?: string;

const fetchModuleImportCode = `import fetchImpl from '${path.relative(outputDir, fetchModuleFile).replace(/\.ts$/, '')}';\n`;
let openApiData: OpenAPIV3.Document;
if (url) {
if (url || filePath) {
const { dereference, parse } = swaggerParser;
const params: any = url || filePath;
if (version === '2') {
const openapi = await swagger2openapi.convertUrl(url, {
const { convertUrl, convertFile } = swagger2openapi;
const openapiConvert = url ? convertUrl : convertFile;
const openapi = await openapiConvert(params, {
patch: true,
});
openApiData = openapi.openapi || await swaggerParser.dereference(openapi.openapi);
openApiData = openapi.openapi || (await dereference(openapi.openapi));
} else {
openApiData = await swaggerParser.parse(url) as OpenAPIV3.Document;
openApiData = (await parse(params)) as OpenAPIV3.Document;
}
} else if (filePath) {
if (version === '2') {
const openapi = await swagger2openapi.convertFile(filePath, {
patch: true,
});
openApiData = openapi.openapi || await swaggerParser.dereference(openapi.openapi);
} else {
openApiData = await swaggerParser.parse(filePath) as OpenAPIV3.Document;
}
} else if (!object) {
throw 'option: url or object must be specified one'
throw 'option: url or object must be specified one';
} else {

@@ -156,6 +199,7 @@ openApiData = object as OpenAPIV3.Document;

let schemasCode: string = '';
const schemasTypesCode: string[] = [];
const schemasClassCode: string[] = [];
const { schemas } = openApiData.components || {};
if (schemas) {
schemasCode = (await Promise.all(Object.keys(schemas).map(async (schemaKey) => {
Object.keys(schemas).forEach(schemaKey => {
const schemaObject = schemas[schemaKey] as IJsonSchema;

@@ -165,13 +209,19 @@ if (pascalCase) {

}
return `export type ${schemaKey} = ${transform(schemaObject)}`;
}))).join('\n');
const transformObject = transform(schemaObject);
schemasTypesCode.push(`export type ${schemaKey} = ${transformObject}`);
schemasClassCode.push(`export class ${schemaKey} ${transformObject.replace(/[()]/g, '')}\n`);
});
}
const { paths } = openApiData;
const methods = ['get', 'post', 'options', 'put', 'delete', 'patch', 'head'];
const pathsCode = (await Promise.all(Object.keys(paths)
.map(async (urlPath) => {
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];
return (await Promise.all(methods.filter(method => !!(pathsObject as any)[method])
.map(async (method) => {
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;

@@ -183,35 +233,20 @@ const {

responses,
summary,
tags,
} = objectElement;
let namespaceName = operationId || `${method.toLowerCase()}${getCamelcase(urlPath, { pascalCase: true })}`;
namespaceName = camelcase(namespaceName.replace(/[^a-zA-Z0-9_]/g, ""), { pascalCase: true });
const responseTypeNames: string[] = [];
const responsesCode: string = (await Promise.all(Object.keys(responses as Object)
.filter(key => key !== 'default')
.map(async (statusCode) => {
const responsesObjectElement: ResponseObject & ReferenceObject = (responses as any)[statusCode];
const { $ref, content, description } = responsesObjectElement;
let namespaceName =
operationId ||
`${method.toLowerCase()}${getCamelcase(urlPath, {
pascalCase: true,
})}`;
namespaceName = camelcase(namespaceName.replace(/[^a-zA-Z0-9_]/g, ''), {
pascalCase: true,
});
if ($ref) {
// TODO
return '';
} else {
// response
const typeNamePrefix = `Response${camelcase(statusCode, { pascalCase: true })}`;
const responseCode = await getCodeFromContent(
content as ContentObject,
typeNamePrefix,
description,
responseTypeNames,
);
return responseCode;
}
}))).join('\n');
// request parameter
const requestHeaders: ParameterMap = {};
const requestCookies: ParameterMap = {};
const requestQuery: ParameterMap = {};
parameters.forEach((parameter) => {
const requestHeaders: IParameterMap = {};
const requestCookies: IParameterMap = {};
const requestQuery: IParameterMap = {};
parameters.forEach(parameter => {
const { in: keyIn, name, ...otherParams } = parameter as ParameterObject;

@@ -226,3 +261,3 @@ switch (keyIn) {

case 'header':
if (["CONTENT-TYPE", "COOKIE"].indexOf(name.toUpperCase()) === -1) {
if (['CONTENT-TYPE', 'COOKIE'].indexOf(name.toUpperCase()) === -1) {
requestHeaders[name] = otherParams;

@@ -233,22 +268,73 @@ }

});
const requestHeaderCode = await getCodeFromParameters(requestHeaders, 'RequestHeader', true);
const requestHeaderCode = await getCodeFromParameters(
requestHeaders,
'RequestHeader',
true,
);
const requestQueryCode = await getCodeFromParameters(requestQuery, 'Query', true);
const requestCookieCode = await getCodeFromParameters(requestCookies, 'Cookie', true);
const { content, required: requestBodyRequired, description: requestBodyDescription } = (requestBody as RequestBodyObject);
// request body
const {
content,
required: requestBodyRequired,
description: requestBodyDescription,
} = requestBody as RequestBodyObject;
const requestBodyTypeNames: string[] = [];
const requestBodyCode = await getCodeFromContent(content, `Body`, requestBodyDescription, requestBodyTypeNames);
const 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;
if ($ref) {
// TODO
return [];
} else {
// response
const typeNamePrefix = `Response${camelcase(statusCode, {
pascalCase: true,
})}`;
const responseCode = await getCodeFromContent(
content as ContentObject,
typeNamePrefix,
description,
responseTypeNames,
);
return responseCode;
}
}),
)
).join('\n');
const requestFuncTypeCode = `
export async function request(options: {
query: Query;
body${requestBodyRequired ? '' : '?'}: ${requestBodyTypeNames.length > 0 ? requestBodyTypeNames.join('|') : 'any'};
headers?: RequestHeader;
cookie?: Cookie;
}, otherOptions?: any): Promise<{ body: ${responseTypeNames.length > 0 ? responseTypeNames.join('|') : 'any'} }> {
return fetchImpl({...options, ...otherOptions, url: '${baseUrl}${urlPath}', method: '${method.toLowerCase()}'});
}
`;
export const request = async (options: {
query: Query;
body${requestBodyRequired ? '' : '?'}: ${
requestBodyTypeNames.length > 0 ? requestBodyTypeNames.join('|') : 'any'
};
headers?: RequestHeader;
cookie?: Cookie;
}, otherOptions?: any): Promise<{ body: ${
responseTypeNames.length > 0 ? responseTypeNames.join('|') : 'any'
} }> => {
return fetchImpl({...options, ...otherOptions, url: '${baseUrl}${urlPath}', method: '${method.toLowerCase()}'});
};
`;
const requestUrl = `export const url = \`${baseUrl}${urlPath}\``;

@@ -262,3 +348,4 @@ let exportObj: { [key: string]: string } = {

requestFuncTypeCode,
}
requestUrl,
};

@@ -271,37 +358,98 @@ if (options.handlePostScript) {

const sortList = ['requestQueryCode', 'requestHeaderCode', 'requestCookieCode', 'requestBodyCode', 'responsesCode', 'requestFuncTypeCode'];
const exportArr: string[] = [];
sortList.forEach(item => {
SortList.forEach(item => {
exportArr.push(exportObj[item]);
})
});
Object.keys(exportObj).forEach(item => {
if (!sortList.includes(item)) {
if (!SortList.includes(item)) {
exportArr.unshift(exportObj[item]);
}
})
});
return `export namespace ${namespaceName} {\n${exportArr.join('\n')
} \n}`;
})))
.join('\n');
})))
.join('\n');
const code = format([
`/* tslint:disable */
/**
* This file was automatically generated by openapi-gen-typescript.
* DO NOT MODIFY IT BY HAND.
*/`,
fetchModuleImportCode,
`export namespace components { export namespace schemas { ${schemasCode} } } `,
`export namespace Api { ${pathsCode} } `,
].join('\n'));
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 => {
return exp
.replace(/ interface | type = /g, ' class ')
.replace(/ type ([^=]+) = components.([a-zA-Z.]+)[;{}]?/g, ' class $1 extends $2 {}');
});
pathsMap[namespaceName] = {
summary,
tags: tags || [],
code: generateClassArr.join('\n'),
};
}),
);
pathsCode.push(pathsTypesCode.join('\n'));
}),
);
await deleteFolderRecursive(outputDir);
// generate code
await mkdirp(outputDir);
fs.writeFileSync(`${outputDir}/index.ts`, code);
const tagWithPaths = getTagWithPaths(allTags, pathsMap);
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 tagIndex: 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$/, '')}';`,
`import * as schemas from '../schemas';\n`,
code,
].join('\n');
tagIndex.push(`export * as ${namespaceName} from './${namespaceName}';`);
fs.writeFileSync(`${currTagNameDir}/${namespaceName}.ts`, format(pathCode));
});
const tagCode = [
`/**
* @description ${currTag.description}
*/\n`,
...tagIndex,
].join('\n');
fs.writeFileSync(`${currTagNameDir}/index.ts`, format(tagCode));
}
}),
);
const typesCode = [
NotModifyCode,
`import fetchImpl from '${path.relative(outputDir, fetchModuleFile).replace(/\.ts$/, '')}';`,
`export namespace components { export namespace schemas { ${schemasTypesCode.join('\n')} } } `,
`export namespace Api { ${pathsCode.join('\n')} } `,
].join('\n');
const schemasCode = [
NotModifyCode,
`import { components } from './index';\n`,
schemasClassCode.join('\n'),
].join('\n');
fs.writeFileSync(`${outputDir}/index.ts`, format(typesCode));
fs.writeFileSync(`${outputDir}/schemas.ts`, format(schemasCode));
console.info(`Generate code successful in directory: ${outputDir}`);
}

@@ -1,2 +0,4 @@

import { format as prettify, Options } from 'prettier'
import { format as prettify, Options } from 'prettier';
import * as fs from 'fs';
import * as path from 'path';

@@ -10,7 +12,43 @@ export const DEFAULT_OPTIONS: Options = {

trailingComma: 'none',
useTabs: false
useTabs: false,
};
export function format(code: string, options: Options = DEFAULT_OPTIONS): string {
return prettify(code, { parser: 'typescript', ...options })
return prettify(code, { parser: 'typescript', ...options });
}
/**
*
* @param {*} filePath
*/
export function deleteFolderRecursive(filePath: string) {
let files = [];
/**
* 判断给定的路径是否存在
*/
if (fs.existsSync(filePath)) {
/**
* 返回文件和子目录的数组
*/
files = fs.readdirSync(filePath);
files.forEach(function (file, index) {
const curPath = path.join(filePath, file);
console.log(curPath);
/**
* fs.statSync同步读取文件夹文件,如果是文件夹,在重复触发函数
*/
if (fs.statSync(curPath).isDirectory()) {
// recurse
deleteFolderRecursive(curPath);
} else {
fs.unlinkSync(curPath);
}
});
/**
* 清除文件夹
*/
fs.rmdirSync(filePath);
} else {
// console.log('给定的路径不存在,请给出正确的路径');
}
}
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