neex 0.6.88 → 0.6.90
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/dist/src/commands/dev-commands.js +16 -20
- package/dist/src/dev-manager.js +222 -424
- package/package.json +1 -1
|
@@ -7,20 +7,18 @@ exports.addDevCommands = void 0;
|
|
|
7
7
|
const dev_manager_js_1 = require("../dev-manager.js");
|
|
8
8
|
const logger_manager_js_1 = require("../logger-manager.js");
|
|
9
9
|
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
-
const path_1 = __importDefault(require("path"));
|
|
11
|
-
const fs_1 = __importDefault(require("fs"));
|
|
12
10
|
const figures_1 = __importDefault(require("figures"));
|
|
13
11
|
function addDevCommands(program) {
|
|
14
12
|
let devManager = null;
|
|
15
|
-
|
|
16
|
-
// Ultra-fast Express dev command optimized for speed
|
|
13
|
+
// Enhanced dev command with built-in TypeScript compilation
|
|
17
14
|
program
|
|
18
15
|
.command('dev [file]')
|
|
19
16
|
.description('Start TypeScript development server with hot reloading (default: src/index.ts)')
|
|
20
17
|
.option('-w, --watch <patterns>', 'Watch additional patterns (comma-separated)', 'src/**/*')
|
|
21
18
|
.option('-i, --ignore <patterns>', 'Ignore patterns (comma-separated)', 'node_modules,dist,build,.git,coverage')
|
|
22
19
|
.option('-e, --ext <extensions>', 'File extensions to watch (comma-separated)', 'ts,tsx,js,jsx,json')
|
|
23
|
-
.option('-d, --delay <ms>', 'Delay before restart (ms)', parseInt,
|
|
20
|
+
.option('-d, --delay <ms>', 'Delay before restart (ms)', parseInt, 500)
|
|
21
|
+
.option('--fast', 'Enable fast hot reload (shorter delays)')
|
|
24
22
|
.option('-c, --no-color', 'Disable colored output')
|
|
25
23
|
.option('-q, --quiet', 'Reduce output verbosity')
|
|
26
24
|
.option('-v, --verbose', 'Verbose output')
|
|
@@ -33,13 +31,11 @@ function addDevCommands(program) {
|
|
|
33
31
|
.option('--no-source-maps', 'Disable source maps')
|
|
34
32
|
.option('--transpile-only', 'Skip type checking for faster compilation')
|
|
35
33
|
.option('--node-args <args>', 'Additional Node.js arguments (comma-separated)', '')
|
|
36
|
-
.option('--port <port>', 'Port to use if available', parseInt)
|
|
37
|
-
.option('--host <host>', 'Host to bind to')
|
|
38
|
-
.option('--hot-reload', 'Enable hot reloading for supported frameworks (e.g., Express)')
|
|
39
|
-
.option('--middleware', 'Inject middleware for features like hot reloading')
|
|
40
34
|
.action(async (file, options) => {
|
|
41
35
|
try {
|
|
42
36
|
const targetFile = file || 'src/index.ts';
|
|
37
|
+
// تنظیمات fast mode
|
|
38
|
+
const delay = options.fast ? 200 : options.delay;
|
|
43
39
|
if (!options.quiet) {
|
|
44
40
|
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue(figures_1.default.info)} Starting ${chalk_1.default.cyan('neex dev')} for ${chalk_1.default.cyan(targetFile)}`, 'info');
|
|
45
41
|
if (options.verbose) {
|
|
@@ -56,7 +52,7 @@ function addDevCommands(program) {
|
|
|
56
52
|
watch: options.watch.split(',').map((p) => p.trim()),
|
|
57
53
|
ignore: options.ignore.split(',').map((p) => p.trim()),
|
|
58
54
|
extensions: options.ext.split(',').map((e) => e.trim()),
|
|
59
|
-
delay:
|
|
55
|
+
delay: delay,
|
|
60
56
|
color: options.color,
|
|
61
57
|
quiet: options.quiet,
|
|
62
58
|
verbose: options.verbose,
|
|
@@ -68,11 +64,7 @@ function addDevCommands(program) {
|
|
|
68
64
|
tsConfig: options.tsconfig,
|
|
69
65
|
sourceMaps: options.sourceMaps,
|
|
70
66
|
transpileOnly: options.transpileOnly,
|
|
71
|
-
nodeArgs: options.nodeArgs ? options.nodeArgs.split(',').map((arg) => arg.trim()) : []
|
|
72
|
-
port: options.port,
|
|
73
|
-
host: options.host,
|
|
74
|
-
hotReload: options.hotReload,
|
|
75
|
-
middleware: options.middleware
|
|
67
|
+
nodeArgs: options.nodeArgs ? options.nodeArgs.split(',').map((arg) => arg.trim()) : []
|
|
76
68
|
});
|
|
77
69
|
await devManager.start();
|
|
78
70
|
}
|
|
@@ -91,9 +83,11 @@ function addDevCommands(program) {
|
|
|
91
83
|
.command('dev:clean')
|
|
92
84
|
.description('Clean development server cache and temporary files')
|
|
93
85
|
.action(() => {
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
86
|
+
const path = require('path');
|
|
87
|
+
const fs = require('fs');
|
|
88
|
+
const tempDir = path.join(process.cwd(), '.neex-temp');
|
|
89
|
+
if (fs.existsSync(tempDir)) {
|
|
90
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
97
91
|
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)} Cleaned development cache`, 'info');
|
|
98
92
|
}
|
|
99
93
|
else {
|
|
@@ -105,13 +99,15 @@ function addDevCommands(program) {
|
|
|
105
99
|
.description('Check TypeScript configuration and dependencies')
|
|
106
100
|
.option('--tsconfig <path>', 'Path to TypeScript configuration file')
|
|
107
101
|
.action((options) => {
|
|
102
|
+
const path = require('path');
|
|
103
|
+
const fs = require('fs');
|
|
108
104
|
const configPath = options.tsconfig || 'tsconfig.json';
|
|
109
|
-
if (!
|
|
105
|
+
if (!fs.existsSync(configPath)) {
|
|
110
106
|
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} TypeScript config not found: ${configPath}`, 'error');
|
|
111
107
|
process.exit(1);
|
|
112
108
|
}
|
|
113
109
|
try {
|
|
114
|
-
const config = JSON.parse(
|
|
110
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
115
111
|
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)} TypeScript config is valid`, 'info');
|
|
116
112
|
if (config.compilerOptions) {
|
|
117
113
|
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Compiler Options:')}`, 'info');
|
package/dist/src/dev-manager.js
CHANGED
|
@@ -27,17 +27,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.DevManager = void 0;
|
|
30
|
-
// src/dev-manager.ts -
|
|
30
|
+
// src/dev-manager.ts - Enhanced TypeScript development server with built-in compilation
|
|
31
31
|
const child_process_1 = require("child_process");
|
|
32
32
|
const chokidar_1 = require("chokidar");
|
|
33
33
|
const logger_manager_js_1 = require("./logger-manager.js");
|
|
34
34
|
const chalk_1 = __importDefault(require("chalk"));
|
|
35
|
+
const figures_1 = __importDefault(require("figures"));
|
|
35
36
|
const path_1 = __importDefault(require("path"));
|
|
36
37
|
const fs_1 = __importDefault(require("fs"));
|
|
37
38
|
const lodash_1 = require("lodash");
|
|
38
39
|
const ts = __importStar(require("typescript"));
|
|
39
|
-
const crypto_1 = __importDefault(require("crypto"));
|
|
40
|
-
const net_1 = __importDefault(require("net"));
|
|
41
40
|
class DevManager {
|
|
42
41
|
constructor(options) {
|
|
43
42
|
this.process = null;
|
|
@@ -46,93 +45,10 @@ class DevManager {
|
|
|
46
45
|
this.restartCount = 0;
|
|
47
46
|
this.startTime = null;
|
|
48
47
|
this.moduleCache = new Map();
|
|
49
|
-
this.
|
|
50
|
-
this.serverInfo = null;
|
|
51
|
-
this.hotReloadClient = null;
|
|
52
|
-
this.isExpressApp = false;
|
|
53
|
-
this.lastCompileTime = 0;
|
|
54
|
-
this.performanceMetrics = {
|
|
55
|
-
averageRestartTime: 0,
|
|
56
|
-
totalRestarts: 0,
|
|
57
|
-
cacheHits: 0,
|
|
58
|
-
cacheMisses: 0
|
|
59
|
-
};
|
|
48
|
+
this.fileWatcher = new Map();
|
|
60
49
|
this.options = options;
|
|
61
|
-
this.
|
|
62
|
-
this.debouncedRestart = (0, lodash_1.debounce)(this.restart.bind(this), Math.max(options.delay, 100));
|
|
50
|
+
this.debouncedRestart = (0, lodash_1.debounce)(this.restart.bind(this), options.delay);
|
|
63
51
|
this.tsCompilerOptions = this.loadTsConfig();
|
|
64
|
-
this.setupTempDir();
|
|
65
|
-
this.detectExpressApp();
|
|
66
|
-
this.setupHotReloadClient();
|
|
67
|
-
}
|
|
68
|
-
setupTempDir() {
|
|
69
|
-
if (fs_1.default.existsSync(this.tempDir)) {
|
|
70
|
-
try {
|
|
71
|
-
fs_1.default.rmSync(this.tempDir, { recursive: true, force: true });
|
|
72
|
-
}
|
|
73
|
-
catch (error) {
|
|
74
|
-
// Ignore cleanup errors
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
fs_1.default.mkdirSync(this.tempDir, { recursive: true });
|
|
78
|
-
// Create cache directory
|
|
79
|
-
const cacheDir = path_1.default.join(this.tempDir, 'cache');
|
|
80
|
-
fs_1.default.mkdirSync(cacheDir, { recursive: true });
|
|
81
|
-
}
|
|
82
|
-
detectExpressApp() {
|
|
83
|
-
try {
|
|
84
|
-
const fileContent = fs_1.default.readFileSync(this.options.file, 'utf8');
|
|
85
|
-
this.isExpressApp = /import.*express|require.*express|app\.listen|server\.listen/.test(fileContent);
|
|
86
|
-
if (this.options.verbose) {
|
|
87
|
-
logger_manager_js_1.loggerManager.printLine(`Detected ${this.isExpressApp ? 'Express' : 'Node.js'} application`, 'info');
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
catch (error) {
|
|
91
|
-
this.isExpressApp = false;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
setupHotReloadClient() {
|
|
95
|
-
if (!this.options.hotReload || !this.isExpressApp)
|
|
96
|
-
return;
|
|
97
|
-
this.hotReloadClient = `
|
|
98
|
-
// Hot reload client for Express development
|
|
99
|
-
(function() {
|
|
100
|
-
if (typeof window === 'undefined') return;
|
|
101
|
-
|
|
102
|
-
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
103
|
-
const wsUrl = protocol + '//' + window.location.host + '/__neex_hot_reload';
|
|
104
|
-
|
|
105
|
-
function connect() {
|
|
106
|
-
const ws = new WebSocket(wsUrl);
|
|
107
|
-
|
|
108
|
-
ws.onopen = function() {
|
|
109
|
-
console.log('🔥 Hot reload connected');
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
ws.onmessage = function(event) {
|
|
113
|
-
const data = JSON.parse(event.data);
|
|
114
|
-
|
|
115
|
-
if (data.type === 'reload') {
|
|
116
|
-
console.log('🔄 Reloading page...');
|
|
117
|
-
window.location.reload();
|
|
118
|
-
} else if (data.type === 'error') {
|
|
119
|
-
console.error('🚨 Build error:', data.message);
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
ws.onclose = function() {
|
|
124
|
-
console.log('🔌 Hot reload disconnected, retrying...');
|
|
125
|
-
setTimeout(connect, 1000);
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
ws.onerror = function(error) {
|
|
129
|
-
console.error('❌ Hot reload error:', error);
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
connect();
|
|
134
|
-
})();
|
|
135
|
-
`;
|
|
136
52
|
}
|
|
137
53
|
loadTsConfig() {
|
|
138
54
|
const configPath = this.options.tsConfig || 'tsconfig.json';
|
|
@@ -141,6 +57,8 @@ class DevManager {
|
|
|
141
57
|
module: ts.ModuleKind.CommonJS,
|
|
142
58
|
moduleResolution: ts.ModuleResolutionKind.NodeJs,
|
|
143
59
|
allowJs: true,
|
|
60
|
+
outDir: undefined,
|
|
61
|
+
rootDir: undefined,
|
|
144
62
|
strict: false,
|
|
145
63
|
esModuleInterop: true,
|
|
146
64
|
skipLibCheck: true,
|
|
@@ -150,519 +68,399 @@ class DevManager {
|
|
|
150
68
|
sourceMap: this.options.sourceMaps,
|
|
151
69
|
inlineSourceMap: false,
|
|
152
70
|
inlineSources: false,
|
|
153
|
-
removeComments: false,
|
|
154
|
-
preserveConstEnums: false,
|
|
155
|
-
isolatedModules: true,
|
|
156
|
-
incremental: true,
|
|
157
|
-
tsBuildInfoFile: path_1.default.join(this.tempDir, 'tsconfig.tsbuildinfo'),
|
|
158
71
|
};
|
|
159
72
|
if (fs_1.default.existsSync(configPath)) {
|
|
160
73
|
try {
|
|
161
74
|
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
162
|
-
if (
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
return { ...defaultOptions, ...parsedConfig.options };
|
|
166
|
-
}
|
|
75
|
+
if (configFile.error) {
|
|
76
|
+
logger_manager_js_1.loggerManager.printLine(`Error reading tsconfig.json: ${configFile.error.messageText}`, 'warn');
|
|
77
|
+
return defaultOptions;
|
|
167
78
|
}
|
|
79
|
+
const parsedConfig = ts.parseJsonConfigFileContent(configFile.config, ts.sys, path_1.default.dirname(configPath));
|
|
80
|
+
if (parsedConfig.errors.length > 0) {
|
|
81
|
+
logger_manager_js_1.loggerManager.printLine(`Error parsing tsconfig.json: ${parsedConfig.errors[0].messageText}`, 'warn');
|
|
82
|
+
return defaultOptions;
|
|
83
|
+
}
|
|
84
|
+
// Override some options for development
|
|
85
|
+
const options = { ...parsedConfig.options, ...defaultOptions };
|
|
86
|
+
if (this.options.verbose) {
|
|
87
|
+
logger_manager_js_1.loggerManager.printLine(`Loaded TypeScript config from ${configPath}`, 'info');
|
|
88
|
+
}
|
|
89
|
+
return options;
|
|
168
90
|
}
|
|
169
91
|
catch (error) {
|
|
170
|
-
|
|
92
|
+
logger_manager_js_1.loggerManager.printLine(`Failed to load tsconfig.json: ${error.message}`, 'warn');
|
|
171
93
|
}
|
|
172
94
|
}
|
|
173
95
|
return defaultOptions;
|
|
174
96
|
}
|
|
175
97
|
loadEnvFile() {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const trimmed = line.trim();
|
|
189
|
-
if (trimmed && !trimmed.startsWith('#')) {
|
|
190
|
-
const [key, ...values] = trimmed.split('=');
|
|
191
|
-
if (key && values.length > 0) {
|
|
192
|
-
const value = values.join('=').trim().replace(/^["']|["']$/g, '');
|
|
193
|
-
if (!process.env[key.trim()]) {
|
|
194
|
-
process.env[key.trim()] = value;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
if (this.options.verbose) {
|
|
200
|
-
logger_manager_js_1.loggerManager.printLine(`Loaded environment from ${envFile}`, 'info');
|
|
201
|
-
}
|
|
202
|
-
break;
|
|
203
|
-
}
|
|
204
|
-
catch (error) {
|
|
205
|
-
if (this.options.verbose) {
|
|
206
|
-
logger_manager_js_1.loggerManager.printLine(`Failed to load ${envFile}: ${error.message}`, 'warn');
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
createHash(content) {
|
|
213
|
-
return crypto_1.default.createHash('sha256').update(content).digest('hex').substring(0, 16);
|
|
214
|
-
}
|
|
215
|
-
extractDependencies(sourceCode, filePath) {
|
|
216
|
-
const dependencies = [];
|
|
217
|
-
const importRegex = /(?:import|require)\s*(?:\([^)]*\)|[^;]+?from\s+)?['"`]([^'"`]+)['"`]/g;
|
|
218
|
-
let match;
|
|
219
|
-
while ((match = importRegex.exec(sourceCode)) !== null) {
|
|
220
|
-
const importPath = match[1];
|
|
221
|
-
if (importPath.startsWith('.')) {
|
|
222
|
-
let resolvedPath = path_1.default.resolve(path_1.default.dirname(filePath), importPath);
|
|
223
|
-
// Try to resolve with extensions
|
|
224
|
-
if (!fs_1.default.existsSync(resolvedPath)) {
|
|
225
|
-
for (const ext of this.options.extensions.map(e => `.${e}`)) {
|
|
226
|
-
const withExt = resolvedPath + ext;
|
|
227
|
-
if (fs_1.default.existsSync(withExt)) {
|
|
228
|
-
resolvedPath = withExt;
|
|
229
|
-
break;
|
|
98
|
+
if (this.options.envFile && fs_1.default.existsSync(this.options.envFile)) {
|
|
99
|
+
try {
|
|
100
|
+
const envContent = fs_1.default.readFileSync(this.options.envFile, 'utf8');
|
|
101
|
+
const lines = envContent.split('\n');
|
|
102
|
+
let loadedCount = 0;
|
|
103
|
+
for (const line of lines) {
|
|
104
|
+
const trimmed = line.trim();
|
|
105
|
+
if (trimmed && !trimmed.startsWith('#')) {
|
|
106
|
+
const [key, ...values] = trimmed.split('=');
|
|
107
|
+
if (key && values.length > 0) {
|
|
108
|
+
process.env[key.trim()] = values.join('=').trim().replace(/^["']|["']$/g, '');
|
|
109
|
+
loadedCount++;
|
|
230
110
|
}
|
|
231
111
|
}
|
|
232
112
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
for (const ext of this.options.extensions.map(e => `.${e}`)) {
|
|
236
|
-
const indexPath = path_1.default.join(resolvedPath, 'index' + ext);
|
|
237
|
-
if (fs_1.default.existsSync(indexPath)) {
|
|
238
|
-
resolvedPath = indexPath;
|
|
239
|
-
break;
|
|
240
|
-
}
|
|
241
|
-
}
|
|
113
|
+
if (!this.options.quiet && loadedCount > 0) {
|
|
114
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim(figures_1.default.info)} Loaded ${loadedCount} env variable${loadedCount > 1 ? 's' : ''} from ${path_1.default.basename(this.options.envFile)}`, 'info');
|
|
242
115
|
}
|
|
243
|
-
if (
|
|
244
|
-
|
|
116
|
+
else if (this.options.verbose) {
|
|
117
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim(figures_1.default.info)} No env variables found in ${this.options.envFile}`, 'info');
|
|
245
118
|
}
|
|
246
119
|
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.warning)} Failed to load ${this.options.envFile}: ${error.message}`, 'warn');
|
|
122
|
+
}
|
|
247
123
|
}
|
|
248
|
-
return dependencies;
|
|
249
|
-
}
|
|
250
|
-
extractExports(sourceCode) {
|
|
251
|
-
const exports = [];
|
|
252
|
-
const exportRegex = /export\s+(?:default\s+)?(?:class|function|const|let|var|interface|type|enum)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)/g;
|
|
253
|
-
let match;
|
|
254
|
-
while ((match = exportRegex.exec(sourceCode)) !== null) {
|
|
255
|
-
exports.push(match[1]);
|
|
256
|
-
}
|
|
257
|
-
return exports;
|
|
258
124
|
}
|
|
259
|
-
|
|
125
|
+
compileTypeScript(filePath) {
|
|
260
126
|
const absolutePath = path_1.default.resolve(filePath);
|
|
261
|
-
|
|
127
|
+
// Check cache first
|
|
128
|
+
const cached = this.moduleCache.get(absolutePath);
|
|
129
|
+
if (cached && !this.options.transpileOnly) {
|
|
130
|
+
return cached;
|
|
131
|
+
}
|
|
262
132
|
try {
|
|
263
133
|
const sourceCode = fs_1.default.readFileSync(absolutePath, 'utf8');
|
|
264
|
-
const
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
134
|
+
const dependencies = new Set();
|
|
135
|
+
// Extract import/require dependencies
|
|
136
|
+
const importRegex = /(?:import|require)\s*(?:\(.*?\)|.*?from\s+)['"`]([^'"`]+)['"`]/g;
|
|
137
|
+
let match;
|
|
138
|
+
while ((match = importRegex.exec(sourceCode)) !== null) {
|
|
139
|
+
if (!match[1].startsWith('.'))
|
|
140
|
+
continue;
|
|
141
|
+
const depPath = path_1.default.resolve(path_1.default.dirname(absolutePath), match[1]);
|
|
142
|
+
dependencies.add(depPath);
|
|
270
143
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
}
|
|
280
|
-
|
|
144
|
+
let result;
|
|
145
|
+
if (this.options.transpileOnly) {
|
|
146
|
+
// Fast transpile without type checking
|
|
147
|
+
result = ts.transpileModule(sourceCode, {
|
|
148
|
+
compilerOptions: this.tsCompilerOptions,
|
|
149
|
+
fileName: absolutePath,
|
|
150
|
+
reportDiagnostics: false
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
// Full compilation with type checking
|
|
155
|
+
const program = ts.createProgram([absolutePath], this.tsCompilerOptions);
|
|
156
|
+
const sourceFile = program.getSourceFile(absolutePath);
|
|
157
|
+
if (!sourceFile) {
|
|
158
|
+
throw new Error(`Could not load source file: ${absolutePath}`);
|
|
159
|
+
}
|
|
160
|
+
// Check for errors
|
|
161
|
+
const diagnostics = ts.getPreEmitDiagnostics(program, sourceFile);
|
|
162
|
+
if (diagnostics.length > 0) {
|
|
163
|
+
const errors = diagnostics.map(diagnostic => {
|
|
164
|
+
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
|
|
165
|
+
if (diagnostic.file && diagnostic.start !== undefined) {
|
|
166
|
+
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
|
167
|
+
return `${path_1.default.relative(process.cwd(), diagnostic.file.fileName)}:${line + 1}:${character + 1} - ${message}`;
|
|
168
|
+
}
|
|
169
|
+
return message;
|
|
170
|
+
});
|
|
171
|
+
logger_manager_js_1.loggerManager.printLine(`TypeScript compilation errors:\n${errors.join('\n')}`, 'error');
|
|
172
|
+
if (!this.options.quiet) {
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
result = ts.transpileModule(sourceCode, {
|
|
177
|
+
compilerOptions: this.tsCompilerOptions,
|
|
178
|
+
fileName: absolutePath,
|
|
179
|
+
reportDiagnostics: true
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
const compiled = {
|
|
281
183
|
code: result.outputText,
|
|
282
184
|
map: result.sourceMapText,
|
|
283
|
-
|
|
284
|
-
timestamp: Date.now(),
|
|
285
|
-
dependencies,
|
|
286
|
-
exports
|
|
185
|
+
dependencies
|
|
287
186
|
};
|
|
288
|
-
this.moduleCache.set(absolutePath,
|
|
289
|
-
|
|
290
|
-
const compileTime = Date.now() - compileStart;
|
|
291
|
-
logger_manager_js_1.loggerManager.printLine(`Compiled ${path_1.default.relative(process.cwd(), filePath)} (${compileTime}ms)`, 'info');
|
|
292
|
-
}
|
|
293
|
-
return moduleInfo;
|
|
187
|
+
this.moduleCache.set(absolutePath, compiled);
|
|
188
|
+
return compiled;
|
|
294
189
|
}
|
|
295
190
|
catch (error) {
|
|
296
191
|
logger_manager_js_1.loggerManager.printLine(`Compilation error in ${filePath}: ${error.message}`, 'error');
|
|
297
192
|
throw error;
|
|
298
193
|
}
|
|
299
194
|
}
|
|
300
|
-
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
toRemove.add(absolutePath);
|
|
305
|
-
// Remove any modules that depend on this file (recursive)
|
|
306
|
-
const findDependents = (targetPath) => {
|
|
307
|
-
for (const [cachedPath, info] of this.moduleCache.entries()) {
|
|
308
|
-
if (info.dependencies.includes(targetPath) && !toRemove.has(cachedPath)) {
|
|
309
|
-
toRemove.add(cachedPath);
|
|
310
|
-
findDependents(cachedPath);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
};
|
|
314
|
-
findDependents(absolutePath);
|
|
315
|
-
// Remove all affected modules
|
|
316
|
-
for (const pathToRemove of toRemove) {
|
|
317
|
-
this.moduleCache.delete(pathToRemove);
|
|
318
|
-
}
|
|
319
|
-
if (this.options.verbose && toRemove.size > 1) {
|
|
320
|
-
logger_manager_js_1.loggerManager.printLine(`Invalidated ${toRemove.size} modules`, 'info');
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
async findFreePort(startPort = 3000) {
|
|
324
|
-
return new Promise((resolve, reject) => {
|
|
325
|
-
const server = net_1.default.createServer();
|
|
326
|
-
server.listen(startPort, () => {
|
|
327
|
-
const port = server.address().port;
|
|
328
|
-
server.close(() => resolve(port));
|
|
329
|
-
});
|
|
330
|
-
server.on('error', () => {
|
|
331
|
-
this.findFreePort(startPort + 1).then(resolve).catch(reject);
|
|
332
|
-
});
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
createExecutableFile() {
|
|
336
|
-
const startCompile = Date.now();
|
|
337
|
-
// Always force recompile the main file
|
|
338
|
-
const mainModule = this.compileModule(this.options.file, true);
|
|
339
|
-
// Create a unique temp file
|
|
340
|
-
const timestamp = Date.now();
|
|
341
|
-
const random = Math.random().toString(36).substr(2, 9);
|
|
342
|
-
const tempFile = path_1.default.join(this.tempDir, `server-${timestamp}-${random}.js`);
|
|
343
|
-
let code = mainModule.code;
|
|
344
|
-
// Add hot reload middleware for Express apps
|
|
345
|
-
if (this.isExpressApp && this.options.hotReload) {
|
|
346
|
-
const hotReloadMiddleware = `
|
|
347
|
-
// Hot reload middleware injected by neex
|
|
348
|
-
const originalListen = require('http').Server.prototype.listen;
|
|
349
|
-
require('http').Server.prototype.listen = function(...args) {
|
|
350
|
-
const server = originalListen.apply(this, args);
|
|
351
|
-
|
|
352
|
-
// Setup WebSocket for hot reload
|
|
353
|
-
const WebSocket = require('ws');
|
|
354
|
-
const wss = new WebSocket.Server({ server, path: '/__neex_hot_reload' });
|
|
355
|
-
|
|
356
|
-
global.__neex_hot_reload = (type, data) => {
|
|
357
|
-
wss.clients.forEach(client => {
|
|
358
|
-
if (client.readyState === WebSocket.OPEN) {
|
|
359
|
-
client.send(JSON.stringify({ type, ...data }));
|
|
360
|
-
}
|
|
361
|
-
});
|
|
362
|
-
};
|
|
363
|
-
|
|
364
|
-
return server;
|
|
365
|
-
};
|
|
366
|
-
`;
|
|
367
|
-
code = hotReloadMiddleware + '\n' + code;
|
|
195
|
+
createTempFile(compiled, originalPath) {
|
|
196
|
+
const tempDir = path_1.default.join(process.cwd(), '.neex-temp');
|
|
197
|
+
if (!fs_1.default.existsSync(tempDir)) {
|
|
198
|
+
fs_1.default.mkdirSync(tempDir, { recursive: true });
|
|
368
199
|
}
|
|
369
|
-
|
|
370
|
-
|
|
200
|
+
const tempFile = path_1.default.join(tempDir, `${path_1.default.basename(originalPath, path_1.default.extname(originalPath))}-${Date.now()}.js`);
|
|
201
|
+
let code = compiled.code;
|
|
202
|
+
// Handle source maps
|
|
203
|
+
if (compiled.map && this.options.sourceMaps) {
|
|
371
204
|
const mapFile = tempFile + '.map';
|
|
372
|
-
fs_1.default.writeFileSync(mapFile,
|
|
205
|
+
fs_1.default.writeFileSync(mapFile, compiled.map);
|
|
373
206
|
code += `\n//# sourceMappingURL=${path_1.default.basename(mapFile)}`;
|
|
374
207
|
}
|
|
375
208
|
fs_1.default.writeFileSync(tempFile, code);
|
|
376
|
-
|
|
377
|
-
|
|
209
|
+
return tempFile;
|
|
210
|
+
}
|
|
211
|
+
cleanupTempFiles() {
|
|
212
|
+
const tempDir = path_1.default.join(process.cwd(), '.neex-temp');
|
|
213
|
+
if (fs_1.default.existsSync(tempDir)) {
|
|
378
214
|
try {
|
|
379
|
-
fs_1.default.
|
|
380
|
-
const mapFile = this.currentTempFile + '.map';
|
|
381
|
-
if (fs_1.default.existsSync(mapFile)) {
|
|
382
|
-
fs_1.default.unlinkSync(mapFile);
|
|
383
|
-
}
|
|
215
|
+
fs_1.default.rmSync(tempDir, { recursive: true, force: true });
|
|
384
216
|
}
|
|
385
217
|
catch (error) {
|
|
386
218
|
// Ignore cleanup errors
|
|
387
219
|
}
|
|
388
220
|
}
|
|
389
|
-
this.currentTempFile = tempFile;
|
|
390
|
-
this.lastCompileTime = Date.now() - startCompile;
|
|
391
|
-
return tempFile;
|
|
392
221
|
}
|
|
393
222
|
async getExecuteCommand() {
|
|
394
223
|
if (this.options.execCommand) {
|
|
395
224
|
const parts = this.options.execCommand.split(' ');
|
|
396
|
-
return { command: parts[0], args: parts.slice(1) };
|
|
225
|
+
return { command: parts[0], args: [...parts.slice(1)] };
|
|
397
226
|
}
|
|
398
|
-
|
|
399
|
-
const
|
|
400
|
-
|
|
401
|
-
|
|
227
|
+
// Compile TypeScript file
|
|
228
|
+
const compiled = this.compileTypeScript(this.options.file);
|
|
229
|
+
const tempFile = this.createTempFile(compiled, this.options.file);
|
|
230
|
+
const args = [...this.options.nodeArgs, tempFile];
|
|
231
|
+
if (this.options.inspect) {
|
|
402
232
|
args.unshift('--inspect');
|
|
403
|
-
|
|
233
|
+
}
|
|
234
|
+
if (this.options.inspectBrk) {
|
|
404
235
|
args.unshift('--inspect-brk');
|
|
405
|
-
|
|
236
|
+
}
|
|
237
|
+
// Enable source map support
|
|
238
|
+
if (this.options.sourceMaps) {
|
|
406
239
|
args.unshift('--enable-source-maps');
|
|
407
|
-
|
|
408
|
-
args.unshift('--max-old-space-size=4096');
|
|
409
|
-
args.unshift('--optimize-for-size');
|
|
240
|
+
}
|
|
410
241
|
return { command: 'node', args };
|
|
411
242
|
}
|
|
412
243
|
clearConsole() {
|
|
413
244
|
if (this.options.clearConsole && process.stdout.isTTY) {
|
|
414
|
-
process.stdout.write('\
|
|
245
|
+
process.stdout.write('\x1b[2J\x1b[0f');
|
|
415
246
|
}
|
|
416
247
|
}
|
|
417
248
|
async startProcess() {
|
|
418
249
|
var _a, _b;
|
|
419
|
-
if (this.process)
|
|
250
|
+
if (this.process) {
|
|
420
251
|
return;
|
|
421
|
-
|
|
252
|
+
}
|
|
422
253
|
this.loadEnvFile();
|
|
423
254
|
try {
|
|
424
255
|
const { command, args } = await this.getExecuteCommand();
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
const port = await this.findFreePort(this.options.port || 3000);
|
|
428
|
-
process.env.PORT = port.toString();
|
|
256
|
+
if (this.options.verbose) {
|
|
257
|
+
logger_manager_js_1.loggerManager.printLine(`Executing: ${command} ${args.join(' ')}`, 'info');
|
|
429
258
|
}
|
|
430
259
|
this.process = (0, child_process_1.spawn)(command, args, {
|
|
431
260
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
261
|
+
shell: false,
|
|
432
262
|
env: {
|
|
433
263
|
...process.env,
|
|
434
264
|
NODE_ENV: process.env.NODE_ENV || 'development',
|
|
435
265
|
FORCE_COLOR: this.options.color ? '1' : '0',
|
|
436
|
-
|
|
437
|
-
|
|
266
|
+
TS_NODE_DEV: '1',
|
|
267
|
+
NEEX_DEV: '1'
|
|
438
268
|
},
|
|
439
|
-
detached:
|
|
269
|
+
detached: true
|
|
440
270
|
});
|
|
441
271
|
this.startTime = new Date();
|
|
442
272
|
this.restartCount++;
|
|
443
|
-
// Update performance metrics
|
|
444
|
-
if (this.restartCount > 1) {
|
|
445
|
-
const restartTime = Date.now() - restartStart;
|
|
446
|
-
this.performanceMetrics.averageRestartTime =
|
|
447
|
-
(this.performanceMetrics.averageRestartTime * (this.restartCount - 2) + restartTime) / (this.restartCount - 1);
|
|
448
|
-
this.performanceMetrics.totalRestarts++;
|
|
449
|
-
}
|
|
450
273
|
if (!this.options.quiet) {
|
|
451
274
|
const timestamp = new Date().toLocaleTimeString();
|
|
452
|
-
|
|
453
|
-
const port = process.env.PORT ? `:${process.env.PORT}` : '';
|
|
454
|
-
const url = this.isExpressApp ? `http://localhost${port}` : '';
|
|
455
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green('▶')} ${chalk_1.default.cyan(fileRelative)} ${chalk_1.default.dim(`#${this.restartCount} ${timestamp}`)}`, 'info');
|
|
456
|
-
if (url) {
|
|
457
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue('🌐')} ${chalk_1.default.underline(url)}`, 'info');
|
|
458
|
-
}
|
|
459
|
-
if (this.options.verbose) {
|
|
460
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Compile time:')} ${this.lastCompileTime}ms`, 'info');
|
|
461
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Cache hits:')} ${this.performanceMetrics.cacheHits}`, 'info');
|
|
462
|
-
}
|
|
275
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.play)} Started ${chalk_1.default.cyan(path_1.default.relative(process.cwd(), this.options.file))} ${chalk_1.default.dim(`(${timestamp})`)}`, 'info');
|
|
463
276
|
}
|
|
464
|
-
this.serverInfo = {
|
|
465
|
-
port: parseInt(process.env.PORT || '3000'),
|
|
466
|
-
host: this.options.host || 'localhost',
|
|
467
|
-
pid: this.process.pid,
|
|
468
|
-
startTime: Date.now(),
|
|
469
|
-
restarts: this.restartCount
|
|
470
|
-
};
|
|
471
|
-
// Handle stdout/stderr with better formatting
|
|
472
277
|
(_a = this.process.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
|
|
473
|
-
const output = data.toString();
|
|
474
278
|
if (!this.options.quiet) {
|
|
475
|
-
process.stdout.write(
|
|
279
|
+
process.stdout.write(data);
|
|
476
280
|
}
|
|
477
281
|
});
|
|
478
282
|
(_b = this.process.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
|
|
479
|
-
const output = data.toString();
|
|
480
283
|
if (!this.options.quiet) {
|
|
481
|
-
process.stderr.write(
|
|
284
|
+
process.stderr.write(data);
|
|
482
285
|
}
|
|
483
286
|
});
|
|
484
287
|
this.process.on('error', (error) => {
|
|
485
288
|
logger_manager_js_1.loggerManager.printLine(`Process error: ${error.message}`, 'error');
|
|
486
|
-
if (this.options.hotReload && global.__neex_hot_reload) {
|
|
487
|
-
global.__neex_hot_reload('error', { message: error.message });
|
|
488
|
-
}
|
|
489
289
|
});
|
|
490
290
|
this.process.on('exit', (code, signal) => {
|
|
491
291
|
if (this.process) {
|
|
492
292
|
this.process = null;
|
|
493
|
-
this.
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
293
|
+
if (!this.isRestarting) {
|
|
294
|
+
if (code !== 0) {
|
|
295
|
+
const duration = this.startTime ? Date.now() - this.startTime.getTime() : 0;
|
|
296
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Process exited with code ${code} after ${duration}ms`, 'error');
|
|
297
|
+
}
|
|
497
298
|
}
|
|
498
299
|
}
|
|
499
300
|
});
|
|
500
301
|
}
|
|
501
302
|
catch (error) {
|
|
502
|
-
logger_manager_js_1.loggerManager.printLine(`Failed to start: ${error.message}`, 'error');
|
|
303
|
+
logger_manager_js_1.loggerManager.printLine(`Failed to start process: ${error.message}`, 'error');
|
|
503
304
|
throw error;
|
|
504
305
|
}
|
|
505
306
|
}
|
|
506
307
|
async stopProcess() {
|
|
507
|
-
if (!this.process)
|
|
308
|
+
if (!this.process) {
|
|
508
309
|
return;
|
|
310
|
+
}
|
|
509
311
|
return new Promise((resolve) => {
|
|
312
|
+
if (!this.process) {
|
|
313
|
+
resolve();
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
510
316
|
const proc = this.process;
|
|
511
317
|
this.process = null;
|
|
512
|
-
this.serverInfo = null;
|
|
513
318
|
const cleanup = () => {
|
|
319
|
+
if (!this.options.quiet) {
|
|
320
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.square)} Stopped process`, 'info');
|
|
321
|
+
}
|
|
322
|
+
this.cleanupTempFiles();
|
|
514
323
|
resolve();
|
|
515
324
|
};
|
|
516
325
|
proc.on('exit', cleanup);
|
|
517
326
|
proc.on('error', cleanup);
|
|
518
327
|
try {
|
|
519
|
-
proc.
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
328
|
+
if (proc.pid) {
|
|
329
|
+
// Kill process group
|
|
330
|
+
process.kill(-proc.pid, 'SIGTERM');
|
|
331
|
+
// Fallback after timeout
|
|
332
|
+
setTimeout(() => {
|
|
333
|
+
if (proc.pid && !proc.killed) {
|
|
334
|
+
try {
|
|
335
|
+
process.kill(-proc.pid, 'SIGKILL');
|
|
336
|
+
}
|
|
337
|
+
catch (e) {
|
|
338
|
+
// Ignore
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}, 3000);
|
|
342
|
+
}
|
|
527
343
|
}
|
|
528
344
|
catch (error) {
|
|
345
|
+
// Process might already be dead
|
|
529
346
|
cleanup();
|
|
530
347
|
}
|
|
531
348
|
});
|
|
532
349
|
}
|
|
350
|
+
invalidateCache(filePath) {
|
|
351
|
+
const absolutePath = path_1.default.resolve(filePath);
|
|
352
|
+
// Remove from cache
|
|
353
|
+
this.moduleCache.delete(absolutePath);
|
|
354
|
+
// Remove dependent modules from cache
|
|
355
|
+
for (const [cachedPath, module] of this.moduleCache.entries()) {
|
|
356
|
+
if (module.dependencies.has(absolutePath)) {
|
|
357
|
+
this.moduleCache.delete(cachedPath);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
533
361
|
async restart() {
|
|
534
|
-
if (this.isRestarting)
|
|
362
|
+
if (this.isRestarting) {
|
|
535
363
|
return;
|
|
364
|
+
}
|
|
536
365
|
this.isRestarting = true;
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
if (!this.options.quiet) {
|
|
540
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow('⟳')} Restarting server...`, 'info');
|
|
366
|
+
if (this.options.clearConsole) {
|
|
367
|
+
this.clearConsole();
|
|
541
368
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
global.__neex_hot_reload('reload', {});
|
|
369
|
+
if (!this.options.quiet) {
|
|
370
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.arrowRight)} Restarting due to changes...`, 'info');
|
|
545
371
|
}
|
|
546
|
-
//
|
|
372
|
+
// Clear module cache
|
|
373
|
+
this.moduleCache.clear();
|
|
547
374
|
await this.stopProcess();
|
|
548
|
-
//
|
|
375
|
+
// Small delay to ensure cleanup
|
|
376
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
549
377
|
await this.startProcess();
|
|
550
378
|
this.isRestarting = false;
|
|
551
379
|
}
|
|
552
380
|
setupWatcher() {
|
|
553
381
|
const watchPatterns = this.options.watch;
|
|
554
|
-
// Optimized ignore patterns for Express projects
|
|
555
382
|
const ignored = [
|
|
556
|
-
'node_modules/**',
|
|
557
|
-
'
|
|
558
|
-
'dist/**',
|
|
559
|
-
'build/**',
|
|
560
|
-
'
|
|
561
|
-
'coverage/**',
|
|
562
|
-
'logs/**',
|
|
383
|
+
'**/node_modules/**',
|
|
384
|
+
'**/.git/**',
|
|
385
|
+
'**/dist/**',
|
|
386
|
+
'**/build/**',
|
|
387
|
+
'**/.neex-temp/**',
|
|
563
388
|
'**/*.log',
|
|
564
389
|
'**/*.d.ts',
|
|
565
|
-
|
|
566
|
-
'**/*.tsbuildinfo',
|
|
567
|
-
'**/package-lock.json',
|
|
568
|
-
'**/yarn.lock',
|
|
569
|
-
...this.options.ignore
|
|
390
|
+
...this.options.ignore.map(pattern => `**/${pattern}/**`)
|
|
570
391
|
];
|
|
571
392
|
this.watcher = (0, chokidar_1.watch)(watchPatterns, {
|
|
572
393
|
ignored,
|
|
573
394
|
ignoreInitial: true,
|
|
574
395
|
followSymlinks: false,
|
|
575
396
|
usePolling: false,
|
|
576
|
-
atomic:
|
|
397
|
+
atomic: 200,
|
|
577
398
|
awaitWriteFinish: {
|
|
578
|
-
stabilityThreshold:
|
|
579
|
-
pollInterval:
|
|
399
|
+
stabilityThreshold: 100,
|
|
400
|
+
pollInterval: 50
|
|
580
401
|
}
|
|
581
402
|
});
|
|
582
403
|
this.watcher.on('change', (filePath) => {
|
|
583
|
-
this.
|
|
404
|
+
this.invalidateCache(filePath);
|
|
584
405
|
if (this.options.verbose) {
|
|
585
|
-
logger_manager_js_1.loggerManager.printLine(
|
|
406
|
+
logger_manager_js_1.loggerManager.printLine(`File changed: ${path_1.default.relative(process.cwd(), filePath)}`, 'info');
|
|
586
407
|
}
|
|
587
408
|
this.debouncedRestart();
|
|
588
409
|
});
|
|
589
410
|
this.watcher.on('add', (filePath) => {
|
|
590
411
|
if (this.options.verbose) {
|
|
591
|
-
logger_manager_js_1.loggerManager.printLine(
|
|
412
|
+
logger_manager_js_1.loggerManager.printLine(`File added: ${path_1.default.relative(process.cwd(), filePath)}`, 'info');
|
|
592
413
|
}
|
|
593
414
|
this.debouncedRestart();
|
|
594
415
|
});
|
|
595
416
|
this.watcher.on('unlink', (filePath) => {
|
|
596
|
-
this.
|
|
417
|
+
this.invalidateCache(filePath);
|
|
597
418
|
if (this.options.verbose) {
|
|
598
|
-
logger_manager_js_1.loggerManager.printLine(
|
|
419
|
+
logger_manager_js_1.loggerManager.printLine(`File removed: ${path_1.default.relative(process.cwd(), filePath)}`, 'info');
|
|
599
420
|
}
|
|
600
421
|
this.debouncedRestart();
|
|
601
422
|
});
|
|
602
423
|
this.watcher.on('error', (error) => {
|
|
603
424
|
logger_manager_js_1.loggerManager.printLine(`Watcher error: ${error.message}`, 'error');
|
|
604
425
|
});
|
|
426
|
+
if (this.options.verbose) {
|
|
427
|
+
logger_manager_js_1.loggerManager.printLine(`Watching: ${watchPatterns.join(', ')}`, 'info');
|
|
428
|
+
logger_manager_js_1.loggerManager.printLine(`Ignoring: ${ignored.join(', ')}`, 'info');
|
|
429
|
+
}
|
|
605
430
|
}
|
|
606
431
|
async start() {
|
|
432
|
+
// Check if target file exists
|
|
607
433
|
if (!fs_1.default.existsSync(this.options.file)) {
|
|
608
434
|
throw new Error(`Target file not found: ${this.options.file}`);
|
|
609
435
|
}
|
|
436
|
+
// Validate TypeScript file
|
|
610
437
|
const ext = path_1.default.extname(this.options.file);
|
|
611
|
-
if (!
|
|
438
|
+
if (!['.ts', '.tsx', '.js', '.jsx'].includes(ext)) {
|
|
612
439
|
throw new Error(`Unsupported file extension: ${ext}`);
|
|
613
440
|
}
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
this.
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
logger_manager_js_1.loggerManager.printLine(
|
|
441
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue(figures_1.default.info)} Starting TypeScript development server...`, 'info');
|
|
442
|
+
// Show configuration in verbose mode
|
|
443
|
+
if (this.options.verbose) {
|
|
444
|
+
logger_manager_js_1.loggerManager.printLine(`Target file: ${this.options.file}`, 'info');
|
|
445
|
+
logger_manager_js_1.loggerManager.printLine(`Watch patterns: ${this.options.watch.join(', ')}`, 'info');
|
|
446
|
+
logger_manager_js_1.loggerManager.printLine(`Restart delay: ${this.options.delay}ms`, 'info');
|
|
447
|
+
logger_manager_js_1.loggerManager.printLine(`Transpile only: ${this.options.transpileOnly}`, 'info');
|
|
448
|
+
logger_manager_js_1.loggerManager.printLine(`Source maps: ${this.options.sourceMaps}`, 'info');
|
|
620
449
|
}
|
|
621
450
|
this.setupWatcher();
|
|
622
451
|
await this.startProcess();
|
|
623
|
-
|
|
624
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green('✓')} Watching for changes...`, 'info');
|
|
625
|
-
if (this.options.hotReload) {
|
|
626
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue('🔥')} Hot reload enabled`, 'info');
|
|
627
|
-
}
|
|
628
|
-
}
|
|
452
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)} TypeScript development server started. Watching for changes...`, 'info');
|
|
629
453
|
}
|
|
630
454
|
async stop() {
|
|
631
|
-
|
|
632
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow('⏹')} Stopping development server...`, 'info');
|
|
633
|
-
}
|
|
455
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.warning)} Stopping development server...`, 'info');
|
|
634
456
|
if (this.watcher) {
|
|
635
457
|
await this.watcher.close();
|
|
636
458
|
this.watcher = null;
|
|
637
459
|
}
|
|
638
460
|
await this.stopProcess();
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
try {
|
|
642
|
-
fs_1.default.rmSync(this.tempDir, { recursive: true, force: true });
|
|
643
|
-
}
|
|
644
|
-
catch (error) {
|
|
645
|
-
// Ignore cleanup errors
|
|
646
|
-
}
|
|
461
|
+
if (this.restartCount > 0) {
|
|
462
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue(figures_1.default.info)} Development server stopped after ${this.restartCount} restart(s)`, 'info');
|
|
647
463
|
}
|
|
648
|
-
this.moduleCache.clear();
|
|
649
|
-
if (this.options.verbose) {
|
|
650
|
-
logger_manager_js_1.loggerManager.printLine('Development server stopped', 'info');
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
getServerInfo() {
|
|
654
|
-
return this.serverInfo;
|
|
655
|
-
}
|
|
656
|
-
getPerformanceMetrics() {
|
|
657
|
-
return {
|
|
658
|
-
...this.performanceMetrics,
|
|
659
|
-
modulesCached: this.moduleCache.size,
|
|
660
|
-
lastCompileTime: this.lastCompileTime
|
|
661
|
-
};
|
|
662
|
-
}
|
|
663
|
-
async forceRestart() {
|
|
664
|
-
this.moduleCache.clear();
|
|
665
|
-
await this.restart();
|
|
666
464
|
}
|
|
667
465
|
}
|
|
668
466
|
exports.DevManager = DevManager;
|