swagger-axios-codegen
Advanced tools
Comparing version 0.9.14 to 0.9.15
### 0.9.15 | ||
- fix: requestParams does not generated isDefinedGenericTypes interfaceTemplate by xxbb #PR86 | ||
- feature: use multimatch filter service and method by xxbb #56 | ||
### 0.9.14 | ||
@@ -3,0 +9,0 @@ |
import { ISwaggerOptions } from './baseInterfaces'; | ||
/** main */ | ||
export declare function codegen(params: ISwaggerOptions): Promise<void>; |
@@ -27,2 +27,3 @@ "use strict"; | ||
const pascalcase_1 = __importDefault(require("pascalcase")); | ||
const multimatch_1 = __importDefault(require("multimatch")); | ||
const template_1 = require("./templates/template"); | ||
@@ -48,2 +49,3 @@ const serviceHeader_1 = require("./templates/serviceHeader"); | ||
}; | ||
/** main */ | ||
function codegen(params) { | ||
@@ -77,3 +79,4 @@ return __awaiter(this, void 0, void 0, function* () { | ||
console.log('isV3', isV3); | ||
let requestClasses = Object.entries(requestCodegen_1.requestCodegen(swaggerSource.paths, isV3, options)); | ||
let requestClass = requestCodegen_1.requestCodegen(swaggerSource.paths, isV3, options); | ||
// let requestClasses = Object.entries(requestCodegen(swaggerSource.paths, isV3, options)) | ||
const { models, enums } = isV3 | ||
@@ -114,127 +117,250 @@ ? componentsCodegen_1.componentsCodegen(swaggerSource.components) | ||
else if (options.include && options.include.length > 0) { | ||
// 接口过滤入口 | ||
let reqSource = ''; | ||
let defSource = ''; | ||
let allModel = Object.values(models); | ||
// console.log(allModel) | ||
let allEnum = Object.values(enums); | ||
let allImport = []; | ||
// 处理接口 | ||
options.include.forEach(item => { | ||
let includeClassName = ''; | ||
let includeRequests = null; | ||
if (Object.prototype.toString.call(item) === '[object String]') { | ||
includeClassName = item; | ||
// codegenInclude(apiSource, options, requestClass, models, enums) | ||
codegenMultimatchInclude(apiSource, options, requestClass, models, enums); | ||
} | ||
else { | ||
codegenAll(apiSource, options, requestClass, models, enums); | ||
} | ||
if (fs.existsSync('./cache_swagger.json')) { | ||
fs.unlinkSync('./cache_swagger.json'); | ||
} | ||
console.timeEnd('finish'); | ||
if (err) { | ||
throw err; | ||
} | ||
}); | ||
} | ||
exports.codegen = codegen; | ||
/** codegenAll */ | ||
function codegenAll(apiSource, options, requestClass, models, enums) { | ||
let requestClasses = Object.entries(requestClass); | ||
// 常规入口 | ||
try { | ||
// 处理接口 | ||
requestClasses.forEach(([className, requests]) => { | ||
let text = ''; | ||
requests.forEach(req => { | ||
const reqName = options.methodNameMode == 'operationId' ? req.operationId : req.name; | ||
text += template_1.requestTemplate(reqName, req.requestSchema, options); | ||
}); | ||
text = template_1.serviceTemplate(className + options.serviceNameSuffix, text); | ||
apiSource += text; | ||
}); | ||
// 处理类和枚举 | ||
Object.values(models).forEach(item => { | ||
const text = options.modelMode === 'interface' | ||
? template_1.interfaceTemplate(item.value.name, item.value.props, [], options.strictNullChecks) | ||
: template_1.classTemplate(item.value.name, item.value.props, [], options.strictNullChecks, options.useClassTransformer, options.generateValidationModel); | ||
apiSource += text; | ||
}); | ||
Object.values(enums).forEach(item => { | ||
let text = ''; | ||
if (item.value) { | ||
if (item.value.type == 'string') { | ||
text = template_1.enumTemplate(item.value.name, item.value.enumProps, options.enumNamePrefix); | ||
} | ||
else { | ||
for (let k of Object.keys(item)) { | ||
includeClassName = k; | ||
includeRequests = item[k]; | ||
} | ||
text = template_1.typeTemplate(item.value.name, item.value.enumProps, options.enumNamePrefix); | ||
} | ||
for (let [className, requests] of requestClasses) { | ||
if (pascalcase_1.default(includeClassName) !== className) | ||
continue; | ||
let text = ''; | ||
for (let req of requests) { | ||
const reqName = options.methodNameMode == 'operationId' ? req.operationId : req.name; | ||
if (includeRequests) { | ||
if (includeRequests.includes(reqName)) { | ||
text += template_1.requestTemplate(reqName, req.requestSchema, options); | ||
// generate ref definition model | ||
let imports = utils_1.findDeepRefs(req.requestSchema.parsedParameters.imports, allModel, allEnum); | ||
allImport = allImport.concat(imports); | ||
} | ||
} | ||
else { | ||
text += template_1.requestTemplate(reqName, req.requestSchema, options); | ||
let imports = utils_1.findDeepRefs(req.requestSchema.parsedParameters.imports, allModel, allEnum); | ||
allImport = allImport.concat(imports); | ||
} | ||
} | ||
else { | ||
text = item.content || ''; | ||
} | ||
apiSource += text; | ||
}); | ||
writeFile(options.outputDir || '', options.fileName || '', format(apiSource, options)); | ||
} | ||
catch (error) { | ||
console.log('error', error); | ||
throw error; | ||
} | ||
} | ||
// last include codegen | ||
function codegenInclude(apiSource, options, requestClass, models, enums) { | ||
let requestClasses = Object.entries(requestClass); | ||
// 接口过滤入口 | ||
let reqSource = ''; | ||
let defSource = ''; | ||
let allModel = Object.values(models); | ||
// console.log(allModel) | ||
let allEnum = Object.values(enums); | ||
let allImport = []; | ||
// 处理接口 | ||
options.include.forEach(item => { | ||
let includeClassName = ''; | ||
let includeRequests = null; | ||
if (Object.prototype.toString.call(item) === '[object String]') { | ||
includeClassName = item; | ||
} | ||
else { | ||
for (let k of Object.keys(item)) { | ||
includeClassName = k; | ||
includeRequests = item[k]; | ||
} | ||
} | ||
for (let [className, requests] of requestClasses) { | ||
if (pascalcase_1.default(includeClassName) !== className) | ||
continue; | ||
let text = ''; | ||
for (let req of requests) { | ||
const reqName = options.methodNameMode == 'operationId' ? req.operationId : req.name; | ||
if (includeRequests) { | ||
if (includeRequests.includes(reqName)) { | ||
text += template_1.requestTemplate(reqName, req.requestSchema, options); | ||
// generate ref definition model | ||
let imports = utils_1.findDeepRefs(req.requestSchema.parsedParameters.imports, allModel, allEnum); | ||
allImport = allImport.concat(imports); | ||
} | ||
text = template_1.serviceTemplate(className + options.serviceNameSuffix, text); | ||
reqSource += text; | ||
} | ||
}); | ||
// 处理类和枚举 | ||
allModel.forEach(item => { | ||
if (allImport.includes(item.name)) { | ||
const text = params.modelMode === 'interface' | ||
? template_1.interfaceTemplate(item.value.name, item.value.props, [], params.strictNullChecks) | ||
: template_1.classTemplate(item.value.name, item.value.props, [], params.strictNullChecks, options.useClassTransformer, options.generateValidationModel); | ||
defSource += text; | ||
else { | ||
text += template_1.requestTemplate(reqName, req.requestSchema, options); | ||
let imports = utils_1.findDeepRefs(req.requestSchema.parsedParameters.imports, allModel, allEnum); | ||
allImport = allImport.concat(imports); | ||
} | ||
}); | ||
allEnum.forEach(item => { | ||
if (allImport.includes(item.name)) { | ||
let text = ''; | ||
if (item.value) { | ||
if (item.value.type == 'string') { | ||
text = template_1.enumTemplate(item.value.name, item.value.enumProps, options.enumNamePrefix); | ||
} | ||
else { | ||
text = template_1.typeTemplate(item.value.name, item.value.enumProps, options.enumNamePrefix); | ||
} | ||
} | ||
else { | ||
text = item.content || ''; | ||
} | ||
defSource += text; | ||
} | ||
text = template_1.serviceTemplate(className + options.serviceNameSuffix, text); | ||
reqSource += text; | ||
} | ||
}); | ||
// 处理类和枚举 | ||
allModel.forEach(item => { | ||
if (allImport.includes(item.name)) { | ||
const text = options.modelMode === 'interface' | ||
? template_1.interfaceTemplate(item.value.name, item.value.props, [], options.strictNullChecks) | ||
: template_1.classTemplate(item.value.name, item.value.props, [], options.strictNullChecks, options.useClassTransformer, options.generateValidationModel); | ||
defSource += text; | ||
} | ||
}); | ||
allEnum.forEach(item => { | ||
if (allImport.includes(item.name)) { | ||
let text = ''; | ||
if (item.value) { | ||
if (item.value.type == 'string') { | ||
text = template_1.enumTemplate(item.value.name, item.value.enumProps, options.enumNamePrefix); | ||
} | ||
else { | ||
text = template_1.typeTemplate(item.value.name, item.value.enumProps, options.enumNamePrefix); | ||
} | ||
} | ||
else { | ||
text = item.content || ''; | ||
} | ||
defSource += text; | ||
} | ||
}); | ||
apiSource += reqSource + defSource; | ||
writeFile(options.outputDir || '', options.fileName || '', format(apiSource, options)); | ||
} | ||
/** current multimatch codegen */ | ||
function codegenMultimatchInclude(apiSource, options, requestClass, models, enums) { | ||
let requestClasses = Object.entries(requestClass); | ||
// 接口过滤入口 | ||
let reqSource = ''; | ||
let defSource = ''; | ||
let allModel = Object.values(models); | ||
// console.log(allModel) | ||
let allEnum = Object.values(enums); | ||
let allImport = []; | ||
// #region 处理匹配集合 | ||
const sourceClassNames = requestClasses.map(v => { | ||
const className = v[0]; | ||
return className; | ||
}); | ||
const includeRules = {}; | ||
options.include.forEach(classNameFilter => { | ||
// *,?,**,{},!, | ||
// NOTICE: 目前要求 className 严格按照pascalcase书写 | ||
if (typeof classNameFilter === 'string') { | ||
if (includeRules[classNameFilter] === undefined) { | ||
includeRules[classNameFilter] = new Set(); | ||
} | ||
includeRules[classNameFilter].add('*'); | ||
} | ||
else { | ||
Object.keys(classNameFilter).forEach(key => { | ||
if (includeRules[key] === undefined) { | ||
includeRules[key] = new Set(); | ||
} | ||
classNameFilter[key].forEach(requestFilter => includeRules[key].add(requestFilter)); | ||
}); | ||
apiSource += reqSource + defSource; | ||
writeFile(options.outputDir || '', options.fileName || '', format(apiSource, options)); | ||
} | ||
else { | ||
// 常规入口 | ||
try { | ||
// 处理接口 | ||
requestClasses.forEach(([className, requests]) => { | ||
let text = ''; | ||
requests.forEach(req => { | ||
const reqName = options.methodNameMode == 'operationId' ? req.operationId : req.name; | ||
text += template_1.requestTemplate(reqName, req.requestSchema, options); | ||
}); | ||
text = template_1.serviceTemplate(className + options.serviceNameSuffix, text); | ||
apiSource += text; | ||
}); | ||
// 处理类和枚举 | ||
Object.values(models).forEach(item => { | ||
const text = params.modelMode === 'interface' | ||
? template_1.interfaceTemplate(item.value.name, item.value.props, [], params.strictNullChecks) | ||
: template_1.classTemplate(item.value.name, item.value.props, [], params.strictNullChecks, options.useClassTransformer, options.generateValidationModel); | ||
apiSource += text; | ||
}); | ||
Object.values(enums).forEach(item => { | ||
let text = ''; | ||
if (item.value) { | ||
if (item.value.type == 'string') { | ||
text = template_1.enumTemplate(item.value.name, item.value.enumProps, options.enumNamePrefix); | ||
} | ||
else { | ||
text = template_1.typeTemplate(item.value.name, item.value.enumProps, options.enumNamePrefix); | ||
} | ||
} | ||
else { | ||
text = item.content || ''; | ||
} | ||
apiSource += text; | ||
}); | ||
writeFile(options.outputDir || '', options.fileName || '', format(apiSource, options)); | ||
}); | ||
// console.log('rules', includeRules) | ||
const matchedClassNames = multimatch_1.default(sourceClassNames, Object.keys(includeRules)); | ||
// console.log('sourceClassNames', sourceClassNames) | ||
// console.log('matchedClassNames', matchedClassNames) | ||
// {tagNames:[...requestFilters]} | ||
const requiredClassNameMap = {}; | ||
Object.keys(includeRules).forEach(classNameFilter => { | ||
// matched tagnames | ||
const requiredClassNames = multimatch_1.default(matchedClassNames, classNameFilter); | ||
requiredClassNames.forEach(className => { | ||
if (requiredClassNameMap[className] === undefined) { | ||
requiredClassNameMap[className] = new Set(); | ||
} | ||
catch (error) { | ||
console.log('error', error); | ||
err = error; | ||
} | ||
includeRules[classNameFilter].forEach(requestFilter => requiredClassNameMap[className].add(requestFilter)); | ||
}); | ||
}); | ||
// console.log('className->requestRules', requiredClassNameMap) | ||
// #endregion | ||
// 处理接口 | ||
requestClasses.forEach(([className, requests]) => { | ||
const includeRequestsFilters = requiredClassNameMap[className]; | ||
if (includeRequestsFilters) { | ||
let text = ''; | ||
const requestKeyMap = {}; | ||
const requestKeys = requests.map(v => { | ||
const reqName = options.methodNameMode == 'operationId' ? v.operationId : v.name; | ||
requestKeyMap[reqName] = v; | ||
return reqName; | ||
}); | ||
const requsetRules = Array.from(includeRequestsFilters); | ||
const requiredRequestKeys = multimatch_1.default(requestKeys, Array.from(requsetRules)); | ||
// console.log(`${className}-methods-requsetRules`, requsetRules) | ||
// console.log(`${className}-methods-all`, requestKeys) | ||
// console.log(`${className}-methods-matched`, requiredRequestKeys) | ||
requiredRequestKeys.forEach(reqName => { | ||
const req = requestKeyMap[reqName]; | ||
text += template_1.requestTemplate(reqName, req.requestSchema, options); | ||
// generate ref definition model | ||
// console.log(`${reqName}-imports`, req.requestSchema.parsedParameters.imports) | ||
let imports = utils_1.findDeepRefs(req.requestSchema.parsedParameters.imports, allModel, allEnum); | ||
allImport = allImport.concat(imports); | ||
}); | ||
text = template_1.serviceTemplate(className + options.serviceNameSuffix, text); | ||
apiSource += text; | ||
} | ||
if (fs.existsSync('./cache_swagger.json')) { | ||
fs.unlinkSync('./cache_swagger.json'); | ||
}); | ||
// console.log(`allModel`, Object.keys(models)) | ||
// console.log(`allImport`, allImport) | ||
// console.log(`allEnum`, Object.keys(enums)) | ||
// 处理类和枚举 | ||
allModel.forEach(item => { | ||
if (allImport.includes(item.name)) { | ||
const text = options.modelMode === 'interface' | ||
? template_1.interfaceTemplate(item.value.name, item.value.props, [], options.strictNullChecks) | ||
: template_1.classTemplate(item.value.name, item.value.props, [], options.strictNullChecks, options.useClassTransformer, options.generateValidationModel); | ||
defSource += text; | ||
} | ||
console.timeEnd('finish'); | ||
if (err) { | ||
throw err; | ||
}); | ||
allEnum.forEach(item => { | ||
if (allImport.includes(item.name)) { | ||
let text = ''; | ||
if (item.value) { | ||
if (item.value.type == 'string') { | ||
text = template_1.enumTemplate(item.value.name, item.value.enumProps, options.enumNamePrefix); | ||
} | ||
else { | ||
text = template_1.typeTemplate(item.value.name, item.value.enumProps, options.enumNamePrefix); | ||
} | ||
} | ||
else { | ||
text = item.content || ''; | ||
} | ||
defSource += text; | ||
} | ||
}); | ||
apiSource += reqSource + defSource; | ||
writeFile(options.outputDir || '', options.fileName || '', format(apiSource, options)); | ||
} | ||
exports.codegen = codegen; | ||
function writeFile(fileDir, name, data) { | ||
@@ -241,0 +367,0 @@ if (!fs.existsSync(fileDir)) { |
@@ -18,3 +18,5 @@ "use strict"; | ||
// TODO:同名但是v.in= query |path |body 的情况同时出现如何处理?分出不同的request参数? | ||
uniqParams[`${v.name}`] = v; | ||
if (!v.name.includes('[0]')) { //DTO class中存在List<T>时会出现这种参数 (list[0].prop) | ||
uniqParams[`${v.name}`] = v; | ||
} | ||
}); | ||
@@ -21,0 +23,0 @@ return Object.values(uniqParams); |
@@ -6,3 +6,3 @@ import { IPaths } from '../swaggerInterfaces'; | ||
} | ||
interface IRequestMethods { | ||
export interface IRequestMethods { | ||
name: string; | ||
@@ -13,2 +13,1 @@ operationId: string; | ||
export declare function requestCodegen(paths: IPaths, isV3: boolean, options: ISwaggerOptions): IRequestClass; | ||
export {}; |
@@ -11,2 +11,6 @@ "use strict"; | ||
function interfaceTemplate(name, props, imports, strictNullChecks = true) { | ||
if (utils_1.isDefinedGenericTypes(name)) { | ||
// 已经定义过的interface不再生成 | ||
return ''; | ||
} | ||
// 所有的引用 | ||
@@ -13,0 +17,0 @@ const importString = imports |
@@ -23,4 +23,14 @@ import { IDefinitionClass, IDefinitionEnum } from './baseInterfaces'; | ||
export declare function trimString(str: string, char: string, type: string): string; | ||
/** | ||
* 泛型类名提取数组 | ||
* A<B<C>> => [A,B,C] | ||
**/ | ||
export declare function genericsToClassNames(modelName: string): string[]; | ||
/** | ||
* 数组类名转泛型类名 | ||
* [A,B,C] => A<B<C>> | ||
*/ | ||
export declare function classNamesToGenerics(classNames: string[]): string; | ||
export declare function findDeepRefs(imports: string[], allDefinition: IDefinitionClass[], allEnums: IDefinitionEnum[]): string[]; | ||
export declare function isOpenApi3(version: string): boolean; | ||
export declare function getValidationModel(propName: string, prop: IDefinitionProperty, required: string[]): any; |
@@ -136,7 +136,40 @@ "use strict"; | ||
exports.trimString = trimString; | ||
/** | ||
* 泛型类名提取数组 | ||
* A<B<C>> => [A,B,C] | ||
**/ | ||
function genericsToClassNames(modelName) { | ||
if (exports.isGenerics(modelName)) { | ||
const names = modelName.split(/[<>]+/); | ||
names.pop(); | ||
return names; | ||
} | ||
else { | ||
return [modelName]; | ||
} | ||
} | ||
exports.genericsToClassNames = genericsToClassNames; | ||
/** | ||
* 数组类名转泛型类名 | ||
* [A,B,C] => A<B<C>> | ||
*/ | ||
function classNamesToGenerics(classNames) { | ||
const len = classNames.length; | ||
if (len > 1) { | ||
const end = new Array(len).join('>'); | ||
const name = classNames.join('<') + end; | ||
return name; | ||
} | ||
else if (len === 1) { | ||
return classNames[1]; | ||
} | ||
} | ||
exports.classNamesToGenerics = classNamesToGenerics; | ||
function findDeepRefs(imports, allDefinition, allEnums) { | ||
let result = []; | ||
imports.forEach(model => { | ||
const modelNames = genericsToClassNames(model); | ||
// console.log('modelNames', modelNames) | ||
let ref = null; | ||
ref = allDefinition.find(item => model.startsWith(item.name)); | ||
ref = allDefinition.find(item => modelNames.some((modelName) => modelName.startsWith(item.name))); | ||
if (ref) { | ||
@@ -149,3 +182,3 @@ result.push(ref.name); | ||
else { | ||
ref = allEnums.find(item => model.startsWith(item.name)); | ||
ref = allEnums.find(item => modelNames.some((modelName) => modelName.startsWith(item.name))); | ||
if (ref) { | ||
@@ -159,2 +192,23 @@ result.push(ref.name); | ||
exports.findDeepRefs = findDeepRefs; | ||
// export function findDeepRefs(imports: string[], allDefinition: IDefinitionClass[], allEnums: IDefinitionEnum[]) { | ||
// let result: string[] = [] | ||
// imports.forEach(model => { | ||
// const modelNames = getClassNamesFromModel(model) | ||
// let modelName = model | ||
// let ref = null | ||
// ref = allDefinition.find(item => modelName.startsWith(item.name)) | ||
// if (ref) { | ||
// result.push(ref.name) | ||
// if (ref.value.imports.length > 0) { | ||
// result = result.concat(findDeepRefs(ref.value.imports, allDefinition, allEnums)) | ||
// } | ||
// } else { | ||
// ref = allEnums.find(item => modelName.startsWith(item.name)) | ||
// if (ref) { | ||
// result.push(ref.name) | ||
// } | ||
// } | ||
// }) | ||
// return result | ||
// } | ||
function isOpenApi3(version) { | ||
@@ -161,0 +215,0 @@ console.log('openApi version:', version); |
{ | ||
"name": "swagger-axios-codegen", | ||
"version": "0.9.14", | ||
"version": "0.9.15", | ||
"main": "./dist/index", | ||
@@ -30,2 +30,3 @@ "typings": "./dist/", | ||
"camelcase": "^5.0.0", | ||
"multimatch": "^4.0.0", | ||
"pascalcase": "^0.1.1", | ||
@@ -32,0 +33,0 @@ "prettier": "^1.15.2", |
@@ -164,8 +164,11 @@ # swagger-axios-codegen | ||
fliter by [multimatch](https://github.com/sindresorhus/multimatch) | ||
```js | ||
let include = [ | ||
'Products', // tagName | ||
'Estimates',//tagName | ||
{ 'User': ['history'] } | ||
'*', | ||
// 'Products*', | ||
'!Products', | ||
{ 'User': ['*', '!history'] }, | ||
] | ||
@@ -172,0 +175,0 @@ codegen({ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
179663
2894
271
6
+ Addedmultimatch@^4.0.0
+ Added@types/minimatch@3.0.5(transitive)
+ Addedarray-differ@3.0.0(transitive)
+ Addedarray-union@2.1.0(transitive)
+ Addedarrify@2.0.1(transitive)
+ Addedbalanced-match@1.0.2(transitive)
+ Addedbrace-expansion@1.1.11(transitive)
+ Addedconcat-map@0.0.1(transitive)
+ Addedminimatch@3.1.2(transitive)
+ Addedmultimatch@4.0.0(transitive)