meocord 1.2.1 → 1.2.2
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.
- package/CHANGELOG.md +35 -0
- package/README.md +152 -140
- package/dist/cjs/_shared/meocord.app-CHjdCAA_.cjs +496 -0
- package/dist/cjs/_shared/theme-BdtbtMZX.cjs +176 -0
- package/dist/cjs/common/index.cjs +16 -0
- package/dist/cjs/core/index.cjs +35 -0
- package/dist/cjs/decorator/index.cjs +360 -0
- package/dist/cjs/enum/index.cjs +20 -0
- package/dist/cjs/interface/index.cjs +2 -0
- package/dist/esm/bin/generator.js +92 -0
- package/dist/esm/bin/helper/controller-generator.helper.js +105 -0
- package/dist/esm/bin/helper/guard-generator.helper.js +33 -0
- package/dist/esm/bin/helper/service-generator.helper.js +33 -0
- package/dist/esm/bin/meocord.js +333 -0
- package/dist/esm/common/index.js +2 -0
- package/dist/esm/common/logger.js +72 -0
- package/dist/{core/index.d.ts → esm/common/theme.js} +8 -2
- package/dist/esm/core/index.js +1 -0
- package/dist/esm/core/meocord-factory.js +28 -0
- package/dist/esm/core/meocord.app.js +267 -0
- package/dist/esm/decorator/app.decorator.js +99 -0
- package/dist/esm/decorator/command-builder.decorator.js +32 -0
- package/dist/esm/decorator/container.js +6 -0
- package/dist/esm/decorator/controller.decorator.js +218 -0
- package/dist/esm/decorator/guard.decorator.js +165 -0
- package/dist/esm/decorator/index.js +6 -0
- package/dist/esm/decorator/service.decorator.js +58 -0
- package/dist/esm/enum/controller.enum.js +43 -0
- package/dist/esm/enum/index.js +1 -0
- package/dist/esm/interface/index.js +1 -0
- package/dist/esm/package.json.js +5 -0
- package/dist/esm/util/common.util.js +68 -0
- package/dist/esm/util/embed.util.js +13 -0
- package/dist/esm/util/generator-cli.util.js +107 -0
- package/dist/{util → esm/util}/json.util.js +10 -6
- package/dist/esm/util/meocord-cli.util.js +172 -0
- package/dist/esm/util/meocord-config-loader.util.js +48 -0
- package/dist/esm/util/tsconfig.util.js +83 -0
- package/dist/{util → esm/util}/wait.util.js +5 -1
- package/dist/{common/logger.d.ts → types/common/index.d.ts} +30 -1
- package/dist/{core/meocord.app.d.ts → types/core/index.d.ts} +30 -2
- package/dist/types/decorator/index.d.ts +425 -0
- package/dist/types/enum/index.d.ts +18 -0
- package/dist/{interface → types/interface}/index.d.ts +11 -7
- package/package.json +64 -48
- package/webpack.config.js +2 -2
- package/dist/bin/generator.d.ts +0 -29
- package/dist/bin/generator.js +0 -17
- package/dist/bin/helper/controller-generator.helper.d.ts +0 -67
- package/dist/bin/helper/controller-generator.helper.js +0 -50
- package/dist/bin/helper/guard-generator.helper.d.ts +0 -32
- package/dist/bin/helper/guard-generator.helper.js +0 -25
- package/dist/bin/helper/service-generator.helper.d.ts +0 -32
- package/dist/bin/helper/service-generator.helper.js +0 -25
- package/dist/bin/meocord.d.ts +0 -19
- package/dist/bin/meocord.js +0 -34
- package/dist/common/index.d.ts +0 -19
- package/dist/common/index.js +0 -17
- package/dist/common/logger.js +0 -17
- package/dist/common/theme.d.ts +0 -24
- package/dist/common/theme.js +0 -17
- package/dist/core/index.js +0 -17
- package/dist/core/meocord-factory.d.ts +0 -24
- package/dist/core/meocord-factory.js +0 -17
- package/dist/core/meocord.app.js +0 -17
- package/dist/decorator/app.decorator.d.ts +0 -59
- package/dist/decorator/app.decorator.js +0 -61
- package/dist/decorator/command-builder.decorator.d.ts +0 -39
- package/dist/decorator/command-builder.decorator.js +0 -35
- package/dist/decorator/container.d.ts +0 -20
- package/dist/decorator/container.js +0 -17
- package/dist/decorator/controller.decorator.d.ts +0 -125
- package/dist/decorator/controller.decorator.js +0 -113
- package/dist/decorator/guard.decorator.d.ts +0 -101
- package/dist/decorator/guard.decorator.js +0 -94
- package/dist/decorator/index.d.ts +0 -23
- package/dist/decorator/index.js +0 -17
- package/dist/decorator/service.decorator.d.ts +0 -36
- package/dist/decorator/service.decorator.js +0 -36
- package/dist/enum/controller.enum.d.ts +0 -42
- package/dist/enum/controller.enum.js +0 -19
- package/dist/enum/index.d.ts +0 -18
- package/dist/enum/index.js +0 -17
- package/dist/interface/command-decorator.interface.d.ts +0 -43
- package/dist/interface/command-decorator.interface.js +0 -1
- package/dist/interface/index.js +0 -1
- package/dist/util/common.util.d.ts +0 -40
- package/dist/util/common.util.js +0 -38
- package/dist/util/embed.util.d.ts +0 -19
- package/dist/util/embed.util.js +0 -17
- package/dist/util/generator-cli.util.d.ts +0 -65
- package/dist/util/generator-cli.util.js +0 -49
- package/dist/util/index.d.ts +0 -18
- package/dist/util/index.js +0 -17
- package/dist/util/json.util.d.ts +0 -27
- package/dist/util/meocord-cli.util.d.ts +0 -62
- package/dist/util/meocord-cli.util.js +0 -50
- package/dist/util/meocord-config-loader.util.d.ts +0 -32
- package/dist/util/meocord-config-loader.util.js +0 -34
- package/dist/util/tsconfig.util.d.ts +0 -29
- package/dist/util/tsconfig.util.js +0 -32
- package/dist/util/wait.util.d.ts +0 -18
- /package/dist/{bin → esm/bin}/builder-template/builder/context-menu.builder.template +0 -0
- /package/dist/{bin → esm/bin}/builder-template/builder/slash.builder.template +0 -0
- /package/dist/{bin → esm/bin}/builder-template/controller/button.controller.template +0 -0
- /package/dist/{bin → esm/bin}/builder-template/controller/context-menu.controller.template +0 -0
- /package/dist/{bin → esm/bin}/builder-template/controller/message.controller.template +0 -0
- /package/dist/{bin → esm/bin}/builder-template/controller/modal-submit.controller.template +0 -0
- /package/dist/{bin → esm/bin}/builder-template/controller/reaction.controller.template +0 -0
- /package/dist/{bin → esm/bin}/builder-template/controller/select-menu.controller.template +0 -0
- /package/dist/{bin → esm/bin}/builder-template/controller/slash.controller.template +0 -0
- /package/dist/{bin → esm/bin}/builder-template/guard.template +0 -0
- /package/dist/{bin → esm/bin}/builder-template/service.template +0 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { Logger } from '../../common/logger.js';
|
|
3
|
+
import '../../common/theme.js';
|
|
4
|
+
import { validateAndFormatName, buildTemplate, createDirectoryIfNotExists, generateFile } from '../../util/generator-cli.util.js';
|
|
5
|
+
|
|
6
|
+
class ServiceGeneratorHelper {
|
|
7
|
+
/**
|
|
8
|
+
* Generates a service file based on the provided service name.
|
|
9
|
+
* Validates and formats the service name, creates the necessary directories,
|
|
10
|
+
* and generates the service file using a predefined template.
|
|
11
|
+
*
|
|
12
|
+
* @param serviceName - The name of the service to generate.
|
|
13
|
+
* It can include slashes for nested paths.
|
|
14
|
+
* @throws Exits the process if the service name is not provided or invalid.
|
|
15
|
+
*/ generateService(serviceName) {
|
|
16
|
+
if (!serviceName) {
|
|
17
|
+
this.logger.error('Service name is required.');
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
const { parts, kebabCaseName, className } = validateAndFormatName(serviceName);
|
|
21
|
+
const serviceDir = path.join(process.cwd(), 'src', 'services', ...parts);
|
|
22
|
+
const serviceFile = path.join(serviceDir, `${kebabCaseName}.service.ts`);
|
|
23
|
+
const serviceTemplate = buildTemplate(className, 'service.template');
|
|
24
|
+
createDirectoryIfNotExists(serviceDir);
|
|
25
|
+
generateFile(serviceFile, serviceTemplate);
|
|
26
|
+
}
|
|
27
|
+
constructor(appName){
|
|
28
|
+
this.appName = appName;
|
|
29
|
+
this.logger = new Logger(this.appName);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export { ServiceGeneratorHelper };
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import webpack from 'webpack';
|
|
4
|
+
import { Logger } from '../common/logger.js';
|
|
5
|
+
import '../common/theme.js';
|
|
6
|
+
import { spawn } from 'node:child_process';
|
|
7
|
+
import { capitalize } from 'lodash-es';
|
|
8
|
+
import wait from '../util/wait.util.js';
|
|
9
|
+
import { GeneratorCLI } from './generator.js';
|
|
10
|
+
import * as fs from 'node:fs';
|
|
11
|
+
import { setEnvironment, compileAndValidateConfig } from '../util/common.util.js';
|
|
12
|
+
import { Command } from 'commander';
|
|
13
|
+
import { simpleGit } from 'simple-git';
|
|
14
|
+
import chalk from 'chalk';
|
|
15
|
+
import { execSync } from 'child_process';
|
|
16
|
+
import { ensureReady, configureCommandHelp } from '../util/meocord-cli.util.js';
|
|
17
|
+
import packageJson from '../package.json.js';
|
|
18
|
+
import { fileURLToPath } from 'url';
|
|
19
|
+
|
|
20
|
+
const __filename$1 = fileURLToPath(import.meta.url);
|
|
21
|
+
const __dirname$1 = path.dirname(__filename$1);
|
|
22
|
+
/**
|
|
23
|
+
* A Command Line Interface (CLI) for managing the MeoCord application.
|
|
24
|
+
*/ class MeoCordCLI {
|
|
25
|
+
/**
|
|
26
|
+
* Configures and runs the MeoCord CLI.
|
|
27
|
+
*/ async run() {
|
|
28
|
+
let program = new Command();
|
|
29
|
+
program.name(this.appName.toLowerCase()).description(`CLI for managing the ${this.appName} application`).version(this.version);
|
|
30
|
+
program.command('show').description('Display information').option('-w, --warranty', 'Display warranty disclaimer').option('-c, --license', 'Display licensing conditions and usage rights').action((options)=>{
|
|
31
|
+
if (!options.warranty && !options.license) {
|
|
32
|
+
program.commands.find((cmd)=>cmd.name() === 'show')?.outputHelp();
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
if (options.warranty) {
|
|
36
|
+
console.log(`
|
|
37
|
+
This program is distributed in the hope that it will be useful,
|
|
38
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
39
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
40
|
+
|
|
41
|
+
The authors of this software are not responsible for damages caused
|
|
42
|
+
by the usage, misuse, or inability to use the software.
|
|
43
|
+
|
|
44
|
+
See the GNU General Public License for full details:
|
|
45
|
+
<https://www.gnu.org/licenses/>.
|
|
46
|
+
`);
|
|
47
|
+
}
|
|
48
|
+
if (options.license) {
|
|
49
|
+
console.log(`
|
|
50
|
+
This program is free software: you can redistribute it and/or
|
|
51
|
+
modify it under the terms of the GNU General Public License as
|
|
52
|
+
published by the Free Software Foundation, either version 3 of
|
|
53
|
+
the License, or (at your option) any later version.
|
|
54
|
+
|
|
55
|
+
Key conditions of the GNU GPL v3:
|
|
56
|
+
- You can use this software for personal, academic, or commercial purposes.
|
|
57
|
+
- If you distribute modified versions, you must share the source code under the same GPL v3 license.
|
|
58
|
+
- The original copyright must be retained.
|
|
59
|
+
|
|
60
|
+
For full license details, refer to:
|
|
61
|
+
<https://www.gnu.org/licenses/gpl-3.0.txt>
|
|
62
|
+
`);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
program.command('create <app-name>').description('Create a new MeoCord application').action(async (appName)=>await this.createApp(appName));
|
|
66
|
+
program.command('build').description('Build the application').option('-d, --dev', 'Build in development mode').option('-p, --prod', 'Build in production mode').action(async (options)=>{
|
|
67
|
+
await ensureReady();
|
|
68
|
+
const mode = options.prod ? 'production' : 'development';
|
|
69
|
+
setEnvironment(mode);
|
|
70
|
+
await compileAndValidateConfig();
|
|
71
|
+
await this.build(mode);
|
|
72
|
+
});
|
|
73
|
+
program.command('start').description('Start the application').option('-b, --build', 'Pre-build before starting').option('-d, --dev', 'Start in development mode').option('-p, --prod', 'Start in production mode').action(async (options)=>{
|
|
74
|
+
await ensureReady();
|
|
75
|
+
const mode = options.prod ? 'production' : 'development';
|
|
76
|
+
setEnvironment(mode);
|
|
77
|
+
if (options.build || options.dev) {
|
|
78
|
+
await compileAndValidateConfig();
|
|
79
|
+
}
|
|
80
|
+
if (options.build) {
|
|
81
|
+
await this.build(mode);
|
|
82
|
+
}
|
|
83
|
+
options.prod ? await this.startProd() : await this.startDev();
|
|
84
|
+
});
|
|
85
|
+
program = this.generatorCLI.register(program);
|
|
86
|
+
configureCommandHelp(program);
|
|
87
|
+
program.showHelpAfterError().parse(process.argv);
|
|
88
|
+
}
|
|
89
|
+
async createApp(appName) {
|
|
90
|
+
const kebabCaseAppName = appName.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
|
|
91
|
+
const appPath = path.resolve(process.cwd(), kebabCaseAppName);
|
|
92
|
+
const gitRepo = 'https://github.com/l7aromeo/meocord-template.git';
|
|
93
|
+
console.info(chalk.blueBright(`🚀 Creating a new MeoCord app: ${chalk.bold(kebabCaseAppName)}`));
|
|
94
|
+
try {
|
|
95
|
+
// Validate if directory already exists
|
|
96
|
+
if (fs.existsSync(appPath)) {
|
|
97
|
+
console.error(chalk.red(`❌ Directory "${chalk.bold(kebabCaseAppName)}" already exists.`));
|
|
98
|
+
await wait(100);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
// Check Node.js version
|
|
102
|
+
const MINIMUM_NODE_VERSION = '22.14.0';
|
|
103
|
+
const [major, minor, patch] = process.version.slice(1).split('.').map(Number);
|
|
104
|
+
const [minMajor, minMinor, minPatch] = MINIMUM_NODE_VERSION.split('.').map(Number);
|
|
105
|
+
if (major < minMajor || major === minMajor && minor < minMinor || major === minMajor && minor === minMinor && patch < minPatch) {
|
|
106
|
+
console.error(chalk.red(`❌ Node.js v${MINIMUM_NODE_VERSION} or higher is required. Current version: v${process.version}.`));
|
|
107
|
+
await wait(100);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
// Clone the template repository
|
|
111
|
+
console.info(chalk.blueBright('📦 Fetching template...'));
|
|
112
|
+
await simpleGit().clone(gitRepo, appPath);
|
|
113
|
+
console.log(chalk.green(`✔ App successfully created at: ${chalk.bold(appPath)}`));
|
|
114
|
+
// Remove .git history from template
|
|
115
|
+
fs.rmSync(path.join(appPath, '.git'), {
|
|
116
|
+
recursive: true,
|
|
117
|
+
force: true
|
|
118
|
+
});
|
|
119
|
+
// Initialize a new Git repository
|
|
120
|
+
console.info(chalk.blueBright('🔧 Initializing Git repository...'));
|
|
121
|
+
const git = simpleGit(appPath);
|
|
122
|
+
await git.init();
|
|
123
|
+
await git.add('./*');
|
|
124
|
+
await git.commit('Initial commit');
|
|
125
|
+
console.log(chalk.green('✔ Git repository initialized.'));
|
|
126
|
+
// Install dependencies
|
|
127
|
+
console.info(chalk.blueBright('📦 Installing dependencies...'));
|
|
128
|
+
execSync(`cd ${kebabCaseAppName} && corepack enable && yarn install`, {
|
|
129
|
+
stdio: 'inherit'
|
|
130
|
+
});
|
|
131
|
+
console.log(chalk.green('✔ Dependencies installed successfully.'));
|
|
132
|
+
console.log(chalk.greenBright(`🎉 MeoCord app "${chalk.bold(kebabCaseAppName)}" is ready!`));
|
|
133
|
+
} catch (error) {
|
|
134
|
+
console.error(chalk.red(`❌ Failed to create app: ${error instanceof Error ? error.message : String(error)}`));
|
|
135
|
+
await wait(100);
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Builds the MeoCord application in the specified mode.
|
|
141
|
+
*
|
|
142
|
+
* @param mode - The build mode ('production' or 'development').
|
|
143
|
+
*/ async build(mode) {
|
|
144
|
+
try {
|
|
145
|
+
this.clearConsole();
|
|
146
|
+
this.logger.info(`Building ${mode} version...`);
|
|
147
|
+
const webpackConfig = (await import(this.webpackConfigPath)).default;
|
|
148
|
+
const compiler = webpack({
|
|
149
|
+
...webpackConfig,
|
|
150
|
+
mode
|
|
151
|
+
});
|
|
152
|
+
if (!compiler) {
|
|
153
|
+
this.logger.error('Failed to create webpack compiler instance.');
|
|
154
|
+
throw new Error('Failed to create webpack compiler instance.');
|
|
155
|
+
}
|
|
156
|
+
// Workaround for Bun: Keep the event loop alive while webpack runs
|
|
157
|
+
// Bun sometimes exits before async callbacks fire
|
|
158
|
+
let keepAliveTimer = null;
|
|
159
|
+
await new Promise((resolve, reject)=>{
|
|
160
|
+
keepAliveTimer = setInterval(()=>{
|
|
161
|
+
// Keeps event loop active
|
|
162
|
+
}, 100);
|
|
163
|
+
compiler.run((err, stats)=>{
|
|
164
|
+
if (keepAliveTimer) {
|
|
165
|
+
clearInterval(keepAliveTimer);
|
|
166
|
+
keepAliveTimer = null;
|
|
167
|
+
}
|
|
168
|
+
if (err) {
|
|
169
|
+
this.logger.error(`Build encountered an error: ${err.message}`);
|
|
170
|
+
return reject(`Build encountered an error: ${err.message}`);
|
|
171
|
+
}
|
|
172
|
+
if (stats?.hasErrors()) {
|
|
173
|
+
this.logger.error('Build failed due to errors in the compilation process:', stats.compilation.errors);
|
|
174
|
+
} else {
|
|
175
|
+
this.logger.info(`${capitalize(mode)} build completed successfully.`);
|
|
176
|
+
}
|
|
177
|
+
compiler.close((closeErr)=>{
|
|
178
|
+
if (closeErr) {
|
|
179
|
+
this.logger.error(`Error occurred while closing the compiler: ${closeErr.message}`);
|
|
180
|
+
return reject(`Error occurred while closing the compiler: ${closeErr.message}`);
|
|
181
|
+
}
|
|
182
|
+
resolve();
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
} catch (error) {
|
|
187
|
+
this.logger.error(`Build process failed: ${error.message}`);
|
|
188
|
+
await wait(100);
|
|
189
|
+
process.exit(1);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Starts the MeoCord application in development mode with live updates.
|
|
194
|
+
*/ async startDev() {
|
|
195
|
+
try {
|
|
196
|
+
this.clearConsole();
|
|
197
|
+
this.logger.log('Starting watch mode...');
|
|
198
|
+
const webpackConfig = (await import(this.webpackConfigPath)).default;
|
|
199
|
+
const compiler = webpack({
|
|
200
|
+
...webpackConfig,
|
|
201
|
+
mode: 'development'
|
|
202
|
+
});
|
|
203
|
+
if (!compiler) {
|
|
204
|
+
this.logger.error('Failed to create webpack compiler instance.');
|
|
205
|
+
await wait(100);
|
|
206
|
+
process.exit(1);
|
|
207
|
+
}
|
|
208
|
+
let nodemonProcess = null;
|
|
209
|
+
let isRunning = false;
|
|
210
|
+
const watch = ()=>compiler.watch({}, (err, stats)=>{
|
|
211
|
+
if (err) {
|
|
212
|
+
this.logger.error(`Webpack Error: ${err.message}`);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (stats?.hasErrors()) {
|
|
216
|
+
this.logger.error('Build failed due to errors in the compilation process:', stats.compilation.errors);
|
|
217
|
+
} else {
|
|
218
|
+
if (nodemonProcess) {
|
|
219
|
+
nodemonProcess.kill();
|
|
220
|
+
nodemonProcess = null;
|
|
221
|
+
}
|
|
222
|
+
nodemonProcess = spawn('npx -y nodemon', [
|
|
223
|
+
'-q',
|
|
224
|
+
this.mainJSPath
|
|
225
|
+
], {
|
|
226
|
+
shell: true,
|
|
227
|
+
cwd: this.projectRoot,
|
|
228
|
+
stdio: 'inherit'
|
|
229
|
+
});
|
|
230
|
+
isRunning = true;
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
watch();
|
|
234
|
+
let debounceWatcher;
|
|
235
|
+
const fsWatcher = fs.watch(path.resolve(process.cwd(), 'meocord.config.ts'), ()=>{
|
|
236
|
+
clearTimeout(debounceWatcher);
|
|
237
|
+
debounceWatcher = setTimeout(async ()=>{
|
|
238
|
+
if (isRunning && nodemonProcess) {
|
|
239
|
+
isRunning = false;
|
|
240
|
+
this.logger.log('MeoCord config change detected, reloading config...');
|
|
241
|
+
if (nodemonProcess && !nodemonProcess.killed) {
|
|
242
|
+
nodemonProcess.kill();
|
|
243
|
+
nodemonProcess = null;
|
|
244
|
+
}
|
|
245
|
+
await new Promise((resolve)=>compiler.close(resolve));
|
|
246
|
+
watch();
|
|
247
|
+
}
|
|
248
|
+
}, 300);
|
|
249
|
+
});
|
|
250
|
+
let sigintReceived = false;
|
|
251
|
+
process.on('SIGINT', async ()=>{
|
|
252
|
+
if (sigintReceived) {
|
|
253
|
+
// Second Ctrl+C — force kill and exit immediately
|
|
254
|
+
if (nodemonProcess && !nodemonProcess.killed) nodemonProcess.kill('SIGKILL');
|
|
255
|
+
process.exit(1);
|
|
256
|
+
}
|
|
257
|
+
sigintReceived = true;
|
|
258
|
+
// Nodemon and the bot already received SIGINT from the process group.
|
|
259
|
+
// Clean up parent-owned resources and wait for nodemon to exit.
|
|
260
|
+
fsWatcher.close();
|
|
261
|
+
if (nodemonProcess && !nodemonProcess.killed) {
|
|
262
|
+
nodemonProcess.on('exit', async ()=>{
|
|
263
|
+
await new Promise((resolve)=>compiler.close(resolve));
|
|
264
|
+
process.exit(0);
|
|
265
|
+
});
|
|
266
|
+
} else {
|
|
267
|
+
await new Promise((resolve)=>compiler.close(resolve));
|
|
268
|
+
process.exit(0);
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
} catch (error) {
|
|
272
|
+
this.logger.error(`Failed to start: ${error.message}`);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Starts the MeoCord application in production mode.
|
|
277
|
+
*/ async startProd() {
|
|
278
|
+
try {
|
|
279
|
+
// Check if mainJS exists before proceeding
|
|
280
|
+
if (!fs.existsSync(this.mainJSPath)) {
|
|
281
|
+
this.logger.error(`Main entry file (main.js) not found! You might need to build before running in production mode.`);
|
|
282
|
+
await wait(100);
|
|
283
|
+
process.exit(1);
|
|
284
|
+
}
|
|
285
|
+
this.clearConsole();
|
|
286
|
+
this.logger.log('Starting...');
|
|
287
|
+
const start = spawn(`node ${this.mainJSPath}`, {
|
|
288
|
+
shell: true,
|
|
289
|
+
cwd: this.projectRoot,
|
|
290
|
+
stdio: 'inherit'
|
|
291
|
+
}).on('spawn', this.clearConsole);
|
|
292
|
+
start.on('exit', (code)=>{
|
|
293
|
+
process.exit(code ?? 0);
|
|
294
|
+
});
|
|
295
|
+
let sigintReceived = false;
|
|
296
|
+
process.on('SIGINT', ()=>{
|
|
297
|
+
if (sigintReceived) {
|
|
298
|
+
// Second Ctrl+C — force kill child and exit immediately
|
|
299
|
+
if (!start.killed) start.kill('SIGKILL');
|
|
300
|
+
process.exit(1);
|
|
301
|
+
}
|
|
302
|
+
sigintReceived = true;
|
|
303
|
+
// Child process receives SIGINT from the process group directly.
|
|
304
|
+
// Wait for it to exit via the 'exit' handler above.
|
|
305
|
+
});
|
|
306
|
+
} catch (error) {
|
|
307
|
+
this.logger.error('Failed to start:', error instanceof Error ? error.message : String(error));
|
|
308
|
+
await wait(100);
|
|
309
|
+
process.exit(1);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Clears the console on all platforms.
|
|
314
|
+
*/ clearConsole() {
|
|
315
|
+
process.stdout.write('\u001b[3J\u001b[2J\u001b[H');
|
|
316
|
+
}
|
|
317
|
+
constructor(){
|
|
318
|
+
this.appName = 'MeoCord';
|
|
319
|
+
this.logger = new Logger(this.appName);
|
|
320
|
+
this.projectRoot = process.cwd();
|
|
321
|
+
this.mainJSPath = path.join(this.projectRoot, 'dist', 'main.js');
|
|
322
|
+
this.webpackConfigPath = path.resolve(__dirname$1, '..', '..', '..', 'webpack.config.js');
|
|
323
|
+
this.generatorCLI = new GeneratorCLI(this.appName);
|
|
324
|
+
this.version = packageJson.version;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
// Create an instance of the CLI and run it
|
|
328
|
+
const cli = new MeoCordCLI();
|
|
329
|
+
cli.run().catch(async (error)=>{
|
|
330
|
+
cli.logger.error('Failed to initialize CLI:', error?.message || error);
|
|
331
|
+
await wait(100);
|
|
332
|
+
process.exit(1);
|
|
333
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { inspect } from 'node:util';
|
|
2
|
+
import dayjs from 'dayjs';
|
|
3
|
+
import utc from 'dayjs/plugin/utc.js';
|
|
4
|
+
import timezone from 'dayjs/plugin/timezone.js';
|
|
5
|
+
import { loadMeoCordConfig } from '../util/meocord-config-loader.util.js';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
|
|
8
|
+
dayjs.extend(utc);
|
|
9
|
+
dayjs.extend(timezone);
|
|
10
|
+
class Logger {
|
|
11
|
+
log(...args) {
|
|
12
|
+
this.logWithContext('log', args);
|
|
13
|
+
}
|
|
14
|
+
info(...args) {
|
|
15
|
+
this.logWithContext('log', args);
|
|
16
|
+
}
|
|
17
|
+
warn(...args) {
|
|
18
|
+
this.logWithContext('warn', args);
|
|
19
|
+
}
|
|
20
|
+
error(...args) {
|
|
21
|
+
this.logWithContext('error', args);
|
|
22
|
+
}
|
|
23
|
+
debug(...args) {
|
|
24
|
+
this.logWithContext('debug', args);
|
|
25
|
+
}
|
|
26
|
+
verbose(...args) {
|
|
27
|
+
this.logWithContext('log', args);
|
|
28
|
+
}
|
|
29
|
+
formatMessage(message, logType) {
|
|
30
|
+
if (typeof message === 'object' && message !== null) {
|
|
31
|
+
return inspect(message, {
|
|
32
|
+
showHidden: true,
|
|
33
|
+
depth: null,
|
|
34
|
+
colors: true,
|
|
35
|
+
compact: false,
|
|
36
|
+
showProxy: true
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
return (this.colorMap[logType] || ((msg)=>msg))(message);
|
|
40
|
+
}
|
|
41
|
+
logWithContext(logLevel, messages) {
|
|
42
|
+
if (messages.length === 0) return;
|
|
43
|
+
const config = loadMeoCordConfig();
|
|
44
|
+
const logType = logLevel.toUpperCase();
|
|
45
|
+
const applyColor = this.colorMap[logType] || ((msg)=>msg);
|
|
46
|
+
const formattedMessages = messages.map((message)=>this.formatMessage(message, logType));
|
|
47
|
+
const coloredAppName = config?.appName ? applyColor(chalk.bold(`[${config.appName}]`)) : undefined;
|
|
48
|
+
const timestamp = chalk.bold(dayjs().format('dddd, MMMM D, YYYY HH:mm:ss [UTC]Z'));
|
|
49
|
+
const coloredLogLevel = applyColor(chalk.bold(`[${logType}]`));
|
|
50
|
+
const coloredContext = this.context ? chalk.yellow.bold(`[${this.context}]`) : '';
|
|
51
|
+
const logTexts = [
|
|
52
|
+
coloredAppName,
|
|
53
|
+
timestamp,
|
|
54
|
+
coloredLogLevel,
|
|
55
|
+
coloredContext,
|
|
56
|
+
...formattedMessages
|
|
57
|
+
].filter((log)=>!!log);
|
|
58
|
+
console[logLevel](...logTexts);
|
|
59
|
+
}
|
|
60
|
+
constructor(context){
|
|
61
|
+
this.context = context;
|
|
62
|
+
this.colorMap = {
|
|
63
|
+
LOG: chalk.green,
|
|
64
|
+
INFO: chalk.cyan,
|
|
65
|
+
WARN: chalk.yellow,
|
|
66
|
+
ERROR: chalk.red,
|
|
67
|
+
DEBUG: chalk.magenta
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export { Logger };
|
|
@@ -14,5 +14,11 @@
|
|
|
14
14
|
*
|
|
15
15
|
* You should have received a copy of the GNU General Public License
|
|
16
16
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
-
*/
|
|
18
|
-
|
|
17
|
+
*/ class Theme {
|
|
18
|
+
}
|
|
19
|
+
Theme.successColor = '#28A745';
|
|
20
|
+
Theme.infoColor = '#17A2B8';
|
|
21
|
+
Theme.errorColor = '#DC3545';
|
|
22
|
+
Theme.warningColor = '#FFC107';
|
|
23
|
+
|
|
24
|
+
export { Theme };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { MeoCordFactory } from './meocord-factory.js';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { Logger } from '../common/logger.js';
|
|
3
|
+
import '../common/theme.js';
|
|
4
|
+
import { MeoCordApp } from './meocord.app.js';
|
|
5
|
+
import { mainContainer } from '../decorator/container.js';
|
|
6
|
+
import 'inversify';
|
|
7
|
+
import 'discord.js';
|
|
8
|
+
import 'path';
|
|
9
|
+
import 'fs';
|
|
10
|
+
import 'jiti';
|
|
11
|
+
|
|
12
|
+
class MeoCordFactory {
|
|
13
|
+
static create(target) {
|
|
14
|
+
const container = Reflect.getMetadata('inversify:container', target);
|
|
15
|
+
if (!container) {
|
|
16
|
+
if (typeof target === 'function') {
|
|
17
|
+
this.logger.error(`No container found for class: ${target.name}`);
|
|
18
|
+
} else {
|
|
19
|
+
this.logger.error('No container found for the provided target.');
|
|
20
|
+
}
|
|
21
|
+
throw new Error('No container found on the target class.');
|
|
22
|
+
}
|
|
23
|
+
return mainContainer.get(MeoCordApp);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
MeoCordFactory.logger = new Logger();
|
|
27
|
+
|
|
28
|
+
export { MeoCordFactory };
|