@runium/cli 0.0.2 → 0.0.3

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 (134) hide show
  1. package/.eslintrc.json +31 -0
  2. package/.prettierrc.json +10 -0
  3. package/README.md +3 -0
  4. package/build.js +125 -0
  5. package/lib/app.js +6 -0
  6. package/{commands → lib/commands}/index.js +0 -0
  7. package/lib/commands/plugin/plugin-add.js +1 -0
  8. package/lib/commands/plugin/plugin-disable.js +1 -0
  9. package/lib/commands/plugin/plugin-enable.js +1 -0
  10. package/lib/commands/plugin/plugin-remove.js +1 -0
  11. package/lib/commands/plugin/plugin.js +1 -0
  12. package/lib/commands/project/project-add.js +1 -0
  13. package/lib/commands/project/project-command.js +1 -0
  14. package/lib/commands/project/project-start.js +1 -0
  15. package/lib/commands/project/project-state-command.js +1 -0
  16. package/lib/commands/project/project-status.js +1 -0
  17. package/lib/commands/project/project-stop.js +1 -0
  18. package/lib/commands/project/project-validate.js +4 -0
  19. package/lib/commands/project/project.js +1 -0
  20. package/lib/commands/runium-command.js +1 -0
  21. package/lib/constants/error-code.js +1 -0
  22. package/{constants → lib/constants}/index.js +0 -0
  23. package/lib/index.js +2 -0
  24. package/lib/macros/date.js +1 -0
  25. package/lib/macros/index.js +1 -0
  26. package/lib/macros/path.js +1 -0
  27. package/lib/package.json +22 -0
  28. package/lib/services/command.js +1 -0
  29. package/lib/services/config.js +1 -0
  30. package/lib/services/file.js +1 -0
  31. package/lib/services/index.js +1 -0
  32. package/lib/services/output.js +3 -0
  33. package/lib/services/plugin-context.js +1 -0
  34. package/lib/services/plugin.js +1 -0
  35. package/lib/services/profile.js +1 -0
  36. package/lib/services/project.js +1 -0
  37. package/lib/services/shutdown.js +1 -0
  38. package/lib/utils/get-version.js +1 -0
  39. package/lib/utils/index.js +1 -0
  40. package/lib/validation/create-validator.js +1 -0
  41. package/lib/validation/get-config-schema.js +1 -0
  42. package/lib/validation/get-error-messages.js +1 -0
  43. package/lib/validation/get-plugin-schema.js +1 -0
  44. package/lib/validation/index.js +1 -0
  45. package/package.json +33 -7
  46. package/src/app.ts +190 -0
  47. package/src/commands/index.ts +2 -0
  48. package/src/commands/plugin/plugin-add.ts +48 -0
  49. package/src/commands/plugin/plugin-command.ts +36 -0
  50. package/src/commands/plugin/plugin-disable.ts +46 -0
  51. package/src/commands/plugin/plugin-enable.ts +50 -0
  52. package/src/commands/plugin/plugin-list.ts +61 -0
  53. package/src/commands/plugin/plugin-remove.ts +42 -0
  54. package/src/commands/plugin/plugin.ts +36 -0
  55. package/src/commands/project/project-add.ts +64 -0
  56. package/src/commands/project/project-command.ts +43 -0
  57. package/src/commands/project/project-list.ts +32 -0
  58. package/src/commands/project/project-remove.ts +41 -0
  59. package/src/commands/project/project-start.ts +158 -0
  60. package/src/commands/project/project-state-command.ts +53 -0
  61. package/src/commands/project/project-status.ts +116 -0
  62. package/src/commands/project/project-stop.ts +59 -0
  63. package/src/commands/project/project-validate.ts +56 -0
  64. package/src/commands/project/project.ts +40 -0
  65. package/src/commands/runium-command.ts +52 -0
  66. package/src/constants/error-code.ts +28 -0
  67. package/src/constants/index.ts +1 -0
  68. package/src/global.d.ts +6 -0
  69. package/src/index.ts +24 -0
  70. package/src/macros/conditional.ts +31 -0
  71. package/src/macros/date.ts +15 -0
  72. package/src/macros/empty.ts +6 -0
  73. package/src/macros/env.ts +8 -0
  74. package/src/macros/index.ts +17 -0
  75. package/src/macros/path.ts +24 -0
  76. package/src/services/command.ts +171 -0
  77. package/src/services/config.ts +119 -0
  78. package/src/services/file.ts +272 -0
  79. package/src/services/index.ts +9 -0
  80. package/src/services/output.ts +205 -0
  81. package/src/services/plugin-context.ts +140 -0
  82. package/src/services/plugin.ts +248 -0
  83. package/src/services/profile.ts +199 -0
  84. package/src/services/project.ts +142 -0
  85. package/src/services/shutdown.ts +147 -0
  86. package/src/utils/convert-path-to-valid-file-name.ts +39 -0
  87. package/src/utils/debounce.ts +23 -0
  88. package/src/utils/format-timestamp.ts +17 -0
  89. package/src/utils/get-version.ts +13 -0
  90. package/src/utils/index.ts +4 -0
  91. package/src/validation/create-validator.ts +27 -0
  92. package/src/validation/get-config-schema.ts +59 -0
  93. package/src/validation/get-error-messages.ts +35 -0
  94. package/src/validation/get-plugin-schema.ts +137 -0
  95. package/src/validation/index.ts +4 -0
  96. package/tsconfig.json +38 -0
  97. package/app.js +0 -6
  98. package/commands/plugin/plugin-add.js +0 -1
  99. package/commands/plugin/plugin-disable.js +0 -1
  100. package/commands/plugin/plugin-enable.js +0 -1
  101. package/commands/plugin/plugin-remove.js +0 -1
  102. package/commands/plugin/plugin.js +0 -1
  103. package/commands/project/project-add.js +0 -1
  104. package/commands/project/project-command.js +0 -1
  105. package/commands/project/project-start.js +0 -1
  106. package/commands/project/project-state-command.js +0 -1
  107. package/commands/project/project-status.js +0 -1
  108. package/commands/project/project-stop.js +0 -1
  109. package/commands/project/project-validate.js +0 -1
  110. package/commands/project/project.js +0 -1
  111. package/commands/runium-command.js +0 -1
  112. package/constants/error-code.js +0 -1
  113. package/index.js +0 -2
  114. package/macros/index.js +0 -1
  115. package/macros/path.js +0 -1
  116. package/services/config.js +0 -1
  117. package/services/index.js +0 -1
  118. package/services/output.js +0 -3
  119. package/services/plugin-context.js +0 -1
  120. package/services/plugin.js +0 -1
  121. package/services/profile.js +0 -1
  122. package/services/project.js +0 -1
  123. package/services/shutdown.js +0 -1
  124. package/utils/index.js +0 -1
  125. /package/{commands → lib/commands}/plugin/plugin-command.js +0 -0
  126. /package/{commands → lib/commands}/plugin/plugin-list.js +0 -0
  127. /package/{commands → lib/commands}/project/project-list.js +0 -0
  128. /package/{commands → lib/commands}/project/project-remove.js +0 -0
  129. /package/{macros → lib/macros}/conditional.js +0 -0
  130. /package/{macros → lib/macros}/empty.js +0 -0
  131. /package/{macros → lib/macros}/env.js +0 -0
  132. /package/{utils → lib/utils}/convert-path-to-valid-file-name.js +0 -0
  133. /package/{utils → lib/utils}/debounce.js +0 -0
  134. /package/{utils → lib/utils}/format-timestamp.js +0 -0
