feat: handle model imports in model schematics

pull/5137/head
Arman Ozak 5 years ago
parent f467dc75c8
commit d31aee32b3

@ -0,0 +1,10 @@
<%
for (const {keyword, specifiers, path} of imports) {
%><%= keyword %> { <%= specifiers.join(', ') %> } from '<%= path %>';
<% }
for (let {base, identifier, properties} of interfaces) { %>
export interface <%= identifier %> <%= base ? `extends ${base} ` : '' %>{<%
for (let {name, optional, type} of properties) { %>
<%= name + optional %>: <%= type %>;<% } %>
}
<% } %>

@ -26,6 +26,7 @@ export default function(params: GenerateProxySchema) {
controllers.map(controller => {
const service = mapControllerToService(controller);
service.imports.forEach(({refs, path}) => refs.forEach(ref => {
if (path === '@abp/ng.core') return;
if (!serviceImports[path]) return (serviceImports[path] = [ref]);
serviceImports[path] = [...new Set([...serviceImports[path], ref])];
}));

@ -1,18 +1,30 @@
import { strings } from '@angular-devkit/core';
import { Interface, Model, Property, Type } from '../models';
import { Import, Interface, Model, Property, Type } from '../models';
import { sortImports } from './import';
import { parseNamespace } from './namespace';
import { createTypeSimplifier } from './type';
import { relativePathToModel } from './path';
import { parseGenerics } from './tree';
import { createTypeSimplifier, createTypesToImportsReducer } from './type';
export function createImportRefsToModelMapper(solution: string, types: Record<string, Type>) {
const mapImportRefToInterface = createImportRefToInterfaceMapper(solution, types);
const createImportRefToImportReducer = createImportRefToImportReducerCreator(solution, types);
return (importRefs: string[]) => {
const model = new Model({
namespace: parseNamespace(solution, importRefs[0]),
});
const namespace = parseNamespace(solution, importRefs[0]);
const model = new Model({ namespace });
importRefs.forEach(ref => {
const reduceImportRefToImport = createImportRefToImportReducer(namespace);
const imports = importRefs.reduce((accumulatedImports, ref) => {
model.interfaces.push(mapImportRefToInterface(ref));
return reduceImportRefToImport(accumulatedImports, ref);
}, []);
sortImports(imports);
const selfPath = relativePathToModel(namespace, namespace);
imports.forEach(i => {
if (i.path === selfPath) return;
model.imports.push(i);
});
model.interfaces.sort((a, b) => (a.identifier > b.identifier ? 1 : -1));
@ -26,10 +38,10 @@ export function createImportRefToInterfaceMapper(solution: string, types: Record
return (ref: string) => {
const typeDef = types[ref];
let identifier = simplifyType(ref);
(typeDef.genericArguments ?? []).forEach((t, i) => {
identifier = identifier.replace(`T${i}`, t);
});
const identifier = (typeDef.genericArguments ?? []).reduce(
(acc, t, i) => acc.replace(`T${i}`, t),
simplifyType(ref),
);
const base = typeDef.baseType ? simplifyType(typeDef.baseType) : null;
const _interface = new Interface({ identifier, base });
@ -45,3 +57,51 @@ export function createImportRefToInterfaceMapper(solution: string, types: Record
return _interface;
};
}
export function createImportRefToImportReducerCreator(
solution: string,
types: Record<string, Type>,
) {
return (namespace: string) => {
const reduceTypesToImport = createTypesToImportsReducer(solution, namespace);
return (imports: Import[], importRef: string) =>
reduceTypesToImport(
imports,
mergeBaseTypeWithProperties(types[importRef]).reduce((typeNames: string[], { type }) => {
parseGenerics(type)
.toGenerics()
.forEach(t => typeNames.push(t));
return typeNames;
}, []),
);
};
}
export function mergeBaseTypeWithProperties({ baseType, genericArguments, properties }: Type) {
const removeGenerics = createGenericRemover(genericArguments);
const baseTypes = baseType ? [{ type: baseType }] : [];
const propTypes = (properties ?? []).map(({ type }) => ({ type }));
return [...baseTypes, ...propTypes].map(removeGenerics);
}
export function createGenericRemover(genericArguments: string[] | null) {
if (!genericArguments) return (def: SimpleTypeDef) => def;
return ({ type }: SimpleTypeDef) => ({
type: genericArguments.includes(type)
? ''
: type.replace(/<([^<>]+)>/, (_, match) => {
return match
.split(/,\s*/)
.filter((t: string) => !genericArguments.includes(t))
.join(',');
}),
});
}
interface SimpleTypeDef {
type: string;
}

@ -30,17 +30,17 @@ export function createTypesToImportsReducer(solution: string, namespace: string)
return (imports: Import[], types: string[]) => {
types.forEach(type => {
const def = mapTypeToImport(type);
if (!def) return;
const newImport = mapTypeToImport(type);
if (!newImport) return;
const existingImport = imports.find(
({ keyword, path }) => keyword === def.keyword && path === def.path,
({ keyword, path }) => keyword === newImport.keyword && path === newImport.path,
);
if (!existingImport) return imports.push(def);
if (!existingImport) return imports.push(newImport);
existingImport.refs = [...new Set([...existingImport.refs, ...def.refs])];
existingImport.refs = [...new Set([...existingImport.refs, ...newImport.refs])];
existingImport.specifiers = [
...new Set([...existingImport.specifiers, ...def.specifiers]),
...new Set([...existingImport.specifiers, ...newImport.specifiers]),
].sort();
});
@ -52,7 +52,7 @@ export function createTypeToImportMapper(solution: string, namespace: string) {
const adaptType = createTypeAdapter(solution);
return (type: string) => {
if (type.startsWith('System')) return;
if (!type || type.startsWith('System')) return;
const modelNamespace = parseNamespace(solution, type);
const path = type.startsWith('Volo.Abp.Application.Dtos')

Loading…
Cancel
Save