@mbc-cqrs-serverless/cli 0.1.49-beta.0 → 0.1.51-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/README.md +94 -63
  2. package/dist/actions/generate.action.js +44 -0
  3. package/dist/actions/new.action.get-package-version.spec.js +29 -0
  4. package/dist/actions/new.action.is-latest-version.spec.js +36 -0
  5. package/dist/actions/new.action.js +12 -6
  6. package/dist/actions/new.action.spec.js +84 -0
  7. package/dist/actions/new.action.update-env-local.spec.js +35 -0
  8. package/dist/actions/new.action.use-package-version.spec.js +46 -0
  9. package/dist/actions/ui.action.js +7 -5
  10. package/dist/commands/command.input.js +2 -0
  11. package/dist/commands/generate.command.js +24 -0
  12. package/dist/commands/index.js +2 -0
  13. package/dist/index.js +13 -2
  14. package/dist/runners/abstract.runner.js +44 -0
  15. package/dist/runners/schematic.runner.js +21 -0
  16. package/dist/schematics/collection.json +34 -0
  17. package/dist/schematics/index.js +17 -0
  18. package/dist/schematics/lib/controller/controller.factory.js +40 -0
  19. package/dist/schematics/lib/controller/controller.factory.spec.js +79 -0
  20. package/dist/schematics/lib/controller/files/__name@dasherize__.controller.ts +11 -0
  21. package/dist/schematics/lib/controller/schema.json +18 -0
  22. package/dist/schematics/lib/controller/units/__name@dasherize__.controller.__specFileSuffix__.ts +19 -0
  23. package/dist/schematics/lib/dto/dto.factory.js +32 -0
  24. package/dist/schematics/lib/dto/dto.factory.spec.js +128 -0
  25. package/dist/schematics/lib/dto/files/dto/__name@dasherize__-attributes.dto.ts +6 -0
  26. package/dist/schematics/lib/dto/files/dto/__name@dasherize__-command.dto.ts +16 -0
  27. package/dist/schematics/lib/dto/files/dto/__name@dasherize__-create.dto.ts +18 -0
  28. package/dist/schematics/lib/dto/files/dto/__name@dasherize__-search.dto.ts +2 -0
  29. package/dist/schematics/lib/dto/files/dto/__name@dasherize__-update.dto.ts +34 -0
  30. package/dist/schematics/lib/dto/schema.json +18 -0
  31. package/dist/schematics/lib/entity/entity.factory.js +30 -0
  32. package/dist/schematics/lib/entity/entity.factory.spec.js +86 -0
  33. package/dist/schematics/lib/entity/files/entity/__name@dasherize__-command.entity.ts +12 -0
  34. package/dist/schematics/lib/entity/files/entity/__name@dasherize__-data-list.entity.ts +12 -0
  35. package/dist/schematics/lib/entity/files/entity/__name@dasherize__-data.entity.ts +12 -0
  36. package/dist/schematics/lib/entity/schema.json +18 -0
  37. package/dist/schematics/lib/module/files/async/__name@dasherize__.controller.ts +74 -0
  38. package/dist/schematics/lib/module/files/async/__name@dasherize__.module.ts +19 -0
  39. package/dist/schematics/lib/module/files/async/__name@dasherize__.service.ts +164 -0
  40. package/dist/schematics/lib/module/files/async/dto/__name@dasherize__-attributes.dto.ts +6 -0
  41. package/dist/schematics/lib/module/files/async/dto/__name@dasherize__-command.dto.ts +16 -0
  42. package/dist/schematics/lib/module/files/async/dto/__name@dasherize__-create.dto.ts +18 -0
  43. package/dist/schematics/lib/module/files/async/dto/__name@dasherize__-search.dto.ts +2 -0
  44. package/dist/schematics/lib/module/files/async/dto/__name@dasherize__-update.dto.ts +34 -0
  45. package/dist/schematics/lib/module/files/async/entity/__name@dasherize__-command.entity.ts +12 -0
  46. package/dist/schematics/lib/module/files/async/entity/__name@dasherize__-data-list.entity.ts +12 -0
  47. package/dist/schematics/lib/module/files/async/entity/__name@dasherize__-data.entity.ts +12 -0
  48. package/dist/schematics/lib/module/files/async/handler/__name@dasherize__-rds.handler.ts +62 -0
  49. package/dist/schematics/lib/module/files/sync/__name@dasherize__.controller.ts +74 -0
  50. package/dist/schematics/lib/module/files/sync/__name@dasherize__.module.ts +19 -0
  51. package/dist/schematics/lib/module/files/sync/__name@dasherize__.service.ts +164 -0
  52. package/dist/schematics/lib/module/files/sync/dto/__name@dasherize__-attributes.dto.ts +6 -0
  53. package/dist/schematics/lib/module/files/sync/dto/__name@dasherize__-command.dto.ts +16 -0
  54. package/dist/schematics/lib/module/files/sync/dto/__name@dasherize__-create.dto.ts +18 -0
  55. package/dist/schematics/lib/module/files/sync/dto/__name@dasherize__-search.dto.ts +2 -0
  56. package/dist/schematics/lib/module/files/sync/dto/__name@dasherize__-update.dto.ts +34 -0
  57. package/dist/schematics/lib/module/files/sync/entity/__name@dasherize__-command.entity.ts +12 -0
  58. package/dist/schematics/lib/module/files/sync/entity/__name@dasherize__-data-list.entity.ts +12 -0
  59. package/dist/schematics/lib/module/files/sync/entity/__name@dasherize__-data.entity.ts +12 -0
  60. package/dist/schematics/lib/module/files/sync/handler/__name@dasherize__-rds.handler.ts +62 -0
  61. package/dist/schematics/lib/module/module.factory.js +204 -0
  62. package/dist/schematics/lib/module/module.factory.spec.js +188 -0
  63. package/dist/schematics/lib/module/schema.json +28 -0
  64. package/dist/schematics/lib/module/units/__name@dasherize__.controller.__specFileSuffix__.ts +19 -0
  65. package/dist/schematics/lib/module/units/__name@dasherize__.service.__specFileSuffix__.ts +19 -0
  66. package/dist/schematics/lib/service/files/__name@dasherize__.service.ts +12 -0
  67. package/dist/schematics/lib/service/schema.json +18 -0
  68. package/dist/schematics/lib/service/service.factory.js +40 -0
  69. package/dist/schematics/lib/service/service.factory.spec.js +81 -0
  70. package/dist/schematics/lib/service/units/__name@dasherize__.service.__specFileSuffix__.ts +19 -0
  71. package/dist/schematics/schematic.colection.js +60 -0
  72. package/dist/schematics/schematic.option.js +44 -0
  73. package/dist/schematics/utils/check-files-exist.js +13 -0
  74. package/dist/schematics/utils/index.js +17 -0
  75. package/dist/ui/index.js +18 -0
  76. package/dist/ui/logger.js +54 -0
  77. package/dist/ui/message.js +6 -0
  78. package/dist/utils/formatting.js +18 -0
  79. package/dist/utils/index.js +18 -0
  80. package/dist/utils/local-binaries.js +20 -0
  81. package/package.json +14 -5
  82. package/templates/.env.local +1 -1
  83. package/templates/README.md +1 -1
  84. package/templates/infra/README.md +6 -1
  85. package/templates/infra/libs/infra-stack.ts +1 -1
  86. package/templates/infra-local/docker-compose.yml +1 -1
  87. package/templates/infra-local/serverless.yml +19 -21
  88. package/templates/infra-local/swagger.json +396 -0
  89. package/templates/package.json +1 -0
  90. package/templates/prisma/dynamodbs/cqrs.json +1 -1
  91. package/templates/prisma/schema.prisma +4 -7
  92. package/templates/src/helpers/id.ts +12 -0
  93. package/templates/src/helpers/index.ts +1 -0
  94. package/templates/src/main.module.ts +2 -2
  95. package/templates/src/{master/dto/master-attributes.dto.ts → sample/dto/sample-attributes.dto.ts} +2 -2
  96. package/templates/src/{master/dto/master-command.dto.ts → sample/dto/sample-command.dto.ts} +4 -4
  97. package/templates/src/sample/entity/sample-command.entity.ts +13 -0
  98. package/templates/src/sample/entity/sample-data-list.entity.ts +13 -0
  99. package/templates/src/sample/entity/sample-data.entity.ts +13 -0
  100. package/templates/src/{master/handler/master-rds.handler.ts → sample/handler/sample-rds.handler.ts} +5 -7
  101. package/templates/src/{master/master.controller.ts → sample/sample.controller.ts} +22 -22
  102. package/templates/src/sample/sample.module.ts +19 -0
  103. package/templates/src/{master/master.service.ts → sample/sample.service.ts} +12 -12
  104. package/templates/test/api.http +25 -0
  105. package/templates/tsconfig.json +1 -1
  106. package/templates/src/master/entity/master-command.entity.ts +0 -13
  107. package/templates/src/master/entity/master-data-list.entity.ts +0 -13
  108. package/templates/src/master/entity/master-data.entity.ts +0 -13
  109. package/templates/src/master/master.module.ts +0 -19
