"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CodeWriter = void 0;
const ts_morph_1 = require("ts-morph");
const typescript_1 = require("typescript");
const config_1 = require("../../config");
const import_driver_1 = require("./drivers/import.driver");
const export_driver_1 = require("./drivers/export.driver");
const array_driver_1 = require("./drivers/array.driver");
const interface_driver_1 = require("./drivers/interface.driver");
const object_tools_1 = require("../object-tools");
const path = require("node:path");
const fs = require("node:fs");
class CodeWriter {
    constructor(srcDirectory, appDirectory, apiDirectory, boundedContextName, moduleName, moduleNames, aggregateName) {
        this.srcDirectory = srcDirectory;
        this.appDirectory = appDirectory;
        this.apiDirectory = apiDirectory;
        this.boundedContextName = boundedContextName;
        this.moduleName = moduleName;
        this.moduleNames = moduleNames;
        this.aggregateName = aggregateName;
        this.project = new ts_morph_1.Project({
            tsConfigFilePath: path.join(process.cwd(), 'tsconfig.json'),
            // these are the defaults
            manipulationSettings: {
                // TwoSpaces, FourSpaces, EightSpaces, or Tab
                indentationText: ts_morph_1.IndentationText.FourSpaces,
                // LineFeed or CarriageReturnLineFeed
                newLineKind: typescript_1.NewLineKind.LineFeed,
                // Single or Double
                quoteKind: ts_morph_1.QuoteKind.Single,
                // Whether to change shorthand property assignments to property assignments
                // and add aliases to import & export specifiers (see more information in
                // the renaming section of the documentation).
                usePrefixAndSuffixTextForRename: false,
                // Whether to use trailing commas in multi-line scenarios where trailing
                // commas would be used.
                useTrailingCommas: false,
            },
        });
    }
    generateTestingForeignReferences(properties) {
        // get foreign relationship
        const foreignRelationships = properties.getForeignRelationship(this.boundedContextName);
        // check that exist bounded context folder
        if (!fs.existsSync(path.join(process.cwd(), 'cliter', this.boundedContextName.toKebabCase())))
            return;
        // get all yaml files to get all modules managed by cli
        const yamlFiles = fs.readdirSync(path.join(process.cwd(), 'cliter', this.boundedContextName.toKebabCase()));
        for (const foreignRelationship of foreignRelationships) {
            if (!foreignRelationship.relationshipModulePath)
                return;
            const foreignBoundedContextName = foreignRelationship.relationshipModulePath.split('/')[0];
            for (const yamlFile of yamlFiles) {
                // get filename of e2e test
                const e2eTestFile = yamlFile.replace(config_1.cliterConfig.schemaDefinitionExtension, '.e2e-spec.ts');
                const e2eTestPath = path.join(process.cwd(), 'test', 'acceptance', this.boundedContextName.toKebabCase(), e2eTestFile);
                // check that exist e2e test file
                if (fs.existsSync(e2eTestPath)) {
                    // get sourceFile of e2e test
                    const sourceFile = this.project.addSourceFileAtPath(e2eTestPath);
                    // register import in e2e test
                    import_driver_1.ImportDriver.createImportItems(sourceFile, foreignRelationship.relationshipPackageName ?
                        foreignRelationship.relationshipPackageName :
                        `./../../../src/${config_1.cliterConfig.apiContainer}/${foreignBoundedContextName.toKebabCase()}/${foreignBoundedContextName.toKebabCase()}.module`, [
                        `${foreignBoundedContextName.toPascalCase()}Module`,
                    ]);
                    // disable import foreign modules, can be micro-services
                    // register import in import array
                    /* ArrayDriver.addArrayItem(
                        sourceFile,
                        `${foreignBoundedContextName.toPascalCase()}Module`,
                        'importForeignModules',
                    ); */
                    sourceFile === null || sourceFile === void 0 ? void 0 : sourceFile.saveSync();
                }
            }
        }
    }
    generateBoundedContextBackReferences(properties) {
        const sourceFile = this.project.addSourceFileAtPath(path.join(process.cwd(), this.srcDirectory, this.appDirectory, this.boundedContextName.toKebabCase(), 'index.ts'));
        // register import in @app/boundedContext/index.ts
        import_driver_1.ImportDriver.createImportItems(sourceFile, `./${this.moduleName.toKebabCase()}`, [
            `${this.boundedContextName.toPascalCase()}${this.moduleName.toPascalCase()}Handlers`,
            `${this.boundedContextName.toPascalCase()}${this.moduleName.toPascalCase()}Services`,
            `${this.boundedContextName.toPascalCase()}${this.moduleName.toPascalCase()}Model`,
            `I${this.moduleName.toPascalCase()}Repository`,
            `Sequelize${this.moduleName.toPascalCase()}Repository`,
            `${this.moduleName.toPascalCase()}Sagas`,
        ]);
        // handlers
        array_driver_1.ArrayDriver.addArrayItem(sourceFile, `...${this.boundedContextName.toPascalCase()}${this.moduleName.toPascalCase()}Handlers`, `${this.boundedContextName.toPascalCase()}Handlers`);
        // services
        array_driver_1.ArrayDriver.addArrayItem(sourceFile, `...${this.boundedContextName.toPascalCase()}${this.moduleName.toPascalCase()}Services`, `${this.boundedContextName.toPascalCase()}Services`);
        // models
        array_driver_1.ArrayDriver.addArrayItem(sourceFile, `${this.boundedContextName.toPascalCase()}${this.moduleName.toPascalCase()}Model`, `${this.boundedContextName.toPascalCase()}Models`);
        // pivot table model
        for (const pivot of properties.withRelationshipManyToMany) {
            import_driver_1.ImportDriver.createImportItems(sourceFile, `./${this.moduleName.toKebabCase()}`, [`${pivot.pivotAggregateName}Model`]);
            array_driver_1.ArrayDriver.addArrayItem(sourceFile, `${pivot.pivotAggregateName}Model`, `${this.boundedContextName.toPascalCase()}Models`);
        }
        // repositories
        array_driver_1.ArrayDriver.addArrayItem(sourceFile, `
{
    provide : I${this.moduleName.toPascalCase()}Repository,
    useClass: Sequelize${this.moduleName.toPascalCase()}Repository
}`, `${this.boundedContextName.toPascalCase()}Repositories`);
        // sagas
        array_driver_1.ArrayDriver.addArrayItem(sourceFile, `${this.moduleName.toPascalCase()}Sagas`, `${this.boundedContextName.toPascalCase()}Sagas`);
        // add i18n registers
        if (properties.hasI18n) {
            // register import
            import_driver_1.ImportDriver.createImportItems(sourceFile, `./${this.moduleName.toKebabCase()}`, [
                `${this.boundedContextName.toPascalCase()}${this.moduleName.toPascalCase()}I18NModel`,
                `I${this.moduleName.toPascalCase()}I18NRepository`,
                `Sequelize${this.moduleName.toPascalCase()}I18NRepository`,
            ]);
            // models
            array_driver_1.ArrayDriver.addArrayItem(sourceFile, `${this.boundedContextName.toPascalCase()}${this.moduleName.toPascalCase()}I18NModel`, `${this.boundedContextName.toPascalCase()}Models`);
            // repositories
            array_driver_1.ArrayDriver.addArrayItem(sourceFile, `
{
    provide : I${this.moduleName.toPascalCase()}I18NRepository,
    useClass: Sequelize${this.moduleName.toPascalCase()}I18NRepository
}`, `${this.boundedContextName.toPascalCase()}Repositories`);
        }
        sourceFile === null || sourceFile === void 0 ? void 0 : sourceFile.saveSync();
    }
    generateFrontInterface(properties, { overwrite = false, } = {}) {
        const sourceFile = this.project.addSourceFileAtPath(path.join(process.cwd(), this.srcDirectory, config_1.cliterConfig.dashboardContainer, this.boundedContextName.toKebabCase(), `${this.boundedContextName.toKebabCase()}.types.ts`));
        // add object type
        interface_driver_1.InterfaceDriver.addInterface(sourceFile, `${this.boundedContextName.toPascalCase()}${this.moduleName.toPascalCase()}`, properties.graphqlProperties.map(property => ({ name: property.name.toCamelCase() + (property.nullable ? '?' : ''), type: property.getJavascriptType })), { overwrite });
        // add create object type
        interface_driver_1.InterfaceDriver.addInterface(sourceFile, `${this.boundedContextName.toPascalCase()}Create${this.moduleName.toPascalCase()}`, properties.graphqlInputProperties.map(property => ({ name: property.name.toCamelCase() + (property.nullable ? '?' : ''), type: property.getJavascriptType })), { overwrite });
        // add update object by id type
        interface_driver_1.InterfaceDriver.addInterface(sourceFile, `${this.boundedContextName.toPascalCase()}Update${this.moduleName.toPascalCase()}ById`, properties.graphqlInputProperties.map(property => ({ name: property.name.toCamelCase() + (property.name === 'id' ? '' : '?'), type: property.getJavascriptType })), { overwrite });
        // add update objects type
        interface_driver_1.InterfaceDriver.addInterface(sourceFile, `${this.boundedContextName.toPascalCase()}Update${this.moduleNames.toPascalCase()}`, properties.graphqlInputProperties.map(property => ({ name: property.name.toCamelCase() + '?', type: property.getJavascriptType })), { overwrite });
        sourceFile === null || sourceFile === void 0 ? void 0 : sourceFile.saveSync();
    }
    generateFrontRoutes(index = 0) {
        const sourceFile = this.project.addSourceFileAtPath(path.join(process.cwd(), this.srcDirectory, config_1.cliterConfig.dashboardContainer, this.boundedContextName.toKebabCase(), `${this.boundedContextName.toKebabCase()}.routing.ts`));
        const routes = sourceFile.getVariableDeclarationOrThrow(this.boundedContextName.toCamelCase() + 'Routes');
        const routesArray = routes.getInitializerIfKindOrThrow(typescript_1.SyntaxKind.ArrayLiteralExpression);
        const objectRoute = routesArray.getElements()[index];
        const childrenRoutes = objectRoute.getPropertyOrThrow('children');
        const childrenRoutesArray = childrenRoutes === null || childrenRoutes === void 0 ? void 0 : childrenRoutes.getInitializerIfKindOrThrow(typescript_1.SyntaxKind.ArrayLiteralExpression);
        // export list component
        import_driver_1.ImportDriver.createImportItems(sourceFile, `./${this.moduleName.toKebabCase()}/${this.moduleName.toKebabCase()}-list.component`, [`${this.moduleName.toPascalCase()}ListComponent`]);
        // export detail component
        import_driver_1.ImportDriver.createImportItems(sourceFile, `./${this.moduleName.toKebabCase()}/${this.moduleName.toKebabCase()}-detail.component`, [`${this.moduleName.toPascalCase()}DetailComponent`]);
        // export resolvers
        import_driver_1.ImportDriver.createImportItems(sourceFile, `./${this.moduleName.toKebabCase()}/${this.moduleName.toKebabCase()}.resolvers`, [
            `${this.moduleName.toPascalCase()}EditResolver`,
            `${this.moduleName.toPascalCase()}NewResolver`,
            `${this.moduleName.toPascalCase()}PaginationResolver`,
        ]);
        // add route to list items
        array_driver_1.ArrayDriver.addArrayItem(sourceFile, `{ path: '${this.moduleName.toKebabCase()}', component: ${this.moduleName.toPascalCase()}ListComponent, resolve: { data: ${this.moduleName.toPascalCase()}PaginationResolver }, data: { permission: '${this.boundedContextName.toCamelCase()}.${this.moduleName.toCamelCase()}.get' }}`, childrenRoutesArray, (item, array) => {
            const foundItem = (array === null || array === void 0 ? void 0 : array.getElements()).find(item => {
                return `'${this.moduleName.toKebabCase()}'` === item.getPropertyOrThrow('path').getInitializerIfKindOrThrow(typescript_1.SyntaxKind.StringLiteral).getText();
            });
            return !!foundItem;
        });
        // add route to new item
        array_driver_1.ArrayDriver.addArrayItem(sourceFile, `{ path: '${this.moduleName.toKebabCase()}/new', component: ${this.moduleName.toPascalCase()}DetailComponent, resolve: { data: ${this.moduleName.toPascalCase()}NewResolver }, data: { permission: '${this.boundedContextName.toCamelCase()}.${this.moduleName.toCamelCase()}.create' }},`, childrenRoutesArray, (item, array) => {
            const foundItem = (array === null || array === void 0 ? void 0 : array.getElements()).find(item => {
                return `'${this.moduleName.toKebabCase()}/new'` === item.getPropertyOrThrow('path').getInitializerIfKindOrThrow(typescript_1.SyntaxKind.StringLiteral).getText();
            });
            return !!foundItem;
        });
        // add route to edit item
        array_driver_1.ArrayDriver.addArrayItem(sourceFile, `{ path: '${this.moduleName.toKebabCase()}/edit/:id', component: ${this.moduleName.toPascalCase()}DetailComponent, resolve: { data: ${this.moduleName.toPascalCase()}EditResolver }, data: { permission: '${this.boundedContextName.toCamelCase()}.${this.moduleName.toCamelCase()}.get' }},`, childrenRoutesArray, (item, array) => {
            const foundItem = (array === null || array === void 0 ? void 0 : array.getElements()).find(item => {
                return `'${this.moduleName.toKebabCase()}/edit/:id'` === item.getPropertyOrThrow('path').getInitializerIfKindOrThrow(typescript_1.SyntaxKind.StringLiteral).getText();
            });
            return !!foundItem;
        });
        sourceFile === null || sourceFile === void 0 ? void 0 : sourceFile.saveSync();
    }
    registerFrontNavigation() {
        const sourceFile = this.project.addSourceFileAtPath(path.join(process.cwd(), this.srcDirectory, config_1.cliterConfig.adminContainer, 'admin.navigation.ts'));
        // import bounded context navigation
        import_driver_1.ImportDriver.createImportItems(sourceFile, `./apps/${this.boundedContextName.toKebabCase()}/${this.boundedContextName.toKebabCase()}.navigation`, [`${this.boundedContextName.toCamelCase()}Navigation`]);
        // add to adminNavigation navigation array the bounded context navigation
        array_driver_1.ArrayDriver.addArrayItem(sourceFile, `${this.boundedContextName.toCamelCase()}Navigation`, 'adminNavigation');
        sourceFile === null || sourceFile === void 0 ? void 0 : sourceFile.saveSync();
    }
    declareDashboardComponents() {
        const sourceFile = this.project.addSourceFileAtPath(path.join(process.cwd(), this.srcDirectory, config_1.cliterConfig.dashboardContainer, this.boundedContextName.toKebabCase(), `${this.boundedContextName.toKebabCase()}.module.ts`));
        const moduleDecoratorArguments = this.getModuleDecoratorArguments(sourceFile, `${this.boundedContextName.toPascalCase()}Module`, 'NgModule');
        // declarations
        const declarations = moduleDecoratorArguments.getProperty('declarations');
        const declarationsArray = declarations === null || declarations === void 0 ? void 0 : declarations.getInitializerIfKindOrThrow(typescript_1.SyntaxKind.ArrayLiteralExpression);
        // export list component
        import_driver_1.ImportDriver.createImportItems(sourceFile, `./${this.moduleName.toKebabCase()}/${this.moduleName.toKebabCase()}-list.component`, [`${this.moduleName.toPascalCase()}ListComponent`]);
        // export detail component
        import_driver_1.ImportDriver.createImportItems(sourceFile, `./${this.moduleName.toKebabCase()}/${this.moduleName.toKebabCase()}-detail.component`, [`${this.moduleName.toPascalCase()}DetailComponent`]);
        array_driver_1.ArrayDriver.addArrayItems(sourceFile, [
            `${this.moduleName.toPascalCase()}DetailComponent`,
            `${this.moduleName.toPascalCase()}ListComponent`,
        ], declarationsArray);
        sourceFile === null || sourceFile === void 0 ? void 0 : sourceFile.saveSync();
    }
    declareFrontBoundedContext(index = 5) {
        const sourceFile = this.project.addSourceFileAtPath(path.join(process.cwd(), this.srcDirectory, 'app', 'app.routing.ts'));
        const appRoutes = sourceFile.getVariableDeclarationOrThrow('appRoutes');
        const appRoutesArray = appRoutes.getInitializerIfKindOrThrow(typescript_1.SyntaxKind.ArrayLiteralExpression);
        const objectRoute = appRoutesArray.getElements()[index];
        const childrenRoutes = objectRoute.getPropertyOrThrow('children');
        const childrenRoutesArray = childrenRoutes === null || childrenRoutes === void 0 ? void 0 : childrenRoutes.getInitializerIfKindOrThrow(typescript_1.SyntaxKind.ArrayLiteralExpression);
        const childrenRoutesElements = childrenRoutesArray.getElements();
        // avoid duplicated declaration
        for (const element of childrenRoutesElements) {
            const pathProperty = element.getPropertyOrThrow('path');
            const pathString = pathProperty.getInitializerIfKindOrThrow(typescript_1.SyntaxKind.StringLiteral);
            if (pathString.getText() === `'${this.boundedContextName.toKebabCase()}'`)
                return;
        }
        // set routes
        childrenRoutesArray === null || childrenRoutesArray === void 0 ? void 0 : childrenRoutesArray.addElement(`{ path: '${this.boundedContextName.toKebabCase()}', loadChildren: () => import('app/modules/admin/apps/${this.boundedContextName.toKebabCase()}/${this.boundedContextName.toKebabCase()}.module').then(m => m.${this.boundedContextName.toPascalCase()}Module) },`, { useNewLines: true });
        sourceFile === null || sourceFile === void 0 ? void 0 : sourceFile.saveSync();
    }
    generateFrontNavigation() {
        const sourceFile = this.project.addSourceFileAtPath(path.join(process.cwd(), this.srcDirectory, config_1.cliterConfig.dashboardContainer, this.boundedContextName.toKebabCase(), `${this.boundedContextName.toKebabCase()}.navigation.ts`));
        const navigation = sourceFile.getVariableDeclarationOrThrow(this.boundedContextName.toCamelCase() + 'Navigation');
        const navigationObject = navigation.getInitializerIfKindOrThrow(typescript_1.SyntaxKind.ObjectLiteralExpression);
        const childrenProperty = navigationObject.getPropertyOrThrow('children');
        const childrenArrayNavigation = childrenProperty.getInitializerIfKindOrThrow(typescript_1.SyntaxKind.ArrayLiteralExpression);
        const navigationElements = childrenArrayNavigation.getElements();
        // avoid duplicated declaration
        for (const element of navigationElements) {
            const pathProperty = element.getPropertyOrThrow('id');
            const pathString = pathProperty.getInitializerIfKindOrThrow(typescript_1.SyntaxKind.StringLiteral);
            if (pathString.getText() === `'${this.moduleName.toCamelCase()}'`)
                return;
        }
        // set routes
        array_driver_1.ArrayDriver.addArrayItem(sourceFile, `{
    id   : '${this.moduleNames.toCamelCase()}',
    title: '${this.moduleName.toPascalCase()}',
    type : 'basic',
    icon : 'heroicons_outline:tag',
    link : '/${this.boundedContextName.toKebabCase()}/${this.moduleName.toKebabCase()}',
},`, childrenArrayNavigation, (item, array) => {
            const foundItem = (array === null || array === void 0 ? void 0 : array.getElements()).find(item => {
                return `'${this.moduleNames.toCamelCase()}'` === item.getPropertyOrThrow('id').getInitializerIfKindOrThrow(typescript_1.SyntaxKind.StringLiteral).getText();
            });
            return !!foundItem;
        });
        sourceFile === null || sourceFile === void 0 ? void 0 : sourceFile.saveSync();
    }
    generateDashboardTranslations(properties, langCode) {
        const translationObject = require(path.join(process.cwd(), this.srcDirectory, config_1.cliterConfig.dashboardTranslations, this.boundedContextName.toKebabCase(), langCode + '.json'));
        // get names to translate
        const names = properties.withoutTimestamps.filter(property => property.name !== 'id').map(property => property.name);
        // add module name/s to translate
        names.push(this.moduleName, this.moduleNames);
        for (const name of names) {
            // avoid overwriting existing properties
            if (translationObject[name.toPascalCase()] === undefined) {
                translationObject[name.toPascalCase()] = name.toPascalCase();
            }
        }
        // sort object by keys
        const newTranslationObject = object_tools_1.ObjectTools.sortByKeys(translationObject);
        fs.writeFileSync(path.join(process.cwd(), this.srcDirectory, config_1.cliterConfig.dashboardTranslations, this.boundedContextName.toKebabCase(), langCode + '.json'), JSON.stringify(newTranslationObject, null, 4));
    }
    generateDashboardNavigationTranslation(langCode) {
        const translationObject = require(path.join(process.cwd(), this.srcDirectory, config_1.cliterConfig.dashboardTranslations, 'navigation', langCode + '.json'));
        // avoid overwriting existing properties
        if (translationObject[this.moduleNames.toCamelCase()] === undefined) {
            translationObject[this.moduleNames.toCamelCase()] = this.moduleNames.toPascalCase();
        }
        // sort object by keys
        const newTranslationObject = object_tools_1.ObjectTools.sortByKeys(translationObject);
        fs.writeFileSync(path.join(process.cwd(), this.srcDirectory, config_1.cliterConfig.dashboardTranslations, 'navigation', langCode + '.json'), JSON.stringify(newTranslationObject, null, 4));
    }
    /****************************************************************
     * Add import and declare application items in bounded context
     * module.
     *
     * @return void
     ****************************************************************/
    declareApplicationItemsInModule() {
        // get decorator arguments
        const sourceFile = this.project.addSourceFileAtPath(path.join(process.cwd(), this.srcDirectory, this.apiDirectory, this.boundedContextName.toKebabCase(), `${this.boundedContextName.toKebabCase()}.module.ts`));
        const moduleDecoratorArguments = this.getModuleDecoratorArguments(sourceFile, `${this.boundedContextName.toPascalCase()}Module`, 'Module');
        // providers
        const providers = moduleDecoratorArguments.getProperty('providers');
        const providersArray = providers === null || providers === void 0 ? void 0 : providers.getInitializerIfKindOrThrow(typescript_1.SyntaxKind.ArrayLiteralExpression);
        // controllers
        const controllers = moduleDecoratorArguments.getProperty('controllers');
        const controllersArray = controllers === null || controllers === void 0 ? void 0 : controllers.getInitializerIfKindOrThrow(typescript_1.SyntaxKind.ArrayLiteralExpression);
        // register imports from bounded context from @app
        import_driver_1.ImportDriver.createImportItems(sourceFile, `../../${config_1.cliterConfig.appContainer}/${this.boundedContextName.toKebabCase()}`, [
            `${this.boundedContextName.toPascalCase()}Models`,
            `${this.boundedContextName.toPascalCase()}Handlers`,
            `${this.boundedContextName.toPascalCase()}Services`,
            `${this.boundedContextName.toPascalCase()}Repositories`,
            `${this.boundedContextName.toPascalCase()}Sagas`,
        ]);
        // register import for controllers and providers from @api
        import_driver_1.ImportDriver.createImportItems(sourceFile, `./${this.moduleName.toKebabCase()}`, [
            `${this.boundedContextName.toPascalCase()}${this.moduleName.toPascalCase()}Controllers`,
            `${this.boundedContextName.toPascalCase()}${this.moduleName.toPascalCase()}Resolvers`,
            `${this.boundedContextName.toPascalCase()}${this.moduleName.toPascalCase()}ApiHandlers`,
            `${this.boundedContextName.toPascalCase()}${this.moduleName.toPascalCase()}Services`,
        ]);
        // add model to ORM array argument
        const modelArrayArgument = this.getModelArrayArgument(moduleDecoratorArguments);
        array_driver_1.ArrayDriver.addArrayItem(sourceFile, `...${this.boundedContextName.toPascalCase()}Models`, modelArrayArgument);
        // add services to providers
        array_driver_1.ArrayDriver.addArrayItems(sourceFile, [
            // from @app
            `...${this.boundedContextName.toPascalCase()}Handlers`,
            `...${this.boundedContextName.toPascalCase()}Services`,
            `...${this.boundedContextName.toPascalCase()}Repositories`,
            `...${this.boundedContextName.toPascalCase()}Sagas`,
            // from @api
            `...${this.boundedContextName.toPascalCase()}${this.moduleName.toPascalCase()}Resolvers`,
            `...${this.boundedContextName.toPascalCase()}${this.moduleName.toPascalCase()}ApiHandlers`,
            `...${this.boundedContextName.toPascalCase()}${this.moduleName.toPascalCase()}Services`,
        ], providersArray);
        // add controller to controllers array
        array_driver_1.ArrayDriver.addArrayItem(sourceFile, `...${this.boundedContextName.toPascalCase()}${this.moduleName.toPascalCase()}Controllers`, controllersArray);
        sourceFile === null || sourceFile === void 0 ? void 0 : sourceFile.saveSync();
    }
    declareBoundedContextModuleInApplicationModule() {
        const sourceFile = this.project.addSourceFileAtPath(path.join(process.cwd(), this.srcDirectory, 'app.module.ts'));
        const moduleDecoratorArguments = this.getModuleDecoratorArguments(sourceFile, 'AppModule', 'Module');
        const modules = this.getImportedDeclarations(sourceFile);
        if (!modules.includes(`${this.boundedContextName.toPascalCase()}Module`)) {
            // import module
            import_driver_1.ImportDriver.createImportItems(sourceFile, `./${config_1.cliterConfig.apiContainer}/${this.boundedContextName.toKebabCase()}/${this.boundedContextName.toKebabCase()}.module`, [`${this.boundedContextName.toPascalCase()}Module`]);
            // register module
            const importsArgument = moduleDecoratorArguments.getProperty('imports');
            const importsArray = importsArgument === null || importsArgument === void 0 ? void 0 : importsArgument.getInitializerIfKindOrThrow(typescript_1.SyntaxKind.ArrayLiteralExpression);
            importsArray.addElement(`${this.boundedContextName.toPascalCase()}Module`, { useNewLines: true });
        }
        sourceFile === null || sourceFile === void 0 ? void 0 : sourceFile.saveSync();
    }
    /****************************************************************
     * Add exports of principal application elements to src/index.ts
     * this is to have access to all elements from index.ts
     *
     * @return void
     ****************************************************************/
    declareApplicationItemsExports() {
        const sourceFile = this.project.addSourceFileAtPath(path.join(process.cwd(), this.srcDirectory, 'index.ts'));
        // export module
        export_driver_1.ExportDriver.createExportItems(sourceFile, `./${config_1.cliterConfig.apiContainer}/${this.boundedContextName.toKebabCase()}/${this.boundedContextName.toKebabCase()}.module`, [`${this.boundedContextName.toPascalCase()}Module`]);
        // export DTO
        export_driver_1.ExportDriver.createExportItems(sourceFile, `./${config_1.cliterConfig.apiContainer}/${this.boundedContextName.toKebabCase()}/${this.moduleName.toKebabCase()}/dto/${this.boundedContextName.toKebabCase()}-${this.moduleName.toKebabCase()}.dto`, [`${this.boundedContextName.toPascalCase()}${this.moduleName.toPascalCase()}Dto`]);
        // export aggregate
        export_driver_1.ExportDriver.createExportItems(sourceFile, `./${config_1.cliterConfig.appContainer}/${this.boundedContextName.toKebabCase()}/${this.moduleName.toKebabCase()}/domain/${this.moduleName.toKebabCase()}.aggregate`, [`${this.aggregateName}`]);
        // export model
        export_driver_1.ExportDriver.createExportItems(sourceFile, `./${config_1.cliterConfig.appContainer}/${this.boundedContextName.toKebabCase()}/${this.moduleName.toKebabCase()}`, [`${this.boundedContextName.toPascalCase()}${this.moduleName.toPascalCase()}Model`]);
        // export response
        export_driver_1.ExportDriver.createExportItems(sourceFile, `./${config_1.cliterConfig.appContainer}/${this.boundedContextName.toKebabCase()}/${this.moduleName.toKebabCase()}/domain/${this.moduleName.toKebabCase()}.response`, [`${this.moduleName.toPascalCase()}Response`]);
        // export mapper
        export_driver_1.ExportDriver.createExportItems(sourceFile, `./${config_1.cliterConfig.appContainer}/${this.boundedContextName.toKebabCase()}/${this.moduleName.toKebabCase()}/domain/${this.moduleName.toKebabCase()}.mapper`, [`${this.moduleName.toPascalCase()}Mapper`]);
        // export seed
        export_driver_1.ExportDriver.createExportItems(sourceFile, `./${config_1.cliterConfig.appContainer}/${this.boundedContextName.toKebabCase()}/${this.moduleName.toKebabCase()}/infrastructure/mock/mock-${this.moduleName.toKebabCase()}.data`, [`${this.moduleNames.toCamelCase()}`]);
        sourceFile === null || sourceFile === void 0 ? void 0 : sourceFile.saveSync();
    }
    getModelArrayArgument(moduleDecoratorArguments) {
        const importsArgument = moduleDecoratorArguments.getProperty('imports');
        const importsArray = importsArgument.getInitializerIfKindOrThrow(typescript_1.SyntaxKind.ArrayLiteralExpression);
        const importsElements = importsArray.getElements();
        const SequelizeModuleElement = importsElements.find(el => el.getText().indexOf('SequelizeModule.forFeature') === 0);
        return SequelizeModuleElement.getArguments()[0];
    }
    getModuleDecoratorArguments(sourceFile, className, decorator) {
        const moduleClass = sourceFile.getClass(className);
        const moduleDecorator = moduleClass === null || moduleClass === void 0 ? void 0 : moduleClass.getDecorator(decorator);
        return moduleDecorator.getArguments()[0];
    }
    getImportedDeclarations(sourceFile) {
        const imports = sourceFile.getImportDeclarations();
        let modules = [];
        for (const importObj of imports) {
            modules = [...modules, ...importObj.getNamedImports().map(i => i.getName())];
        }
        return modules;
    }
}
exports.CodeWriter = CodeWriter;
