import { join } from 'node:path' import { writeBackendModule } from '#services/module_generator/writers/backend_module_writer' import DataTableSourceBuilder from '#services/module_generator/builders/data_table_source_builder' import FormSourceBuilder from '#services/module_generator/builders/form_source_builder' import ListPageSourceBuilder from '#services/module_generator/builders/list_page_source_builder' import ManageTriggerSourceBuilder from '#services/module_generator/builders/manage_trigger_source_builder' import MenuSourceBuilder from '#services/module_generator/builders/menu_source_builder' import ModuleConfigSourceBuilder from '#services/module_generator/builders/module_config_source_builder' import { writeFrontendModule } from '#services/module_generator/writers/frontend_module_writer' import { buildModuleContext, ModuleContext } from '#services/module_generator/module_context' import { capitalize } from '#services/module_generator/naming' import { ModuleAsset, ModuleGeneratorConfig } from '#services/module_generator/types' /** * Generates a full module from its table schema and generator config: * frontend module in the sibling admin workspace, backend assets under * modules/. Returns the generated module's name. */ export async function generateModule(config: ModuleGeneratorConfig): Promise { const appBase = process.cwd() const context = await buildModuleContext(config.table) writeFrontendAssets(config, context, appBase) await writeBackendModule({ name: config.name, table: config.table, generate: config.generate, appBase, context, }) return capitalize(config.name) } // Template tree first (hbs rendered, the rest copied verbatim), then builder // output for the selected assets. Files whose asset is not selected keep the // scaffold defaults from the template tree. function writeFrontendAssets( config: ModuleGeneratorConfig, context: ModuleContext, appBase: string ) { const { name, generate, form, datatable } = config const shouldGenerateForm = generate.includes(ModuleAsset.FORM) && !!form const shouldGenerateDataTable = generate.includes(ModuleAsset.DATATABLE) && !!datatable writeFrontendModule({ templateDir: join(appBase, 'app', 'templates', 'frontend', 'module'), outDir: join(appBase, '..', 'admin', 'src', 'modules', capitalize(name)), context: { name, fields: context.frontendFields }, overrides: { 'view/forms/MainForm/Component.tsx': shouldGenerateForm ? FormSourceBuilder.buildComponent(form) : null, 'view/forms/MainForm/form.ts': shouldGenerateForm ? FormSourceBuilder.buildDefinition(form) : null, 'view/widgets/ManageTrigger.tsx': shouldGenerateForm ? ManageTriggerSourceBuilder.build(form.size) : null, 'view/widgets/DataTable.tsx': shouldGenerateDataTable ? DataTableSourceBuilder.build(config) : null, 'pages/ListPage/index.tsx': ListPageSourceBuilder.build({ addTable: shouldGenerateDataTable, }), 'config/menu.ts': shouldGenerateDataTable ? MenuSourceBuilder.build() : null, 'config/module.ts': ModuleConfigSourceBuilder.build(name, { includeMenu: shouldGenerateDataTable, }), }, }) }