@adocasts.com/dto
Version:
Easily make and generate DTOs from Lucid Models
107 lines (106 loc) • 4.21 kB
JavaScript
import string from '@adonisjs/core/helpers/string';
import UtilService from './util_service.js';
export class ImportService {
/**
* Get grouped import statements from generated entity type information
* @param entity Either a DtoInfo or ValidatorInfo object
*/
static getImportStatements(entity, modelFileLines) {
const imports = [];
const importLines = this.#getImportFileLines(modelFileLines);
for (let property of entity.properties) {
// get imports for relationship DTOs
for (let item of property.typeRaw) {
if (item.isRelationship && item.dto) {
imports.push({
name: item.dto,
namespace: '#dtos/' + string.snakeCase(item.dto).replace('_dto', ''),
isDefault: true,
});
}
}
const importMatch = this.#findImportLineMatch(property, importLines);
if (importMatch) {
imports.push(importMatch);
}
}
// don't try to import the entity we're generating
const nonSelfReferencingImports = imports.filter((imp) => imp.name !== entity.className);
// join default and named imports into a single import statement for the namespace
return this.#buildImportStatements(nonSelfReferencingImports);
}
static #buildImportStatements(imports) {
const groups = this.#getGroupedImportNamespaces(imports);
return Object.values(groups).map((items) => {
const defaultImport = items.find((item) => item.isDefault)?.name;
const namedImports = items
.filter((item) => !item.isDefault)
.map((item) => item.name)
.join(', ');
const names = [defaultImport, namedImports && `{ ${namedImports} }`]
.filter(Boolean)
.join(', ');
return `import ${names} from '${items[0].namespace}'`;
});
}
/**
* groups imports by namespace
* @param imports
* @private
*/
static #getGroupedImportNamespaces(imports) {
return imports.reduce((groups, item) => {
const group = groups[item.namespace] || [];
if (!group.some((map) => map.name === item.name)) {
group.push(item);
}
groups[item.namespace] = group;
return groups;
}, {});
}
static #getImportFileLines(fileLines) {
const lines = fileLines.filter((line) => line.startsWith('import '));
return lines.map((line) => {
const part = line.replace('import ', '').replace('type ', '').split('from ').at(0);
const namespace = line.split('from ').at(1) || '';
const [defaultPart = '', namedPart = ''] = part?.split('{') || [];
const names = namedPart
.split('}')
.at(0)
?.split(',')
.map((name) => name.trim()) || [];
return {
name: UtilService.cleanDefinition(defaultPart),
names: names.filter((name) => name !== ''),
namespace,
line,
};
});
}
static #findImportLineMatch(property, lines) {
const types = property.type.split('|').map((type) => type.trim());
const defaultMatch = lines.find((line) => types.includes(line.name));
if (defaultMatch) {
return {
name: defaultMatch.name,
namespace: UtilService.cleanDefinition(defaultMatch.namespace),
isDefault: true,
};
}
let namedMatch;
for (const line of lines) {
const name = line.names.find((item) => types.includes(item));
if (!name)
continue;
namedMatch = { name, namespace: line.namespace };
break;
}
if (!namedMatch)
return;
return {
name: namedMatch.name,
namespace: UtilService.cleanDefinition(namedMatch.namespace),
isDefault: false,
};
}
}