neex 0.6.83 → 0.6.87

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.
@@ -7,45 +7,36 @@ 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 figures_1 = __importDefault(require("figures"));
11
10
  function addDevCommands(program) {
12
11
  let devManager = null;
13
- // Enhanced dev command with built-in TypeScript compilation
12
+ // Ultra-fast dev command optimized for speed
14
13
  program
15
14
  .command('dev [file]')
16
- .description('Start TypeScript development server with hot reloading (default: src/index.ts)')
17
- .option('-w, --watch <patterns>', 'Watch additional patterns (comma-separated)', 'src/**/*')
18
- .option('-i, --ignore <patterns>', 'Ignore patterns (comma-separated)', 'node_modules,dist,build,.git,coverage')
19
- .option('-e, --ext <extensions>', 'File extensions to watch (comma-separated)', 'ts,tsx,js,jsx,json')
20
- .option('-d, --delay <ms>', 'Delay before restart (ms)', parseInt, 500)
21
- .option('--fast', 'Enable fast hot reload (shorter delays)')
22
- .option('-c, --no-color', 'Disable colored output')
23
- .option('-q, --quiet', 'Reduce output verbosity')
24
- .option('-v, --verbose', 'Verbose output')
15
+ .description('Start ultra-fast TypeScript development server (like tsx)')
16
+ .option('-w, --watch <patterns>', 'Watch patterns (comma-separated)', 'src/**/*')
17
+ .option('-i, --ignore <patterns>', 'Ignore patterns (comma-separated)', 'node_modules,dist,build,.git')
18
+ .option('-e, --ext <extensions>', 'File extensions to watch', 'ts,tsx,js,jsx')
19
+ .option('-d, --delay <ms>', 'Restart delay in milliseconds', parseInt, 100)
20
+ .option('--fast', 'Ultra-fast mode (50ms delay)')
25
21
  .option('--no-clear', 'Don\'t clear console on restart')
22
+ .option('--no-color', 'Disable colored output')
23
+ .option('-q, --quiet', 'Minimal output')
24
+ .option('-v, --verbose', 'Verbose logging')
26
25
  .option('--inspect', 'Enable Node.js inspector')
27
- .option('--inspect-brk', 'Enable Node.js inspector with break')
28
- .option('--env <file>', 'Load environment variables from file', '.env')
29
- .option('--exec <command>', 'Command to execute instead of built-in TypeScript compilation')
30
- .option('--tsconfig <path>', 'Path to TypeScript configuration file')
31
- .option('--no-source-maps', 'Disable source maps')
32
- .option('--transpile-only', 'Skip type checking for faster compilation')
33
- .option('--node-args <args>', 'Additional Node.js arguments (comma-separated)', '')
26
+ .option('--inspect-brk', 'Enable Node.js inspector with breakpoint')
27
+ .option('--env <file>', 'Environment file to load', '.env')
28
+ .option('--exec <command>', 'Custom command to execute')
29
+ .option('--tsconfig <path>', 'TypeScript config file path')
30
+ .option('--no-source-maps', 'Disable source map generation')
31
+ .option('--transpile-only', 'Skip type checking (faster)')
32
+ .option('--node-args <args>', 'Node.js arguments (comma-separated)', '')
34
33
  .action(async (file, options) => {
35
34
  try {
36
35
  const targetFile = file || 'src/index.ts';
37
- // تنظیمات fast mode
38
- const delay = options.fast ? 200 : options.delay;
36
+ const delay = options.fast ? 50 : options.delay;
39
37
  if (!options.quiet) {
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');
41
- if (options.verbose) {
42
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Features:')}`, 'info');
43
- logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Built-in TypeScript compilation`, 'info');
44
- logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Hot reloading with intelligent caching`, 'info');
45
- logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Source map support`, 'info');
46
- logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Fast transpilation mode`, 'info');
47
- logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Dependency tracking`, 'info');
48
- }
38
+ console.log(''); // Empty line for better visual separation
39
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue('⚡')} ${chalk_1.default.bold('neex dev')} ${chalk_1.default.dim('v1.0.0')} - ${chalk_1.default.cyan(targetFile)}`, 'info');
49
40
  }
50
41
  devManager = new dev_manager_js_1.DevManager({
51
42
  file: targetFile,
@@ -70,58 +61,119 @@ function addDevCommands(program) {
70
61
  }
71
62
  catch (error) {
72
63
  if (error instanceof Error) {
73
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Development server error: ${error.message}`, 'error');
64
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red('✖')} ${error.message}`, 'error');
74
65
  }
75
66
  else {
76
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} An unknown development server error occurred`, 'error');
67
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red('✖')} Unknown error occurred`, 'error');
77
68
  }
78
69
  process.exit(1);
79
70
  }
80
71
  });
