import { IModuleBuilder, IParseResult, IProjectBuilder, IProjectPlugins, IProjectSchema, IProjectTemplate, IResultDir, IResultFile, ISchemaParser, } from '../types'; import ResultDir from '@/model/ResultDir'; import SchemaParser from '@/parse/SchemaParser'; import { createModuleBuilder } from '@/generator/ModuleBuilder'; interface IModuleInfo { moduleName?: string; path: string[]; files: IResultFile[]; } function getDirFromRoot(root: IResultDir, path: string[]): IResultDir { let current: IResultDir = root; path.forEach(p => { const exist = current.dirs.find(d => d.name === p); if (exist) { current = exist; } else { const newDir = new ResultDir(p); current.addDirectory(newDir); current = newDir; } }); return current; } export class ProjectBuilder implements IProjectBuilder { private template: IProjectTemplate; private plugins: IProjectPlugins; constructor({ template, plugins, }: { template: IProjectTemplate; plugins: IProjectPlugins; }) { this.template = template; this.plugins = plugins; } public async generateProject(schema: IProjectSchema): Promise { // Init working parts const schemaParser: ISchemaParser = new SchemaParser(); const builders = this.createModuleBuilders(); const projectRoot = this.template.generateTemplate(); // Validate // Parse / Format // Preprocess // Colllect Deps // Parse JSExpression const parseResult: IParseResult = schemaParser.parse(schema); let buildResult: IModuleInfo[] = []; // Generator Code module // components // pages const containerBuildResult: IModuleInfo[] = await Promise.all( parseResult.containers.map(async containerInfo => { let builder: IModuleBuilder; let path: string[]; if (containerInfo.containerType === 'Page') { builder = builders.pages; path = this.template.slots.pages.path; } else { builder = builders.components; path = this.template.slots.components.path; } const { files } = await builder.generateModule(containerInfo); return { moduleName: containerInfo.fileName, path, files, }; }), ); buildResult = buildResult.concat(containerBuildResult); // router if (parseResult.globalRouter && builders.router) { const { files } = await builders.router.generateModule( parseResult.globalRouter, ); buildResult.push({ path: this.template.slots.router.path, files, }); } // entry if (parseResult.project && builders.entry) { const { files } = await builders.entry.generateModule( parseResult.project, ); buildResult.push({ path: this.template.slots.entry.path, files, }); } // constants? if ( parseResult.project && builders.constants && this.template.slots.constants ) { const { files } = await builders.constants.generateModule( parseResult.project, ); buildResult.push({ path: this.template.slots.constants.path, files, }); } // utils? if ( parseResult.globalUtils && builders.utils && this.template.slots.utils ) { const { files } = await builders.utils.generateModule( parseResult.globalUtils, ); buildResult.push({ path: this.template.slots.utils.path, files, }); } // i18n? if (parseResult.globalI18n && builders.i18n && this.template.slots.i18n) { const { files } = await builders.i18n.generateModule( parseResult.globalI18n, ); buildResult.push({ path: this.template.slots.i18n.path, files, }); } // globalStyle if (parseResult.project && builders.globalStyle) { const { files } = await builders.globalStyle.generateModule( parseResult.project, ); buildResult.push({ path: this.template.slots.globalStyle.path, files, }); } // htmlEntry if (parseResult.project && builders.htmlEntry) { const { files } = await builders.htmlEntry.generateModule( parseResult.project, ); buildResult.push({ path: this.template.slots.htmlEntry.path, files, }); } // packageJSON if (parseResult.project && builders.packageJSON) { const { files } = await builders.packageJSON.generateModule( parseResult.project, ); buildResult.push({ path: this.template.slots.packageJSON.path, files, }); } // Post Process // Combine Modules buildResult.forEach(moduleInfo => { let targetDir = getDirFromRoot(projectRoot, moduleInfo.path); if (moduleInfo.moduleName) { const dir = new ResultDir(moduleInfo.moduleName); targetDir.addDirectory(dir); targetDir = dir; } moduleInfo.files.forEach(file => targetDir.addFile(file)); }); return projectRoot; } private createModuleBuilders(): Record { const builders: Record = {}; builders.components = createModuleBuilder({ plugins: this.plugins.components, }); builders.pages = createModuleBuilder({ plugins: this.plugins.pages }); builders.router = createModuleBuilder({ plugins: this.plugins.router, mainFileName: this.template.slots.router.fileName, }); builders.entry = createModuleBuilder({ plugins: this.plugins.entry, mainFileName: this.template.slots.entry.fileName, }); builders.globalStyle = createModuleBuilder({ plugins: this.plugins.globalStyle, mainFileName: this.template.slots.globalStyle.fileName, }); builders.htmlEntry = createModuleBuilder({ plugins: this.plugins.htmlEntry, mainFileName: this.template.slots.htmlEntry.fileName, }); builders.packageJSON = createModuleBuilder({ plugins: this.plugins.packageJSON, mainFileName: this.template.slots.packageJSON.fileName, }); if (this.template.slots.constants && this.plugins.constants) { builders.constants = createModuleBuilder({ plugins: this.plugins.constants, mainFileName: this.template.slots.constants.fileName, }); } if (this.template.slots.utils && this.plugins.utils) { builders.utils = createModuleBuilder({ plugins: this.plugins.utils, mainFileName: this.template.slots.utils.fileName, }); } if (this.template.slots.i18n && this.plugins.i18n) { builders.i18n = createModuleBuilder({ plugins: this.plugins.i18n, mainFileName: this.template.slots.i18n.fileName, }); } return builders; } } export function createProjectBuilder({ template, plugins, }: { template: IProjectTemplate; plugins: IProjectPlugins; }): IProjectBuilder { return new ProjectBuilder({ template, plugins, }); }