@adocasts.com/dto
Version:
Easily make and generate DTOs from Lucid Models
123 lines (122 loc) • 4 kB
JavaScript
import { generators } from '@adonisjs/core/app';
import string from '@adonisjs/core/helpers/string';
export default class ValidatorService {
app;
constructor(app) {
this.app = app;
}
/**
* Get validator file, class, and property info
* @param name
* @param model
*/
getValidatorInfo(name, model) {
const entity = generators.createEntity(this.#getValidatorName(name));
const fileName = generators
.modelFileName(entity.name)
.replace('_validator', '')
.replace('.ts', '');
const data = {
entity,
fileName,
className: generators.modelName(entity.name),
variable: string.camelCase(name) + 'Validator',
exportPath: this.app.makePath('app/validators', entity.path, fileName + '.ts'),
properties: [],
};
if (!model.isReadable)
return data;
data.properties = this.#getValidatorProperties(model);
return data;
}
/**
* Normalize name of the validator
* @param name
* @private
*/
#getValidatorName(name) {
return name.toLowerCase().endsWith('validator') ? name : name + '_validator';
}
/**
* Get validator's property, type, and validation rule info
* @param model
* @private
*/
#getValidatorProperties(model) {
return model.properties.map((property) => {
const typeRaw = this.#getValidatorType(property);
const type = typeRaw.map((item) => item.type).join(' | ');
return {
name: property.name,
type,
typeRaw: typeRaw,
validationRule: this.#getValidationRule(property, typeRaw),
};
});
}
/**
* Get normalized validator types
* @param property
* @private
*/
#getValidatorType(property) {
if (property.relation?.isRelationship) {
const types = [{ ...property.relation }];
// Add null type for non-plural relationships that might be null
if (!property.relation.isPlural) {
types.push({ type: 'null' });
}
return types;
}
return property.types;
}
/**
* Get VineJS validation rule for property
* @param property
* @param types
* @private
*/
#getValidationRule(property, types) {
// Handle relationships
if (property.relation?.isRelationship) {
return property.relation.isPlural ? `vine.array(vine.object({}))` : `vine.object({})`;
}
// Check if property is optional
const isOptional = property.isOptionallyModified ||
types.some((type) => type.type === 'null' || type.type === 'undefined');
// Get base rule based on primary type
const primaryType = types.find((type) => !['null', 'undefined', 'optional'].includes(type.type));
let rule = '';
if (!primaryType) {
// Default to string if no primary type found
rule = 'vine.string()';
}
else if (primaryType.type === 'string') {
rule = 'vine.string().trim()';
}
else if (primaryType.type === 'number') {
rule = 'vine.number()';
}
else if (primaryType.type === 'boolean') {
rule = 'vine.boolean()';
}
else if (primaryType.type === 'Date') {
rule = 'vine.date()';
}
else if (primaryType.type === 'DateTime') {
rule = 'vine.date({ formats: { utc: true } })';
}
else if (primaryType.type.includes('[]')) {
rule = 'vine.array()';
}
else {
// Default to string for unknown types
rule = 'vine.string()';
}
// Add optional modifier if needed
if (isOptional) {
rule += '.optional()';
}
return rule;
}
}