81
- // Additional helper commands
72
+ // Clean cache command
82
73
  program
83
74
  .command('dev:clean')
84
- .description('Clean development server cache and temporary files')
75
+ .description('Clean development cache and temp files')
85
76
  .action(() => {
86
77
  const path = require('path');
87
78
  const fs = require('fs');
88
79
  const tempDir = path.join(process.cwd(), '.neex-temp');
80
+ const nodeModulesCache = path.join(process.cwd(), 'node_modules/.cache');
81
+ let cleaned = false;
89
82
  if (fs.existsSync(tempDir)) {
90
83
  fs.rmSync(tempDir, { recursive: true, force: true });
91
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)} Cleaned development cache`, 'info');
84
+ cleaned = true;
85
+ }
86
+ if (fs.existsSync(nodeModulesCache)) {
87
+ try {
88
+ fs.rmSync(nodeModulesCache, { recursive: true, force: true });
89
+ cleaned = true;
90
+ }
91
+ catch (error) {
92
+ // Ignore cache cleanup errors
93
+ }
94
+ }
95
+ if (cleaned) {
96
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green('✓')} Cache cleaned successfully`, 'info');
92
97
  }
93
98
  else {
94
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.info)} No cache to clean`, 'info');
99
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue('ℹ')} No cache to clean`, 'info');
95
100
  }
96
101
  });
102
+ // TypeScript config check
97
103
  program
98
104
  .command('dev:check')
99
- .description('Check TypeScript configuration and dependencies')
100
- .option('--tsconfig <path>', 'Path to TypeScript configuration file')
105
+ .description('Check TypeScript configuration')
106
+ .option('--tsconfig <path>', 'TypeScript config file path')
101
107
  .action((options) => {
102
108
  const path = require('path');
103
109
  const fs = require('fs');
104
110
  const configPath = options.tsconfig || 'tsconfig.json';
105
111
  if (!fs.existsSync(configPath)) {
106
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} TypeScript config not found: ${configPath}`, 'error');
112
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red('✖')} TypeScript config not found: ${configPath}`, 'error');
107
113
  process.exit(1);
108
114
  }
109
115
  try {
110
116
  const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
111
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)} TypeScript config is valid`, 'info');
112
- if (config.compilerOptions) {
113
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Compiler Options:')}`, 'info');
114
- logger_manager_js_1.loggerManager.printLine(` Target: ${config.compilerOptions.target || 'default'}`, 'info');
115
- logger_manager_js_1.loggerManager.printLine(` Module: ${config.compilerOptions.module || 'default'}`, 'info');
116
- logger_manager_js_1.loggerManager.printLine(` Strict: ${config.compilerOptions.strict || 'false'}`, 'info');
117
- logger_manager_js_1.loggerManager.printLine(` Source Maps: ${config.compilerOptions.sourceMap || 'false'}`, 'info');
117
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green('✓')} TypeScript config is valid`, 'info');
118
+ if (config.compilerOptions && !options.quiet) {
119
+ const opts = config.compilerOptions;
120
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Configuration:')}`, 'info');
121
+ logger_manager_js_1.loggerManager.printLine(` Target: ${opts.target || 'ES5'}`, 'info');
122
+ logger_manager_js_1.loggerManager.printLine(` Module: ${opts.module || 'CommonJS'}`, 'info');
123
+ logger_manager_js_1.loggerManager.printLine(` Strict: ${opts.strict || false}`, 'info');
124
+ logger_manager_js_1.loggerManager.printLine(` Source Maps: ${opts.sourceMap || false}`, 'info');
125
+ logger_manager_js_1.loggerManager.printLine(` Skip Lib Check: ${opts.skipLibCheck || false}`, 'info');
118
126
  }
119
127
  }
120
128
  catch (error) {
121
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Invalid TypeScript config: ${error.message}`, 'error');
129
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red('✖')} Invalid TypeScript config: ${error.message}`, 'error');
122
130
  process.exit(1);
123
131
  }
124
132
  });
