From dc4208ad0f42ad8516cb7c1d7c48dfc269b82934 Mon Sep 17 00:00:00 2001 From: Kononnable Date: Tue, 24 Dec 2019 10:40:36 +0100 Subject: [PATCH] Option to generate index file (#174) --- src/IGenerationOptions.ts | 4 +- src/ModelGeneration.ts | 59 +++++++++++++++++-- src/index.ts | 16 ++++- src/templates/index.mst | 3 + .../modelCustomization.test.ts | 48 +++++++++++++++ 5 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 src/templates/index.mst diff --git a/src/IGenerationOptions.ts b/src/IGenerationOptions.ts index a12b3c4..1cb8568 100644 --- a/src/IGenerationOptions.ts +++ b/src/IGenerationOptions.ts @@ -18,6 +18,7 @@ export default interface IGenerationOptions { relationIds: boolean; strictMode: "none" | "?" | "!"; skipSchema: boolean; + indexFile: boolean; } export function getDefaultGenerationOptions(): IGenerationOptions { const generationOptions: IGenerationOptions = { @@ -34,7 +35,8 @@ export function getDefaultGenerationOptions(): IGenerationOptions { customNamingStrategyPath: "", relationIds: false, strictMode: "none", - skipSchema: false + skipSchema: false, + indexFile: false }; return generationOptions; } diff --git a/src/ModelGeneration.ts b/src/ModelGeneration.ts index dfc8e1f..758dc2a 100644 --- a/src/ModelGeneration.ts +++ b/src/ModelGeneration.ts @@ -14,8 +14,7 @@ export default function modelGenerationPhase( databaseModel: Entity[] ): void { createHandlebarsHelpers(generationOptions); - const templatePath = path.resolve(__dirname, "templates", "entity.mst"); - const template = fs.readFileSync(templatePath, "UTF-8"); + const resultPath = generationOptions.resultsPath; if (!fs.existsSync(resultPath)) { fs.mkdirSync(resultPath); @@ -29,7 +28,24 @@ export default function modelGenerationPhase( fs.mkdirSync(entitiesPath); } } - const compliedTemplate = Handlebars.compile(template, { + if (generationOptions.indexFile) { + createIndexFile(databaseModel, generationOptions, entitiesPath); + } + generateModels(databaseModel, generationOptions, entitiesPath); +} + +function generateModels( + databaseModel: Entity[], + generationOptions: IGenerationOptions, + entitiesPath: string +) { + const entityTemplatePath = path.resolve( + __dirname, + "templates", + "entity.mst" + ); + const entityTemplate = fs.readFileSync(entityTemplatePath, "UTF-8"); + const entityCompliedTemplate = Handlebars.compile(entityTemplate, { noEscape: true }); databaseModel.forEach(element => { @@ -54,7 +70,7 @@ export default function modelGenerationPhase( entitiesPath, `${casedFileName}.ts` ); - const rendered = compliedTemplate(element); + const rendered = entityCompliedTemplate(element); const withImportStatements = removeUnusedImports(rendered); const formatted = Prettier.format(withImportStatements, { parser: "typescript" @@ -65,6 +81,41 @@ export default function modelGenerationPhase( }); }); } + +function createIndexFile( + databaseModel: Entity[], + generationOptions: IGenerationOptions, + entitiesPath: string +) { + const templatePath = path.resolve(__dirname, "templates", "index.mst"); + const template = fs.readFileSync(templatePath, "UTF-8"); + const compliedTemplate = Handlebars.compile(template, { + noEscape: true + }); + const rendered = compliedTemplate({ entities: databaseModel }); + const formatted = Prettier.format(rendered, { + parser: "typescript" + }); + let fileName = "index"; + switch (generationOptions.convertCaseFile) { + case "camel": + fileName = changeCase.camelCase(fileName); + break; + case "param": + fileName = changeCase.paramCase(fileName); + break; + case "pascal": + fileName = changeCase.pascalCase(fileName); + break; + default: + } + const resultFilePath = path.resolve(entitiesPath, `${fileName}.ts`); + fs.writeFileSync(resultFilePath, formatted, { + encoding: "UTF-8", + flag: "w" + }); +} + function removeUnusedImports(rendered: string) { const openBracketIndex = rendered.indexOf("{") + 1; const closeBracketIndex = rendered.indexOf("}"); diff --git a/src/index.ts b/src/index.ts index b0264fb..07375ba 100644 --- a/src/index.ts +++ b/src/index.ts @@ -255,6 +255,11 @@ function checkYargsParameters(options: options): options { choices: ["none", "?", "!"], default: options.generationOptions.strictMode, describe: "Mark fields as optional(?) or non-null(!)" + }, + index: { + boolean: true, + default: options.generationOptions.indexFile, + describe: "Generate index file" } }); @@ -272,6 +277,7 @@ function checkYargsParameters(options: options): options { : standardSchema; options.connectionOptions.ssl = argv.ssl; options.connectionOptions.user = argv.u || standardUser; + options.connectionOptions.skipTables = argv.skipTables.split(","); options.generationOptions.activeRecord = argv.a; options.generationOptions.generateConstructor = argv.generateConstructor; options.generationOptions.convertCaseEntity = argv.ce as IGenerationOptions["convertCaseEntity"]; @@ -286,7 +292,7 @@ function checkYargsParameters(options: options): options { options.generationOptions.resultsPath = argv.o; options.generationOptions.pluralizeNames = !argv.disablePluralization; options.generationOptions.strictMode = argv.strictMode as IGenerationOptions["strictMode"]; - options.connectionOptions.skipTables = argv.skipTables.split(","); + options.generationOptions.indexFile = argv.index; return options; } @@ -499,9 +505,14 @@ async function useInquirer(options: options): Promise { }, { name: - "Pluralize OneToMany, ManyToMany relation names.", + "Pluralize OneToMany, ManyToMany relation names", value: "pluralize", checked: options.generationOptions.pluralizeNames + }, + { + name: "Generate index file", + value: "index", + checked: options.generationOptions.indexFile } ], message: "Available customizations", @@ -555,6 +566,7 @@ async function useInquirer(options: options): Promise { options.generationOptions.generateConstructor = customizations.includes( "constructor" ); + options.generationOptions.indexFile = customizations.includes("index"); if (customizations.includes("namingStrategy")) { const namingStrategyPath = ( diff --git a/src/templates/index.mst b/src/templates/index.mst new file mode 100644 index 0000000..928dd19 --- /dev/null +++ b/src/templates/index.mst @@ -0,0 +1,3 @@ +{{#entities~}} +export { {{toEntityName tscName}} } from './{{toFileName tscName}}' +{{/entities~}} \ No newline at end of file diff --git a/test/modelCustomization/modelCustomization.test.ts b/test/modelCustomization/modelCustomization.test.ts index b474300..acbde5f 100644 --- a/test/modelCustomization/modelCustomization.test.ts +++ b/test/modelCustomization/modelCustomization.test.ts @@ -665,4 +665,52 @@ describe("Model customization phase", async () => { compileGeneratedModel(generationOptions.resultsPath, [""]); }) }) + describe("index file generation", () => { + it("enabled", async () => { + + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + generationOptions.indexFile = true; + clearGenerationDir(); + + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + getDefaultConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + const indexFileContent = fs + .readFileSync(path.resolve(filesGenPath, "Index.ts")) + .toString(); + expect(indexFileContent).to.contain('export { Post } from "./Post";'); + expect(indexFileContent).to.contain('export { PostAuthor } from "./PostAuthor";'); + compileGeneratedModel(generationOptions.resultsPath, [""]); + }) + it("disabled", async () => { + + const data = generateSampleData(); + const generationOptions = generateGenerationOptions(); + generationOptions.pluralizeNames = false; + clearGenerationDir(); + + const customizedModel = modelCustomizationPhase( + data, + generationOptions, + {} + ); + modelGenerationPhase( + getDefaultConnectionOptions(), + generationOptions, + customizedModel + ); + const filesGenPath = path.resolve(resultsPath, "entities"); + expect(fs.existsSync(path.resolve(filesGenPath, "Index.ts"))).to.equal(false); + compileGeneratedModel(generationOptions.resultsPath, [""]); + }) + }) });