UNPKG

midway-dto-prisma

Version:

根据 prisma 模型自动生成MidwayJS DTO 类和 Swagger 参数信息

332 lines (325 loc) 12.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.genAllDtos = void 0; const extractDecoratorContent = (line, rulePrefix, wrapperPrefix) => { if (line.startsWith(rulePrefix)) { return line.replace(rulePrefix.slice(0, -1), '@Rule'); } return line.substring(wrapperPrefix.length, line.length - 1); }; const parseCustomDecorators = (documentation) => { if (!documentation) { return { description: null, commonDecorators: [], createDecorators: [], updateDecorators: [], }; } const lines = documentation.split('\n').map((line) => line.trim()); let description = null; const decorators = { common: [], create: [], update: [], }; let firstNonDecoratorLine = true; for (const line of lines) { if (line && line.startsWith('@')) { if (line.startsWith('@CreateRule(') || line.startsWith('@Create(')) { const content = extractDecoratorContent(line, '@CreateRule(', '@Create('); decorators.create.push(content); } else if (line.startsWith('@UpdateRule(') || line.startsWith('@Update(')) { const content = extractDecoratorContent(line, '@UpdateRule(', '@Update('); decorators.update.push(content); } else { decorators.common.push(line); } } else if (line && firstNonDecoratorLine) { description = line; firstNonDecoratorLine = false; } } return { description, commonDecorators: decorators.common, createDecorators: decorators.create, updateDecorators: decorators.update, }; }; const genAllDtos = (models, ignoreFields = [], enableSwagger = false, customImports = []) => { const defaultImports = [ "import { Rule, RuleType } from '@midwayjs/validate';", enableSwagger ? "import { ApiProperty } from '@midwayjs/swagger';" : '', ].filter(Boolean); const imports = customImports.length > 0 ? customImports : defaultImports; const importsContent = imports.join('\n') + '\n\n'; const allDtos = models .map((model) => { const createDto = genCreateDto(model, ignoreFields, enableSwagger); const batchCreateDto = genBatchCreateDto(model, ignoreFields, enableSwagger); const updateDto = genUpdateDto(model, ignoreFields, enableSwagger); const batchUpdateDto = genBatchUpdateDto(model, ignoreFields, enableSwagger); const deleteDto = genDeleteDto(model, enableSwagger); const batchDeleteDto = genBatchDeleteDto(model, enableSwagger); const getByIdDto = genGetByIdDto(model, enableSwagger); const modelSchema = genModelSchema(model, ignoreFields, enableSwagger); return `${createDto} ${batchCreateDto} ${updateDto} ${batchUpdateDto} ${deleteDto} ${batchDeleteDto} ${getByIdDto} ${modelSchema}`; }) .join('\n\n'); return `${importsContent}${allDtos}`; }; exports.genAllDtos = genAllDtos; const generateFieldProperty = (field, isOptional, enableSwagger, isUpdate = false, includeRule = true, dtoType = 'create') => { const fieldName = field.name; const fieldType = getFieldType(field); const isRequired = field.isRequired; const { description, commonDecorators, createDecorators, updateDecorators } = parseCustomDecorators(field.documentation); let specificDecorators = []; switch (dtoType) { case 'create': specificDecorators = createDecorators; break; case 'update': specificDecorators = updateDecorators; break; } let finalDecorators = []; if (specificDecorators.length > 0) { finalDecorators = [...specificDecorators]; const nonRuleCommonDecorators = commonDecorators.filter((decorator) => !decorator.includes('@Rule')); finalDecorators = [...nonRuleCommonDecorators, ...finalDecorators]; } else { finalDecorators = [...commonDecorators]; } const comment = description ? ` /** ${description} */\n` : ''; const customDecoratorLines = finalDecorators .map((decorator) => ` ${decorator}`) .join('\n'); const customDecoratorBlock = customDecoratorLines ? `${customDecoratorLines}\n` : ''; const hasApiProperty = finalDecorators.some((decorator) => decorator.includes('@ApiProperty')); const hasRule = finalDecorators.some((decorator) => decorator.includes('@Rule')); let defaultDecorators = ''; if (!hasApiProperty && enableSwagger) { const requiredValue = isUpdate ? false : isRequired; if (description) { defaultDecorators += ` @ApiProperty({ description: "${description}", required: ${requiredValue} })\n`; } else { defaultDecorators += ` @ApiProperty({ required: ${requiredValue} })\n`; } } if (!hasRule && includeRule) { defaultDecorators += ` @Rule(${getFieldRule(field, isUpdate)})\n`; } const fieldDeclaration = isOptional ? `${fieldName}?: ${fieldType};` : `${fieldName}: ${fieldType};`; return `${comment}${customDecoratorBlock}${defaultDecorators} ${fieldDeclaration}`; }; const findIdField = (model) => { const idField = model.fields.find((field) => field.isId); if (!idField) { throw new Error(`Model ${model.name} does not have an ID field`); } return idField; }; const generateStandardDecorators = (field, enableSwagger, description, isUpdate = false, includeRule = true) => { let decorators = ''; if (enableSwagger) { const requiredValue = isUpdate ? false : field.isRequired; decorators += ` @ApiProperty({ description: "${description}", required: ${requiredValue} })\n`; } if (includeRule) { decorators += ` @Rule(${getFieldRule(field, isUpdate)})\n`; } return decorators; }; const generateBatchDto = (className, itemClassName, description, enableSwagger) => { let decorators = ''; if (enableSwagger) { decorators = ` @ApiProperty({ description: '${description}' })\n`; } decorators += ` @Rule(RuleType.array().items(RuleType.object().required()))\n`; return `export class ${className} { ${decorators} items: ${itemClassName}[]; }`; }; const filterModelFields = (model, ignoreFields, excludeId = true) => { return model.fields .filter((field) => !excludeId || !field.isId) .filter((field) => field.kind !== 'object') .filter((field) => !ignoreFields.includes(field.name)); }; const genCreateDto = (model, ignoreFields = [], enableSwagger = false) => { const className = `Create${model.name}DTO`; const properties = filterModelFields(model, ignoreFields, true) .map((field) => generateFieldProperty(field, false, enableSwagger, false, true, 'create')) .join('\n\n'); return `export class ${className} { ${properties} }`; }; const genBatchCreateDto = (model, ignoreFields = [], enableSwagger = false) => { const className = `BatchCreate${model.name}DTO`; const createClassName = `Create${model.name}DTO`; return generateBatchDto(className, createClassName, `${model.name}创建数据列表`, enableSwagger); }; const genUpdateDto = (model, ignoreFields = [], enableSwagger = false) => { const className = `Update${model.name}DTO`; const properties = filterModelFields(model, ignoreFields, true) .map((field) => generateFieldProperty(field, true, enableSwagger, true, true, 'update')) .join('\n\n'); return `export class ${className} { ${properties} }`; }; const genBatchUpdateDto = (model, ignoreFields = [], enableSwagger = false) => { const className = `BatchUpdate${model.name}DTO`; const updateClassName = `Update${model.name}DTO`; return generateBatchDto(className, updateClassName, `${model.name}更新数据列表`, enableSwagger); }; const genGetByIdDto = (model, enableSwagger = false) => { const className = `Get${model.name}ByIdDTO`; const idField = findIdField(model); const idType = getFieldType(idField); const decorators = generateStandardDecorators(idField, enableSwagger, `${model.name}ID`); return `export class ${className} { ${decorators} id: ${idType}; }`; }; const genDeleteDto = (model, enableSwagger = false) => { const className = `Delete${model.name}DTO`; const idField = findIdField(model); const idType = getFieldType(idField); const decorators = generateStandardDecorators(idField, enableSwagger, `${model.name}ID`); return `export class ${className} { ${decorators} id: ${idType}; }`; }; const genBatchDeleteDto = (model, enableSwagger = false) => { const className = `BatchDelete${model.name}DTO`; const idField = findIdField(model); const idType = getFieldType(idField); let decorators = ''; if (enableSwagger) { decorators = ` @ApiProperty({ description: '${model.name}ID列表' })\n`; } decorators += ` @Rule(RuleType.array().items(${getFieldRule(idField, false)}))\n`; return `export class ${className} { ${decorators} ids: ${idType}[]; }`; }; const genModelSchema = (model, ignoreFields = [], enableSwagger = false) => { const className = `${model.name}Schema`; const properties = model.fields .filter((field) => field.kind !== 'object') .map((field) => { const fieldName = field.name; const fieldType = getFieldType(field); const { description } = parseCustomDecorators(field.documentation); const comment = description ? ` /** ${description} */\n` : ''; let apiPropertyDecorator = ''; if (enableSwagger) { if (description) { apiPropertyDecorator = ` @ApiProperty({ description: "${description}" })\n`; } else { apiPropertyDecorator = ` @ApiProperty()\n`; } } const fieldDeclaration = field.isRequired ? `${fieldName}: ${fieldType};` : `${fieldName}?: ${fieldType};`; return `${comment}${apiPropertyDecorator} ${fieldDeclaration}`; }) .join('\n\n'); return `export class ${className} { ${properties} }`; }; const getFieldType = (field) => { if (field.isList) { return `${getBaseType(field)}[]`; } return getBaseType(field); }; const TYPE_MAPPINGS = { typescript: { String: 'string', Boolean: 'boolean', Int: 'number', BigInt: 'number', Float: 'number', Decimal: 'number', DateTime: 'Date', Json: 'any', Bytes: 'Buffer', }, rule: { String: 'RuleType.string()', Boolean: 'RuleType.boolean()', Int: 'RuleType.number()', BigInt: 'RuleType.number()', Float: 'RuleType.number()', Decimal: 'RuleType.number()', DateTime: 'RuleType.date()', Json: 'RuleType.any()', Bytes: 'RuleType.binary()', }, }; const getBaseType = (field) => { if (field.type in TYPE_MAPPINGS.typescript) { return TYPE_MAPPINGS.typescript[field.type]; } if (field.kind === 'enum') { return field.type; } if (field.kind === 'object') { return field.isList ? `${field.type}ResponseDTO[]` : `${field.type}ResponseDTO`; } return 'any'; }; const getFieldRule = (field, isUpdate = false) => { const baseRule = getBaseRule(field); const requiredRule = isUpdate ? '.optional()' : field.isRequired ? '.required()' : '.optional()'; return baseRule + requiredRule; }; const getBaseRule = (field) => { if (field.type in TYPE_MAPPINGS.rule) { return TYPE_MAPPINGS.rule[field.type]; } if (field.kind === 'enum') { return `RuleType.string().valid(...Object.values(${field.type}))`; } if (field.kind === 'object') { if (field.isList) { return `RuleType.array().items(RuleType.object().schema(${field.type}ResponseDTO))`; } else { return `RuleType.object().schema(${field.type}ResponseDTO)`; } } return 'RuleType.any()'; }; //# sourceMappingURL=genDto.js.map