meocord 3.0.0 → 3.2.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.
- package/AUTHOR.md +2 -3
- package/README.md +361 -55
- package/dist/cjs/_shared/controller.decorator-MUHA_A3z.cjs +529 -0
- package/dist/cjs/core/index.cjs +246 -86
- package/dist/cjs/decorator/index.cjs +4 -2
- package/dist/cjs/enum/index.cjs +17 -4
- package/dist/cjs/testing/index.cjs +88 -4
- package/dist/esm/bin/app-template/README.md.template +61 -0
- package/dist/esm/bin/app-template/_env.example.template +2 -0
- package/dist/esm/bin/app-template/_gitignore.template +22 -0
- package/dist/esm/bin/app-template/_prettierrc.mjs.template +10 -0
- package/dist/esm/bin/app-template/eslint.config.ts.template +25 -0
- package/dist/esm/bin/app-template/meocord.config.ts.template +25 -0
- package/dist/esm/bin/app-template/package.json.template +38 -0
- package/dist/esm/bin/app-template/src/app.ts.template +44 -0
- package/dist/esm/bin/app-template/src/controllers/button/sample.button.controller.spec.ts.template +17 -0
- package/dist/esm/bin/app-template/src/controllers/button/sample.button.controller.ts.template +19 -0
- package/dist/esm/bin/app-template/src/controllers/context-menu/builders/sample.builder.ts.template +10 -0
- package/dist/esm/bin/app-template/src/controllers/context-menu/sample.context-menu.controller.spec.ts.template +17 -0
- package/dist/esm/bin/app-template/src/controllers/context-menu/sample.context-menu.controller.ts.template +13 -0
- package/dist/esm/bin/app-template/src/controllers/message/sample.message.controller.spec.ts.template +17 -0
- package/dist/esm/bin/app-template/src/controllers/message/sample.message.controller.ts.template +28 -0
- package/dist/esm/bin/app-template/src/controllers/modal-submit/sample.modal-submit.controller.spec.ts.template +17 -0
- package/dist/esm/bin/app-template/src/controllers/modal-submit/sample.modal-submit.controller.ts.template +13 -0
- package/dist/esm/bin/app-template/src/controllers/reaction/sample.reaction.controller.spec.ts.template +17 -0
- package/dist/esm/bin/app-template/src/controllers/reaction/sample.reaction.controller.ts.template +29 -0
- package/dist/esm/bin/app-template/src/controllers/select-menu/sample.select-menu.controller.spec.ts.template +17 -0
- package/dist/esm/bin/app-template/src/controllers/select-menu/sample.select-menu.controller.ts.template +11 -0
- package/dist/esm/bin/app-template/src/controllers/slash/builders/sample.builder.ts.template +10 -0
- package/dist/esm/bin/app-template/src/controllers/slash/sample.slash.controller.spec.ts.template +17 -0
- package/dist/esm/bin/app-template/src/controllers/slash/sample.slash.controller.ts.template +19 -0
- package/dist/esm/bin/app-template/src/guards/rate-limit.guard.spec.ts.template +13 -0
- package/dist/esm/bin/app-template/src/guards/rate-limit.guard.ts.template +52 -0
- package/dist/esm/bin/app-template/src/main.ts.template +14 -0
- package/dist/esm/bin/app-template/src/services/sample.service.spec.ts.template +17 -0
- package/dist/esm/bin/app-template/src/services/sample.service.ts.template +9 -0
- package/dist/esm/bin/app-template/tsconfig.eslint.json.template +5 -0
- package/dist/esm/bin/app-template/tsconfig.json.template +30 -0
- package/dist/esm/bin/app-template/tsconfig.test.json.template +8 -0
- package/dist/esm/bin/app-template/vitest.config.ts.template +35 -0
- package/dist/esm/bin/builder-template/builder/primary-entry-point.builder.template +26 -0
- package/dist/esm/bin/builder-template/controller/autocomplete.controller.template +16 -0
- package/dist/esm/bin/builder-template/controller/button.controller.template +1 -1
- package/dist/esm/bin/builder-template/controller/channel-select-menu.controller.template +12 -0
- package/dist/esm/bin/builder-template/controller/context-menu.controller.template +2 -2
- package/dist/esm/bin/builder-template/controller/mentionable-select-menu.controller.template +12 -0
- package/dist/esm/bin/builder-template/controller/modal-submit.controller.template +1 -1
- package/dist/esm/bin/builder-template/controller/primary-entry-point.controller.template +12 -0
- package/dist/esm/bin/builder-template/controller/role-select-menu.controller.template +12 -0
- package/dist/esm/bin/builder-template/controller/slash.controller.template +1 -1
- package/dist/esm/bin/builder-template/controller/user-select-menu.controller.template +12 -0
- package/dist/esm/bin/generator.js +4 -9
- package/dist/esm/bin/helper/app-generator.helper.js +78 -0
- package/dist/esm/bin/helper/controller-generator.helper.js +24 -7
- package/dist/esm/bin/meocord.js +156 -75
- package/dist/esm/core/meocord.app.js +247 -86
- package/dist/esm/decorator/controller.decorator.js +73 -10
- package/dist/esm/decorator/guard.decorator.js +1 -1
- package/dist/esm/decorator/index.js +1 -1
- package/dist/esm/enum/controller.enum.js +23 -4
- package/dist/esm/testing/mock-interaction.js +89 -5
- package/dist/esm/util/common.util.js +11 -3
- package/dist/esm/util/generator-cli.util.js +21 -4
- package/dist/esm/util/interaction.util.js +174 -0
- package/dist/esm/util/package-manager.util.js +9 -2
- package/dist/esm/util/package-version.util.js +32 -0
- package/dist/esm/util/runtime.util.js +72 -0
- package/dist/types/controller.enum-DYfhYaat.d.ts +36 -0
- package/dist/types/core/index.d.ts +75 -2
- package/dist/types/decorator/index.d.ts +61 -49
- package/dist/types/enum/index.d.ts +1 -1
- package/dist/types/interface/index.d.ts +89 -3
- package/dist/types/testing/index.d.ts +3 -21
- package/package.json +11 -12
- package/dist/cjs/_shared/controller.decorator-CC6BjHkS.cjs +0 -288
- package/dist/types/controller.enum-QA-IuReF.d.ts +0 -18
package/dist/esm/bin/meocord.js
CHANGED
|
@@ -7,8 +7,9 @@ import { spawn } from 'node:child_process';
|
|
|
7
7
|
import { capitalize } from 'lodash-es';
|
|
8
8
|
import wait from '../util/wait.util.js';
|
|
9
9
|
import { GeneratorCLI } from './generator.js';
|
|
10
|
+
import { runtimePrefixFor, AppGeneratorHelper } from './helper/app-generator.helper.js';
|
|
10
11
|
import * as fs from 'node:fs';
|
|
11
|
-
import { setEnvironment, compileAndValidateConfig } from '../util/common.util.js';
|
|
12
|
+
import { setEnvironment, compileAndValidateConfig, validateDiscordToken } from '../util/common.util.js';
|
|
12
13
|
import { prepareModifiedTsConfig } from '../util/tsconfig.util.js';
|
|
13
14
|
import { Command } from 'commander';
|
|
14
15
|
import { simpleGit } from 'simple-git';
|
|
@@ -16,6 +17,8 @@ import { execSync } from 'child_process';
|
|
|
16
17
|
import * as p from '@clack/prompts';
|
|
17
18
|
import { detectInstalledPMs, getInstallCommand } from '../util/package-manager.util.js';
|
|
18
19
|
import { ensureReady, configureCommandHelp } from '../util/meocord-cli.util.js';
|
|
20
|
+
import { resolveOwnVersion } from '../util/package-version.util.js';
|
|
21
|
+
import { buildAppCommand, resolveRuntime } from '../util/runtime.util.js';
|
|
19
22
|
import packageJson from '../package.json.js';
|
|
20
23
|
import { fileURLToPath } from 'url';
|
|
21
24
|
import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin';
|
|
@@ -25,7 +28,35 @@ const __filename$1 = fileURLToPath(import.meta.url);
|
|
|
25
28
|
const __dirname$1 = path.dirname(__filename$1);
|
|
26
29
|
/**
|
|
27
30
|
* A Command Line Interface (CLI) for managing the MeoCord application.
|
|
28
|
-
*/
|
|
31
|
+
*/ /**
|
|
32
|
+
* Oldest Node the framework supports, mirroring `engines.node`.
|
|
33
|
+
*
|
|
34
|
+
* A test holds the two together, since a floor that drifted from the manifest would warn
|
|
35
|
+
* about versions npm is happy to install on.
|
|
36
|
+
*/ const MINIMUM_NODE_MAJOR = 22;
|
|
37
|
+
/**
|
|
38
|
+
* Warns when the running Node is older than the framework supports.
|
|
39
|
+
*
|
|
40
|
+
* Advisory only. Comparing against the newest LTS release meant warning about being a
|
|
41
|
+
* patch behind, and reaching the network to find out meant a failed request could stop
|
|
42
|
+
* the command outright — for a check whose only outcome is a warning.
|
|
43
|
+
*/ function warnIfNodeIsBelowSupported() {
|
|
44
|
+
const major = Number.parseInt(process.versions.node.split('.')[0], 10);
|
|
45
|
+
if (Number.isFinite(major) && major < MINIMUM_NODE_MAJOR) {
|
|
46
|
+
p.log.warn(`Node ${process.versions.node} is older than the supported minimum (v${MINIMUM_NODE_MAJOR}). ` + `The app will be created, but may not run.`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The package manager's own complaint, which `execSync` buries on the thrown object.
|
|
51
|
+
*
|
|
52
|
+
* Its `message` says only that a command exited non-zero, which is never the part worth
|
|
53
|
+
* reading.
|
|
54
|
+
*/ function installFailure(error) {
|
|
55
|
+
const { stderr, message } = error ?? {};
|
|
56
|
+
const reported = stderr?.toString().trim();
|
|
57
|
+
return new Error(reported || message || String(error));
|
|
58
|
+
}
|
|
59
|
+
class MeoCordCLI {
|
|
29
60
|
/**
|
|
30
61
|
* Configures and runs the MeoCord CLI.
|
|
31
62
|
*/ async run() {
|
|
@@ -81,6 +112,9 @@ copies or substantial portions of the Software.
|
|
|
81
112
|
if (options.build || options.dev) {
|
|
82
113
|
await compileAndValidateConfig();
|
|
83
114
|
}
|
|
115
|
+
// Checked for every start, including one that skips the build: this is the point
|
|
116
|
+
// where the application actually needs to log in.
|
|
117
|
+
await validateDiscordToken();
|
|
84
118
|
if (options.build) {
|
|
85
119
|
await this.build(mode);
|
|
86
120
|
await this.compileConfig();
|
|
@@ -94,7 +128,6 @@ copies or substantial portions of the Software.
|
|
|
94
128
|
async createApp(appName, options) {
|
|
95
129
|
const kebabCaseAppName = appName.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
|
|
96
130
|
const appPath = path.resolve(process.cwd(), kebabCaseAppName);
|
|
97
|
-
const gitRepo = 'https://github.com/l7aromeo/meocord-template.git';
|
|
98
131
|
p.intro(`meocord v${this.version}`);
|
|
99
132
|
// Validate directory
|
|
100
133
|
if (fs.existsSync(appPath)) {
|
|
@@ -102,24 +135,7 @@ copies or substantial portions of the Software.
|
|
|
102
135
|
await wait(100);
|
|
103
136
|
process.exit(1);
|
|
104
137
|
}
|
|
105
|
-
|
|
106
|
-
try {
|
|
107
|
-
const res = await fetch('https://nodejs.org/dist/index.json');
|
|
108
|
-
const releases = await res.json();
|
|
109
|
-
const ltsRelease = releases.find((r)=>r.lts !== false);
|
|
110
|
-
if (ltsRelease) latestLTS = ltsRelease.version.slice(1);
|
|
111
|
-
} catch {
|
|
112
|
-
p.cancel('No internet connection. Creating a MeoCord app requires network access.');
|
|
113
|
-
await wait(100);
|
|
114
|
-
process.exit(1);
|
|
115
|
-
}
|
|
116
|
-
if (latestLTS) {
|
|
117
|
-
const [major, minor, patch] = process.version.slice(1).split('.').map(Number);
|
|
118
|
-
const [minMajor, minMinor, minPatch] = latestLTS.split('.').map(Number);
|
|
119
|
-
if (major < minMajor || major === minMajor && minor < minMinor || major === minMajor && minor === minMinor && patch < minPatch) {
|
|
120
|
-
p.log.warn(`Your Node.js (${process.version}) is behind the latest LTS (v${latestLTS}). Consider upgrading for best compatibility.`);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
138
|
+
warnIfNodeIsBelowSupported();
|
|
123
139
|
// Determine package manager
|
|
124
140
|
const installedPMs = detectInstalledPMs();
|
|
125
141
|
let pm;
|
|
@@ -155,47 +171,42 @@ copies or substantial portions of the Software.
|
|
|
155
171
|
pm = selected;
|
|
156
172
|
}
|
|
157
173
|
const s = p.spinner();
|
|
158
|
-
// Clone template
|
|
159
174
|
s.start(`Creating a new MeoCord app: ${kebabCaseAppName}`);
|
|
160
175
|
try {
|
|
161
|
-
|
|
176
|
+
this.appGeneratorHelper.generateApp(appPath, {
|
|
177
|
+
appName: kebabCaseAppName,
|
|
178
|
+
displayName: appName,
|
|
179
|
+
version: this.version,
|
|
180
|
+
packageManager: pm,
|
|
181
|
+
runtimePrefix: runtimePrefixFor(pm)
|
|
182
|
+
});
|
|
162
183
|
} catch (error) {
|
|
163
|
-
s.stop('Failed to
|
|
164
|
-
|
|
165
|
-
await wait(100);
|
|
166
|
-
process.exit(1);
|
|
184
|
+
s.stop('Failed to create the app.');
|
|
185
|
+
await this.abortCreate(appPath, error);
|
|
167
186
|
}
|
|
168
187
|
s.stop(`App created at: ${appPath}`);
|
|
169
|
-
// Initialize git
|
|
170
188
|
s.start('Initializing Git repository...');
|
|
171
189
|
try {
|
|
172
|
-
fs.rmSync(path.join(appPath, '.git'), {
|
|
173
|
-
recursive: true,
|
|
174
|
-
force: true
|
|
175
|
-
});
|
|
176
190
|
const git = simpleGit(appPath);
|
|
177
191
|
await git.init();
|
|
178
192
|
await git.add('./*');
|
|
179
193
|
await git.commit('Initial commit');
|
|
180
194
|
} catch (error) {
|
|
181
195
|
s.stop('Failed to initialize Git.');
|
|
182
|
-
|
|
183
|
-
await wait(100);
|
|
184
|
-
process.exit(1);
|
|
196
|
+
await this.abortCreate(appPath, error);
|
|
185
197
|
}
|
|
186
198
|
s.stop('Git repository initialized.');
|
|
187
|
-
// Install dependencies
|
|
188
199
|
s.start(`Installing dependencies with ${pm}...`);
|
|
189
200
|
try {
|
|
201
|
+
// Output is captured rather than discarded: a failed install is only actionable
|
|
202
|
+
// if the resolver's complaint survives to the error message.
|
|
190
203
|
execSync(getInstallCommand(pm), {
|
|
191
204
|
cwd: appPath,
|
|
192
|
-
stdio: '
|
|
205
|
+
stdio: 'pipe'
|
|
193
206
|
});
|
|
194
207
|
} catch (error) {
|
|
195
208
|
s.stop('Failed to install dependencies.');
|
|
196
|
-
|
|
197
|
-
await wait(100);
|
|
198
|
-
process.exit(1);
|
|
209
|
+
await this.abortCreate(appPath, installFailure(error));
|
|
199
210
|
}
|
|
200
211
|
s.stop('Dependencies installed.');
|
|
201
212
|
p.outro(`MeoCord app "${kebabCaseAppName}" is ready!`);
|
|
@@ -341,6 +352,40 @@ copies or substantial portions of the Software.
|
|
|
341
352
|
}
|
|
342
353
|
}
|
|
343
354
|
/**
|
|
355
|
+
* Replaces the running application with one built from the current sources.
|
|
356
|
+
*
|
|
357
|
+
* The replacement is spawned only once the previous process has exited. Both would
|
|
358
|
+
* hold the same gateway session, and claiming it before the first lets go produces a
|
|
359
|
+
* login conflict rather than a reload.
|
|
360
|
+
*/ restartApp() {
|
|
361
|
+
const previous = this.appProcess;
|
|
362
|
+
this.appProcess = null;
|
|
363
|
+
if (!previous || previous.killed) {
|
|
364
|
+
this.appProcess = this.spawnApp();
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
previous.removeAllListeners('exit');
|
|
368
|
+
previous.once('exit', ()=>{
|
|
369
|
+
this.appProcess = this.spawnApp();
|
|
370
|
+
});
|
|
371
|
+
previous.kill();
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Runs the built application.
|
|
375
|
+
*
|
|
376
|
+
* Shared by both start modes so watching and production launch the bundle the same
|
|
377
|
+
* way; a watcher that spawned it differently could pass in development and fail in
|
|
378
|
+
* production on the difference alone.
|
|
379
|
+
*
|
|
380
|
+
* @returns The application process.
|
|
381
|
+
*/ spawnApp() {
|
|
382
|
+
const { command, args } = buildAppCommand(this.runtime, this.mainJSPath);
|
|
383
|
+
return spawn(command, args, {
|
|
384
|
+
cwd: this.projectRoot,
|
|
385
|
+
stdio: 'inherit'
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
344
389
|
* Starts the MeoCord application in development mode with live updates.
|
|
345
390
|
*/ async startDev() {
|
|
346
391
|
try {
|
|
@@ -357,7 +402,6 @@ copies or substantial portions of the Software.
|
|
|
357
402
|
await wait(100);
|
|
358
403
|
process.exit(1);
|
|
359
404
|
}
|
|
360
|
-
let nodemonProcess = null;
|
|
361
405
|
let isRunning = false;
|
|
362
406
|
const watch = ()=>compiler.watch({}, (err, stats)=>{
|
|
363
407
|
if (err) {
|
|
@@ -367,18 +411,7 @@ copies or substantial portions of the Software.
|
|
|
367
411
|
if (stats?.hasErrors()) {
|
|
368
412
|
this.logger.error('Build failed due to errors in the compilation process:', stats.compilation.errors);
|
|
369
413
|
} else {
|
|
370
|
-
|
|
371
|
-
nodemonProcess.kill();
|
|
372
|
-
nodemonProcess = null;
|
|
373
|
-
}
|
|
374
|
-
nodemonProcess = spawn('npx -y nodemon', [
|
|
375
|
-
'-q',
|
|
376
|
-
this.mainJSPath
|
|
377
|
-
], {
|
|
378
|
-
shell: true,
|
|
379
|
-
cwd: this.projectRoot,
|
|
380
|
-
stdio: 'inherit'
|
|
381
|
-
});
|
|
414
|
+
this.restartApp();
|
|
382
415
|
isRunning = true;
|
|
383
416
|
}
|
|
384
417
|
});
|
|
@@ -387,12 +420,12 @@ copies or substantial portions of the Software.
|
|
|
387
420
|
const fsWatcher = fs.watch(path.resolve(process.cwd(), 'meocord.config.ts'), ()=>{
|
|
388
421
|
clearTimeout(debounceWatcher);
|
|
389
422
|
debounceWatcher = setTimeout(async ()=>{
|
|
390
|
-
if (isRunning &&
|
|
423
|
+
if (isRunning && this.appProcess) {
|
|
391
424
|
isRunning = false;
|
|
392
425
|
this.logger.log('MeoCord config change detected, reloading config...');
|
|
393
|
-
if (
|
|
394
|
-
|
|
395
|
-
|
|
426
|
+
if (this.appProcess && !this.appProcess.killed) {
|
|
427
|
+
this.appProcess.kill();
|
|
428
|
+
this.appProcess = null;
|
|
396
429
|
}
|
|
397
430
|
await new Promise((resolve)=>compiler.close(resolve));
|
|
398
431
|
watch();
|
|
@@ -403,15 +436,15 @@ copies or substantial portions of the Software.
|
|
|
403
436
|
process.on('SIGINT', async ()=>{
|
|
404
437
|
if (sigintReceived) {
|
|
405
438
|
// Second Ctrl+C — force kill and exit immediately
|
|
406
|
-
if (
|
|
439
|
+
if (this.appProcess && !this.appProcess.killed) this.appProcess.kill('SIGKILL');
|
|
407
440
|
process.exit(1);
|
|
408
441
|
}
|
|
409
442
|
sigintReceived = true;
|
|
410
|
-
//
|
|
411
|
-
//
|
|
443
|
+
// The application already received SIGINT from the process group. Clean up
|
|
444
|
+
// parent-owned resources and wait for it to exit on its own terms.
|
|
412
445
|
fsWatcher.close();
|
|
413
|
-
if (
|
|
414
|
-
|
|
446
|
+
if (this.appProcess && !this.appProcess.killed) {
|
|
447
|
+
this.appProcess.on('exit', async ()=>{
|
|
415
448
|
await new Promise((resolve)=>compiler.close(resolve));
|
|
416
449
|
process.exit(0);
|
|
417
450
|
});
|
|
@@ -436,11 +469,7 @@ copies or substantial portions of the Software.
|
|
|
436
469
|
}
|
|
437
470
|
this.clearConsole();
|
|
438
471
|
this.logger.log('Starting...');
|
|
439
|
-
const start = spawn
|
|
440
|
-
shell: true,
|
|
441
|
-
cwd: this.projectRoot,
|
|
442
|
-
stdio: 'inherit'
|
|
443
|
-
}).on('spawn', this.clearConsole);
|
|
472
|
+
const start = this.spawnApp().on('spawn', this.clearConsole);
|
|
444
473
|
start.on('exit', (code)=>{
|
|
445
474
|
process.exit(code ?? 0);
|
|
446
475
|
});
|
|
@@ -462,6 +491,20 @@ copies or substantial portions of the Software.
|
|
|
462
491
|
}
|
|
463
492
|
}
|
|
464
493
|
/**
|
|
494
|
+
* Reports why creation failed and removes what was written.
|
|
495
|
+
*
|
|
496
|
+
* A directory left behind from a failed attempt is indistinguishable from one the user
|
|
497
|
+
* meant to keep, and the next attempt refuses to start because the name is taken.
|
|
498
|
+
*/ async abortCreate(appPath, error) {
|
|
499
|
+
fs.rmSync(appPath, {
|
|
500
|
+
recursive: true,
|
|
501
|
+
force: true
|
|
502
|
+
});
|
|
503
|
+
p.cancel(error instanceof Error ? error.message : String(error));
|
|
504
|
+
await wait(100);
|
|
505
|
+
process.exit(1);
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
465
508
|
* Clears the console on all platforms.
|
|
466
509
|
*/ clearConsole() {
|
|
467
510
|
process.stdout.write('\u001b[3J\u001b[2J\u001b[H');
|
|
@@ -473,13 +516,51 @@ copies or substantial portions of the Software.
|
|
|
473
516
|
this.mainJSPath = path.join(this.projectRoot, 'dist', 'main.js');
|
|
474
517
|
this.webpackConfigPath = path.resolve(__dirname$1, '..', '..', '..', 'webpack.config.js');
|
|
475
518
|
this.generatorCLI = new GeneratorCLI(this.appName);
|
|
476
|
-
this.
|
|
519
|
+
this.appGeneratorHelper = new AppGeneratorHelper();
|
|
520
|
+
this.version = resolveOwnVersion(__dirname$1, packageJson.version);
|
|
521
|
+
/**
|
|
522
|
+
* Binary the application is spawned with, so it runs on the same runtime as the CLI
|
|
523
|
+
* rather than on whichever one happens to be named in the source.
|
|
524
|
+
*/ this.runtime = resolveRuntime(process.env, process.execPath);
|
|
525
|
+
/** The running application, while a watch session owns one. */ this.appProcess = null;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Whether this file is what the process was started with.
|
|
530
|
+
*
|
|
531
|
+
* The bin ships behind a `node_modules/.bin` symlink, so `argv[1]` is the link while
|
|
532
|
+
* `import.meta.url` is its target; the two only agree once the link is resolved.
|
|
533
|
+
* Anything undecidable counts as a launch, so the published CLI still starts in cases
|
|
534
|
+
* this cannot classify.
|
|
535
|
+
*/ function isProcessEntry() {
|
|
536
|
+
const invoked = process.argv[1];
|
|
537
|
+
if (invoked === undefined) return true;
|
|
538
|
+
try {
|
|
539
|
+
return samePath(fs.realpathSync(invoked), __filename$1);
|
|
540
|
+
} catch {
|
|
541
|
+
return true;
|
|
477
542
|
}
|
|
478
543
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
544
|
+
/**
|
|
545
|
+
* Whether two resolved paths name the same file.
|
|
546
|
+
*
|
|
547
|
+
* Windows paths differ in case and separator without naming different files — npm's
|
|
548
|
+
* shim passes the script path in whatever form it recorded — and a comparison that
|
|
549
|
+
* missed would leave the CLI exiting without a word, since it would decide it was
|
|
550
|
+
* merely being imported.
|
|
551
|
+
*/ function samePath(left, right) {
|
|
552
|
+
const normalise = (value)=>process.platform === 'win32' ? path.resolve(value).toLowerCase() : value;
|
|
553
|
+
return normalise(left) === normalise(right);
|
|
554
|
+
}
|
|
555
|
+
// Importing this module must not launch the command parser: its own tests do exactly
|
|
556
|
+
// that to inspect how the application is spawned.
|
|
557
|
+
if (isProcessEntry()) {
|
|
558
|
+
const cli = new MeoCordCLI();
|
|
559
|
+
cli.run().catch(async (error)=>{
|
|
560
|
+
cli.logger.error('Failed to initialize CLI:', error?.message || error);
|
|
561
|
+
await wait(100);
|
|
562
|
+
process.exit(1);
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
export { MINIMUM_NODE_MAJOR, MeoCordCLI };
|