package/README.md CHANGED
@@ -4,11 +4,11 @@
4
4
 
5
5
  ## Description
6
6
 
7
- The MBC CLI is a command-line interface tool that helps you to initialize your mbc-cqrs-serverless applications.
7
+ The MBC CLI is a command-line interface tool that helps you initialize and manage MBC CQRS Serverless applications. It provides commands for project creation, version management, and development workflow automation.
8
8
 
9
9
  ## Installation
10
10
 
11
- To install `mbc` command, run:
11
+ To install the `mbc` command globally, run:
12
12
 
13
13
  ```bash
14
14
  npm install -g @mbc-cqrs-serverless/cli
@@ -16,86 +16,117 @@ npm install -g @mbc-cqrs-serverless/cli
16
16
 
17
17
  ## Usage
18
18
 
19
- ### `mbc new|n [projectName@version]`
19
+ ### Project Creation
20
20
 
21
- There are 3 usages for the new command:
21
+ The CLI provides flexible options for creating new projects:
22
22
 
23
- - `mbc new`
24
- - Creates a new project in the current folder using a default name with the latest framework version.
25
- - `mbc new [projectName]`
26
- - Creates a new project in the `projectName` folder using the latest framework version.
27
- - `mbc new [projectName@version]`
28
- - If the specified version exists, the CLI uses that exact version.
29
- - If the provided version is a prefix, the CLI uses the latest version matching that prefix.
30
- - If no matching version is found, the CLI logs an error and provides a list of available versions for the user.
23
+ ```bash
24
+ mbc new [projectName[@version]]
25
+ ```
31
26
 
32
- To change current directory
27
+ #### Basic Usage Examples
28
+
29
+ 1. Create a new project in the current directory:
30
+ ```bash
31
+ mbc new
32
+ ```
33
+
34
+ 2. Create a project with a specific name:
35
+ ```bash
36
+ mbc new my-cqrs-app
37
+ ```
33
38
 
39
+ 3. Create a project with a specific version:
34
40
  ```bash
