diff --git a/README.md b/README.md index 082131b..2bd23ef 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,9 @@ export interface ISwaggerOptions { urlFilters?: Array /** custom function to format the output file (default: prettier.format()) **/ format?: (s: string) => string - /** match with tsconfig */ + /** force required option for fields */ + strictRequiredChecks?: boolean | undefined + /** force nullable option for fields */ strictNullChecks?: boolean | undefined /** definition Class mode */ modelMode?: 'class' | 'interface' @@ -86,6 +88,7 @@ const defaultOptions: ISwaggerOptions = { useStaticMethod: true, useCustomerRequestInstance: false, include: [], + strictRequiredChecks: true, strictNullChecks: true, /** definition Class mode ,auto use interface mode to streamlined code*/ modelMode?: 'interface' diff --git a/example/swagger/codegen-customMethodNameMode.js b/example/swagger/codegen-customMethodNameMode.js index 6735590..e6e80c2 100644 --- a/example/swagger/codegen-customMethodNameMode.js +++ b/example/swagger/codegen-customMethodNameMode.js @@ -1,4 +1,4 @@ -const { codegen } = require('../../dist/index.js') +const { codegen } = require('../../dist/index.js'); codegen({ methodNameMode: (reqProps) => { @@ -9,9 +9,10 @@ codegen({ }, source: require('../swagger-operationId.json'), outputDir: './swagger/services', + strictRequiredChecks: false, strictNullChecks: false, modelMode: 'interface', extendDefinitionFile: './swagger/customerDefinition.ts', extendGenericType: ['JsonResult'], sharedServiceOptions: true -}) +}); diff --git a/example/swagger/codegen-shortOperationId.js b/example/swagger/codegen-shortOperationId.js index 13f1e8c..ad8bad3 100644 --- a/example/swagger/codegen-shortOperationId.js +++ b/example/swagger/codegen-shortOperationId.js @@ -1,12 +1,13 @@ -const { codegen } = require('../../dist/index.js') +const { codegen } = require('../../dist/index.js'); codegen({ methodNameMode: 'shortOperationId', source: require('../swagger-operationId.json'), outputDir: './swagger/services', + strictRequiredChecks: false, strictNullChecks: false, modelMode: 'interface', extendDefinitionFile: './swagger/customerDefinition.ts', extendGenericType: ['JsonResult'], sharedServiceOptions: true -}) +}); diff --git a/example/swagger/codegen.generic.js b/example/swagger/codegen.generic.js index 16d5032..499ab9e 100644 --- a/example/swagger/codegen.generic.js +++ b/example/swagger/codegen.generic.js @@ -1,5 +1,5 @@ // const { codegen } = require('swagger-axios-codegen') -const { codegen } = require('../../dist/index.js') +const { codegen } = require('../../dist/index.js'); codegen({ methodNameMode: 'path', @@ -7,6 +7,7 @@ codegen({ // remoteUrl: 'http://localhost:44307/swagger/v1/swagger.json', outputDir: './swagger/services', fileName: 'indexGeneric.ts', + strictRequiredChecks: false, strictNullChecks: false, modelMode: 'interface' -}) +}); diff --git a/example/swagger/codegen.include.js b/example/swagger/codegen.include.js index 058b050..39ba5fb 100644 --- a/example/swagger/codegen.include.js +++ b/example/swagger/codegen.include.js @@ -1,5 +1,5 @@ // const { codegen } = require('swagger-axios-codegen') -const { codegen } = require('../../dist/index.js') +const { codegen } = require('../../dist/index.js'); let include = [ // "products-test", @@ -11,12 +11,13 @@ let include = [ // 'Products*', '!Products', { 'User': ['*', '!history'] }, -] +]; codegen({ methodNameMode: 'path', + strictRequiredChecks: false, strictNullChecks: false, modelMode: 'interface', source: require('../swagger.json'), outputDir: './swagger/services', include -}) +}); diff --git a/example/swagger/codegen.js b/example/swagger/codegen.js index a052f31..7ee43f9 100644 --- a/example/swagger/codegen.js +++ b/example/swagger/codegen.js @@ -1,15 +1,16 @@ // const { codegen } = require('swagger-axios-codegen') -const { codegen } = require('../../dist/index.js') +const { codegen } = require('../../dist/index.js'); codegen({ methodNameMode: 'path', source: require('../swagger.json'), // remoteUrl: 'http://localhost:44307/swagger/v1/swagger.json', outputDir: './swagger/services', + strictRequiredChecks: false, strictNullChecks: false, // useCustomerRequestInstance: true, modelMode: 'interface', extendDefinitionFile: './swagger/customerDefinition.ts', extendGenericType: ['JsonResult'], sharedServiceOptions: true -}) +}); diff --git a/example/swagger/codegen.v3.js b/example/swagger/codegen.v3.js index 6722584..d8b3de6 100644 --- a/example/swagger/codegen.v3.js +++ b/example/swagger/codegen.v3.js @@ -1,5 +1,5 @@ // const { codegen } = require('swagger-axios-codegen') -const { codegen } = require('../../dist/index.js') +const { codegen } = require('../../dist/index.js'); codegen({ methodNameMode: 'path', @@ -7,6 +7,7 @@ codegen({ // remoteUrl: 'http://localhost:44307/swagger/v1/swagger.json', outputDir: './swagger/services', fileName: 'indexv3.ts', + strictRequiredChecks: false, strictNullChecks: false, modelMode: 'interface' -}) +}); diff --git a/src/baseInterfaces.ts b/src/baseInterfaces.ts index bb7f1df..3876d9a 100644 --- a/src/baseInterfaces.ts +++ b/src/baseInterfaces.ts @@ -14,7 +14,9 @@ export interface ISwaggerOptions { /** include types which are not included during the filtering **/ includeTypes?: Array format?: (s: string) => string - /** match with tsconfig */ + /** force required option for fields */ + strictRequiredChecks?: boolean | undefined + /** force required option for fields */ strictNullChecks?: boolean | undefined /** definition Class mode */ modelMode?: 'class' | 'interface' diff --git a/src/index.filter.ts b/src/index.filter.ts index fd6eddd..773e021 100644 --- a/src/index.filter.ts +++ b/src/index.filter.ts @@ -79,11 +79,12 @@ function codegenInclude( if (allImport.includes(item.name)) { const text = options.modelMode === 'interface' - ? interfaceTemplate(item.value.name, item.value.props, [], options.strictNullChecks) + ? interfaceTemplate(item.value.name, item.value.props, [], options.strictRequiredChecks, options.strictNullChecks) : classTemplate( item.value.name, item.value.props, [], + options.strictRequiredChecks, options.strictNullChecks, options.useClassTransformer, options.generateValidationModel @@ -225,11 +226,12 @@ function codegenMultimatchInclude( if (allImport.includes(item.name)) { const text = options.modelMode === 'interface' - ? interfaceTemplate(item.value.name, item.value.props, [], options.strictNullChecks) + ? interfaceTemplate(item.value.name, item.value.props, [], options.strictRequiredChecks, options.strictNullChecks) : classTemplate( item.value.name, item.value.props, [], + options.strictRequiredChecks, options.strictNullChecks, options.useClassTransformer, options.generateValidationModel diff --git a/src/index.ts b/src/index.ts index ac0b25b..9116527 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,7 +14,7 @@ import { classTemplate, typeTemplate } from './templates/template' -import { customerServiceHeader, serviceHeader, definitionHeader, disableLint } from './templates/serviceHeader' +import { customerServiceHeader, serviceHeader, definitionHeader } from './templates/serviceHeader' import { isOpenApi3, findDeepRefs, setDefinedGenericTypes, getDefinedGenericTypes, trimString } from './utils' import { requestCodegen, IRequestClass, IRequestMethods } from './requestCodegen' import { componentsCodegen } from './componentsCodegen' @@ -31,6 +31,7 @@ const defaultOptions: ISwaggerOptions = { modelMode: 'interface', include: [], includeTypes: [], + strictRequiredChecks: true, strictNullChecks: true, useClassTransformer: false, extendGenericType: [], @@ -125,9 +126,7 @@ export async function codegen(params: ISwaggerOptions) { for (const item of allImport) { if (!uniqueImports.includes(item)) uniqueImports.push(item) } - console.log(disableLint()); - text = disableLint() + text text = serviceTemplate(className + options.serviceNameSuffix, text, uniqueImports) writeFile(options.outputDir || '', className + 'Service.ts', format(text, options)) }) @@ -139,11 +138,12 @@ export async function codegen(params: ISwaggerOptions) { Object.values(models).forEach(item => { const text = params.modelMode === 'interface' - ? interfaceTemplate(item.value.name, item.value.props, [], params.strictNullChecks) + ? interfaceTemplate(item.value.name, item.value.props, [], params.strictRequiredChecks, params.strictNullChecks) : classTemplate( item.value.name, item.value.props, [], + params.strictRequiredChecks, params.strictNullChecks, options.useClassTransformer, options.generateValidationModel @@ -219,11 +219,12 @@ function codegenAll( Object.values(models).forEach(item => { const text = options.modelMode === 'interface' - ? interfaceTemplate(item.value.name, item.value.props, [], options.strictNullChecks) + ? interfaceTemplate(item.value.name, item.value.props, [], options.strictRequiredChecks, options.strictNullChecks) : classTemplate( item.value.name, item.value.props, [], + options.strictRequiredChecks, options.strictNullChecks, options.useClassTransformer, options.generateValidationModel @@ -244,9 +245,7 @@ function codegenAll( } apiSource += text }) - // console.log(disableLint()); - apiSource = disableLint() + apiSource writeFile(options.outputDir || '', options.fileName || '', format(apiSource, options)) } catch (error) { console.log('error', error) @@ -313,11 +312,12 @@ function codegenInclude( if (allImport.includes(item.name) || options.includeTypes.includes(item.name)) { const text = options.modelMode === 'interface' - ? interfaceTemplate(item.value.name, item.value.props, [], options.strictNullChecks) + ? interfaceTemplate(item.value.name, item.value.props, [], options.strictRequiredChecks, options.strictNullChecks) : classTemplate( item.value.name, item.value.props, [], + options.strictRequiredChecks, options.strictNullChecks, options.useClassTransformer, options.generateValidationModel @@ -459,11 +459,12 @@ function codegenMultimatchInclude( if (allImport.includes(item.name) || options.includeTypes.includes(item.name)) { const text = options.modelMode === 'interface' - ? interfaceTemplate(item.value.name, item.value.props, [], options.strictNullChecks) + ? interfaceTemplate(item.value.name, item.value.props, [], options.strictRequiredChecks, options.strictNullChecks) : classTemplate( item.value.name, item.value.props, [], + options.strictRequiredChecks, options.strictNullChecks, options.useClassTransformer, options.generateValidationModel @@ -489,7 +490,6 @@ function codegenMultimatchInclude( } }) - apiSource = disableLint() + apiSource apiSource += reqSource + defSource writeFile(options.outputDir || '', options.fileName || '', format(apiSource, options)) } diff --git a/src/swaggerInterfaces.ts b/src/swaggerInterfaces.ts index 737f6f0..479ffba 100644 --- a/src/swaggerInterfaces.ts +++ b/src/swaggerInterfaces.ts @@ -107,6 +107,8 @@ export interface IDefinitionProperty { type: string enum: any[] format: string + readOnly: boolean + nullable: boolean maxLength: number $ref: string allOf: IDefinitionProperty[] diff --git a/src/templates/serviceHeader.ts b/src/templates/serviceHeader.ts index a61720f..f49f822 100644 --- a/src/templates/serviceHeader.ts +++ b/src/templates/serviceHeader.ts @@ -35,13 +35,6 @@ export function serviceHeader(options: ISwaggerOptions) { `; } -export function disableLint() { - return `/** Generate by swagger-axios-codegen */ - // @ts-nocheck -/* eslint-disable */ - -`} - export function customerServiceHeader(options: ISwaggerOptions) { diff --git a/src/templates/template.ts b/src/templates/template.ts index 64b2f61..acc4eeb 100644 --- a/src/templates/template.ts +++ b/src/templates/template.ts @@ -11,6 +11,7 @@ export function interfaceTemplate( name: string, props: IPropDef[], imports: string[], + strictRequiredChecks: boolean = true, strictNullChecks: boolean = true ) { if (isDefinedGenericTypes(name)) { @@ -29,15 +30,20 @@ export function interfaceTemplate( export interface ${name} { - ${props.map(p => classPropsTemplate( - p.name, - p.type, - p.format, - p.desc, - (!strictNullChecks || !(p.validationModel as any)?.required) && !isAdditionalProperties(p.name), - false, - false - )).join('')} + ${props.map(p => { + const validationModel = p.validationModel as any; + const isRequired = !strictRequiredChecks ? false : (validationModel?.required && !validationModel?.readOnly); + return classPropsTemplate( + p.name, + p.type, + p.format, + p.desc, + isRequired && !isAdditionalProperties(p.name), + (!strictNullChecks || validationModel?.nullable) && !isAdditionalProperties(p.name), + false, + false + ) + }).join('')} } ` } @@ -47,6 +53,7 @@ export function classTemplate( name: string, props: IPropDef[], imports: string[], + strictRequiredChecks: boolean = true, strictNullChecks: boolean = true, useClassTransformer: boolean, generateValidationModel: boolean @@ -67,16 +74,20 @@ export function classTemplate( export class ${name} { ${props - .map(p => - classPropsTemplate( - p.name, - p.type, - p.format, - p.desc, - !strictNullChecks || !(p.validationModel as any)?.required, - useClassTransformer, - p.isEnum || p.isType, - ) + .map(p => { + const validationModel = p.validationModel as any; + const isRequired = !strictRequiredChecks ? false : (validationModel?.required && !validationModel?.readOnly); + return classPropsTemplate( + p.name, + p.type, + p.format, + p.desc, + isRequired && !isAdditionalProperties(p.name), + (!strictNullChecks || validationModel?.nullable) && !isAdditionalProperties(p.name), + false, + false + ) + } ) .join('')} @@ -94,7 +105,8 @@ export function classPropsTemplate( type: string, format: string, description: string, - canNull: boolean, + isRequired: boolean, + isNullable: boolean, useClassTransformer: boolean, isType: boolean ) { @@ -113,12 +125,12 @@ export function classPropsTemplate( return ` /** ${description || ''} */ ${decorators} - ${filedName}${canNull ? '?' : ''}:${type}; + ${filedName}${!isRequired && '?'}:${type}${isNullable && ' | null'}; ` } else { return ` /** ${description || ''} */ - ${filedName}${canNull ? '?' : ''}:${type}; + ${filedName}${!isRequired && '?'}:${type}${isNullable && ' | null'}; ` } } @@ -172,7 +184,7 @@ export function enumTemplate(name: string, enumString: string, prefix?: string) export function typeTemplate(name: string, typeString: string, prefix?: string) { return ` - export type ${name} = ${typeString}; + export type ${name} = ${typeString || '""'}; ` } diff --git a/src/utils.ts b/src/utils.ts index 45420ea..a411031 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -280,5 +280,13 @@ export function getValidationModel(propName: string, prop: IDefinitionProperty, validationModel.maxLength = prop.maxLength hasValidationRules = true } + if (prop.nullable) { + validationModel.nullable = prop.nullable + hasValidationRules = true + } + if (prop.readOnly) { + validationModel.readOnly = prop.readOnly + hasValidationRules = true + } return hasValidationRules ? validationModel : null } \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 440175c..b3ff7cd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -32,6 +32,7 @@ /* Strict Type-Checking Options */ "strict": true, /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + "strictRequiredChecks": false, /* Enable strict required checks. */ "strictNullChecks": false, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */