UNPKG

@mbc-cqrs-serverless/cli

Version:

a CLI to get started with MBC CQRS serverless framework

205 lines (202 loc) 9.32 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.main = main; const core_1 = require("@angular-devkit/core"); const schematics_1 = require("@angular-devkit/schematics"); const ts = __importStar(require("typescript")); const yaml_1 = require("yaml"); function main(options) { return (tree, _context) => { const filePath = (0, core_1.normalize)(`/src/${core_1.strings.dasherize(options.name)}/${core_1.strings.dasherize(options.name)}.module.ts`); const isFileExists = tree.exists(filePath); if (isFileExists) { _context.logger.info(`Module file already exists at: ${filePath}`); return; } updateMainModule(tree, options); updateCdkInfraStack(tree, options); updateCqrsTable(tree, options); updateServerlessYaml(tree, options); if (options.schema) { updatePrismaSchema(tree, options); } return (0, schematics_1.chain)([createModule(options), createUnitTest(options)]); }; } // create rule function createModule(options) { return (0, schematics_1.mergeWith)((0, schematics_1.apply)((0, schematics_1.url)(`./files/${options.mode}`), [ options.schema ? (0, schematics_1.noop)() : (0, schematics_1.filter)((path) => !path.endsWith('.handler.ts')), (0, schematics_1.template)({ ...core_1.strings, ...options, }), (0, schematics_1.move)((0, core_1.normalize)(`/src/${core_1.strings.dasherize(options.name)}`)), ])); } function createUnitTest(options) { return (0, schematics_1.mergeWith)((0, schematics_1.apply)((0, schematics_1.url)('./units'), [ (0, schematics_1.template)({ ...core_1.strings, ...options, specFileSuffix: 'spec', }), (0, schematics_1.move)((0, core_1.normalize)(`/test/unit/${core_1.strings.dasherize(options.name)}`)), ])); } // modify main.module.ts function updateMainModule(tree, options) { const mainModulePath = 'src/main.module.ts'; const isMainModulePathExists = tree.exists(mainModulePath); if (isMainModulePathExists) { const fileBuffer = tree.read(mainModulePath); const content = fileBuffer.toString('utf-8'); const lines = content.split('\n'); lines.splice(5, 0, `import { ${core_1.strings.classify(options.name)}Module } from './${core_1.strings.dasherize(options.name)}/${core_1.strings.dasherize(options.name)}.module'`); lines.splice(23, 0, ` ${core_1.strings.classify(options.name)}Module,`); const newContent = lines.join('\n'); tree.overwrite(mainModulePath, newContent); return tree; } } // modify infra cdk function updateCdkInfraStack(tree, options) { const infraStackPath = 'infra/libs/infra-stack.ts'; const isInfraStackExists = tree.exists(infraStackPath); if (isInfraStackExists) { const fileBuffer = tree.read(infraStackPath); const content = fileBuffer.toString('utf-8'); const sourceFile = ts.createSourceFile(infraStackPath, content, ts.ScriptTarget.Latest, true); const updatedContent = updateTableNamesArray(sourceFile, [`${core_1.strings.dasherize(options.name)}-command`], content); tree.overwrite(infraStackPath, updatedContent); return tree; } } function updateTableNamesArray(sourceFile, newTableNames, content) { let updatedContent = content; const visit = (node) => { if (ts.isVariableDeclaration(node) && node.name.getText() === 'tableNames' && ts.isArrayLiteralExpression(node.initializer)) { // Extract existing table names const existingElements = node.initializer.elements.map((element) => element.getText().replace(/['"]/g, '')); // Append new table names, ensuring no duplicates const updatedTableNames = Array.from(new Set([...existingElements, ...newTableNames])); // Generate the updated array string const newArray = `[${updatedTableNames.map((name) => `'${name}'`).join(', ')}]`; // Replace the existing array with the new array updatedContent = updatedContent.slice(0, node.initializer.getStart()) + newArray + updatedContent.slice(node.initializer.getEnd()); } ts.forEachChild(node, visit); }; visit(sourceFile); return updatedContent; } // modify cqrs.json function updateCqrsTable(tree, options) { const cqrsTablePath = 'prisma/dynamodbs/cqrs.json'; const isCqrsTableExists = tree.exists(cqrsTablePath); if (isCqrsTableExists) { const fileContent = tree.read(cqrsTablePath)?.toString(); const jsonContent = JSON.parse(fileContent.toString()); jsonContent.push(core_1.strings.dasherize(options.name)); tree.overwrite(cqrsTablePath, JSON.stringify(jsonContent, null, 2)); return tree; } } // modify prisma.schema function updatePrismaSchema(tree, options) { const schemaPath = 'prisma/schema.prisma'; const isSchemaExists = tree.exists(schemaPath); if (isSchemaExists) { const fileContent = tree.read(schemaPath)?.toString('utf-8'); const stringToAppend = generateModelTemplate(options.name); const updatedContent = fileContent + stringToAppend; tree.overwrite(schemaPath, updatedContent); return tree; } } // modify serverless.yaml function updateServerlessYaml(tree, options) { const serverlessPath = 'infra-local/serverless.yml'; const isServerlessExists = tree.exists(serverlessPath); if (isServerlessExists) { const fileContent = tree.read(serverlessPath)?.toString('utf-8'); const newStreamEvent = { type: 'dynamodb', maximumRetryAttempts: 10, arn: '${env:LOCAL_DDB_%%TABLE_NAME%%_STREAM}'.replace('%%TABLE_NAME%%', options.name.toUpperCase()), filterPatterns: [{ eventName: ['INSERT'] }], }; const doc = (0, yaml_1.parseDocument)(fileContent); const mainFunction = doc.getIn(['functions', 'main']); const events = mainFunction.get('events'); events.items.push({ stream: newStreamEvent }); const updatedYamlContent = (0, yaml_1.stringify)(doc); tree.overwrite(serverlessPath, updatedYamlContent); return tree; } } const generateModelTemplate = (name) => ` model ${core_1.strings.classify(name)} { id String @id cpk String // コマンド用PK csk String // コマンド用SK pk String // データ用PK, ${name.toUpperCase()}#tenantCode (テナントコード) sk String // データ用SK, マスタ種別コード#マスタコード tenantCode String @map("tenant_code") // テナントコード, 【テナントコードマスタ】 seq Int @default(0) // 並び順, 採番機能を使用する code String // レコードのコード, マスタ種別コード#マスタコード name String // レコード名, 名前 version Int // バージョン isDeleted Boolean @default(false) @map("is_deleted") // 削除フラグ createdBy String @default("") @map("created_by") // 作成者 createdIp String @default("") @map("created_ip") // 作成IP, IPv6も考慮する createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(0) // 作成日時 updatedBy String @default("") @map("updated_by") // 更新者 updatedIp String @default("") @map("updated_ip") // 更新IP, IPv6も考慮する updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamp(0) // 更新日時 attributes Json? @map("attributes") @@unique([cpk, csk]) @@unique([pk, sk]) @@unique([tenantCode, code]) @@index([tenantCode, name]) @@map("${core_1.strings.underscore(name)}s") } `;