Files
system-builder/src/frontend-services/fe-service-creator.ts

166 lines
8.3 KiB
TypeScript

import {ComponentDef, EndpointDef, SystemDef} from "../systemGenService";
import path from "path";
import {
componentDestination,
initializeComponentFile,
removeTemplateFiles,
removeTemplateFolder,
uppercaseFirstLetter
} from "../helpers";
import fs from "fs";
import {buildServiceFunctionName, getFuncParams} from "../views/service-creator";
import {METHOD, URL} from "../views/routes-creator";
import {buildDetailsView} from "./details-view-builder";
import {buildListView} from "./list-view-builder";
import {buildEditorView} from "./editor-view-builder";
import {buildTypesView} from "./types-view-builder";
import {buildRoute} from "./route-view-builder";
import {buildAppLinks} from "./app-view-builder";
const ncp = require('ncp').ncp;
export function createFrontend(systemDef: SystemDef): Promise<void> {
let fePromises = [];
for (let i in systemDef.components) {
fePromises.push(createComponent(systemDef.components[i], systemDef).then(() => {
// build app router logic
return buildRoute(systemDef.components[i], componentDestination(systemDef.name, systemDef.components[i].component), systemDef);
}).then(() => {
// add a vue view and add it to App.vue
return buildAppLinks(systemDef.components[i], componentDestination(systemDef.name, systemDef.components[i].component), systemDef);
}).then(() => {
return removeTemplateFiles(componentDestination(systemDef.name, systemDef.components[i].component));
}));
}
// TODO: after all is done clean up the template files
return Promise.all(fePromises).then((res: void[]) => {
return removeTemplateFolder(componentDestination(systemDef.name, '{{component}}')).catch((err) => {
console.log(err);
});
});
}
function componentSource() {
return path.join(process.cwd(), 'frontend-frame', 'src', 'components', '{{component}}');
}
function createComponent(component: ComponentDef, systemDef: SystemDef) {
return new Promise<void>((componentResolve, componentReject) => {
ncp(componentSource(), componentDestination(systemDef.name, component.component), (err: any) => {
if (err) {
console.log(err);
componentReject();
return;
} else {
let componentDest: string = componentDestination(systemDef.name, component.component);
let servicePromise = initializeComponentFile(path.join(componentDest, '{{component}}Service.ets'), path.join(componentDest, `${component.component}Service.ts`), component.component, systemDef.name);
for (let i in component.endpoints) {
servicePromise = servicePromise.then(() => {
return insertFEServiceCode(component.endpoints[i], componentDest);
});
// TODO: use templates for Details, Editor, List and Types view based on the endpoints provided
// servicePromise = servicePromise.then(() => {
//
// return initializeComponentFile(path.join(componentDest, '{{component}}Service.ets'), path.join(componentDest, `${component.component}Service.ts`), component.component, systemDef.name);
// });
}
if (componentContains('list', component)) {
servicePromise = servicePromise.then(() => {
return initializeComponentFile(path.join(componentDest, '{{component}}List.vue'), path.join(componentDest, `${component.component}List.vue`), component.component, systemDef.name);
}).then(() => {
// TODO: build list contents based on the list endpoint
return buildListView(component, componentDest, systemDef);
});
}
if (componentContains('item', component)) {
servicePromise = servicePromise.then(() => {
return initializeComponentFile(path.join(componentDest, '{{component}}Details.vue'), path.join(componentDest, `${component.component}Details.vue`), component.component, systemDef.name);
}).then(() => {
// build list contents based on the item endpoint
return buildDetailsView(component, componentDest, systemDef);
});
}
if (componentContains('update', component) || componentContains('create', component)) {
servicePromise = servicePromise.then(() => {
return initializeComponentFile(path.join(componentDest, '{{component}}Editor.vue'), path.join(componentDest, `${component.component}Editor.vue`), component.component, systemDef.name);
}).then(() => {
// build list contents based on the item endpoint
return buildEditorView(component, componentDest, systemDef);
});
}
if (component.endpoints.length) {
// add a types file to power the whole component
servicePromise = servicePromise.then(() => {
return initializeComponentFile(path.join(componentDest, '{{component}}Types.ets'), path.join(componentDest, `${component.component}Types.ts`), component.component, systemDef.name);
}).then(() => {
return buildTypesView(component, componentDest, systemDef);
});
}
servicePromise.then(() => {
componentResolve();
});
}
});
});
}
function componentContains(type: string, component: ComponentDef) {
return component.endpoints.some((epd: EndpointDef) => {
return epd.type === type;
});
}
function insertFEServiceCode(view: EndpointDef, outDir: string) {
return new Promise<void>((resolve) => {
const separator: string = `// SYSTEM-BUILDER-service-functions`;
let fileLocation = path.join(outDir, `${view.component}Service.ts`)
let initServiceFile: string = fs.readFileSync(fileLocation, 'utf8');
let parts = initServiceFile.split(separator);
parts[0] = parts[0] + createFEServiceFunc(view);
let newServiceFile = parts.join(separator);
fs.writeFileSync(fileLocation, newServiceFile, 'utf8');
resolve();
});
}
function createFEServiceFunc(view: EndpointDef): string {
let func: string = '';
let isListOrSearch: boolean = view.type === 'list' || view.type === 'search';
let funcName: string = buildServiceFunctionName(view);
let funcParams: string[] = getFuncParams(view, true);
let columnParams: string[] = view.columns?.filter(column => column.param).map(column => { return '\n ' + column.param + ': ' + column.param; });
let filterParams: string[] = view.filters?.filter(filter => filter.param).map(filter => { return '\n ' + filter.param + ': ' + filter.param; }) || [];
if (isListOrSearch) {
funcParams.push('offset: number');
funcParams.push('limit: number');
filterParams.push('\n offset: offset');
filterParams.push('\n limit: limit');
}
let isGetOrDelete = view.type === 'item' || view.type === 'delete';
let method = METHOD[view.type];
if (method === 'delete') {
method = 'del';
}
let addTypeDeclaration = method === 'get' || method === 'post';
let useList = view.type === 'list' || view.type === 'search';
let url = view.component + '/' + URL[view.type](view).replace(':' + view.component + '_id', '\' + ' + view.component + '_id');
let isUpdateOrCreate = view.type === 'update' || view.type === 'create';
func = `
public ${funcName}(${view.type === 'update' ? view.component + '_id: string, ': ''}${isUpdateOrCreate ? 'params: ' + uppercaseFirstLetter(view.component) + 'Config' : funcParams.join(', ')}) {`;
if (!isGetOrDelete && !isUpdateOrCreate) {
func = func + `
let params = {${columnParams}${columnParams.length ? ',' : ''}${filterParams}
};`;
}
func = func + `
return ${method}${addTypeDeclaration ? '<' + uppercaseFirstLetter(view.component) + 'Config' + (useList ? '[]' : '') + '>': ''}('/api/v1/${url}${isGetOrDelete ? '' : (view.type === 'update' ? ', params' : '\', params')});
}
`;
return func;
}