133
+ // Performance info command
134
+ program
135
+ .command('dev:info')
136
+ .description('Show development server information')
137
+ .action(() => {
138
+ const path = require('path');
139
+ const fs = require('fs');
140
+ const os = require('os');
141
+ console.log('');
142
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue('⚡')} ${chalk_1.default.bold('neex dev')} - Development Server Info`, 'info');
143
+ console.log('');
144
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('System:')}`, 'info');
145
+ logger_manager_js_1.loggerManager.printLine(` Platform: ${os.platform()} ${os.arch()}`, 'info');
146
+ logger_manager_js_1.loggerManager.printLine(` Node.js: ${process.version}`, 'info');
147
+ logger_manager_js_1.loggerManager.printLine(` Memory: ${Math.round(process.memoryUsage().heapUsed / 1024 / 1024)}MB used`, 'info');
148
+ console.log('');
149
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Features:')}`, 'info');
150
+ logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Ultra-fast TypeScript compilation`, 'info');
151
+ logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Intelligent module caching`, 'info');
152
+ logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Hot reload with dependency tracking`, 'info');
153
+ logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Source map support`, 'info');
154
+ logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Memory-optimized processing`, 'info');
155
+ const tsConfigExists = fs.existsSync('tsconfig.json');
156
+ const packageJsonExists = fs.existsSync('package.json');
157
+ console.log('');
158
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Project:')}`, 'info');
159
+ logger_manager_js_1.loggerManager.printLine(` TypeScript Config: ${tsConfigExists ? chalk_1.default.green('✓') : chalk_1.default.red('✖')}`, 'info');
160
+ logger_manager_js_1.loggerManager.printLine(` Package.json: ${packageJsonExists ? chalk_1.default.green('✓') : chalk_1.default.red('✖')}`, 'info');
161
+ if (packageJsonExists) {
162
+ try {
163
+ const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
164
+ if (pkg.name) {
165
+ logger_manager_js_1.loggerManager.printLine(` Name: ${pkg.name}`, 'info');
166
+ }
167
+ if (pkg.version) {
168
+ logger_manager_js_1.loggerManager.printLine(` Version: ${pkg.version}`, 'info');
169
+ }
170
+ }
171
+ catch (error) {
172
+ // Ignore package.json parsing errors
173
+ }
174
+ }
175
+ console.log('');
176
+ });
125
177
  // Cleanup function
