166 lines
8.3 KiB
TypeScript
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;
|
|
} |