neex 0.1.8 → 0.2.6
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/README.md +72 -238
- package/bun.lock +669 -0
- package/dist/src/cli.js +457 -24
- package/dist/src/index.js +1 -3
- package/dist/src/logger.js +0 -36
- package/dist/src/process-manager.js +146 -607
- package/dist/src/runner.js +78 -112
- package/package.json +7 -5
- package/dist/src/commands/dev-commands.js +0 -190
- package/dist/src/commands/index.js +0 -21
- package/dist/src/commands/process-commands.js +0 -679
- package/dist/src/commands/run-commands.js +0 -87
- package/dist/src/commands/server-commands.js +0 -50
- package/dist/src/dev-runner.js +0 -209
- package/dist/src/utils.js +0 -10
- package/dist/src/watcher.js +0 -245
- package/feet.txt +0 -16
|
@@ -1,87 +0,0 @@
|
|
|
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.addRunCommands = void 0;
|
|
7
|
-
const index_js_1 = require("../index.js");
|
|
8
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
-
const figures_1 = __importDefault(require("figures"));
|
|
10
|
-
function addRunCommands(program) {
|
|
11
|
-
let cleanupRunner = null;
|
|
12
|
-
// Main command for sequential execution (similar to run-s)
|
|
13
|
-
program
|
|
14
|
-
.command('run <commands...>')
|
|
15
|
-
.alias('s')
|
|
16
|
-
.description('Run commands sequentially')
|
|
17
|
-
.option('-c, --no-color', 'Disable colored output')
|
|
18
|
-
.option('-t, --no-timing', 'Hide timing information')
|
|
19
|
-
.option('-p, --no-prefix', 'Hide command prefix')
|
|
20
|
-
.option('-s, --stop-on-error', 'Stop on first error')
|
|
21
|
-
.option('-o, --no-output', 'Hide command output')
|
|
22
|
-
.option('-m, --minimal', 'Use minimal output format')
|
|
23
|
-
.action(async (commands, options) => {
|
|
24
|
-
try {
|
|
25
|
-
await (0, index_js_1.run)(commands, {
|
|
26
|
-
parallel: false,
|
|
27
|
-
color: options.color,
|
|
28
|
-
showTiming: options.timing,
|
|
29
|
-
prefix: options.prefix,
|
|
30
|
-
stopOnError: options.stopOnError,
|
|
31
|
-
printOutput: options.output,
|
|
32
|
-
minimalOutput: options.minimal,
|
|
33
|
-
registerCleanup: (cleanup) => { cleanupRunner = cleanup; }
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
catch (error) {
|
|
37
|
-
if (error instanceof Error) {
|
|
38
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} Error: ${error.message}`));
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown error occurred`));
|
|
42
|
-
}
|
|
43
|
-
process.exit(1);
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
// runx command: parallel execution by default (with alias 'p'), can run sequentially with -q
|
|
47
|
-
program
|
|
48
|
-
.command('px <commands...>', { isDefault: true })
|
|
49
|
-
.description('Run commands in parallel (default) or sequentially with -q. This is the default command.')
|
|
50
|
-
.option('-c, --no-color', 'Disable colored output')
|
|
51
|
-
.option('-t, --no-timing', 'Hide timing information')
|
|
52
|
-
.option('-p, --no-prefix', 'Hide command prefix')
|
|
53
|
-
.option('-s, --stop-on-error', 'Stop on first error')
|
|
54
|
-
.option('-o, --no-output', 'Hide command output')
|
|
55
|
-
.option('-m, --minimal', 'Use minimal output format')
|
|
56
|
-
.option('-x, --max-parallel <number>', 'Maximum number of parallel processes', parseInt)
|
|
57
|
-
.option('-q, --sequential', 'Run commands sequentially instead of in parallel')
|
|
58
|
-
.option('--retry <count>', 'Number of times to retry a failed command', parseInt)
|
|
59
|
-
.option('--retry-delay <ms>', 'Delay in milliseconds between retries', parseInt)
|
|
60
|
-
.action(async (commands, options) => {
|
|
61
|
-
try {
|
|
62
|
-
await (0, index_js_1.run)(commands, {
|
|
63
|
-
parallel: !options.sequential,
|
|
64
|
-
maxParallel: options.maxParallel,
|
|
65
|
-
color: options.color,
|
|
66
|
-
showTiming: options.timing,
|
|
67
|
-
prefix: options.prefix,
|
|
68
|
-
stopOnError: options.stopOnError,
|
|
69
|
-
printOutput: options.output,
|
|
70
|
-
minimalOutput: options.minimal,
|
|
71
|
-
retry: options.retry,
|
|
72
|
-
retryDelay: options.retryDelay,
|
|
73
|
-
registerCleanup: (cleanup) => { cleanupRunner = cleanup; }
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
catch (error) {
|
|
77
|
-
if (error instanceof Error) {
|
|
78
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} Error: ${error.message}`));
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown error occurred`));
|
|
82
|
-
}
|
|
83
|
-
process.exit(1);
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
exports.addRunCommands = addRunCommands;
|
|
@@ -1,50 +0,0 @@
|
|
|
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.addServerCommands = void 0;
|
|
7
|
-
const index_js_1 = require("../index.js");
|
|
8
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
-
const figures_1 = __importDefault(require("figures"));
|
|
10
|
-
function addServerCommands(program) {
|
|
11
|
-
let cleanupRunner = null;
|
|
12
|
-
// Servers command specifically optimized for running web servers
|
|
13
|
-
program
|
|
14
|
-
.command('servers <commands...>')
|
|
15
|
-
.alias('srv')
|
|
16
|
-
.description('Run multiple servers with optimized output for API, frontend, etc.')
|
|
17
|
-
.option('-c, --no-color', 'Disable colored output')
|
|
18
|
-
.option('-t, --no-timing', 'Hide timing information')
|
|
19
|
-
.option('-p, --no-prefix', 'Hide command prefix')
|
|
20
|
-
.option('-s, --stop-on-error', 'Stop when any server crashes')
|
|
21
|
-
.option('-x, --max-parallel <number>', 'Maximum number of parallel servers', parseInt)
|
|
22
|
-
.option('-g, --group-output', 'Group outputs by server')
|
|
23
|
-
.action(async (commands, options) => {
|
|
24
|
-
try {
|
|
25
|
-
console.log(chalk_1.default.blue(`${figures_1.default.info} Starting servers in parallel mode...`));
|
|
26
|
-
await (0, index_js_1.run)(commands, {
|
|
27
|
-
parallel: true,
|
|
28
|
-
maxParallel: options.maxParallel,
|
|
29
|
-
color: options.color,
|
|
30
|
-
showTiming: options.timing,
|
|
31
|
-
prefix: options.prefix,
|
|
32
|
-
stopOnError: options.stopOnError,
|
|
33
|
-
printOutput: true,
|
|
34
|
-
registerCleanup: (cleanup) => { cleanupRunner = cleanup; },
|
|
35
|
-
groupOutput: options.groupOutput,
|
|
36
|
-
isServerMode: true
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
catch (error) {
|
|
40
|
-
if (error instanceof Error) {
|
|
41
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} Server Error: ${error.message}`));
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
console.error(chalk_1.default.red(`${figures_1.default.cross} An unknown server error occurred`));
|
|
45
|
-
}
|
|
46
|
-
process.exit(1);
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
exports.addServerCommands = addServerCommands;
|
package/dist/src/dev-runner.js
DELETED
|
@@ -1,209 +0,0 @@
|
|
|
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.DevRunner = void 0;
|
|
7
|
-
// src/dev-runner.ts - Development runner with file watching (nodemon functionality)
|
|
8
|
-
const watcher_1 = require("./watcher");
|
|
9
|
-
const runner_1 = require("./runner");
|
|
10
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
11
|
-
const figures_1 = __importDefault(require("figures"));
|
|
12
|
-
const logger_1 = __importDefault(require("./logger"));
|
|
13
|
-
class DevRunner {
|
|
14
|
-
constructor(options) {
|
|
15
|
-
this.commands = [];
|
|
16
|
-
this.isRunning = false;
|
|
17
|
-
this.restartCount = 0;
|
|
18
|
-
this.startTime = new Date();
|
|
19
|
-
const defaultOptions = {
|
|
20
|
-
parallel: false,
|
|
21
|
-
printOutput: true,
|
|
22
|
-
color: true,
|
|
23
|
-
showTiming: true,
|
|
24
|
-
prefix: true,
|
|
25
|
-
stopOnError: false,
|
|
26
|
-
minimalOutput: false,
|
|
27
|
-
groupOutput: false,
|
|
28
|
-
isServerMode: false,
|
|
29
|
-
restartOnChange: true,
|
|
30
|
-
clearConsole: false,
|
|
31
|
-
signal: 'SIGTERM',
|
|
32
|
-
watch: ['./'],
|
|
33
|
-
ignore: [
|
|
34
|
-
'node_modules/**',
|
|
35
|
-
'.git/**',
|
|
36
|
-
'*.log',
|
|
37
|
-
'dist/**',
|
|
38
|
-
'build/**',
|
|
39
|
-
'coverage/**',
|
|
40
|
-
'.nyc_output/**',
|
|
41
|
-
'*.tmp',
|
|
42
|
-
'*.temp'
|
|
43
|
-
],
|
|
44
|
-
ext: ['js', 'mjs', 'json', 'ts', 'tsx', 'jsx'],
|
|
45
|
-
delay: 1000,
|
|
46
|
-
verbose: false,
|
|
47
|
-
runnerName: 'watch', // Default runner name if not specified
|
|
48
|
-
};
|
|
49
|
-
this.options = {
|
|
50
|
-
...defaultOptions,
|
|
51
|
-
...options
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
setupFileWatcher() {
|
|
55
|
-
const watchOptions = {
|
|
56
|
-
watch: this.options.watch || ['./'],
|
|
57
|
-
ignore: this.options.ignore,
|
|
58
|
-
ext: this.options.ext,
|
|
59
|
-
delay: this.options.delay,
|
|
60
|
-
verbose: this.options.verbose
|
|
61
|
-
};
|
|
62
|
-
this.fileWatcher = new watcher_1.FileWatcher(watchOptions);
|
|
63
|
-
this.fileWatcher.on('change', (event) => {
|
|
64
|
-
if (this.options.restartOnChange && this.isRunning) {
|
|
65
|
-
this.handleFileChange(event);
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
async handleFileChange(event) {
|
|
70
|
-
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
71
|
-
logger_1.default.printLine(`${prefix} File changed: ${chalk_1.default.yellow(event.relativePath)}`, 'info');
|
|
72
|
-
if (this.options.clearConsole) {
|
|
73
|
-
console.clear();
|
|
74
|
-
}
|
|
75
|
-
await this.restart();
|
|
76
|
-
}
|
|
77
|
-
async runCommands() {
|
|
78
|
-
if (this.commands.length === 0) {
|
|
79
|
-
return [];
|
|
80
|
-
}
|
|
81
|
-
this.runner = new runner_1.Runner(this.options);
|
|
82
|
-
try {
|
|
83
|
-
const results = await this.runner.run(this.commands);
|
|
84
|
-
return results;
|
|
85
|
-
}
|
|
86
|
-
catch (error) {
|
|
87
|
-
logger_1.default.printLine(`Execution failed: ${error.message}`, 'error');
|
|
88
|
-
return [];
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
printDevBanner() {
|
|
92
|
-
var _a, _b;
|
|
93
|
-
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
94
|
-
const uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
|
|
95
|
-
const uptimeStr = this.formatUptime(uptime);
|
|
96
|
-
console.log('\n' + chalk_1.default.bgGreen.black(` ${(_a = this.options.runnerName) === null || _a === void 0 ? void 0 : _a.toUpperCase()} MODE `) + '\n');
|
|
97
|
-
if (this.restartCount > 0) {
|
|
98
|
-
console.log(`${prefix} ${chalk_1.default.green(`${figures_1.default.arrowUp} Restarted ${this.restartCount} times`)}`);
|
|
99
|
-
}
|
|
100
|
-
console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Uptime: ${uptimeStr}`)}`);
|
|
101
|
-
console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Watching: ${((_b = this.options.watch) === null || _b === void 0 ? void 0 : _b.join(', ')) || 'current directory'}`)}`);
|
|
102
|
-
if (this.options.ext && this.options.ext.length > 0) {
|
|
103
|
-
console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Extensions: ${this.options.ext.join(', ')}`)}`);
|
|
104
|
-
}
|
|
105
|
-
console.log('');
|
|
106
|
-
}
|
|
107
|
-
formatUptime(seconds) {
|
|
108
|
-
if (seconds < 60) {
|
|
109
|
-
return `${seconds}s`;
|
|
110
|
-
}
|
|
111
|
-
else if (seconds < 3600) {
|
|
112
|
-
const minutes = Math.floor(seconds / 60);
|
|
113
|
-
const remainingSeconds = seconds % 60;
|
|
114
|
-
return `${minutes}m ${remainingSeconds}s`;
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
const hours = Math.floor(seconds / 3600);
|
|
118
|
-
const minutes = Math.floor((seconds % 3600) / 60);
|
|
119
|
-
return `${hours}h ${minutes}m`;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
async start(commands) {
|
|
123
|
-
this.commands = commands;
|
|
124
|
-
this.isRunning = true;
|
|
125
|
-
this.startTime = new Date();
|
|
126
|
-
// Setup file watcher
|
|
127
|
-
this.setupFileWatcher();
|
|
128
|
-
// Print development banner
|
|
129
|
-
this.printDevBanner();
|
|
130
|
-
// Start file watcher
|
|
131
|
-
if (this.fileWatcher) {
|
|
132
|
-
await this.fileWatcher.start();
|
|
133
|
-
}
|
|
134
|
-
// Run initial commands
|
|
135
|
-
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
136
|
-
logger_1.default.printLine(`${prefix} Starting development server...`, 'info');
|
|
137
|
-
await this.runCommands();
|
|
138
|
-
// Set up graceful shutdown
|
|
139
|
-
this.setupGracefulShutdown();
|
|
140
|
-
logger_1.default.printLine(`${prefix} Development server started. Watching for changes...`, 'info');
|
|
141
|
-
logger_1.default.printLine(`${prefix} Press ${chalk_1.default.cyan('Ctrl+C')} to stop`, 'info');
|
|
142
|
-
}
|
|
143
|
-
async restart() {
|
|
144
|
-
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
145
|
-
if (!this.isRunning) {
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
logger_1.default.printLine(`${prefix} Restarting due to file changes...`, 'info');
|
|
149
|
-
this.restartCount++;
|
|
150
|
-
// Stop current processes
|
|
151
|
-
if (this.runner) {
|
|
152
|
-
this.runner.cleanup(this.options.signal);
|
|
153
|
-
}
|
|
154
|
-
// Wait a moment before restarting
|
|
155
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
156
|
-
// Print restart banner
|
|
157
|
-
this.printDevBanner();
|
|
158
|
-
// Run commands again
|
|
159
|
-
await this.runCommands();
|
|
160
|
-
logger_1.default.printLine(`${prefix} Restart completed. Watching for changes...`, 'info');
|
|
161
|
-
}
|
|
162
|
-
async stop() {
|
|
163
|
-
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
164
|
-
if (!this.isRunning) {
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
logger_1.default.printLine(`${prefix} Stopping development server...`, 'info');
|
|
168
|
-
this.isRunning = false;
|
|
169
|
-
// Stop file watcher
|
|
170
|
-
if (this.fileWatcher) {
|
|
171
|
-
this.fileWatcher.stop();
|
|
172
|
-
}
|
|
173
|
-
// Stop current processes
|
|
174
|
-
if (this.runner) {
|
|
175
|
-
this.runner.cleanup(this.options.signal);
|
|
176
|
-
}
|
|
177
|
-
const uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
|
|
178
|
-
const uptimeStr = this.formatUptime(uptime);
|
|
179
|
-
logger_1.default.printLine(`${prefix} ${this.options.runnerName} development server stopped after ${uptimeStr}`, 'info');
|
|
180
|
-
if (this.restartCount > 0) {
|
|
181
|
-
logger_1.default.printLine(`${prefix} Total restarts: ${this.restartCount}`, 'info');
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
setupGracefulShutdown() {
|
|
185
|
-
const handleSignal = (signal) => {
|
|
186
|
-
console.log(`\n${chalk_1.default.yellow(`${figures_1.default.warning} Received ${signal}. Shutting down development server...`)}`);
|
|
187
|
-
this.stop().then(() => {
|
|
188
|
-
process.exit(0);
|
|
189
|
-
});
|
|
190
|
-
};
|
|
191
|
-
process.on('SIGINT', () => handleSignal('SIGINT'));
|
|
192
|
-
process.on('SIGTERM', () => handleSignal('SIGTERM'));
|
|
193
|
-
process.on('SIGQUIT', () => handleSignal('SIGQUIT'));
|
|
194
|
-
}
|
|
195
|
-
isActive() {
|
|
196
|
-
return this.isRunning;
|
|
197
|
-
}
|
|
198
|
-
getUptime() {
|
|
199
|
-
return Math.floor((Date.now() - this.startTime.getTime()) / 1000);
|
|
200
|
-
}
|
|
201
|
-
getRestartCount() {
|
|
202
|
-
return this.restartCount;
|
|
203
|
-
}
|
|
204
|
-
getWatchedFiles() {
|
|
205
|
-
var _a;
|
|
206
|
-
return ((_a = this.fileWatcher) === null || _a === void 0 ? void 0 : _a.getWatchedFiles()) || [];
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
exports.DevRunner = DevRunner;
|
package/dist/src/utils.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.formatDuration = void 0;
|
|
4
|
-
function formatDuration(ms) {
|
|
5
|
-
if (ms < 1000) {
|
|
6
|
-
return `${ms}ms`;
|
|
7
|
-
}
|
|
8
|
-
return `${(ms / 1000).toFixed(2)}s`;
|
|
9
|
-
}
|
|
10
|
-
exports.formatDuration = formatDuration;
|
package/dist/src/watcher.js
DELETED
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
-
};
|
|
28
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.FileWatcher = void 0;
|
|
30
|
-
// src/watcher.ts - File watcher for development (nodemon functionality)
|
|
31
|
-
const fs = __importStar(require("fs"));
|
|
32
|
-
const path = __importStar(require("path"));
|
|
33
|
-
const events_1 = require("events");
|
|
34
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
35
|
-
const logger_1 = __importDefault(require("./logger"));
|
|
36
|
-
class FileWatcher extends events_1.EventEmitter {
|
|
37
|
-
constructor(options) {
|
|
38
|
-
super();
|
|
39
|
-
this.watchers = [];
|
|
40
|
-
this.watchedFiles = new Set();
|
|
41
|
-
this.debounceTimer = null;
|
|
42
|
-
this.isWatching = false;
|
|
43
|
-
this.ignorePatterns = [];
|
|
44
|
-
// Initialize with a copy of user-provided options.
|
|
45
|
-
const processedOptions = { ...options };
|
|
46
|
-
// Apply defaults if properties were not set in the provided 'options'.
|
|
47
|
-
if (processedOptions.watch === undefined) {
|
|
48
|
-
processedOptions.watch = ['./'];
|
|
49
|
-
}
|
|
50
|
-
if (processedOptions.ignore === undefined) {
|
|
51
|
-
processedOptions.ignore = [
|
|
52
|
-
'node_modules/**',
|
|
53
|
-
'.git/**',
|
|
54
|
-
'*.log',
|
|
55
|
-
'dist/**',
|
|
56
|
-
'build/**',
|
|
57
|
-
'coverage/**',
|
|
58
|
-
'.nyc_output/**',
|
|
59
|
-
'*.tmp',
|
|
60
|
-
'*.temp'
|
|
61
|
-
];
|
|
62
|
-
}
|
|
63
|
-
if (processedOptions.ext === undefined) {
|
|
64
|
-
processedOptions.ext = ['js', 'mjs', 'json', 'ts', 'tsx', 'jsx'];
|
|
65
|
-
}
|
|
66
|
-
if (processedOptions.delay === undefined) {
|
|
67
|
-
processedOptions.delay = 1000;
|
|
68
|
-
}
|
|
69
|
-
if (processedOptions.verbose === undefined) {
|
|
70
|
-
processedOptions.verbose = false;
|
|
71
|
-
}
|
|
72
|
-
if (processedOptions.legacyWatch === undefined) {
|
|
73
|
-
processedOptions.legacyWatch = false;
|
|
74
|
-
}
|
|
75
|
-
if (processedOptions.pollingInterval === undefined) {
|
|
76
|
-
processedOptions.pollingInterval = 1000;
|
|
77
|
-
}
|
|
78
|
-
// 'cwd' and 'env' are optional and don't have explicit defaults in this setup;
|
|
79
|
-
// they will be taken from 'options' or remain undefined if not provided.
|
|
80
|
-
this.options = processedOptions;
|
|
81
|
-
this.setupIgnorePatterns();
|
|
82
|
-
}
|
|
83
|
-
setupIgnorePatterns() {
|
|
84
|
-
this.ignorePatterns = (this.options.ignore || []).map(pattern => {
|
|
85
|
-
// Convert glob patterns to regex
|
|
86
|
-
const regexPattern = pattern
|
|
87
|
-
.replace(/\*\*/g, '.*')
|
|
88
|
-
.replace(/\*/g, '[^/]*')
|
|
89
|
-
.replace(/\?/g, '[^/]')
|
|
90
|
-
.replace(/\./g, '\\.');
|
|
91
|
-
return new RegExp(regexPattern, 'i');
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
shouldIgnoreFile(filePath) {
|
|
95
|
-
const relativePath = path.relative(process.cwd(), filePath);
|
|
96
|
-
// Check ignore patterns
|
|
97
|
-
for (const pattern of this.ignorePatterns) {
|
|
98
|
-
if (pattern.test(relativePath) || pattern.test(filePath)) {
|
|
99
|
-
return true;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
// Check file extension
|
|
103
|
-
if (this.options.ext && this.options.ext.length > 0) {
|
|
104
|
-
const ext = path.extname(filePath).slice(1);
|
|
105
|
-
if (!this.options.ext.includes(ext)) {
|
|
106
|
-
return true;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return false;
|
|
110
|
-
}
|
|
111
|
-
async isValidFile(filePath) {
|
|
112
|
-
try {
|
|
113
|
-
const stats = await fs.promises.stat(filePath);
|
|
114
|
-
return stats.isFile();
|
|
115
|
-
}
|
|
116
|
-
catch (_a) {
|
|
117
|
-
return false;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
async watchDirectory(dirPath) {
|
|
121
|
-
try {
|
|
122
|
-
const absolutePath = path.resolve(dirPath);
|
|
123
|
-
if (this.options.verbose) {
|
|
124
|
-
logger_1.default.printLine(`Watching directory: ${chalk_1.default.cyan(absolutePath)}`, 'info');
|
|
125
|
-
}
|
|
126
|
-
const watcher = fs.watch(absolutePath, { recursive: true }, async (eventType, filename) => {
|
|
127
|
-
if (!filename)
|
|
128
|
-
return;
|
|
129
|
-
const fullPath = path.join(absolutePath, filename);
|
|
130
|
-
if (this.shouldIgnoreFile(fullPath)) {
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
if (!(await this.isValidFile(fullPath))) {
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
this.handleFileChange(fullPath, eventType);
|
|
137
|
-
});
|
|
138
|
-
this.watchers.push(watcher);
|
|
139
|
-
}
|
|
140
|
-
catch (error) {
|
|
141
|
-
if (this.options.verbose) {
|
|
142
|
-
logger_1.default.printLine(`Failed to watch directory ${dirPath}: ${error.message}`, 'warn');
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
async watchFile(filePath) {
|
|
147
|
-
try {
|
|
148
|
-
const absolutePath = path.resolve(filePath);
|
|
149
|
-
if (this.shouldIgnoreFile(absolutePath)) {
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
if (!(await this.isValidFile(absolutePath))) {
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
if (this.options.verbose) {
|
|
156
|
-
logger_1.default.printLine(`Watching file: ${chalk_1.default.cyan(absolutePath)}`, 'info');
|
|
157
|
-
}
|
|
158
|
-
const watcher = fs.watch(absolutePath, (eventType) => {
|
|
159
|
-
this.handleFileChange(absolutePath, eventType);
|
|
160
|
-
});
|
|
161
|
-
this.watchers.push(watcher);
|
|
162
|
-
this.watchedFiles.add(absolutePath);
|
|
163
|
-
}
|
|
164
|
-
catch (error) {
|
|
165
|
-
if (this.options.verbose) {
|
|
166
|
-
logger_1.default.printLine(`Failed to watch file ${filePath}: ${error.message}`, 'warn');
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
handleFileChange(filePath, eventType) {
|
|
171
|
-
if (this.options.verbose) {
|
|
172
|
-
logger_1.default.printLine(`File ${eventType}: ${chalk_1.default.yellow(path.relative(process.cwd(), filePath))}`, 'info');
|
|
173
|
-
}
|
|
174
|
-
// Debounce file changes
|
|
175
|
-
if (this.debounceTimer) {
|
|
176
|
-
clearTimeout(this.debounceTimer);
|
|
177
|
-
}
|
|
178
|
-
this.debounceTimer = setTimeout(() => {
|
|
179
|
-
this.emit('change', {
|
|
180
|
-
path: filePath,
|
|
181
|
-
event: eventType,
|
|
182
|
-
relativePath: path.relative(process.cwd(), filePath)
|
|
183
|
-
});
|
|
184
|
-
}, this.options.delay);
|
|
185
|
-
}
|
|
186
|
-
async start() {
|
|
187
|
-
if (this.isWatching) {
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
this.isWatching = true;
|
|
191
|
-
logger_1.default.printLine('Starting file watcher...', 'info');
|
|
192
|
-
for (const watchPath of this.options.watch) {
|
|
193
|
-
const absolutePath = path.resolve(watchPath);
|
|
194
|
-
try {
|
|
195
|
-
const stats = await fs.promises.stat(absolutePath);
|
|
196
|
-
if (stats.isDirectory()) {
|
|
197
|
-
await this.watchDirectory(absolutePath);
|
|
198
|
-
}
|
|
199
|
-
else if (stats.isFile()) {
|
|
200
|
-
await this.watchFile(absolutePath);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
catch (error) {
|
|
204
|
-
logger_1.default.printLine(`Cannot watch ${watchPath}: ${error.message}`, 'warn');
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
const watchedCount = this.watchers.length;
|
|
208
|
-
logger_1.default.printLine(`File watcher started. Monitoring ${chalk_1.default.green(watchedCount)} locations`, 'info');
|
|
209
|
-
if (this.options.ext && this.options.ext.length > 0) {
|
|
210
|
-
logger_1.default.printLine(`Watching extensions: ${chalk_1.default.cyan(this.options.ext.join(', '))}`, 'info');
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
stop() {
|
|
214
|
-
if (!this.isWatching) {
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
-
logger_1.default.printLine('Stopping file watcher...', 'info');
|
|
218
|
-
this.watchers.forEach(watcher => {
|
|
219
|
-
try {
|
|
220
|
-
watcher.close();
|
|
221
|
-
}
|
|
222
|
-
catch (error) {
|
|
223
|
-
// Ignore errors when closing watchers
|
|
224
|
-
}
|
|
225
|
-
});
|
|
226
|
-
this.watchers = [];
|
|
227
|
-
this.watchedFiles.clear();
|
|
228
|
-
this.isWatching = false;
|
|
229
|
-
if (this.debounceTimer) {
|
|
230
|
-
clearTimeout(this.debounceTimer);
|
|
231
|
-
this.debounceTimer = null;
|
|
232
|
-
}
|
|
233
|
-
logger_1.default.printLine('File watcher stopped', 'info');
|
|
234
|
-
}
|
|
235
|
-
isActive() {
|
|
236
|
-
return this.isWatching;
|
|
237
|
-
}
|
|
238
|
-
getWatchedFiles() {
|
|
239
|
-
return Array.from(this.watchedFiles);
|
|
240
|
-
}
|
|
241
|
-
getOptions() {
|
|
242
|
-
return { ...this.options };
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
exports.FileWatcher = FileWatcher;
|
package/feet.txt
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
نمیشه توی این cli که ترکیب nodemon cuncurently pm2 هست بهش یک قابلیت اضافه کنم که یک چیز شبیه به nginx باشه که اگر بدونی هنگام دیپلوی بهینه pm2 با nginx استفاده میکنن منم میخوام وقتی neex دارن توی حالت production به عنوان pm2 ازش استفاده میکنن یک چیزی باشه که توی پروژه های شبیه به nginx درونی در neex که وظیفه نقش: وب سرور معکوس (Reverse Proxy)
|
|
3
|
-
|
|
4
|
-
کارهایی که NGINX انجام میدهد:
|
|
5
|
-
|
|
6
|
-
مدیریت درخواستها به پورت 80 یا 443 (HTTP/HTTPS)
|
|
7
|
-
|
|
8
|
-
به طور پیشفرض، اپلیکیشنهای Node روی پورتهایی مثل 3000 یا 5000 کار میکنند. NGINX روی پورتهای استاندارد (مثل 80 برای HTTP) گوش میدهد و درخواستها را به اپلیکیشن Node فوروارد میکند. لود بالانسینگ (در صورت نیاز)
|
|
9
|
-
|
|
10
|
-
اگر چند نسخه از اپلیکیشن را اجرا کردهاید (مثلاً با PM2 در حالت cluster)، NGINX میتواند بین آنها توزیع بار انجام دهد.
|
|
11
|
-
|
|
12
|
-
سرویسدهی فایلهای استاتیک
|
|
13
|
-
|
|
14
|
-
مثلاً فایلهای HTML، CSS، JS یا تصاویر میتوانند مستقیماً از طریق NGINX سرو شوند بدون درگیر کردن Node.js.
|
|
15
|
-
|
|
16
|
-
مثال کانفیگ ساده در /etc/nginx/sites-available/default: این توی پروژه های neex انجام بده این یک جوری حرفه ای بهش اضافه کن تا به خوبی اتوماتیک این داشته باشه neex
|