35
- cd [projectName]
41
+ mbc new my-cqrs-app@0.1.45
36
42
  ```
37
43
 
38
- ## Run the Development Server
39
- 1. Run npm run build to the build project using development mode.
40
- 2. Open in other terminal session and run npm run offline:docker
41
- 3. Open in other terminal session and run npm run migrate to migrate RDS and dynamoDB table
42
- 4. Finally, run npm run offline:sls to start serverless offline mode.
44
+ ### Project Structure
45
+
46
+ The CLI creates a standardized project structure:
43
47
 
44
- After the server runs successfully, you can see:
48
+ ```
49
+ my-cqrs-app/
50
+ ├── src/
51
+ │ ├── commands/ # Command handlers
52
+ │ ├── events/ # Event handlers
53
+ │ ├── interfaces/ # TypeScript interfaces
54
+ │ └── services/ # Business logic services
55
+ ├── test/
56
+ │ ├── e2e/ # End-to-end tests
57
+ │ └── unit/ # Unit tests
58
+ ├── package.json
59
+ └── serverless.yml # Serverless Framework configuration
60
+ ```
45
61
 
62
+ ### Development Workflow
63
+
64
+ 1. After creating a project, install dependencies:
46
65
  ```bash
47
- DEBUG[serverless-offline-sns][adapter]: successfully subscribed queue "http://localhost:9324/101010101010/notification-queue" to topic: "arn:aws:sns:ap-northeast-1:101010101010:MySnsTopic"
48
- Offline Lambda Server listening on http://localhost:4000
49
- serverless-offline-aws-eventbridge :: Plugin ready
50
- serverless-offline-aws-eventbridge :: Mock server running at port: 4010
51
- Starting Offline SQS at stage dev (ap-northeast-1)
52
- Starting Offline Dynamodb Streams at stage dev (ap-northeast-1)
53
-
54
- Starting Offline at stage dev (ap-northeast-1)
55
-
56
- Offline [http for lambda] listening on http://localhost:3002
57
- Function names exposed for local invocation by aws-sdk:
58
- * main: serverless-example-dev-main
59
- Configuring JWT Authorization: ANY /{proxy+}
60
-
61
- ┌────────────────────────────────────────────────────────────────────────┐
62
- │ │
63
- │ ANY | http://localhost:3000/api/public │
64
- │ POST | http://localhost:3000/2015-03-31/functions/main/invocations │
65
- │ ANY | http://localhost:3000/swagger-ui/{proxy*} │
66
- │ POST | http://localhost:3000/2015-03-31/functions/main/invocations │
67
- │ ANY | http://localhost:3000/{proxy*} │
68
- │ POST | http://localhost:3000/2015-03-31/functions/main/invocations │
69
- │ │
70
- └────────────────────────────────────────────────────────────────────────┘
71
-
72
- Server ready: http://localhost:3000 🚀
66
+ cd my-cqrs-app
67
+ npm install
73
68
  ```
74
69
 
75
- You can also use several endpoints:
70
+ 2. Build the project:
71
+ ```bash
72
+ npm run build
73
+ ```
76
74
 
77
- - API gateway: http://localhost:3000
78
- - Offline Lambda Server: http://localhost:4000
79
- - HTTP for lambda: http://localhost:3002
80
- - Step functions: http://localhost:8083
81
- - DynamoDB: http://localhost:8000
82
- - DynamoDB admin: http://localhost:8001
83
- - SNS: http://localhost:4002
84
- - SQS: http://localhost:9324
85
- - SQS admin: http://localhost:9325
86
- - Localstack: http://localhost:4566
87
- - AppSync: http://localhost:4001
88
- - Cognito: http://localhost:9229
89
- - EventBridge: http://localhost:4010
90
- - Simple Email Service: http://localhost:8005
91
- - Run `npx prisma studio` to open studio web: http://localhost:5000
75
+ 3. Start local development environment:
76
+ ```bash
77
+ npm run offline:docker # Start local infrastructure
78
+ npm run migrate # Run database migrations
79
+ npm run offline:sls # Start serverless offline
80
+ ```
92
81
 
82
+ ### Available Commands
93
83
 
84
+ - `mbc new`: Create a new project
85
+ - `mbc version`: Display CLI version
86
+ - `mbc help`: Show command help
87
+ - `mbc list`: List available project templates
94
88
 
89
+ ### Configuration
90
+
91
+ The CLI supports configuration through:
92
+ - Command line arguments
93
+ - Environment variables
94
+ - Configuration files
95
+
96
+ Example configuration file (`.mbcrc.json`):
97
+ ```json
98
+ {
99
+ "defaultTemplate": "basic",
100
+ "region": "ap-northeast-1",
101
+ "stage": "dev"
102
+ }
103
+ ```
95
104
 
96
105
  ## Documentation
97
106
 
98
- Visit https://mbc-cqrs-serverless.mbc-net.com/ to view the full documentation.
107
+ Visit https://mbc-cqrs-serverless.mbc-net.com/ to view the full documentation, including:
108
+ - Detailed CLI commands and options
109
+ - Project setup and configuration
110
+ - Development server setup
111
+ - Available endpoints and services
112
+
113
+ ## Troubleshooting
114
+
115
+ Common issues and solutions:
116
+
117
+ 1. Version not found:
118
+ ```bash
119
+ mbc new myapp@999.999.999
120
+ # Error: Version not found. Available versions: [0.1.45, 0.1.44, ...]
121
+ ```
122
+ Solution: Use `mbc list versions` to see available versions.
123
+
124
+ 2. Project creation fails:
125
+ ```bash
126
+ mbc new my-project
127
+ # Error: Directory not empty
128
+ ```
129
+ Solution: Use a new directory or remove existing files.
99
130
 
100
131
  ## License
101
132
 
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = generateAction;
4
+ const schematic_runner_1 = require("../runners/schematic.runner");
5
+ const schematics_1 = require("../schematics");
6
+ const ui_1 = require("../ui");
7
+ /* eslint-disable no-console */
8
+ async function generateAction(schematic, name, options, command) {
9
+ ui_1.logger.info(`Executing command '${command.name()}' for application with options '${JSON.stringify(options)}'`);
10
+ const commandOptions = command.opts();
11
+ const formatOptions = [];
12
+ formatOptions.push({ name: 'dry-run', value: !!commandOptions.dryRun });
13
+ formatOptions.push({ name: 'mode', value: commandOptions.mode });
14
+ formatOptions.push({
15
+ name: 'schema',
16
+ value: !!commandOptions.schema || !!commandOptions.noSchema, // noSchema > schema
17
+ });
18
+ const inputs = [];
19
+ inputs.push({ name: 'schematic', value: schematic });
20
+ inputs.push({ name: 'name', value: name });
21
+ const fullInputs = formatOptions.concat(inputs);
22
+ const schematicOptions = mapSchematicOptions(fullInputs);
23
+ const runner = new schematic_runner_1.SchematicRunner();
24
+ const fullCommand = buildCommandLine(schematic, schematicOptions);
25
+ runner.run(fullCommand);
26
+ }
27
+ function buildCommandLine(name, options) {
28
+ return `@mbc-cqrs-serverless/cli:${name}${buildOptions(options)}`;
29
+ }
30
+ function buildOptions(options) {
31
+ return options.reduce((line, option) => {
32
+ return line.concat(` ${option.toCommandString()}`);
33
+ }, '');
34
+ }
35
+ const mapSchematicOptions = (inputs) => {
36
+ const excludedInputNames = ['schematic', 'spec', 'flat', 'specFileSuffix'];
37
+ const options = [];
38
+ inputs.forEach((input) => {
39
+ if (!excludedInputNames.includes(input.name) && input.value !== undefined) {
40
+ options.push(new schematics_1.SchematicOption(input.name, input.value));
41
+ }
42
+ });
43
+ return options;
44
+ };
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const child_process_1 = require("child_process");
4
+ const new_action_1 = require("./new.action");
5
+ const { getPackageVersion } = new_action_1.exportsForTesting;
6
+ jest.mock('child_process', () => ({
7
+ execSync: jest.fn(),
8
+ }));
9
+ describe('getPackageVersion', () => {
10
+ const mockExecSync = child_process_1.execSync;
11
+ const packageName = '@mbc-cqrs-serverless/core';
12
+ afterEach(() => {
13
+ jest.clearAllMocks();
14
+ });
15
+ it('should return the latest version when isLatest is true', () => {
16
+ const mockLatestVersion = '1.2.3';
17
+ mockExecSync.mockReturnValue(Buffer.from(`${mockLatestVersion}\n`));
18
+ const result = getPackageVersion(packageName, true);
19
+ expect(mockExecSync).toHaveBeenCalledWith(`npm view ${packageName} dist-tags.latest`);
20
+ expect(result).toEqual([mockLatestVersion]);
21
+ });
22
+ it('should return all versions when isLatest is false', () => {
23
+ const mockVersions = ['1.0.0', '1.1.0', '1.2.0'];
24
+ mockExecSync.mockReturnValue(Buffer.from(JSON.stringify(mockVersions)));
25
+ const result = getPackageVersion(packageName, false);
26
+ expect(mockExecSync).toHaveBeenCalledWith(`npm view ${packageName} versions --json`);
27
+ expect(result).toEqual(mockVersions);
28
+ });
29
+ });
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const child_process_1 = require("child_process");
4
+ const new_action_1 = require("./new.action");
5
+ const { isLatestCli } = new_action_1.exportsForTesting;
6
+ jest.mock('child_process', () => ({
7
+ execSync: jest.fn(),
8
+ }));
9
+ jest.mock('fs', () => ({
10
+ readFileSync: jest.fn(() => JSON.stringify({ version: '1.0.0' })),
11
+ }));
12
+ jest.mock('path', () => ({
13
+ join: jest.fn(() => '/mocked/path/to/package.json'),
14
+ }));
15
+ describe('isLatestCli', () => {
16
+ const mockExecSync = child_process_1.execSync;
17
+ afterEach(() => {
18
+ jest.clearAllMocks();
19
+ });
20
+ it('should return true if the current version matches the latest version', () => {
21
+ const mockLatestVersion = ['1.0.0'];
22
+ mockExecSync.mockReturnValue(Buffer.from(`${mockLatestVersion}\n`));
23
+ // Run the function
24
+ const result = isLatestCli();
25
+ // Assert that the result is true
26
+ expect(result).toBe(true);
27
+ });
28
+ it('should return false if the current version does not match the latest version', () => {
29
+ const mockLatestVersion = ['1.2.3'];
30
+ mockExecSync.mockReturnValue(Buffer.from(`${mockLatestVersion}\n`));
31
+ // Run the function
32
+ const result = isLatestCli();
33
+ // Assert that the result is true
34
+ expect(result).toBe(false);
35
+ });
36
+ });
@@ -5,13 +5,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.exportsForTesting = void 0;
7
7
  exports.default = newAction;
8
+ const chalk_1 = __importDefault(require("chalk"));
8
9
  const child_process_1 = require("child_process");
9
10
  const fs_1 = require("fs");
10
11
  const path_1 = __importDefault(require("path"));
12
+ const ui_1 = require("../ui");
11
13
  /* eslint-disable no-console */
12
14
  async function newAction(name = '', options, command) {
13
15
  const [projectName, version = 'latest'] = name.split('@');
14
- console.log(`Executing command '${command.name()}' for application '${projectName}' with options '${JSON.stringify(options)}'`);
16
+ ui_1.logger.info(`Executing command '${command.name()}' for application '${projectName}' with options '${JSON.stringify(options)}'`);
15
17
  let packageVersion;
16
18
  if (version === 'latest') {
17
19
  packageVersion = `^${getPackageVersion('@mbc-cqrs-serverless/core', true)[0]}`; // use the latest patch and minor versions
@@ -27,12 +29,12 @@ async function newAction(name = '', options, command) {
27
29
  packageVersion = `^${matchVersions.at(-1)}`; // use the patch and minor versions
28
30
  }
29
31
  else {
30
- console.log('The specified package version does not exist. Please chose a valid version!\n', versions);
32
+ ui_1.logger.error(`The specified package version does not exist. Please chose a valid version! ${versions}`);
31
33
  return;
32
34
  }
33
35
  }
34
36
  const destDir = path_1.default.join(process.cwd(), projectName);
35
- console.log('Generating MBC cqrs serverless application in', destDir);
37
+ ui_1.logger.title('MBC', `Generating MBC cqrs serverless application in ${chalk_1.default.green(destDir)}`);
36
38
  (0, fs_1.mkdirSync)(destDir, { recursive: true });
37
39
  useTemplate(destDir);
38
40
  usePackageVersion(destDir, packageVersion, projectName);
@@ -49,12 +51,16 @@ async function newAction(name = '', options, command) {
49
51
  // cp .env.local .env
50
52
  (0, fs_1.copyFileSync)(path_1.default.join(destDir, '.env.local'), path_1.default.join(destDir, '.env'));
51
53
  // git init
54
+ ui_1.logger.title('git', 'Initializing git repository.');
52
55
  let logs = (0, child_process_1.execSync)('git init', { cwd: destDir });
53
- console.log(logs.toString());
56
+ ui_1.logger.success('Initialized a git repository.');
54
57
  // npm install
55
- console.log('Installing packages in', destDir);
56
- logs = (0, child_process_1.execSync)('npm i', { cwd: destDir });
58
+ ui_1.logger.title('deps', `Installing dependencies`);
59
+ logs = (0, child_process_1.execSync)('npm i --ignore-scripts', { cwd: destDir });
60
+ (0, child_process_1.execSync)('npx prisma generate', { cwd: destDir });
57
61
  console.log(logs.toString());
62
+ ui_1.logger.success(`Dependencies installed`);
63
+ ui_1.logger.title('MBC', `Your application was created!`);
58
64
  }
59
65
  function useTemplate(destDir) {
60
66
  if (isLatestCli()) {
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const child_process_1 = require("child_process");
7
+ const commander_1 = require("commander");
8
+ const fs_1 = require("fs");
9
+ const path_1 = __importDefault(require("path"));
10
+ const new_action_1 = __importDefault(require("./new.action"));
11
+ jest.mock('child_process', () => ({
12
+ execSync: jest.fn(),
13
+ }));
14
+ jest.mock('fs', () => ({
15
+ copyFileSync: jest.fn(),
16
+ cpSync: jest.fn(),
17
+ mkdirSync: jest.fn(),
18
+ unlinkSync: jest.fn(),
19
+ writeFileSync: jest.fn(),
20
+ readFileSync: jest.fn(() => JSON.stringify({ version: '1.2.3', dependencies: {}, devDependencies: {} })),
21
+ }));
22
+ describe('newAction', () => {
23
+ const mockExecSync = child_process_1.execSync;
24
+ const mockCommand = new commander_1.Command().name('new'); // Mock command with name 'new'
25
+ beforeEach(() => {
26
+ jest.clearAllMocks();
27
+ });
28
+ it('should generate a project with the latest version when version is not specified', async () => {
29
+ const projectName = 'test-project';
30
+ const latestVersion = '1.2.3';
31
+ mockExecSync
32
+ .mockReturnValueOnce(Buffer.from(latestVersion)) // latest core
33
+ .mockReturnValueOnce(Buffer.from(latestVersion)) // latest cli
34
+ .mockReturnValue(Buffer.from(''));
35
+ await (0, new_action_1.default)(`${projectName}`, {}, mockCommand);
36
+ expect(child_process_1.execSync).toHaveBeenCalledWith('npm view @mbc-cqrs-serverless/core dist-tags.latest');
37
+ expect(fs_1.mkdirSync).toHaveBeenCalledWith(path_1.default.join(process.cwd(), projectName), { recursive: true });
38
+ expect(fs_1.cpSync).toHaveBeenCalledWith(path_1.default.join(__dirname, '../../templates'), path_1.default.join(process.cwd(), projectName), { recursive: true });
39
+ expect(fs_1.copyFileSync).toHaveBeenCalledTimes(3); // For .gitignore, infra/.gitignore and .env.local
40
+ expect(mockExecSync).toHaveBeenCalledWith('git init', {
41
+ cwd: path_1.default.join(process.cwd(), projectName),
42
+ });
43
+ expect(mockExecSync).toHaveBeenCalledWith('npm i --ignore-scripts', {
44
+ cwd: path_1.default.join(process.cwd(), projectName),
45
+ });
46
+ expect(mockExecSync).toHaveBeenCalledWith('npx prisma generate', {
47
+ cwd: path_1.default.join(process.cwd(), projectName),
48
+ });
49
+ });
50
+ it('should use a specific version if specified', async () => {
51
+ const projectName = 'test-project';
52
+ const version = '1.0.0';
53
+ const mockVersions = ['1.0.0', '1.1.0', '1.2.0'];
54
+ mockExecSync
55
+ .mockReturnValueOnce(Buffer.from(JSON.stringify(mockVersions))) // list version core
56
+ .mockReturnValueOnce(Buffer.from('1.2.3')) // latest cli
57
+ .mockReturnValue(Buffer.from(''));
58
+ await (0, new_action_1.default)(`${projectName}@${version}`, {}, mockCommand);
59
+ expect(child_process_1.execSync).toHaveBeenCalledWith('npm view @mbc-cqrs-serverless/core versions --json');
60
+ expect(fs_1.mkdirSync).toHaveBeenCalledWith(path_1.default.join(process.cwd(), projectName), { recursive: true });
61
+ expect(fs_1.cpSync).toHaveBeenCalledWith(path_1.default.join(__dirname, '../../templates'), path_1.default.join(process.cwd(), projectName), { recursive: true });
62
+ expect(fs_1.copyFileSync).toHaveBeenCalledTimes(3); // For .gitignore, infra/.gitignore and .env.local
63
+ expect(mockExecSync).toHaveBeenCalledWith('git init', {
64
+ cwd: path_1.default.join(process.cwd(), projectName),
65
+ });
66
+ expect(mockExecSync).toHaveBeenCalledWith('npm i --ignore-scripts', {
67
+ cwd: path_1.default.join(process.cwd(), projectName),
68
+ });
69
+ expect(mockExecSync).toHaveBeenCalledWith('npx prisma generate', {
70
+ cwd: path_1.default.join(process.cwd(), projectName),
71
+ });
72
+ });
73
+ it('should throw an error for an invalid version', async () => {
74
+ const projectName = 'test-project';
75
+ const invalidVersion = '2.0.0';
76
+ const mockVersions = ['1.0.0', '1.1.0', '1.2.0'];
77
+ mockExecSync.mockReturnValueOnce(Buffer.from(JSON.stringify(mockVersions)));
78
+ const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
79
+ await (0, new_action_1.default)(`${projectName}@${invalidVersion}`, {}, mockCommand);
80
+ expect(child_process_1.execSync).toHaveBeenCalledWith('npm view @mbc-cqrs-serverless/core versions --json');
81
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('The specified package version does not exist'));
82
+ consoleSpy.mockRestore();
83
+ });
84
+ });
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const fs_1 = require("fs");
4
+ const new_action_1 = require("./new.action");
5
+ const { updateEnvLocal } = new_action_1.exportsForTesting;
6
+ jest.mock('fs');
7
+ describe('updateEnvLocal', () => {
8
+ const mockEnvContent = `
9
+ # name of application
10
+ APP_NAME=%%projectName%%
11
+ # name of docker compose
12
+ COMPOSE_PROJECT_NAME=%%projectName%%
13
+ `;
14
+ const envPath = './.env.local';
15
+ beforeEach(() => {
16
+ jest.clearAllMocks();
17
+ });
18
+ it('should update the specified value in the .env.local file', () => {
19
+ const searchValue = '%%projectName%%';
20
+ const replaceValue = 'new-project-name';
21
+ fs_1.readFileSync.mockReturnValue(mockEnvContent);
22
+ updateEnvLocal(envPath, searchValue, replaceValue);
23
+ expect(fs_1.readFileSync).toHaveBeenCalledWith(envPath, 'utf8');
24
+ const expectedContent = mockEnvContent.replaceAll(searchValue, replaceValue);
25
+ expect(fs_1.writeFileSync).toHaveBeenCalledWith(envPath, expectedContent);
26
+ });
27
+ it('should not change the file content if searchValue is not found', () => {
28
+ const searchValue = 'non-existent-value';
29
+ const replaceValue = 'new-project-name';
30
+ fs_1.readFileSync.mockReturnValue(mockEnvContent);
31
+ updateEnvLocal(envPath, searchValue, replaceValue);
32
+ expect(fs_1.readFileSync).toHaveBeenCalledWith(envPath, 'utf8');
33
+ expect(fs_1.writeFileSync).toHaveBeenCalledWith(envPath, mockEnvContent);
34
+ });
35
+ });
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const faker_1 = require("@faker-js/faker");
7
+ const fs_1 = require("fs");
8
+ const path_1 = __importDefault(require("path"));
9
+ const new_action_1 = require("./new.action");
10
+ const { usePackageVersion } = new_action_1.exportsForTesting;
11
+ // create testcase for usePackageVersion function in new.action.ts file
12
+ describe('usePackageVersion', () => {
13
+ const fname = path_1.default.join(__dirname, 'package.json');
14
+ const packageVersion = '1.0.0';
15
+ const packageJson = JSON.parse((0, fs_1.readFileSync)(path_1.default.join(__dirname, '../../package.json')).toString());
16
+ beforeEach(() => {
17
+ (0, fs_1.copyFileSync)(path_1.default.join(__dirname, '../../templates/package.json'), fname);
18
+ });
19
+ afterEach(() => {
20
+ (0, fs_1.unlinkSync)(fname);
21
+ });
22
+ it('it should update deps', () => {
23
+ usePackageVersion(__dirname, packageVersion);
24
+ const tplPackageJson = JSON.parse((0, fs_1.readFileSync)(fname).toString());
25
+ expect(tplPackageJson.dependencies['@mbc-cqrs-serverless/core']).toBe(packageVersion);
26
+ expect(packageJson.version).toBe(tplPackageJson.devDependencies['@mbc-cqrs-serverless/cli']);
27
+ });
28
+ it('it should not update name', () => {
29
+ const { name } = JSON.parse((0, fs_1.readFileSync)(fname).toString());
30
+ usePackageVersion(__dirname, packageVersion);
31
+ const tplPackageJson = JSON.parse((0, fs_1.readFileSync)(fname).toString());
32
+ expect(name).toBe(tplPackageJson.name);
33
+ });
34
+ it('it should not update name with empty name', () => {
35
+ const { name } = JSON.parse((0, fs_1.readFileSync)(fname).toString());
36
+ usePackageVersion(__dirname, packageVersion, '');
37
+ const tplPackageJson = JSON.parse((0, fs_1.readFileSync)(fname).toString());
38
+ expect(name).toBe(tplPackageJson.name);
39
+ });
40
+ it('it should update name', () => {
41
+ const name = faker_1.faker.word.sample();
42
+ usePackageVersion(__dirname, packageVersion, name);
43
+ const tplPackageJson = JSON.parse((0, fs_1.readFileSync)(fname).toString());
44
+ expect(name).toBe(tplPackageJson.name);
45
+ });
46
+ });
@@ -8,18 +8,19 @@ const child_process_1 = require("child_process");
8
8
  const fs_1 = require("fs");
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const rimraf_1 = require("rimraf");
11
+ const ui_1 = require("../ui");
11
12
  const repoUrl = 'https://gitlab.com/mbc-net/common/mbc-cqrs-ui-common.git';
12
13
  const componentOptions = ['all', 'appsync', 'component'];
13
14
  /* eslint-disable no-console */
14
15
  async function uiAction(options, command) {
15
- console.log(`Executing command '${command.name()}' for application with options '${JSON.stringify(options)}'`);
16
+ ui_1.logger.info(`Executing command '${command.name()}' for application with options '${JSON.stringify(options)}'`);
16
17
  const { branch, auth, component, pathDir, token = '' } = options;
17
18
  if (componentOptions.findIndex((optionName) => optionName === component) === -1) {
18
- console.error(`Please choose correct component options: ${componentOptions.join(', ')}`);
19
+ ui_1.logger.error(`Please choose correct component options: ${componentOptions.join(', ')}`);
19
20
  }
20
21
  // Check command run in base src
21
22
  if (!(0, fs_1.existsSync)(path_1.default.join(process.cwd(), 'tsconfig.json'))) {
22
- console.log('Please run command in base folder');
23
+ ui_1.logger.error('Please run command in base folder');
23
24
  return;
24
25
  }
25
26
  // Check tsconfig.json contain path @ms
@@ -27,7 +28,7 @@ async function uiAction(options, command) {
27
28
  if (tsconfig?.compilerOptions &&
28
29
  tsconfig?.compilerOptions?.paths &&
29
30
  tsconfig?.compilerOptions?.paths.hasOwnProperty('@ms/*')) {
30
- console.log('The project already contain mbc-cqrs-ui-common');
31
+ ui_1.logger.error('The project already contain mbc-cqrs-ui-common');
31
32
  return;
32
33
  }
33
34
  // Copy source
@@ -52,9 +53,10 @@ async function uiAction(options, command) {
52
53
  // Modify package.json
53
54
  modifyDependencies({ pathDir, component });
54
55
  // npm install
55
- console.log('Installing packages');
56
+ ui_1.logger.title('deps', `Installing dependencies`);
56
57
  const logs = (0, child_process_1.execSync)('npm i');
57
58
  console.log(logs.toString());
59
+ ui_1.logger.success(`Dependencies installed`);
58
60
  }
59
61
  const installTemplate = ({ auth, token, pathDir, branch, component, }) => {
60
62
  let gitUrl = repoUrl;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateCommand = generateCommand;
7
+ const generate_action_1 = __importDefault(require("../actions/generate.action"));
8
+ const schematic_colection_1 = require("../schematics/schematic.colection");
9
+ async function generateCommand(program) {
10
+ program
11
+ .command('generate <schematic> [name]')
12
+ .alias('g')
13
+ .description(buildDescription())
14
+ .option('-d, --dry-run', 'Report actions that would be taken without writing out results.')
15
+ .option('--mode <mode>', 'Specify the mode of operation: sync or async (default: async)', 'async')
16
+ .option('--schema', 'Enable schema generation (default: true)', true)
17
+ .option('--no-schema', 'Disable schema generation (default: false)', false)
18
+ .action(generate_action_1.default);
19
+ }
20
+ function buildDescription() {
21
+ return ('Generate a MBC-cqrs-serverless element.\n' +
22
+ ` Schematics available on the collection:\n` +
23
+ (0, schematic_colection_1.buildSchematicsListAsTable)());
24
+ }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = loadCommands;
4
+ const generate_command_1 = require("./generate.command");
4
5
  const new_command_1 = require("./new.command");
5
6
  const start_command_1 = require("./start.command");
6
7
  const ui_command_1 = require("./ui.command");
@@ -8,6 +9,7 @@ function loadCommands(program) {
8
9
  (0, new_command_1.newCommand)(program);
9
10
  (0, start_command_1.startCommand)(program);
10
11
  (0, ui_command_1.uiCommand)(program);
12
+ (0, generate_command_1.generateCommand)(program);
11
13
  // error handling
12
14
  program.on('command:*', () => {
13
15
  console.error(`\nInvalid command: '${program.args.join(' ')}'`);
package/dist/index.js CHANGED
@@ -6,11 +6,22 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const commander_1 = require("commander");
8
8
  const commands_1 = __importDefault(require("./commands"));
9
+ const utils_1 = require("./utils");
9
10
  async function bootstrap() {
10
11
  const program = new commander_1.Command();
12
+ program
13
+ .version(
11
14
  // eslint-disable-next-line @typescript-eslint/no-var-requires
12
- program.version(require('../package.json').version);
13
- (0, commands_1.default)(program);
15
+ require('../package.json').version, '-v, --version', 'Output the current version.')
16
+ .usage('<command> [options]')
17
+ .helpOption('-h, --help', 'Output usage information.');
18
+ if ((0, utils_1.localBinExists)()) {
19
+ const localCommandLoader = (0, utils_1.loadLocalBinCommandLoader)();
20
+ localCommandLoader.default(program);
21
+ }
22
+ else {
23
+ (0, commands_1.default)(program);
24
+ }
14
25
  await program.parseAsync(process.argv);
15
26
  if (!process.argv.slice(2).length) {
16
27
  program.outputHelp();