Browse Source

feat: handle model imports in model schematics

pull/5137/head
Arman Ozak 6 years ago
parent
commit
d31aee32b3
  1. 10
      npm/ng-packs/packages/schematics/src/commands/api/files-model/shared/models/__namespace@dir__/index.ts.template
  2. 1
      npm/ng-packs/packages/schematics/src/commands/api/index.ts
  3. 80
      npm/ng-packs/packages/schematics/src/utils/model.ts
  4. 14
      npm/ng-packs/packages/schematics/src/utils/type.ts

10
npm/ng-packs/packages/schematics/src/commands/api/files-model/shared/models/__namespace@dir__/index.ts.template

@ -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 %>;<% } %>
}
<% } %>

1
npm/ng-packs/packages/schematics/src/commands/api/index.ts

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

80
npm/ng-packs/packages/schematics/src/utils/model.ts

@ -1,18 +1,30 @@
import { strings } from '@angular-devkit/core'; 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 { 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>) { export function createImportRefsToModelMapper(solution: string, types: Record<string, Type>) {
const mapImportRefToInterface = createImportRefToInterfaceMapper(solution, types); const mapImportRefToInterface = createImportRefToInterfaceMapper(solution, types);
const createImportRefToImportReducer = createImportRefToImportReducerCreator(solution, types);
return (importRefs: string[]) => { return (importRefs: string[]) => {
const model = new Model({ const namespace = parseNamespace(solution, importRefs[0]);
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)); 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)); 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) => { return (ref: string) => {
const typeDef = types[ref]; const typeDef = types[ref];
let identifier = simplifyType(ref); const identifier = (typeDef.genericArguments ?? []).reduce(
(typeDef.genericArguments ?? []).forEach((t, i) => { (acc, t, i) => acc.replace(`T${i}`, t),
identifier = identifier.replace(`T${i}`, t); simplifyType(ref),
}); );
const base = typeDef.baseType ? simplifyType(typeDef.baseType) : null; const base = typeDef.baseType ? simplifyType(typeDef.baseType) : null;
const _interface = new Interface({ identifier, base }); const _interface = new Interface({ identifier, base });
@ -45,3 +57,51 @@ export function createImportRefToInterfaceMapper(solution: string, types: Record
return _interface; 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;
}

14
npm/ng-packs/packages/schematics/src/utils/type.ts

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

Loading…
Cancel
Save