126
178
  const cleanupDev = () => {
127
179
  if (devManager) {
@@ -129,20 +181,27 @@ function addDevCommands(program) {
129
181
  devManager = null;
130
182
  }
131
183
  };
132
- // Handle process termination
133
- process.on('SIGINT', () => {
184
+ // Enhanced signal handling
185
+ const handleSignal = (signal) => {
134
186
  if (devManager) {
135
- logger_manager_js_1.loggerManager.printLine(`\n${chalk_1.default.yellow(figures_1.default.warning)} Received SIGINT, shutting down gracefully...`, 'info');
187
+ console.log(''); // New line for better formatting
188
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow('⏹')} Received ${signal}, shutting down...`, 'info');
136
189
  cleanupDev();
137
190
  process.exit(0);
138
191
  }
192
+ };
193
+ process.on('SIGINT', () => handleSignal('SIGINT'));
194
+ process.on('SIGTERM', () => handleSignal('SIGTERM'));
195
+ // Handle uncaught exceptions
196
+ process.on('uncaughtException', (error) => {
197
+ console.error(chalk_1.default.red('Uncaught Exception:'), error);
198
+ cleanupDev();
199
+ process.exit(1);
139
200
  });
140
- process.on('SIGTERM', () => {
141
- if (devManager) {
142
- logger_manager_js_1.loggerManager.printLine(`\n${chalk_1.default.yellow(figures_1.default.warning)} Received SIGTERM, shutting down gracefully...`, 'info');
143
- cleanupDev();
144
- process.exit(0);
145
- }
201
+ process.on('unhandledRejection', (reason, promise) => {
202
+ console.error(chalk_1.default.red('Unhandled Rejection at:'), promise, 'reason:', reason);
203
+ cleanupDev();
204
+ process.exit(1);
146
205
  });
147
206
  return { cleanupDev };
148
207
  }
@@ -27,16 +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 - Enhanced TypeScript development server with built-in compilation
30
+ // src/dev-manager.ts - Ultra-fast TypeScript development server like tsx
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"));
36
35
  const path_1 = __importDefault(require("path"));
37
36
  const fs_1 = __importDefault(require("fs"));
38
37
  const lodash_1 = require("lodash");
39
38
  const ts = __importStar(require("typescript"));
39
+ const crypto_1 = __importDefault(require("crypto"));
40
40
  class DevManager {
41
41
  constructor(options) {
42
42
  this.process = null;
@@ -45,10 +45,23 @@ class DevManager {
45
45
  this.restartCount = 0;
46
46
  this.startTime = null;
47
47
  this.moduleCache = new Map();
48
- this.fileWatcher = new Map();
48
+ this.currentTempFile = null;
49
49
  this.options = options;
50
- this.debouncedRestart = (0, lodash_1.debounce)(this.restart.bind(this), options.delay);
50
+ this.tempDir = path_1.default.join(process.cwd(), '.neex-temp');
51
+ this.debouncedRestart = (0, lodash_1.debounce)(this.restart.bind(this), Math.max(options.delay, 100));
51
52
  this.tsCompilerOptions = this.loadTsConfig();
53
+ this.setupTempDir();
54
+ }
55
+ setupTempDir() {
56
+ if (fs_1.default.existsSync(this.tempDir)) {
57
+ try {
58
+ fs_1.default.rmSync(this.tempDir, { recursive: true, force: true });
59
+ }
60
+ catch (error) {
61
+ // Ignore cleanup errors
62
+ }
63
+ }
64
+ fs_1.default.mkdirSync(this.tempDir, { recursive: true });
52
65
  }
53
66
  loadTsConfig() {
54
67
  const configPath = this.options.tsConfig || 'tsconfig.json';
@@ -57,8 +70,6 @@ class DevManager {
57
70
  module: ts.ModuleKind.CommonJS,
58
71
  moduleResolution: ts.ModuleResolutionKind.NodeJs,
59
72
  allowJs: true,
60
- outDir: undefined,
61
- rootDir: undefined,
62
73
  strict: false,
63
74
  esModuleInterop: true,
64
75
  skipLibCheck: true,
@@ -68,28 +79,22 @@ class DevManager {
68
79
  sourceMap: this.options.sourceMaps,
69
80
  inlineSourceMap: false,
70
81
  inlineSources: false,
82
+ removeComments: false,
83
+ preserveConstEnums: false,
84
+ isolatedModules: true, // For faster compilation
71
85
  };
72
86
  if (fs_1.default.existsSync(configPath)) {
73
87
  try {
74
88
  const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
75
- if (configFile.error) {
76
- logger_manager_js_1.loggerManager.printLine(`Error reading tsconfig.json: ${configFile.error.messageText}`, 'warn');
77
- return defaultOptions;
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');
89
+ if (!configFile.error) {
90
+ const parsedConfig = ts.parseJsonConfigFileContent(configFile.config, ts.sys, path_1.default.dirname(configPath));
91
+ if (parsedConfig.errors.length === 0) {
92
+ return { ...defaultOptions, ...parsedConfig.options };
93
+ }
88
94
  }
89
- return options;
90
95
  }
91
96
  catch (error) {
92
- logger_manager_js_1.loggerManager.printLine(`Failed to load tsconfig.json: ${error.message}`, 'warn');
97
+ // Fall back to defaults
93
98
  }
94
99
  }
95
100
  return defaultOptions;
@@ -99,190 +104,196 @@ class DevManager {
99
104
  try {
100
105
  const envContent = fs_1.default.readFileSync(this.options.envFile, 'utf8');
101
106
  const lines = envContent.split('\n');
102
- let loadedCount = 0;
103
107
  for (const line of lines) {
104
108
  const trimmed = line.trim();
105
109
  if (trimmed && !trimmed.startsWith('#')) {
106
110
  const [key, ...values] = trimmed.split('=');
107
111
  if (key && values.length > 0) {
108
112
  process.env[key.trim()] = values.join('=').trim().replace(/^["']|["']$/g, '');
109
- loadedCount++;
110
113
  }
111
114
  }
112
115
  }
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');
115
- }
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');
118
- }
119
116
  }
120
117
  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');
118
+ if (this.options.verbose) {
119
+ logger_manager_js_1.loggerManager.printLine(`Failed to load ${this.options.envFile}: ${error.message}`, 'warn');
120
+ }
122
121
  }
123
122
  }
124
123
  }
125
- compileTypeScript(filePath) {
126
- const absolutePath = path_1.default.resolve(filePath);
127
- // Check cache first
128
- const cached = this.moduleCache.get(absolutePath);
129
- if (cached && !this.options.transpileOnly) {
130
- return cached;
131
- }
132
- try {
133
- const sourceCode = fs_1.default.readFileSync(absolutePath, 'utf8');
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);
143
- }
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}`);
124
+ createHash(content) {
125
+ return crypto_1.default.createHash('md5').update(content).digest('hex');
126
+ }
127
+ extractDependencies(sourceCode, filePath) {
128
+ const dependencies = [];
129
+ const importRegex = /(?:import|require)\s*(?:\([^)]*\)|[^;]+?from\s+)?['"`]([^'"`]+)['"`]/g;
130
+ let match;
131
+ while ((match = importRegex.exec(sourceCode)) !== null) {
132
+ const importPath = match[1];
133
+ if (importPath.startsWith('.')) {
134
+ let resolvedPath = path_1.default.resolve(path_1.default.dirname(filePath), importPath);
135
+ // Try to resolve with extensions
136
+ if (!fs_1.default.existsSync(resolvedPath)) {
137
+ for (const ext of ['.ts', '.tsx', '.js', '.jsx']) {
138
+ const withExt = resolvedPath + ext;
139
+ if (fs_1.default.existsSync(withExt)) {
140
+ resolvedPath = withExt;
141
+ break;
142
+ }
143
+ }
159
144
  }
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}`;
145
+ // Try index files
146
+ if (!fs_1.default.existsSync(resolvedPath)) {
147
+ for (const ext of ['.ts', '.tsx', '.js', '.jsx']) {
148
+ const indexPath = path_1.default.join(resolvedPath, 'index' + ext);
149
+ if (fs_1.default.existsSync(indexPath)) {
150
+ resolvedPath = indexPath;
151
+ break;
168
152
  }
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
153
  }
175
154
  }
176
- result = ts.transpileModule(sourceCode, {
177
- compilerOptions: this.tsCompilerOptions,
178
- fileName: absolutePath,
179
- reportDiagnostics: true
180
- });
155
+ if (fs_1.default.existsSync(resolvedPath)) {
156
+ dependencies.push(resolvedPath);
157
+ }
158
+ }
159
+ }
160
+ return dependencies;
161
+ }
162
+ compileModule(filePath, forceRecompile = false) {
163
+ const absolutePath = path_1.default.resolve(filePath);
164
+ try {
165
+ const sourceCode = fs_1.default.readFileSync(absolutePath, 'utf8');
166
+ const hash = this.createHash(sourceCode);
167
+ const cached = this.moduleCache.get(absolutePath);
168
+ // Check if we can use cached version
169
+ if (!forceRecompile && cached && cached.hash === hash) {
170
+ return cached;
181
171
  }
182
- const compiled = {
172
+ const dependencies = this.extractDependencies(sourceCode, absolutePath);
173
+ // Fast transpile without type checking for development
174
+ const result = ts.transpileModule(sourceCode, {
175
+ compilerOptions: this.tsCompilerOptions,
176
+ fileName: absolutePath,
177
+ reportDiagnostics: false // Skip diagnostics for speed
178
+ });
179
+ const moduleInfo = {
183
180
  code: result.outputText,
184
181
  map: result.sourceMapText,
182
+ hash,
183
+ timestamp: Date.now(),
185
184
  dependencies
186
185
  };
187
- this.moduleCache.set(absolutePath, compiled);
188
- return compiled;
186
+ this.moduleCache.set(absolutePath, moduleInfo);
187
+ if (this.options.verbose) {
188
+ logger_manager_js_1.loggerManager.printLine(`Compiled ${path_1.default.relative(process.cwd(), filePath)}`, 'info');
189
+ }
190
+ return moduleInfo;
189
191
  }
190
192
  catch (error) {
191
- logger_manager_js_1.loggerManager.printLine(`Compilation error in ${filePath}: ${error.message}`, 'error');
193
+ logger_manager_js_1.loggerManager.printLine(`Compilation error: ${error.message}`, 'error');
192
194
  throw error;
193
195
  }
194
196
  }
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 });
197
+ invalidateModuleCache(filePath) {
198
+ const absolutePath = path_1.default.resolve(filePath);
199
+ // Remove the file itself
200
+ this.moduleCache.delete(absolutePath);
201
+ // Remove any modules that depend on this file
202
+ const toRemove = [];
203
+ for (const [cachedPath, info] of this.moduleCache.entries()) {
204
+ if (info.dependencies.includes(absolutePath)) {
205
+ toRemove.push(cachedPath);
206
+ }
207
+ }
208
+ for (const pathToRemove of toRemove) {
209
+ this.moduleCache.delete(pathToRemove);
210
+ }
211
+ if (this.options.verbose && toRemove.length > 0) {
212
+ logger_manager_js_1.loggerManager.printLine(`Invalidated ${toRemove.length + 1} modules`, 'info');
199
213
  }
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) {
214
+ }
215
+ createExecutableFile() {
216
+ // Always force recompile the main file
217
+ const mainModule = this.compileModule(this.options.file, true);
218
+ // Create a unique temp file
219
+ const timestamp = Date.now();
220
+ const random = Math.random().toString(36).substr(2, 9);
221
+ const tempFile = path_1.default.join(this.tempDir, `main-${timestamp}-${random}.js`);
222
+ let code = mainModule.code;
223
+ // Add source map support
224
+ if (mainModule.map && this.options.sourceMaps) {
204
225
  const mapFile = tempFile + '.map';
205
- fs_1.default.writeFileSync(mapFile, compiled.map);
226
+ fs_1.default.writeFileSync(mapFile, mainModule.map);
206
227
  code += `\n//# sourceMappingURL=${path_1.default.basename(mapFile)}`;
207
228
  }
208
229
  fs_1.default.writeFileSync(tempFile, code);
209
- return tempFile;
210
- }
211
- cleanupTempFiles() {
212
- const tempDir = path_1.default.join(process.cwd(), '.neex-temp');
213
- if (fs_1.default.existsSync(tempDir)) {
230
+ // Clean up old temp file
231
+ if (this.currentTempFile && fs_1.default.existsSync(this.currentTempFile)) {
214
232
  try {
215
- fs_1.default.rmSync(tempDir, { recursive: true, force: true });
233
+ fs_1.default.unlinkSync(this.currentTempFile);
234
+ const mapFile = this.currentTempFile + '.map';
235
+ if (fs_1.default.existsSync(mapFile)) {
236
+ fs_1.default.unlinkSync(mapFile);
237
+ }
216
238
  }
217
239
  catch (error) {
218
240
  // Ignore cleanup errors
219
241
  }
220
242
  }
243
+ this.currentTempFile = tempFile;
244
+ return tempFile;
221
245
  }
222
246
  async getExecuteCommand() {
223
247
  if (this.options.execCommand) {
224
248
  const parts = this.options.execCommand.split(' ');
225
- return { command: parts[0], args: [...parts.slice(1)] };
249
+ return { command: parts[0], args: parts.slice(1) };
226
250
  }
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) {
251
+ const executableFile = this.createExecutableFile();
252
+ const args = [...this.options.nodeArgs, executableFile];
253
+ // Add Node.js flags
254
+ if (this.options.inspect)
232
255
  args.unshift('--inspect');
233
- }
234
- if (this.options.inspectBrk) {
256
+ if (this.options.inspectBrk)
235
257
  args.unshift('--inspect-brk');
236
- }
237
- // Enable source map support
238
- if (this.options.sourceMaps) {
258
+ if (this.options.sourceMaps)
239
259
  args.unshift('--enable-source-maps');
240
- }
241
260
  return { command: 'node', args };
242
261
  }