@@ -0,0 +1,158 @@
1
+ import { dirname } from 'node:path';
2
+ import { Command, Option } from 'commander';
3
+ import { Container } from 'typedi';
4
+ import {
5
+ Project,
6
+ ProjectEvent,
7
+ ProjectState,
8
+ RuniumError,
9
+ TaskState,
10
+ } from '@runium/core';
11
+ import { ErrorCode } from '@constants';
12
+ import { AtomicWriter, ShutdownService } from '@services';
13
+ import { ProjectData, ProjectStateCommand } from './project-state-command.js';
14
+
15
+ /**
16
+ * Project start command
17
+ */
18
+ export class ProjectStartCommand extends ProjectStateCommand {
19
+ protected shutdownService: ShutdownService;
20
+ protected fileWriter: AtomicWriter | null = null;
21
+
22
+ constructor(parent: Command) {
23
+ super(parent);
24
+ this.shutdownService = Container.get(ShutdownService);
25
+ }
26
+
27
+ /**
28
+ * Config command
29
+ */
30
+ protected config(): void {
31
+ this.command
32
+ .name('start')
33
+ .description('start project')
34
+ .option('-f, --file', 'use file path instead of project name')
35
+ .option('-o, --output', 'output project state changes')
36
+ .addOption(
37
+ new Option('-w, --working-dir <choice>', 'set working directory')
38
+ .choices(['cwd', 'project'])
39
+ .default('cwd')
40
+ )
41
+ .argument('<name>', 'project name');
42
+ }
43
+
44
+ /**
45
+ * Handle command
46
+ * @param name
47
+ * @param file
48
+ * @param workingDir
49
+ * @param output
50
+ */
51
+ protected async handle(
52
+ name: string,
53
+ {
54
+ file,
55
+ workingDir,
56
+ output,
57
+ }: { file: boolean; workingDir?: string; output?: boolean }
58
+ ): Promise<void> {
59
+ const path = file
60
+ ? this.projectService.resolvePath(name)
61
+ : this.ensureProfileProject(name).path;
62
+
63
+ const projectDataFileName = this.getProjectDataFileName(file ? path : name);
64
+ const projectDataFilePath = this.profileService.getPath(
65
+ 'projects',
66
+ projectDataFileName
67
+ );
68
+
69
+ // check if project is started
70
+ const projectData = await this.readProjectData(projectDataFilePath);
71
+ if (projectData && this.isProjectProcessStarted(projectData.pid)) {
72
+ throw new RuniumError(
73
+ `Project "${name}" is already started`,
74
+ ErrorCode.PROJECT_ALREADY_STARTED,
75
+ { name }
76
+ );
77
+ }
78
+
79
+ if (workingDir === 'project') {
80
+ const projectDir = dirname(path);
81
+ if (projectDir !== process.cwd()) {
82
+ process.chdir(projectDir);
83
+ }
84
+ }
85
+
86
+ const project = await this.projectService.initProject(path);
87
+ this.shutdownService.addBlocker((reason?: string) => project.stop(reason));
88
+
89
+ await this.fileService.ensureDirExists(dirname(projectDataFilePath));
90
+ this.fileWriter = this.fileService.createAtomicWriter(projectDataFilePath);
91
+
92
+ this.addProjectListeners(project, {
93
+ projectPath: path,
94
+ output,
95
+ });
96
+
97
+ await this.projectService.runHook('project.beforeStart', project);
98
+
99
+ await project.start();
100
+ }
101
+
102
+ /**
103
+ * Add project listeners
104
+ * @param project
105
+ * @param options
106
+ */
107
+ protected addProjectListeners(
108
+ project: Project,
109
+ options: { projectPath: string; output?: boolean }
110
+ ): void {
111
+ const { projectPath, output } = options;
112
+
113
+ const projectData: ProjectData = {
114
+ id: project.getConfig().id,
115
+ pid: process.pid,
116
+ cwd: process.cwd(),
117
+ path: projectPath,
118
+ state: {
119
+ project: [],
120
+ tasks: {},
121
+ },
122
+ };
123
+
124
+ const writeProjectData = () => {
125
+ this.fileWriter!.writeJson(projectData).then();
126
+ };
127
+
128
+ // write initial data
129
+ writeProjectData();
130
+
131
+ project.on(ProjectEvent.STATE_CHANGE, async (state: ProjectState) => {
132
+ projectData.state.project.push(state);
133
+ writeProjectData();
134
+ if (output) {
135
+ this.outputService.info('Project %s', state.status);
136
+ }
137
+ });
138
+
139
+ project.on(
140
+ ProjectEvent.TASK_STATE_CHANGE,
141
+ (taskId: string, state: TaskState) => {
142
+ if (!projectData.state.tasks[taskId]) {
143
+ projectData.state.tasks[taskId] = [];
144
+ }
145
+ projectData.state.tasks[taskId].push(state);
146
+ writeProjectData();
147
+ if (output) {
148
+ this.outputService.info(
149
+ 'Task %s %s %s',
150
+ taskId,
151
+ state.status,
152
+ state.exitCode || state.error || ''
153
+ );
154
+ }
155
+ }
156
+ );
157
+ }
158
+ }
@@ -0,0 +1,53 @@
1
+ import { convertPathToValidFileName } from '@utils';
2
+ import { ProjectCommand } from './project-command.js';
3
+ import { ProjectState, TaskState } from '@runium/core';
4
+
5
+ export interface ProjectData {
6
+ id: string;
7
+ pid: number;
8
+ cwd: string;
9
+ path: string;
10
+ state: {
11
+ project: ProjectState[];
12
+ tasks: Record<string, TaskState[]>;
13
+ };
14
+ }
15
+
16
+ /**
17
+ * Base project state command
18
+ */
19
+ export abstract class ProjectStateCommand extends ProjectCommand {
20
+ /**
21
+ * Get project data file name
22
+ * @param name
23
+ */
24
+ protected getProjectDataFileName(name: string): string {
25
+ let fileName = convertPathToValidFileName(name);
26
+ if (!fileName.endsWith('.json')) {
27
+ fileName = fileName + '.json';
28
+ }
29
+ return fileName;
30
+ }
31
+
32
+ /**
33
+ * Read project data
34
+ * @param path
35
+ */
36
+ protected async readProjectData(path: string): Promise<ProjectData | null> {
37
+ return this.fileService
38
+ .readJson(path)
39
+ .catch(() => null) as Promise<ProjectData | null>;
40
+ }
41
+
42
+ /**
43
+ * Checks if a project process is started
44
+ * @param pid
45
+ */
46
+ protected isProjectProcessStarted(pid: number): boolean {
47
+ try {
48
+ return process.kill(Number(pid), 0);
49
+ } catch (ex) {
50
+ return (ex as { code?: string }).code === 'EPERM';
51
+ }
52
+ }
53
+ }
@@ -0,0 +1,116 @@
1
+ import { formatTimestamp } from '@utils';
2
+ import { ProjectStateCommand } from './project-state-command.js';
3
+
4
+ interface StateRecord {
5
+ name: string;
6
+ status: string;
7
+ time: string;
8
+ timestamp: number;
9
+ reason?: string;
10
+ exitCode?: number;
11
+ }
12
+
13
+ /**
14
+ * Project status command
15
+ */
16
+ export class ProjectStatusCommand extends ProjectStateCommand {
17
+ /**
18
+ * Config command
19
+ */
20
+ protected config(): void {
21
+ this.command
22
+ .name('status')
23
+ .description('get project status')
24
+ .option('-f, --file', 'use file path instead of project name')
25
+ .option('-t, --tasks', 'show tasks status')
26
+ .option('-a, --all', 'show status change history')
27
+ .argument('<name>', 'project name');
28
+ }
29
+
30
+ /**
31
+ * Handle command
32
+ * @param name
33
+ * @param file
34
+ * @param tasks
35
+ * @param all
36
+ */
37
+ protected async handle(
38
+ name: string,
39
+ { file, tasks, all }: { file: boolean; tasks: boolean; all: boolean }
40
+ ): Promise<void> {
41
+ const path = file
42
+ ? this.projectService.resolvePath(name)
43
+ : this.ensureProfileProject(name).path;
44
+
45
+ const projectDataFileName = this.getProjectDataFileName(file ? path : name);
46
+ const projectDataFilePath = this.profileService.getPath(
47
+ 'projects',
48
+ projectDataFileName
49
+ );
50
+
51
+ const projectData = await this.readProjectData(projectDataFilePath);
52
+ if (projectData) {
53
+ let { project: projectState = [] } = projectData.state;
54
+ if (!all) {
55
+ projectState =
56
+ projectState.length > 0
57
+ ? [projectState[projectState.length - 1]]
58
+ : [];
59
+ }
60
+
61
+ if (tasks) {
62
+ const projectMappedState = projectState.map(state => {
63
+ return {
64
+ name: 'Project',
65
+ status: state.status,
66
+ time: formatTimestamp(state.timestamp),
67
+ timestamp: state.timestamp,
68
+ reason: state.reason || '',
69
+ };
70
+ });
71
+
72
+ const { tasks: tasksState = [] } = projectData.state;
73
+
74
+ const tasksMappedState: StateRecord[] = [];
75
+ Object.entries(tasksState).forEach(([key, value]) => {
76
+ if (!all) {
77
+ value = value.length > 0 ? [value[value.length - 1]] : [];
78
+ }
79
+ value.forEach(task => {
80
+ tasksMappedState.push({
81
+ name: key,
82
+ status: task.status,
83
+ time: formatTimestamp(task.timestamp),
84
+ timestamp: task.timestamp,
85
+ reason: [task.reason, task.exitCode].filter(Boolean).join(' '),
86
+ });
87
+ });
88
+ });
89
+
90
+ const mappedState: StateRecord[] = [
91
+ ...projectMappedState,
92
+ ...tasksMappedState,
93
+ ];
94
+ mappedState.sort((a, b) => a.timestamp - b.timestamp);
95
+
96
+ this.outputService.table(mappedState, [
97
+ 'time',
98
+ 'name',
99
+ 'status',
100
+ 'reason',
101
+ ]);
102
+ } else {
103
+ const mappedState = projectState.map(state => {
104
+ return {
105
+ status: state.status,
106
+ time: formatTimestamp(state.timestamp),
107
+ };
108
+ });
109
+
110
+ this.outputService.table(mappedState, ['time', 'status']);
111
+ }
112
+ } else {
113
+ this.outputService.info(`No project status for "${name}"`);
114
+ }
115
+ }
116
+ }
@@ -0,0 +1,59 @@
1
+ import { RuniumError } from '@runium/core';
2
+ import { ErrorCode } from '@constants';
3
+ import { ProjectStateCommand } from './project-state-command.js';
4
+
5
+ /**
6
+ * Project stop command
7
+ */
8
+ export class ProjectStopCommand extends ProjectStateCommand {
9
+ /**
10
+ * Config command
11
+ */
12
+ protected config(): void {
13
+ this.command
14
+ .name('stop')
15
+ .description('stop project')
16
+ .option('-f, --file', 'use file path instead of project name')
17
+ .argument('<name>', 'project name');
18
+ }
19
+
20
+ /**
21
+ * Handle command
22
+ * @param name
23
+ * @param file
24
+ */
25
+ protected async handle(
26
+ name: string,
27
+ { file }: { file: boolean }
28
+ ): Promise<void> {
29
+ const path = file
30
+ ? this.projectService.resolvePath(name)
31
+ : this.ensureProfileProject(name).path;
32
+
33
+ const projectDataFileName = this.getProjectDataFileName(file ? path : name);
34
+ const projectDataFilePath = this.profileService.getPath(
35
+ 'projects',
36
+ projectDataFileName
37
+ );
38
+
39
+ // check if project is started
40
+ const projectData = await this.readProjectData(projectDataFilePath);
41
+ if (!projectData || !this.isProjectProcessStarted(projectData.pid)) {
42
+ throw new RuniumError(
43
+ `Project "${name}" is not started`,
44
+ ErrorCode.PROJECT_NOT_STARTED,
45
+ { name }
46
+ );
47
+ }
48
+
49
+ try {
50
+ process.kill(projectData.pid, 'SIGTERM');
51
+ } catch (ex) {
52
+ throw new RuniumError(
53
+ `Failed to stop project "${name}"`,
54
+ ErrorCode.PROJECT_STOP_ERROR,
55
+ { name, original: ex }
56
+ );
57
+ }
58
+ }
59
+ }
@@ -0,0 +1,56 @@
1
+ import * as ajv from 'ajv';
2
+ import { ProjectCommand } from './project-command.js';
3
+ import { getErrorMessages } from '@validation';
4
+
5
+ interface ValidationError {
6
+ code: string;
7
+ payload: { errors: ajv.ErrorObject[] };
8
+ }
9
+
10
+ /**
11
+ * Project validate command
12
+ */
13
+ export class ProjectValidateCommand extends ProjectCommand {
14
+ /**
15
+ * Config command
16
+ */
17
+ protected config(): void {
18
+ this.command
19
+ .name('validate')
20
+ .description('validate project')
21
+ .option('-f, --file', 'use file path instead of project name')
22
+ .argument('<name>', 'project name');
23
+ }
24
+
25
+ /**
26
+ * Handle command
27
+ * @param name
28
+ * @param file
29
+ */
30
+ protected async handle(
31
+ name: string,
32
+ { file }: { file: boolean }
33
+ ): Promise<void> {
34
+ const path = file
35
+ ? this.projectService.resolvePath(name)
36
+ : this.ensureProfileProject(name).path;
37
+ const projectInstance = await this.projectService.initProject(path);
38
+ try {
39
+ await projectInstance.validate();
40
+ this.outputService.success(`Project "%s" is valid`, name);
41
+ } catch (error) {
42
+ const errorMessages = getErrorMessages(
43
+ (error as ValidationError).payload.errors,
44
+ {
45
+ filter: error => error.original?.keyword !== 'oneOf',
46
+ }
47
+ );
48
+
49
+ this.outputService.error(
50
+ `Project "%s" validation failed:\n\n%s`,
51
+ name,
52
+ errorMessages.join('\n')
53
+ );
54
+ }
55
+ }
56
+ }
@@ -0,0 +1,40 @@
1
+ import { RuniumCommand } from '@commands/runium-command.js';
2
+ import { ProjectAddCommand } from './project-add.js';
3
+ import { ProjectListCommand } from './project-list.js';
4
+ import { ProjectRemoveCommand } from './project-remove.js';
5
+ import { ProjectStartCommand } from './project-start.js';
6
+ import { ProjectStopCommand } from './project-stop.js';
7
+ import { ProjectStatusCommand } from './project-status.js';
8
+ import { ProjectValidateCommand } from './project-validate.js';
9
+
10
+ /**
11
+ * Project group command
12
+ */
13
+ export class ProjectCommand extends RuniumCommand {
14
+ /**
15
+ * Subcommands
16
+ */
17
+ subcommands = [
18
+ ProjectListCommand,
19
+ ProjectAddCommand,
20
+ ProjectRemoveCommand,
21
+ ProjectStartCommand,
22
+ ProjectStopCommand,
23
+ ProjectStatusCommand,
24
+ ProjectValidateCommand,
25
+ ];
26
+
27
+ /**
28
+ * Config command
29
+ */
30
+ protected config(): void {
31
+ this.command.name('project').description('manage projects');
32
+ }
33
+
34
+ /**
35
+ * Handle command
36
+ */
37
+ protected async handle(): Promise<void> {
38
+ this.command.help();
39
+ }
40
+ }
@@ -0,0 +1,52 @@
1
+ import { Command } from 'commander';
2
+ import { Container } from 'typedi';
3
+ import { CommandService, OutputService } from '@services';
4
+
5
+ export type RuniumCommandConstructor = new (program: Command) => RuniumCommand;
6
+
7
+ /**
8
+ * Base runium command
9
+ */
10
+ export abstract class RuniumCommand {
11
+ /**
12
+ * Output service
13
+ */
14
+ protected outputService: OutputService;
15
+
16
+ /**
17
+ * Current command
18
+ */
19
+ command: Command;
20
+
21
+ /**
22
+ * Subcommands
23
+ */
24
+ subcommands: RuniumCommandConstructor[] = [];
25
+
26
+ /**
27
+ * Run command
28
+ */
29
+ run: (...args: unknown[]) => Promise<void>;
30
+
31
+ constructor(parent: Command) {
32
+ const commandService = Container.get(CommandService);
33
+ this.run = commandService.createRunCommand(this.handle, this);
34
+
35
+ this.outputService = Container.get(OutputService);
36
+ this.command = new Command();
37
+ this.config();
38
+ this.command.action(this.run.bind(this));
39
+
40
+ parent.addCommand(this.command);
41
+ }
42
+
43
+ /**
44
+ * Config command
45
+ */
46
+ protected abstract config(): void;
47
+
48
+ /**
49
+ * Handle command
50
+ */
51
+ protected abstract handle(...args: unknown[]): Promise<void>;
52
+ }
@@ -0,0 +1,28 @@
1
+ export enum ErrorCode {
2
+ FILE_READ_JSON_ERROR = 'file-read-json-error',
3
+ FILE_WRITE_JSON_ERROR = 'file-write-json-error',
4
+ FILE_READ_ERROR = 'file-read-error',
5
+ FILE_WRITE_ERROR = 'file-write-error',
6
+ FILE_CREATE_DIR_ERROR = 'file-create-dir-error',
7
+ PLUGIN_NOT_FOUND = 'plugin-not-found',
8
+ PLUGIN_FILE_NOT_FOUND = 'plugin-file-not-found',
9
+ PLUGIN_INCORRECT_MODULE = 'plugin-incorrect-module',
10
+ PLUGIN_INVALID = 'plugin-invalid',
11
+ PLUGIN_PATH_RESOLVE_ERROR = 'plugin-path-resolve-error',
12
+ PLUGIN_LOAD_ERROR = 'plugin-load-error',
13
+ PLUGIN_HOOK_ERROR = 'plugin-hook-error',
14
+ PROJECT_ALREADY_STARTED = 'project-already-started',
15
+ PROJECT_NOT_STARTED = 'project-not-started',
16
+ PROJECT_STOP_ERROR = 'project-stop-error',
17
+ PROJECT_NOT_FOUND = 'project-not-found',
18
+ PROJECT_FILE_NOT_FOUND = 'project-file-not-found',
19
+ PROJECT_FILE_CAN_NOT_READ = 'project-file-can-not-read',
20
+ PROJECT_JSON_PARSE_ERROR = 'project-json-parse-error',
21
+ INVALID_ARGUMENT = 'invalid-argument',
22
+ INVALID_PATH = 'invalid-path',
23
+ CONFIG_INVALID_DATA = 'config-invalid-data',
24
+ COMMAND_REGISTRATION_ERROR = 'command-registration-error',
25
+ COMMAND_INCORRECT = 'command-incorrect',
26
+ COMMAND_NOT_FOUND = 'command-not-found',
27
+ COMMAND_RUN_ERROR = 'command-run-error',
28
+ }
@@ -0,0 +1 @@
1
+ export * from './error-code.js';
@@ -0,0 +1,6 @@
1
+ declare global {
2
+ // eslint-disable-next-line
3
+ var runium: unknown;
4
+ }
5
+
6
+ export {};
package/src/index.ts ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+
3
+ import 'reflect-metadata';
4
+ import { Container } from 'typedi';
5
+ import { RuniumCliApp } from './app.js';
6
+ import { OutputService, ShutdownService } from '@services';
7
+
8
+ async function main() {
9
+ const app = new RuniumCliApp();
10
+ await app.start();
11
+ }
12
+
13
+ main().catch(error => {
14
+ const outputService = Container.get(OutputService);
15
+ outputService.error('Error: %s', error.message);
16
+ outputService.debug('Error details:', {
17
+ code: error.code,
18
+ payload: error.payload,
19
+ });
20
+ const shutdownService = Container.get(ShutdownService);
21
+ shutdownService.shutdown('error').catch(() => {
22
+ process.exit(1);
23
+ });
24
+ });
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Equal
3
+ * @param value1
4
+ * @param value2
5
+ * @param trueValue
6
+ * @param falseValue
7
+ */
8
+ export function eqMacro(
9
+ value1: string,
10
+ value2: string,
11
+ trueValue?: string,
12
+ falseValue?: string
13
+ ): string {
14
+ return value1 === value2 ? (trueValue ?? '') : (falseValue ?? '');
15
+ }
16
+
17
+ /**
18
+ * Not equal
19
+ * @param value1
20
+ * @param value2
21
+ * @param trueValue
22
+ * @param falseValue
23
+ */
24
+ export function neMacro(
25
+ value1: string,
26
+ value2: string,
27
+ trueValue?: string,
28
+ falseValue?: string
29
+ ): string {
30
+ return value1 !== value2 ? (trueValue ?? '') : (falseValue ?? '');
31
+ }
@@ -0,0 +1,15 @@
1
+ import { formatTimestamp } from '@utils/format-timestamp.js';
2
+
3
+ /**
4
+ * Date
5
+ */
6
+ export function dateMacro(): string {
7
+ return formatTimestamp(Date.now());
8
+ }
9
+
10
+ /**
11
+ * Timestamp
12
+ */
13
+ export function timestampMacro(): string {
14
+ return Date.now().toString();
15
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Empty string
3
+ */
4
+ export function emptyMacro(): string {
5
+ return '';
6
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Get environment variable
3
+ * @param name
4
+ * @param defaultValue
5
+ */
6
+ export function envMacro(name: string, defaultValue?: string): string {
7
+ return process.env[name] ?? defaultValue ?? '';
8
+ }
@@ -0,0 +1,17 @@
1
+ import { eqMacro, neMacro } from './conditional.js';
2
+ import { dateMacro, timestampMacro } from './date.js';
3
+ import { emptyMacro } from './empty.js';
4
+ import { envMacro } from './env.js';
5
+ import { homeDirMacro, pathMacro, tmpDirMacro } from './path.js';
6
+
7
+ export const macros = {
8
+ date: dateMacro,
9
+ homedir: homeDirMacro,
10
+ env: envMacro,
11
+ empty: emptyMacro,
12
+ eq: eqMacro,
13
+ ne: neMacro,
14
+ path: pathMacro,
15
+ tmpdir: tmpDirMacro,
16
+ timestamp: timestampMacro,
17
+ };