midway-dto-prisma
Version:
根据 prisma 模型自动生成MidwayJS DTO 类和 Swagger 参数信息
332 lines (325 loc) • 12.4 kB
JavaScript
;
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