243
262
  clearConsole() {
244
263
  if (this.options.clearConsole && process.stdout.isTTY) {
245
- process.stdout.write('\x1b[2J\x1b[0f');
264
+ process.stdout.write('\x1Bc'); // Clear screen and scrollback
246
265
  }
247
266
  }
248
267
  async startProcess() {
249
268
  var _a, _b;
250
- if (this.process) {
269
+ if (this.process)
251
270
  return;
252
- }
253
271
  this.loadEnvFile();
254
272
  try {
255
273
  const { command, args } = await this.getExecuteCommand();
256
- if (this.options.verbose) {
257
- logger_manager_js_1.loggerManager.printLine(`Executing: ${command} ${args.join(' ')}`, 'info');
258
- }
259
274
  this.process = (0, child_process_1.spawn)(command, args, {
260
275
  stdio: ['ignore', 'pipe', 'pipe'],
261
- shell: false,
262
276
  env: {
263
277
  ...process.env,
264
278
  NODE_ENV: process.env.NODE_ENV || 'development',
265
279
  FORCE_COLOR: this.options.color ? '1' : '0',
266
- TS_NODE_DEV: '1',
267
- NEEX_DEV: '1'
280
+ NODE_OPTIONS: '--max-old-space-size=4096', // Prevent memory issues
268
281
  },
269
- detached: true
282
+ detached: false // Keep attached for better cleanup
270
283
  });
271
284
  this.startTime = new Date();
272
285
  this.restartCount++;
273
286
  if (!this.options.quiet) {
274
287
  const timestamp = new Date().toLocaleTimeString();
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');
288
+ const fileRelative = path_1.default.relative(process.cwd(), this.options.file);
289
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green('▶')} ${chalk_1.default.cyan(fileRelative)} ${chalk_1.default.dim(`#${this.restartCount} ${timestamp}`)}`, 'info');
276
290
  }
291
+ // Handle stdout/stderr
277
292
  (_a = this.process.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
278
- if (!this.options.quiet) {
279
- process.stdout.write(data);
280
- }
293
+ process.stdout.write(data);
281
294
  });
282
295
  (_b = this.process.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
283
- if (!this.options.quiet) {
284
- process.stderr.write(data);
285
- }
296
+ process.stderr.write(data);
286
297
  });
287
298
  this.process.on('error', (error) => {
288
299
  logger_manager_js_1.loggerManager.printLine(`Process error: ${error.message}`, 'error');
@@ -290,177 +301,147 @@ class DevManager {
290
301
  this.process.on('exit', (code, signal) => {
291
302
  if (this.process) {
292
303
  this.process = null;
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
- }
304
+ if (!this.isRestarting && code !== 0) {
305
+ const duration = this.startTime ? Date.now() - this.startTime.getTime() : 0;
306
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red('✖')} Process exited with code ${code} (${duration}ms)`, 'error');
298
307
  }
299
308
  }
300
309
  });
301
310
  }
302
311
  catch (error) {
303
- logger_manager_js_1.loggerManager.printLine(`Failed to start process: ${error.message}`, 'error');
312
+ logger_manager_js_1.loggerManager.printLine(`Failed to start: ${error.message}`, 'error');
304
313
  throw error;
305
314
  }
306
315
  }
307
316
  async stopProcess() {
308
- if (!this.process) {
317
+ if (!this.process)
309
318
  return;
310
- }
311
319
  return new Promise((resolve) => {
312
- if (!this.process) {
313
- resolve();
314
- return;
315
- }
316
320
  const proc = this.process;
317
321
  this.process = null;
318
322
  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();
323
323
  resolve();
324
324
  };
325
325
  proc.on('exit', cleanup);
326
326
  proc.on('error', cleanup);
327
327
  try {
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
- }
328
+ proc.kill('SIGTERM');
329
+ // Force kill after timeout
330
+ setTimeout(() => {
331
+ if (!proc.killed) {
332
+ proc.kill('SIGKILL');
333
+ }
334
+ }, 1000);
343
335
  }
344
336
  catch (error) {
345
- // Process might already be dead
346
337
  cleanup();
347
338
  }
348
339
  });
349
340
  }
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
- }
361
341
  async restart() {
362
- if (this.isRestarting) {
342
+ if (this.isRestarting)
363
343
  return;
364
- }
365
344
  this.isRestarting = true;
366
- if (this.options.clearConsole) {
367
- this.clearConsole();
368
- }
345
+ // Clear console immediately for better UX
346
+ this.clearConsole();
369
347
  if (!this.options.quiet) {
370
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.arrowRight)} Restarting due to changes...`, 'info');
348
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow('⟳')} Restarting...`, 'info');
371
349
  }
372
- // Clear module cache
373
- this.moduleCache.clear();
350
+ // Stop current process
374
351
  await this.stopProcess();
375
- // Small delay to ensure cleanup
376
- await new Promise(resolve => setTimeout(resolve, 100));
352
+ // Start new process
377
353
  await this.startProcess();
378
354
  this.isRestarting = false;
379
355
  }
380
356
  setupWatcher() {
381
357
  const watchPatterns = this.options.watch;
358
+ // Optimized ignore patterns
382
359
  const ignored = [
383
- '**/node_modules/**',
384
- '**/.git/**',
385
- '**/dist/**',
386
- '**/build/**',
387
- '**/.neex-temp/**',
360
+ 'node_modules/**',
361
+ '.git/**',
362
+ 'dist/**',
363
+ 'build/**',
364
+ '.neex-temp/**',
388
365
  '**/*.log',
389
366
  '**/*.d.ts',
390
- ...this.options.ignore.map(pattern => `**/${pattern}/**`)
367
+ '**/*.map',
368
+ '**/*.tsbuildinfo',
369
+ ...this.options.ignore
391
370
  ];
392
371
  this.watcher = (0, chokidar_1.watch)(watchPatterns, {
393
372
  ignored,
394
373
  ignoreInitial: true,
395
374
  followSymlinks: false,
396
375
  usePolling: false,
397
- atomic: 200,
376
+ atomic: 50,
398
377
  awaitWriteFinish: {
399
378
  stabilityThreshold: 100,
400
379
  pollInterval: 50
401
380
  }
402
381
  });
403
382
  this.watcher.on('change', (filePath) => {
404
- this.invalidateCache(filePath);
383
+ this.invalidateModuleCache(filePath);
405
384
  if (this.options.verbose) {
406
- logger_manager_js_1.loggerManager.printLine(`File changed: ${path_1.default.relative(process.cwd(), filePath)}`, 'info');
385
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue('●')} ${path_1.default.relative(process.cwd(), filePath)}`, 'info');
407
386
  }
408
387
  this.debouncedRestart();
409
388
  });
410
389
  this.watcher.on('add', (filePath) => {
411
390
  if (this.options.verbose) {
412
- logger_manager_js_1.loggerManager.printLine(`File added: ${path_1.default.relative(process.cwd(), filePath)}`, 'info');
391
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green('+')} ${path_1.default.relative(process.cwd(), filePath)}`, 'info');
413
392
  }
414
393
  this.debouncedRestart();
415
394
  });
416
395
  this.watcher.on('unlink', (filePath) => {
417
- this.invalidateCache(filePath);
396
+ this.invalidateModuleCache(filePath);
418
397
  if (this.options.verbose) {
419
- logger_manager_js_1.loggerManager.printLine(`File removed: ${path_1.default.relative(process.cwd(), filePath)}`, 'info');
398
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red('-')} ${path_1.default.relative(process.cwd(), filePath)}`, 'info');
420
399
  }
421
400
  this.debouncedRestart();
422
401
  });
423
402
  this.watcher.on('error', (error) => {
424
403
  logger_manager_js_1.loggerManager.printLine(`Watcher error: ${error.message}`, 'error');
425
404
  });
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
- }
430
405
  }
431
406
  async start() {
432
- // Check if target file exists
433
407
  if (!fs_1.default.existsSync(this.options.file)) {
434
408
  throw new Error(`Target file not found: ${this.options.file}`);
435
409
  }
436
- // Validate TypeScript file
437
410
  const ext = path_1.default.extname(this.options.file);
438
411
  if (!['.ts', '.tsx', '.js', '.jsx'].includes(ext)) {
439
412
  throw new Error(`Unsupported file extension: ${ext}`);
440
413
  }
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');
414
+ // Clear any existing cache
415
+ this.moduleCache.clear();
416
+ this.setupTempDir();
417
+ if (!this.options.quiet) {
418
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue('')} Starting dev server...`, 'info');
449
419
  }
450
420
  this.setupWatcher();
451
421
  await this.startProcess();
452
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)} TypeScript development server started. Watching for changes...`, 'info');
422
+ if (!this.options.quiet) {
423
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green('✓')} Watching for changes...`, 'info');
424
+ }
453
425
  }
454
426
  async stop() {
455
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.warning)} Stopping development server...`, 'info');
427
+ if (!this.options.quiet) {
428
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow('⏹')} Stopping dev server...`, 'info');
429
+ }
456
430
  if (this.watcher) {
457
431
  await this.watcher.close();
458
432
  this.watcher = null;
459
433
  }
460
434
  await this.stopProcess();
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');
435
+ // Cleanup temp files
436
+ if (fs_1.default.existsSync(this.tempDir)) {
437
+ try {
438
+ fs_1.default.rmSync(this.tempDir, { recursive: true, force: true });
439
+ }
440
+ catch (error) {
441
+ // Ignore cleanup errors
442
+ }
463
443
  }
444
+ this.moduleCache.clear();
464
445
  }
465
446
  }
466
447
  exports.DevManager = DevManager;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neex",
3
- "version": "0.6.83",
3
+ "version": "0.6.87",
4
4
  "description": "The Modern Build System for Polyrepo-in-Monorepo Architecture",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",